WDM callback objects

0 Likes

Problem:

I need help using WDM callback objects, a little overview and some direction would be great.

Resolution:

Using WDM Callback Objects

Suppose you have a kernel mode driver that wants to provide notification of an event to other drivers, but the driver has no way of knowing which other drivers in the system might be interested in being notified. In other words, the driver would like to broadcast a message to whichever drivers are ready to receive it. For example, suppose a driver wants to inform related drivers that it has modified some registry setting, but the driver doesn't know which of those related drivers are currently running.

WDM provides a little known mechanism for implementing exactly this kind of communication between drivers. The mechanism uses a system entity somewhat ambiguously named a callback object. A callback object is essentially a named object associated with a list of function addresses. A driver can notify the callback, which causes the system to call each of the functions on the callback's function list. Other drivers can add or remove function addresses from the callback's function list.

To create a callback object, a driver calls ExCreateCallback:

NTSTATUS

ExCreateCallback(

OUT PCALLBACK_OBJECT *CallbackObject,

IN POBJECT_ATTRIBUTES ObjectAttributes,

IN BOOLEAN Create,

IN BOOLEAN AllowMultipleCallbacks

);

The system uses the name in the object attributes structure to create a named callback object. There is a branch of the object directory named "Callback," and this is where callback objects are normally created. The calling driver must specify the full object path when initializing the object attributes. A successful call to ExCreateCallback sets *CallbackObject to a pointer to a system callback object that the driver can later use to notify the callback.

This same service is used by other drivers that want to be called when the object is notified. Such drivers set parameter Create to FALSE.

To register a function to be called when the callback is notified, a driver calls ExRegisterCallback, whose prototype is as follows:

PVOID

ExRegisterCallback(

IN PCALLBACK_OBJECT CallbackObject,

IN PCALLBACK_FUNCTION CallbackFunction,

IN PVOID CallbackContext

);

For this call, CallbackObject is the object pointer obtained from an earlier call to ExCreateCallback, and CallbackFunction is the address of the function to be called when the callback is notified. The callback function must have the following prototype:

VOID CallbackFunction (

IN PVOID CallbackContext,

IN PVOID Argument1,

IN PVOID Argument2

);

To notify the callback, i.e. to cause all registered callback functions to be called, a driver calls ExNotifyCallback:

VOID

ExNotifyCallback(

IN PCALLBACK_OBJECT CallbackObject,

IN PVOID Argument1,

IN PVOID Argument2

);

To remove a function from the list of functions to be called when a callback is notified, a driver calls ExUnregisterCallback. This parameter to this function is the value returned from the call to ExRegisterCallback.

You can view the callback objects that exist on your system (Windows 98 or Windows 2000) using a tool like Winobj, or by using the objdir command in SoftICE™. You will probably see these three callbacks, which are created by the system: SetSystemTime, SuspendHibernateSystem, and SetSystemInformation.

Any driver can register a function to be called when the system notifies these callback objects. For example, if you wanted to get notification of whenever the system time was changed, you would add this code to your driver:

At global scope:

PVOID gUnregisterToken=0;

VOID MySetTimeFunction(PVOID ctx, PVOID arg1, PVOID arg2)

{

DbgPrint("The set time function was called

");

}

During initialization:

NTSTATUS status;

OBJECT_ATTRIBUTES Oa;

UNICODE_STRING CallbackName;

PCALLBACK_OBJECT pSetTimeCallback;

RtlInitUnicodeString(&CallbackName,L"\\Callback\\SetSystemTime");

InitializeObjectAttributes(

&Oa,

&CallbackName,

OBJ_CASE_INSENSITIVE,

NULL,

NULL

);

status = ExCreateCallback(&pSetTimeCallback, &Oa, FALSE, FALSE);

if ( NT_SUCCESS(status) && pSetTimeCallback )

{

gUnregisterToken =

ExRegisterCallback(

pSetTimeCallback,

MySetTimeFunction,

NULL);

}

In your unload or remove routine:

if ( gUnregisterToken )

ExUnregisterCallback(gUnregisterToken);

Two final notes about callbacks:

Compuware's DriverWorks™ class library will provide a class that wraps up callback functionality in an easy to use C class.

The callback services exist on NT 4.0, but are stubbed out.

Old KB# 11875
Comment List
Anonymous
Related Discussions
Recommended