IUnknown

IUnknownインターフェイスは、Component Object Model (COM) において基盤となる抽象型である。COMの仕様では、すべてのCOMオブジェクトはIUnknownインターフェイスを実装していなければならないとされている。すなわち、IUnknownは、COMにおけるルートクラスである。また、すべてのCOMインターフェイスはIUnknownの派生型である。

メソッド
IUnknownには、QueryInerface、AddRef、Releaseの3つのメソッドがある。QueryInterfaceは、ほかに実装しているインタフェースを問い合わせ、取得するメソッドである。AddRefとReleaseは、それぞれ参照カウントの増減を行う。

QueryInterfaceはインタフェースを識別するGUID (通常インタフェースID (IID) と呼ぶ) に基づいて、他のインタフェースへのポインタを得るために用いる。対象のCOMオブジェクトが実装していないインタフェースを要求された場合には、エラー値としてE_NOINTERFACEを返す。
なお、すべてのCOMオブジェクトはIUnknownを実装しているという性質上、IUnknownのIIDを引数に指定してのQueryInterfaceは必ず成功する。
AddRefはクライアントがこのCOMオブジェクトの参照を始めることを伝えるために用いる。
ReleaseはクライアントがこのCOMオブジェクトの使用を終了することを伝えるために用いる。
AddRefとReleaseの戻り値は現在の参照カウントの値であるが、あくまでテスト用を目的としている。
interface IUnknown
{
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) = 0;
    virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;
    virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
};
なお、IUnknownのインタフェースIDは、{00000000-0000-0000-C000-000000000046}と定義されている。

C++
COMの仕様にはないが、旧Platform SDK・現Windows SDKに用意されているヘッダファイルをC++で用いると、テンプレートによって型安全性を向上させた次のようなQueryInterfaceが定義される。
template<class Q>
HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp)
{
    return QueryInterface(__uuidof(Q), (void **)pp);
}
なお、__uuidof(Q)は、型Qに関連付けられたGUIDを取得するVisual C++の拡張である。こちらを用いると、インタフェースへのポインタと異なるインタフェースIDを指定するという誤りを避けることが可能である。

役割
前述のように、IUnknownは実装しているほかのインタフェースの問い合わせ・取得(QueryInterface)と参照カウントの管理を行うメソッドを持っているのみである。そして、すべてのCOMインタフェースはIUnknownから派生（直接に、またはIUnknownから派生したインタフェースから派生することによって間接的に）しているため、すべてのCOMインタフェースで必ずこれらのメソッドが呼び出し可能であることが保証される。

逆に、IUnknownを直接扱う有用な例は少ない。

2つの異なるインタフェースを指すポインタが同じCOMオブジェクトであるか否かを調べるには、IUnknownのIIDを指定してのQueryInterfaceの呼び出しを双方で行い、得られたインタフェースへのポインタが一致するか否かを調べるとよい。これは、あるCOMオブジェクトに対し、IUnknownのIIDを指定してのQueryInterfaceの呼び出しで得られるポインタは、かならず（どのインタフェースでQueryInterfaceを呼んでも）同じポインタ値となる保証がある（逆に言えば、実装者はそのように実装する必要がある）ためである。

bool EqualObject(IUnknown* lhs, IUnknown* rhs)
{
    bool ret = false;
    IUnknown* lhsUnk;
    if (SUCCEEDED(lhs->QueryInterface(&lhsUnk)))
    {
        IUnknown* rhsUnk;
        if (SUCCEEDED(rhs->QueryInterface(&rhsUnk)))
        {
            ret = (lhsUnk == rhsUnk);
            rhsUnk->Release();
        }
        lhsUnk->Release();
    }
    return ret;
}

脚注

オブジェクト指向
マイクロソフトのAPI