「IUnknown」の版間の差分
編集の要約なし |
|||
9行目: | 9行目: | ||
*ReleaseはクライアントがこのCOMオブジェクトの使用を終了することを伝えるために用いる。 |
*ReleaseはクライアントがこのCOMオブジェクトの使用を終了することを伝えるために用いる。 |
||
AddRefとReleaseの戻り値は現在の参照カウントの値であるが、あくまでテスト用を目的としている。 |
AddRefとReleaseの戻り値は現在の参照カウントの値であるが、あくまでテスト用を目的としている。 |
||
< |
<syntaxhighlight lang="cpp"> |
||
interface IUnknown |
interface IUnknown |
||
{ |
{ |
||
16行目: | 16行目: | ||
virtual ULONG STDMETHODCALLTYPE Release(void) = 0; |
virtual ULONG STDMETHODCALLTYPE Release(void) = 0; |
||
}; |
}; |
||
</syntaxhighlight> |
|||
</source> |
|||
なお、IUnknownのインタフェースIDは、{00000000-0000-0000-C000-000000000046}と定義されている。 |
なお、IUnknownのインタフェースIDは、{00000000-0000-0000-C000-000000000046}と定義されている。 |
||
===C++=== |
===C++=== |
||
COMの仕様にはないが、旧Platform SDK・現[[Windows SDK]]に用意されている[[ヘッダファイル]]をC++で用いると、テンプレートによって[[型安全|型安全性]]を向上させた次のようなQueryInterfaceが定義される<ref>Visual Studio 2005付属Windows SDK 5.0 Unknwn.h 121–125行目から引用した。</ref>。 |
COMの仕様にはないが、旧Platform SDK・現[[Windows SDK]]に用意されている[[ヘッダファイル]]をC++で用いると、テンプレートによって[[型安全|型安全性]]を向上させた次のようなQueryInterfaceが定義される<ref>Visual Studio 2005付属Windows SDK 5.0 Unknwn.h 121–125行目から引用した。</ref>。 |
||
< |
<syntaxhighlight lang="cpp"> |
||
template<class Q> |
template<class Q> |
||
HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp) |
HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp) |
||
27行目: | 27行目: | ||
return QueryInterface(__uuidof(Q), (void **)pp); |
return QueryInterface(__uuidof(Q), (void **)pp); |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
なお、<code>__uuidof(Q)</code>は、型<code>Q</code>に関連付けられたGUIDを取得する[[Visual C++]]の拡張である。こちらを用いると、インタフェースへのポインタと異なるインタフェースIDを指定するという誤りを避けることが可能である。 |
なお、<code>__uuidof(Q)</code>は、型<code>Q</code>に関連付けられたGUIDを取得する[[Visual C++]]の拡張である。こちらを用いると、インタフェースへのポインタと異なるインタフェースIDを指定するという誤りを避けることが可能である。 |
||
37行目: | 37行目: | ||
2つの異なるインタフェースを指すポインタが同じCOMオブジェクトであるか否かを調べるには、IUnknownのIIDを指定してのQueryInterfaceの呼び出しを双方で行い、得られたインタフェースへのポインタが一致するか否かを調べるとよい。これは、あるCOMオブジェクトに対し、IUnknownのIIDを指定してのQueryInterfaceの呼び出しで得られるポインタは、かならず(どのインタフェースでQueryInterfaceを呼んでも)同じポインタ値となる保証がある(逆に言えば、実装者はそのように実装する必要がある)ためである。 |
2つの異なるインタフェースを指すポインタが同じCOMオブジェクトであるか否かを調べるには、IUnknownのIIDを指定してのQueryInterfaceの呼び出しを双方で行い、得られたインタフェースへのポインタが一致するか否かを調べるとよい。これは、あるCOMオブジェクトに対し、IUnknownのIIDを指定してのQueryInterfaceの呼び出しで得られるポインタは、かならず(どのインタフェースでQueryInterfaceを呼んでも)同じポインタ値となる保証がある(逆に言えば、実装者はそのように実装する必要がある)ためである。 |
||
< |
<syntaxhighlight lang="cpp"> |
||
bool EqualObject(IUnknown* lhs, IUnknown* rhs) |
bool EqualObject(IUnknown* lhs, IUnknown* rhs) |
||
{ |
{ |
||
54行目: | 54行目: | ||
return ret; |
return ret; |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
==脚注== |
==脚注== |
2020年7月5日 (日) 23:01時点における版
IUnknownインターフェイスは、Component Object Model (COM) において基盤となる抽象型である。COMの仕様では、すべてのCOMオブジェクトはIUnknownインターフェイスを実装していなければならないとされている。すなわち、IUnknownは、COMにおけるルートクラスである。また、すべてのCOMインターフェイスはIUnknownの派生型である。
メソッド
IUnknownには、QueryInerface、AddRef、Releaseの3つのメソッドがある[1]。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が定義される[2]。
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;
}
脚注
- ^ “IUnknown Interface (COM)” (英語). MSDN ライブラリ. マイクロソフト (2009年7月9日). 2009年9月19日閲覧。
- ^ Visual Studio 2005付属Windows SDK 5.0 Unknwn.h 121–125行目から引用した。