KS-AUDIO-COM
+ -

CUnknown和INonDelegatingUnknown

2022-08-23 26 0

CUnknown继承于INonDelegatingUnknown,并且CUnknown是所有COM的基类。

class CUnknown : public INonDelegatingUnknown

而INonDelegatingUnknown是一个虚基结构体。

INonDelegatingUnknown

basetype.h

DECLARE_INTERFACE(INonDelegatingUnknown)
{
    STDMETHOD_(NTSTATUS,NonDelegatingQueryInterface)
    (   THIS_
        _In_             REFIID,
        _COM_Outptr_     PVOID *
    )   PURE;

    STDMETHOD_(ULONG,NonDelegatingAddRef)
    (   THIS
    )   PURE;

    STDMETHOD_(ULONG,NonDelegatingRelease)
    (   THIS
    )   PURE;
};

typedef INonDelegatingUnknown *PNONDELEGATINGUNKNOWN;

以上的宏:

#define __STRUCT__ struct
#define interface __STRUCT__

#define DECLSPEC_NOVTABLE   __declspec(novtable)

#define DECLARE_INTERFACE(iface)    interface DECLSPEC_NOVTABLE iface

故DECLARE_INTERFACE(INonDelegatingUnknown)宏展开为:

struct __declspec(novtable) INonDelegatingUnknown

而STDMETHOD_宏定义如下:

#define DECLSPEC_NOTHROW   __declspec(nothrow)
#define COM_DECLSPEC_NOTHROW DECLSPEC_NOTHROW

#define STDMETHODCALLTYPE       __stdcall
#define PURE                    = 0

#define STDMETHOD_(type,method)  virtual COM_DECLSPEC_NOTHROW type STDMETHODCALLTYPE method

故 STDMETHOD_(NTSTATUS,NonDelegatingQueryInterface)展开如下:

virtual 
_declspec(nothrow) 
NTSTATUS 
__stdcall 
NonDelegatingQueryInterface
(   THIS_
    _In_             REFIID,
    _COM_Outptr_     PVOID *
)   = 0;

可以看到,其实现的是一个纯虚函数

CUnknown

class CUnknown : public INonDelegatingUnknown
{
private:

    LONG            m_lRefCount;        // Reference count.
    PUNKNOWN        m_pUnknownOuter;    // Outer IUnknown.

public:

    /*************************************************************************
        * CUnknown methods.
     */
    CUnknown(PUNKNOWN pUnknownOuter);
        virtual ~CUnknown(void);
    PUNKNOWN GetOuterUnknown(void)
    {
        return m_pUnknownOuter;
    }

    /*************************************************************************
         * INonDelegatingUnknown methods.
     */
     STDMETHODIMP_(ULONG) NonDelegatingAddRef
    (   void
    );
    STDMETHODIMP_(ULONG) NonDelegatingRelease
    (   void
    );
    STDMETHODIMP_(NTSTATUS) NonDelegatingQueryInterface
        (
                __in REFIID          rIID,
                __out PVOID *     ppVoid
        );
};

可以看到,CUnknown重写了INonDelegatingUnknown的三个方法,当然CUnknown也实现了自己的构造函数(带一个参数)和对构造函数指针的引用函数GetOuterUnknown。

CUnkonw的具体实现可参考WDK的stdunk.cpp文件

CUnknown构造和成员函数

/*****************************************************************************
 * CUnknown::CUnknown()
 *****************************************************************************
 * Constructor.
 */
CUnknown::CUnknown(PUNKNOWN pUnknownOuter)
:   m_lRefCount(0)
{
    if (pUnknownOuter)
    {
        m_pUnknownOuter = pUnknownOuter;
    }
    else
    {
        m_pUnknownOuter = PUNKNOWN(dynamic_cast<PNONDELEGATINGUNKNOWN>(this));
    }
}

/*****************************************************************************
 * CUnknown::~CUnknown()
 *****************************************************************************
 * Destructor.
 */
CUnknown::~CUnknown(void)
{
}

CUnknown继承的三个虚函数实现

  • NonDelegatingAddRef:增加引用计数
  • NonDelegatingQueryInterface:减少引用计数
  • NonDelegatingQueryInterface:通过接口GUID返回接口

/*****************************************************************************
 * CUnknown::NonDelegatingAddRef()
 *****************************************************************************
 * Register a new reference to the object without delegating to the outer
 * unknown.
 */
STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef(void)
{
    ASSERT(m_lRefCount >= 0);

    InterlockedIncrement(&m_lRefCount);

    return ULONG(m_lRefCount);
}

/*****************************************************************************
 * CUnknown::NonDelegatingRelease()
 *****************************************************************************
 * Release a reference to the object without delegating to the outer unknown.
 */
STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease(void)
{
    ASSERT(m_lRefCount > 0);

    if (InterlockedDecrement(&m_lRefCount) == 0)
    {
        m_lRefCount++;
        delete this;
        return 0;
    }

    return ULONG(m_lRefCount); 
}

/*****************************************************************************
 * CUnknown::NonDelegatingQueryInterface()
 *****************************************************************************
 * Obtains an interface.
 */
STDMETHODIMP_(NTSTATUS) CUnknown::NonDelegatingQueryInterface
(
    REFIID  rIID,
    PVOID * ppVoid
)
{
    ASSERT(ppVoid);

    if (IsEqualGUIDAligned(rIID,IID_IUnknown))
    {
        *ppVoid = PVOID(PUNKNOWN(this));
    }
    else
    {
        *ppVoid = NULL;
    }

    if (*ppVoid)
    {
        PUNKNOWN(*ppVoid)->AddRef();
        return STATUS_SUCCESS;
    }

    return STATUS_INVALID_PARAMETER;
}

