Basic KMDF question - WDF_DECLARE_CONTEXT_TYPE_WITH_NAME

I am really new to KMDF and while I am looking into USBSamp samples from WDK6000 I came upon a quetion about the powerful macro : WDF_DECLARE_CONTEXT_TYPE_WITH_NAME

There are 4 declarations in the <private.h>

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(
FILE_CONTEXT, GetFileContext)

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(
DEVICE_CONTEXT, GetDeviceContext)

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(REQUEST_CONTEXT , GetRequestContext)

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WORKITEM_CONTEXT, GetWorkItemContext)

Whenever you need one of the context we just call the casting function of the macro like below.

pDeviceContext = GetDeviceContext(Device);
fileContext = GetFileContext(WdfRequestGetFileObject(Request));

Then what kind of argument can go in the casting function to call GetDeviceContext(??) or GetFileContext(??) ?

In this example they used WDFDEVICE for GetDeviceContext() and WDFFILEOBJECT for GetFileContext()

Thank you.</private.h>

The contexts you retrieve with these functions (which I prefer to think of as accessor or retrieval functions) have to be placed in a KMDF object in the first place.

In these cases, if you look at the object attributes with which the device and file objects are created, you will see the underlying types referenced- typically with WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE.

The argument to the accessor function for a typed context has to be derived from WDFOBJECT (and all WDF objects are).

If you wish to use these context types in other objects that already have a different context type from the time they were created, you can always place them there, using WdfObjectAllocateContext. If no context of the given type exists in a WDF object, you will get a NULL pointer back.

Primary exception to the above that I can recall is that for framework created requests (since it creates them, not your own code), you must specify any per-request context type you use in WdfDeviceInitSetRequestAttributes.

I’m rather fond of KMDF context types, they’re virtually leak-free and you can hang as many as you need off of any convenient object. I find it really simplifies some otherwise complicated problems.

I find they’re particularly useful in C++ (the generator macro works wine with class::method notation, so a static class member for an accessor, coupled with a placement new that uses it is a fine pattern for C++), for any surviving aficionados of the language that is not to be named…

Thank you Bob for your detailed explanation.

WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE is filling the type of accessor function. So after finishing set this, I can access this WDFOBJECT with feeding same argument. Is it right?

Thank you.

>>
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE is filling the type of accessor function. So after finishing set this, I can access this WDFOBJECT with feeding same argument. Is it right?
<<

Just to be clear, you have to create the object first. The macro simply lets the creation function know what the main context type for the new WDF object is going to be- nothing is created until the object is created.

The usual pattern is (hope my pseudo-code is clear enough, here):

In header:
// Define “MyType” in some way
WDF_DECLARE_CONTEXT_TYPE(MyType) or WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(MyType, GetMyType) for the type.

In implementation:

WDF_OBJECT_ATTRIBUTES attributes;
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT(attributes, MyType); OR
WDF_OBJECT_ATTRIBUTES_INIT(attributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(attributes, MyType);

WDFXXX Handle; // XXX being a WDF object type placeholder here

WdfXxxCreate(…, &attributes, …, &Handle);

Assuming the preceding call succeeded, you may then use:

MyType* MyStuff = GetMyType(Handle);

If you are considering multiple types on an object, then you create them with an existing object handle and WdfObjectAllocateContext. Once this succeeds, then the accessor function will retrieve it.

You can use the accessor function on any valid object handle, but if the object contains no context information of the type you’re requesting, it will return NULL.