WDF对象上下文2

    上回讲到ToasterFdoGetData内部通过调用WdfObjectGetTypedContextWorker以获得自定义Context结构,当时由于篇幅所限,没有展开分析WdfObjectGetTypedContextWorker的实现。为了填补这个空白,乃有此文。其实<竹林蹊径>中提到过函数WdfObjectGetTypedContextWorker,只是作者成书之时限制太多,因此没有深入分析。我相信以作者的文笔,应该更让读者收益,但是,既然作者没有再版,那就先由我做个引子吧。

     WdfObjectGetTypedContextWorker的实现倒也不难,且核心代码不过寥寥数行:

WDFAPI    
PVOID
FASTCALL
WDFEXPORT(WdfObjectGetTypedContextWorker)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFOBJECT Handle,
    __in
    PCWDF_OBJECT_CONTEXT_TYPE_INFO TypeInfo
    )
{
    FxContextHeader* pHeader;
    FxObject* pObject;
    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    WDFOBJECT_OFFSET offset;

    offset = 0;
    pObject = FxObject::_GetObjectFromHandle(Handle, &offset); //从WDF句柄获得FxObject对象地址,其实这个函数内部仅仅做了几次位运算
    pFxDriverGlobals = pObject->GetDriverGlobals(); //FxObject!m_Globals域指向驱动程序的FxDriverGlobals全局变量

    pHeader = pObject->GetContextHeader(); //3).

    for ( ; pHeader != NULL; pHeader = pHeader->NextHeader) { //4)
        if (pHeader->ContextTypeInfo == TypeInfo) {
            return &pHeader->Context[0];
        }
    }
    //...
    return NULL;
}

先给出WDF源码给出的上下文结构,以及一个宏,然后再慢慢缕清WdfObjectGetTypedContextWorker的脉络:

struct FxContextHeader {
    // Backpointer to the object that this is a context for
    FxObject* Object;

    // Next context in the chain
    FxContextHeader* NextHeader;

    // Function to call when object is deleted
    PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback; //<---------熟悉的结构体成员#1
    // Function to call when the object's memory is destroyed
    // when the last reference count goes to zero
    PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback;  //<---------熟悉的结构体成员#2

    // Type associated with this context
    PCWDF_OBJECT_CONTEXT_TYPE_INFO ContextTypeInfo;

    // Start of client's context
    DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) ULONG_PTR Context[1];
};

除了定义FxContextHeader结构,源码还额外给出了基于x86架构的FxObject内存布局示意图:

/**

 Framework Object Memory Layout (x86 32 bit)

 Note: The handle is XOR'ed with (-1) to scramble it

                        ---------------------- handle + sizeof(ContextSize) <-----内存高地址
                        |                    |
                        | Drivers Context    |
                        | Memory             |
                        |                    |
WDFOBJECT handle ->     ---------------------- this + sizeof(C++_OBJECT) + _extrasize + sizeof(FxContextHeader)
                        |                    |
                        | FxContextHeader    |
                        |                    |
                        ---------------------- this + sizeof(C++_OBJECT) + _extrasize (m_ObjectSize)
                        |                    |
                        |  C++ Object        |
                        |  "extra" memory    |
                        |                    |
                        |--------------------| this + sizeof(C++_OBJECT)
                        |                    |
                        |  C++ Object        |
                        |                    |
                        |                    |
Base Pool Allocation -> ---------------------- this         <-----内存低地址
C++ this pointer

**/

示意图中,1.最底部标有C++ Object的是FxObject对象所占据的空间;2.往上C++ Object "extra" memory按照我的理解,可能是继承FxObject的子类对象所占有的空间,如FxDevice/FxDriver对象,它们都继承自FxObject,所以FxObject是它们的公共头结构----共性,然而,每个子对象又各实现所特有的特性,这部分特性所需的空间占据"extra" memory部分;3.再往上,是自定义的对象上下文结构。

另外,在WdfObjectGetTypedContextWorker函数中,我们还看到一个函数GetContextHeader,它是内联函数,定义如下:

#define WDF_PTR_ADD_OFFSET_TYPE(_ptr, _offset, _type) \
    ((_type) (((PUCHAR) (_ptr)) + (_offset)))

#define GET_CONTEXT_HEADER() WDF_PTR_ADD_OFFSET_TYPE(this, m_ObjectSize, FxContextHeader*)

__inline
    FxContextHeader*
    GetContextHeader(
        VOID
        )
    {
        if (m_ObjectSize == 0) {
            return NULL;
        }
        else {
            return GET_CONTEXT_HEADER();
        }
    }
结合示意图,要理解这个函数应该不成问题,我就不废话了~让我们回到FxContextHeader结构的定义,其头部有个指针
FxObject* Object;

注释指明它的作用为后向指针,指向前面FxObject对象头部,这倒是个好信号:驱动中获得Context后,就能顺带获得整个对象了! 一个FxObject可能具有多个Context结构,WDF框架使用链表管理这串Context结构,所以代码的最后根据传入的TypeInfo比较各个Context!TypeInfo域。这么看来TypeInfo颇有ID的感觉?

大家可以翻看前一篇WDF对象上下文1 在定义Context全局变量时,其中已包含了TypeInfo的定义:

WDF_DECLARE_TYPE_AND_GLOBALS(                                           
    FDO_DATA,                                                       
    &_WDF_FDO_DATA_TYPE_INFO,                            
    NULL,                                                               
    ".data")                                      
                                                                        
WDF_DECLARE_CASTING_FUNCTION(FDO_DATA, ToasterFdoGetData)
至此,大家应该知道通过WdfObjectGetTypedContextWorker函数Get上下文的过程了,有Get()则必然有Set(),下一篇我来讲讲所谓的Set()。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值