0 篇笔记 写笔记

IRP的完成IoCompleteRequest
每当一个IRP在下层设备层完成时,是需要调用IoCompleteRequest来实现IRP的完成,这个完成其实是实现对执行的IRP的善后操作,这个操作其实是一个宏,真实函数数是IofCompleteRequest。#define IoCompleteRequest IofCompleteReque......
IoCopyCurrentIrpStackLocationToNext和IoSkipCurrentIrpStackLocation操作的IO_STACK_LOCATION有什么区别
在Windows驱动中,传递IPR一般有两种操作:一种是调用IoSkipCurrentIrpStackLocation,表示跳过本层驱动的操作,直接转发至下层: IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(FDODeviceEx......
IRP完成APC执行函数IopCompleteRequest
IRP在完成时调用IoCompleteRequest,其最终会执行一个APC调用,该调用的函数名为IopCompleteRequest。其调用APC调用时的代码如下:KeInitializeApc(&Irp->Tail.Apc, &......
WDDM 显卡及显卡驱动的分类
随着显卡的技术的发展,对于三维图形处理的功能越来越强,所以直接导致的一个结果就是显卡的数学处理能力(浮点计算)的功能越来越强。所以对于一些需要进行大量数学计算的模块,将这些功能交由显卡来进行处理相比较CPU更能大幅度提高效率。如现在的人功智能AI,还有前几年火热的挖矿…这些都是需要复杂的数学计算......
PortClass中的COM
一般的Windows驱动我们采用的是WDM驱动架构,最近的Windows驱动架构WDF也是建立在WDM基础上的。这些基于WDM的一般设备驱动可以应付大部分的设备驱动,如串口,PCI,USB等通用设备驱动。但是微软的关于流的处理的一些服务及驱动采用的面向对象的设计方法,是基于COM进行开发的,典型的像......
PortClass流式音频架构
在Windows操作系统中,PortClass仅用于纯音频设备驱动的开发,其配合内核流式驱动模块ks.sys实现音频设备驱动的开发。内核流式驱动模块ks.sys包含两部分内容,一部分是提供内核通用的流式驱动模块,另一部分是avstream模块。avstream模块即可用于开发音频设备驱动,也可用......
PortClass音频驱动程序架构
音频适配器驱动程序是最低层的音频驱动,对下实现对硬件的操作,以上提供端口驱动的函数回调。所以音频适配器驱动的代码来自两部分,一部分是厂商提供的硬件驱动代码,一般是由portclass提供的通用音频驱动模块。入口函数因为适配器驱动程序是作为内核模式驱动程序服务安装的,所以和其它驱动一样,由操作系统加......
IRP完成例程IoSetCompletionRoutine的设计和实现原理
在进行IRP下层传递时,通过上一节可知道,一种中使用IoCopyCurrentIrpStackLocationToNext,另一种是IoSkipCurrentIrpStackLocation。其中在使用IoCopyCurrentIrpStackLocationToNext表示的是对当前的IRP当留当......
PortClass提供的音频MINI端口驱动
PortClass提供了以下几种MiniPort驱动类型。Cyclic DMA wave input and output:此类Mini端口驱动程序支持访问ISA和其他声卡的基于DMA的wave I/O功能。接口专门处理循环(autoinit)DMA缓冲区,流问题由端口驱动程序解决。Scatt......
PortClass InitializeAdapterDriver函数
InitializeAdapterDriver函数是PortClass驱动DriverEntry调用的第一个函数,也是惟一的函数。该函数的功能和其它的MINI小端口驱动一样,都是初始化相应的MIN小端口驱动框架的“结构体”,并使用系统提供的类驱动的回调函数来初始化相应的IRP回调函数,而我们函数的第......
PortClass PcAddAdapterDevice函数
PcAddAdapterDevice函数在WDK中声名如下:PORTCLASSAPI NTSTATUS NTAPI PcAddAdapterDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalD......
PortClass 自定义启动函数StartDevice
通过上一节知道,IPR_MN_START_DEVICE的回调函数其实是PnpStartDevice,不过兜兜转转,最终执行的是我们在通过在PcAddAdapterDevcie函数的第三参数StartDevice。当然在执行我们自定义的这个StartDevice函数之前,PortClass框架类已经通......
PortClass 电源管理
电源管理实现的COM是AdapterPowerMgr,继承于IAdapterPowerManagement和CUnknown,用于电源的管理。class AdapterPowerMgr: public IAdapterPowerManagement, public CUnkn......
COM的QueryInterface与NonDelegatingQueryInterface关系
COM类的实现如下:class CMyComponent : public CUnknown, public ISomeInterface{public: DECLARE_IUNKNOWN; STDMETHODIMP NonDelegatingQueryInterface(RE......
COM的QueryInterface与NonDelegatingQueryInterface的测试用例
COM中,函数的调用实际是汇编 call 函数地址.对于一个类里定义的函数实际是一个一个的地址偏移.如果地址偏移是一样而且参数个数与排列都一样,函数叫什么名字是没有关系的。这里关于这句话做一个测试用例,用于测试COMM的妙用:#include #include......
作者信息
我爱内核
Windows驱动开发,网站开发
好好学习,天天向上。
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!