MicrosoftがGitHubでMITライセンス公開しているWILのGitHub WikiからWinRT and COM wrappersの記事を和訳・改変したものです。素人による翻訳なので、誤訳や著作権上の問題などありましたらご連絡いただけますと幸いです。
一部のリンク切れは意図的なものです。原文をご参照ください。
WinRT&COMラッパー
Raymond Chen、2019/10/4、リビジョン9個
WILのWinRT&COMラッパーはstd
スマートポインタであるstd::unique_ptr
に似た方法でCOMポインタを安全に使う手助けをします。
使い方
COMラッパーは正しいヘッダーファイルをインクルードすれば使用できます。
#include <wil/com.h>
wil::com_ptr_t
WILのリソースラッパーと同じように、COMラッパーはwil::com_ptr_t<T>
テンプレートクラスに基づいて使用できます。このテンプレートクラスはWILのCOMラッパーの基本機能を提供します。このクラスを直接インスタンス化する必要はありません。代わりに以下で示すようなエイリアスのひとつを使用します。
template <typename T, typename err_policy = err_exception_policy> class com_ptr_t;
テンプレート引数
T
com_ptr_t
の管理する基底型。普通はCOMインターフェイスの名前です(末尾の*
は不要です)。T
がIAgileReference
またはIWeakReference
の場合はラッパークラスの動作がわずかに異なることに注意してください。詳細は以下のcom_agile_ref
またはcom_weak_ref
を参照してください。err_policy
エラーハンドルポリシー。以下のエイリアスを参照してください。
エイリアス
以下のエイリアスは共通のエラーハンドリングポリシーのために定義されています。
エイリアス | ポリシー | 概要 |
---|---|---|
com_ptr<T> |
err_exception_policy |
失敗時に例外を発生します。 |
com_ptr_nothrow<T> |
err_returncode_policy |
失敗を示すHRESULT を返します。 |
com_ptr_failfast<T> |
err_failfast_policy |
失敗時はフェイルファストします。 |
APIリファレンス
メンバー型
result
エラーポリシーの提供する関数の戻り値。例外またはフェイルファストではvoid
、リターンコードポリシーではHRESULT
です。element_type
com_ptr_t
の保持するテンプレート型T
。pointer
com_ptr_t
の保持するテンプレート型T
へのポインタ。T*
。
コンストラクタ
com_ptr_t()
(デフォルトコンストラクタ) 空のラッパーを作成します。com_ptr_t(nullptr)
空のラッパーを作成します。com_ptr_t(T* ptr)
生のポインタの指すCOMオブジェクトへの追加参照を作成します。ptr
がnullptr
の場合、空のラッパーを作成します。com_ptr_t(const com_ptr_t<...>& other)
&com_ptr_t(const Microsoft::WRL::ComPtr<...>& other)
(コピーコンストラクタ)other
の指すCOMオブジェクトへの追加参照を作成します。other
が空の場合、空のラッパーを作成します。ソースの基底要素がターゲットと互換性があれば、other
はどんな種類のcom_ptr_t
とComPtr
でも指定できます。エラーハンドリングポリシーは一致する必要がありません。com_ptr_t(com_ptr_t<...>&& other)
&com_ptr_t(Microsoft::WRL::ComPtr<...>&& other)
(ムーブコンストラクタ)他のラッパーから所有権を転送された新しいラッパーを作成します。ソースの基底要素がターゲットと互換性があれば、
other
はどんな種類のcom_ptr_t
とComPtr
でも指定できます。
デストラクタ
~com_ptr_t
ラップするCOMオブジェクトを解放します。
オブジェクト管理メソッド
T* get() const
ラップするCOMオブジェクトを返します。ラッパーが空ならnullptr
を返します。void reset()
現在のCOMオブジェクトを解放してラッパーを空にします。void reset(nullptr)
現在のCOMオブジェクトを解放してラッパーを空にします。
reset(T* ptr)
は存在しないことに注意してください。代わりに割り当て操作を使います。
void attach(T* ptr)
現在のCOMオブジェクトを解放して、与えられた生ポインタの所有権を与えます。ptr
がnullptr
の場合、ラッパーは空になります。T* detach()
現在のCOMオブジェクトを返してラッパーを空にします。返された生ポインタがnullではない場合、呼び出し側は解放の責任を持ちます。T** addressof()
現在のCOMオブジェクトを解放せずに内部ポインタのアドレスを返します。現在のCOMオブジェクトがメモリリークする可能性があるため、出力引数では使わないでください。出力引数ではアドレスを返す前に現在のCOMオブジェクトを開放する&
演算子を使用します。T* const* addressof() const
上のconst
版です。返されたポインタは変更できません。T** put()
現在のCOMオブジェクトを解放して内部ポインタのアドレスを返します。com_ptr_t
を出力引数に渡す場合に使用します。T** operator&()
put()
と同じです。void** put_void()
put()
と同じですが、void**
を返します。IUnknown** put_unknown()
put()
と同じですが、IUnknown**
を返します。swap(com_ptr_t<T, ...>& other)
とswap(Microsoft::WRL::ComPtr<T>& other)
別のラッパーとポインタを交換します。ラッパーは同じCOMインターフェイスをラップすべきですが、エラーポリシーは異なっても構いません。ADL(Argument Dependent Lookup)用途の解放関数としても使用可能です。swap(com_ptr_t<T, ...>&& other)
とswap(Microsoft::WRL::ComPtr<T>&& other)
右辺値参照(rvalue reference) 別のラッパーとポインタを交換します。ラッパーは同じCOMインターフェイスをラップすべきですが、エラーポリシーは異なっても構いません。
COM型変換関数
query
とcopy
の2つの変換関数ファミリーがあります。
query
メソッドはラッパーが空ではないことを要求します。ラッパーが空の場合、動作は未定義です(普通はnullポインタでクラッシュします)。
copy
メソッドはラッパーが空でも構いません。空の場合は戻り値も空になります。
try_
プリフィックスはその関数が失敗する可能性を意味します。失敗時、関数は空のラッパーを作り、false
を返します(適切な場合)。
query
、copy
メソッドは元のCOM型が目的のCOM型と等しいか変換可能な場合を最適化しています。この場合、コピー時にAddRef
が呼び出され、QueryInterface
は呼び出されません。
すべてのquery
、copy
メソッドはconst
です。
直接 | Try |
---|---|
com_ptr_t<U> query<U>() com_ptr_t<U> copy<U>() 以下のノート1、2を参照 |
com_ptr_t<U> try_query<U>() com_ptr_t<U> try_copy<U>() 以下のノート1、2を参照 |
result query_to(U** p) result copy_to(U** p) |
bool try_query_to(U** p) bool try_copy_to(U** p) |
result query_to(REFIID riid, void** ppv) result copy_to(REFIID riid, void** ppv) |
bool try_query_to(REFIID riid, void** ppv) bool try_copy_to(REFIID riid, void** ppv) |
エラーポリシーに従ってエラーを報告します。 | 失敗時は空のラッパーかfalse を返します。 |
- ノート1:
query
、copy
はリターンコードポリシーでは使えません。 - ノート2:(
try_
)query
、 (try_
)copy
は元のラッパーと同じエラーポリシーのcom_ptr_t
を返します。
例外ベースラッパーとフェイルファストベースラッパーの典型的な使い方です。
// 以下のcom_ptrはcom_ptr_failfastと置き換えられます。 wil::com_ptr<IBaz> TryGetInnerBaz() { wil::com_ptr<IBar> bar = ...; // barは空ではない必要があります。 auto foo = bar.query<IFoo>(); auto baz = foo->TryGetBaz(); return baz; } // 上は以下のように単純化できます。 wil::com_ptr<IBaz> TryGetInnerBaz() { wil::com_ptr<IBar> bar = ...; // barは空ではない必要があります。 return bar.query<IFoo>()->TryGetBaz(); } void Example() { wil::com_ptr<IBar> bar = ...; auto foo = bar.try_query<IFoo>(); if (foo) { foo->Method(); } }
リターンコードベースラッパーの典型的な使い方です。
HRESULT TryGetInnerBaz(_COM_Outptr_ IBaz** result) { *result = nullptr; wil::com_ptr_nothrow<IBar> bar = ...; // barは空ではない必要があります。 wil::com_ptr_nothrow<IFoo> foo; RETURN_IF_FAILED(bar.query_to(&foo)); wil::com_ptr_nothrow<IBaz> baz; RETURN_IF_FAILED(foo->TryGetBaz(&baz)); // bazは空かもしれないのでcopy_toを使います。 RETURN_IF_FAILED(baz.copy_to(result)); return S_OK; } HRESULT Example() { wil::com_ptr_nothrow<IBar> bar = ...; auto foo = bar.try_query<IFoo>(); if (foo) { foo->Method(); } wil::com_ptr_nothrow<IBaz> baz; RETURN_IF_FAILED(bar.try_query_to(&baz)); baz->Method(); return S_OK; }
演算子
operator=(nullptr)
現在のCOMオブジェクトを解放してラッパーを空にします。operator=(T* ptr)
現在のCOMオブジェクトを解放して、生のポインタの指すCOMオブジェクトへの追加参照を作成します。operator=(const com_ptr_t<...>& other)
&operator=(const Microsoft::WRL::ComPtr<...>& other)
現在のCOMオブジェクトを解放して、生のポインタの指すCOMオブジェクトへの追加参照を作成します。ソースの基底型がターゲットと互換性であればother
には任意の種類のcom_ptr_t
、ComPtr
を指定できます。例えば、com_ptr_failfast<IStream>
からcom_ptr_nothrow<IUnknown>
を作成できます。これはIStream*
がIUnknown*
へ変換できるためです。エラーハンドリングポリシーは一致する必要がありません。operator=(com_ptr_t<...>&& other)
&operator=(Microsoft::WRL::ComPtr<...>&& other)
(ムーブ代入) 現在のCOMオブジェクトを解放してother
から所有権を転送します。ソースの基底型がターゲットと互換性であればother
には任意の種類のcom_ptr_t
、ComPtr
を指定できます。T** operator&()
現在のCOMオブジェクトを解放して内部ポインタのアドレスを返します。内部ポインタのアドレスを取得するだけでCOMオブジェクトを解放しない場合(まれな入出力引数で使用する場合)はaddressof
メソッドを使用します。operator bool()
現在のCOMオブジェクトが存在すればtrue
を返します。空の場合はfalse
を返します。T* operator->() const
ラップするCOMオブジェクトのポインタを返します。ラッパーが空の場合はクラッシュを起こします。T& operator*() const
ラップするCOMオブジェクトを参照解除します。ラッパーが空の場合はクラッシュを起こします。==
,!=
,<
,<=
,>
,>=
比較演算子 これらは基底生ポインタの比較を実行します。左辺と右辺は基底ポインタの変換可能だけが要求され、エラーポリシーは異なってもかまいません。例えば、com_ptr<IUnknown>
とComPtr<IStream>
を比較できます。生ポインタとnullptr
の一致または不一致も比較できます。
wil::com_ptr_t vs Microsoft::WRL::ComPtr
wil::com_ptr_t
は以下のように簡潔な使用を可能とする例外とフェイルファストをサポートしています。
someObj.query<ISomeInterface>()->CallMethod();
ComPtr
はエラーコードのみサポートします。例外の使用やフェイルファスト動作を求めるなら選択肢は明白です。例外へ変換するならwil::com_ptr
を使います。HRESULT
ベースで既にWRL ComPtr
を使うコードを使用する場合、ComPtr
を使い続けられます。HRESULT
ベースで新しいコードを書く場合、wil::com_ptr_nothrow
を使うことが推奨されます。
com_ptr様動作の独立関数
T* com_raw_ptr(x)
生のポインタを抽出します。x
は生のポインタ、com_ptr<T>
、WRL::ComPtr<T>
、C++/CXT^
ハットポインタのいずれかを指定できます(C++/CXハットポインタでは生のポインタは常にIInspectable*
です)。
直接 | Try |
---|---|
com_ptr<U> com_query<U>(x) com_ptr_failfast<U> com_query_failfast<U>(x) (例外なし版) |
com_ptr<U> try_com_query<U>(x) com_ptr_failfast<U> try_com_query_failfast<U>(x) com_ptr_nothrow<U> try_com_query_nothrow<U>(x) |
com_ptr<U> com_copy<U>(x) com_ptr_failfast<U> com_copy_failfast<U>(x) (例外なし版) |
com_ptr<U> try_com_copy<U>(x) com_ptr_failfast<U> try_com_copy_failfast<U>(x) com_ptr_nothrow<U> try_com_copy_nothrow<U>(x) |
void com_query_to(x, U** p) void com_query_to_failfast(x, U** p) HRESULT com_query_to_nothrow(x, U** p) |
bool try_com_query_to(x, U** p) bool try_com_query_to_failfast(x, U** p) bool try_com_query_to_nothrow(x, U** p) |
void com_copy_to(x, U** p) void com_copy_to_failfast(x, U** p) HRESULT com_copy_to_nothrow(x, U** p) |
bool try_com_copy_to(x, U** p) (no fastfail version) (例外なし版) |
void com_query_to(x, REFIID riid, void** ppv) void com_query_to_failfast(x, REFIID riid, void** ppv) HRESULT com_query_to_nothrow(x, REFIID riid, void** ppv) |
bool try_com_query_to(x, REFIID riid, void** ppv) bool try_com_query_to_failfast(x, REFIID riid, void** ppv) bool try_com_query_to_nothrow(x, REFIID riid, void** ppv) |
void com_copy_to(x, REFIID riid, void** ppv) void com_copy_to_failfast(x, REFIID riid, void** ppv) HRESULT com_copy_to_nothrow(x, REFIID riid, void** ppv) |
bool try_com_copy_to(x, REFIID riid, void** ppv) (フェイルファストなし版)(例外なし版) |
query
、com
メソッドにも独立関数版があります。これらはcom_raw_ptr
が最初の引数で受け取る引数を受け取り、対応するquery
、copy
メソッドと同じ動作をします。これらの関数は、生ポインタでそのままCOM操作を実行したい場合に便利です。
C++/CXヘルパー
Object^ wil::cx_object_from_abi(x)
com_raw_ptr
の受け取る任意の引数を受け取り、IInspectable*
、Object^
の順に変換します。U^ wil::cx_safe_cast<U>(x)
com_raw_ptr
の受け取る任意の引数を受け取り、IInspectable*
、Object^
の順に変換してからU^
へsafe_cast
します。U^ wil::cx_dynamic_cast<U>(x)
com_raw_ptr
の受け取る任意の引数を受け取り、IInspectable*
、Object^
の順に変換してからU^
へdynamic_cast
します。
wil::com_agile_ref
wil::com_agile_ref
ファミリクラスはcom_ptr<IAgileReference>
のエイリアスですが、以下の点が異なります。
クラス | 等しい | 説明 |
---|---|---|
com_agile_ref |
com_ptr<IAgileReference> |
エラー時に例外を発生するIAgileReference ラッパー。 |
com_agile_ref_failfast |
com_ptr_failfast<IAgileReference> |
エラー時にファイルファストするIAgileReference ラッパー。 |
com_agile_ref_nothrow |
com_ptr_nothrow<IAgileReference> |
エラーコードを返すIAgileReference ラッパー。 |
com_agile_ref
ラッパークラスは普通のcom_ptr
とquery
、copy
メソッドの動作が異なります。これらはアジャイル参照そのものではなく、アジャイル参照のターゲットに動作します。言い換えれば、IUnknoqn::QueryInterface
ではなくIAgileReference::Resolve
を使用します。query
、copy
動作はすべて解決動作となり、普通のcom_ptr
のようなショートサーキットではありません。
com_agile_ref
オブジェクトで使用される追加の解放関数ヘルパー:
クエリファミリ | コピーファミリ | 説明 |
---|---|---|
com_agile_ref com_agile_query(anything) |
com_agile_ref com_agile_copy(anything) |
例外を発生するcom_agile_ref を返します。 |
com_agile_ref_failfast com_agile_query_failfast(anything) |
com_agile_ref_failfast com_agile_copy_failfast(anything) |
フェイルファストするcom_agile_ref_failfast を返します。 |
HRESULT com_agile_query_nothrow(anything, IAgileReference** result) |
HRESULT com_agile_copy_nothrow(anything, IAgileReference** result) |
エラーコードベースのcom_agile_ref_nothrow を返します。 |
anything はnullポインタや空のラッパー以外です。 |
anything はnullポインタや空のラッパーでも可能です。 |
anything
引数はcom_raw_ptr
の受け取る任意の引数であり、このアジャイル参照はanything
の指すCOMインターフェイスをラップします。
コピー関数にはnullポインタや空のラッパーを渡すことが可能で、その場合は空のアジャイル参照を返して関数は成功するか(com_agile_copy
、com_agile_copy_failfast
)、nullポインタを返して関数は成功します(com_agile_copy_nothrow
)。
上のすべての関数はAgileReferenceOptions
最終引数を受け取ります。省略時の既定値はAGILEREFERENCE_DEFAULT
です。
以下は最後の独立関数です。
bool is_agile(anything)
IAgileObject
をクエリすることでオブジェクトがアジャイルか判断します。anything
はcom_raw_ptr
が受け取る任意の引数で、nullポインタや空のラッパー以外です。
wil::com_weak_ref
wil::com_weak_ref
ファミリのクラスはcom_ptr<IWeakReference>
のエイリアスですが、以下の点が異なります。
クラス | 等しい | 説明 |
---|---|---|
com_weak_ref |
com_ptr<IWeakReference> |
エラー時に例外を発生するIWeakReference ラッパー。 |
com_weak_ref_failfast |
com_ptr_failfast<IWeakReference> |
エラー時にフェイルファストするIWeakReference ラッパー。rror. |
com_weak_ref_nothrow |
com_ptr_nothrow<IWeakReference> |
エラーコードを返すIWeakReference ラッパー。 |
com_weak_ref
ラッパークラスは普通のcom_ptr
とquery
、copy
メソッドの動作が異なります。これらは弱い参照そのものではなく弱い参照のターゲットに動作します。言い換えれば、IUnknown::QueryInterface
ではなくIWeakReference::Resolve
を呼び出します。すべてのquery
、copy
動作は解決動作となり、普通のcom_ptr
のようなショートサーキットではありません。
弱い参照のターゲットが破壊済みの場合、動作はE_NOT_SET
で失敗します。これはCOM自体が報告する失敗、RPC_E_DISCONNECTED
とは異なることに注意してください。
弱い参照を取得するオブジェクトはIInspectable
を実装しているべきです。
com_weak_ref
オブジェクトで使用される追加の解放関数ヘルパー:
クエリファミリ | コピーファミリ | 説明 |
---|---|---|
com_weak_ref com_weak_query(anything) |
com_weak_ref com_weak_copy(anything) |
例外を発生するcom_weak_ref を返します。 |
com_weak_ref_failfast com_weak_query_failfast(anything) |
com_weak_ref_failfast com_weak_copy_failfast(anything) |
フェイルファストするcom_weak_ref_failfast`を返します。 |
HRESULT com_weak_query_nothrow(anything, IAgileReference** result) |
HRESULT com_weak_copy_nothrow(anything, IAgileReference** result) |
エラーコードベースのcom_weak_ref_nothrow`を返します。 |
anything はnullポインタや空のラッパー以外です。 |
anything はnullポインタや空のラッパーでも可能です。 |
anything
引数はcom_raw_ptr
の受け取る任意の引数です。
コピー関数の場合、
コピー関数にはnullポインタや空のラッパーを渡すことが可能で、その場合は空のアジャイル参照を返して関数は成功するか(com_weak_copy
、com_weak_copy_failfast
)、nullポインタを返して関数は成功します(com_weak_copy_nothrow
)。
オブジェクト作成ヘルパー
オブジェクト作成ヘルパーは次のパターンに従います。
com_ptr<Interface> CoCreateInstance<Class, Interface>(DWORD dwClsContext)
com_ptr<Interface> CoCreateInstance<Interface>(REFCLSID rclsid, DWORD dwClsContext)
com_ptr<Interface> CoGetClassObject<Class, Interface>(DWORD dwClsContext)
com_ptr<Interface> CoGetClassObject<Interface>(REFCLSID rclsid, DWORD dwClsContext)
ノート:
- You can specify a
Class
(which must support__uuidof
) as a template parameter or aREFCLSID
as a function parameter. - テンプレート引数
Class
(__uuidof
をサポートしているべきです)か関数引数REFCLSID
が使用できます。 - テンプレート引数
Interface
は省略可能です。既定値はIUnknown
です。 - 関数引数
dwClsContext
は省略可能です。既定値はCLSCTX_INPROC_SERVER
です。
以下の表はすべてのエラーポリシーを示します。
Error policy | Functions |
---|---|
err_exception_policy 失敗時は例外発生。 |
com_ptr<Interface> CoCreateInstance(...) com_ptr<Interface> CoGetClassObject(...) |
err_failfast_policy 失敗時はフェイルファスト。 |
com_ptr_failfast<Interface> CoCreateInstanceFailFast(...) com_ptr_failfast<Interface> CoGetClassObjectFailFast(...) |
err_returncode_policy 失敗時は空を返す。 |
com_ptr_nothrow<Interface> CoCreateInstanceNoThrow(...) com_ptr_nothrow<Interface> CoGetClassObjectNoThrow(...) |
ストリームヘルパー
引数は以下に従います。
ISequentialStream* stream
、null以外。void* dest
、size
バイトの大きさ。const void* source
、size
バイトの大きさ。unsigned long size
、dest
と`sourceバッファーのバイトサイズ。long long distance
、ストリーム中の相対位置。unsigned long long position
、ストリーム中の絶対位置(ストリームの開始からの相対位置)。unsigned long origin
、distance
の解釈を決めるSTREAM_SEEK
.aspx) 値。ISequentialStream* sourceStream
&ISequentialStream* targetStream
、ストリームのコピーメソッドで使用される。unsigned long long amount
、コピーするバイト数。
すべてのヘルパー関数はCOMストリームに基づく単一の呼び出しをラップします。読み取り、書き込み、コピー操作が部分的な結果を返す場合、関数は保持するデータに対するそれら動作を内部でループしません。
_nothrow
版は例外発生版と同じですが、HRESULT
を返すこと、例外発生版の戻り値は最終引数に出力引数として明示することが異なります。
例外発生版 | 非例外発生版 | ノート |
---|---|---|
void something(...) |
HRESULT something(...) |
|
ReturnType something(...) |
HRESULT something_nothrow(..., ReturnType* result) |
|
HRESULT something_nothrow(..., ReturnType* result = nullptr) |
最終引数は省略可能。 |
関数 | 説明 |
---|---|
unsigned long |
stream_read_partial(stream, dest, size) |
HRESULT |
stream_read_partial_nothrow(stream, dest, size, unsigned long* result) |
void |
stream_read(stream, dest, size) |
HRESULT |
stream_read_nothrow(stream, dest, size) |
void |
stream_read(stream, T* dest) |
HRESULT |
stream_read_nothrow(stream, T* dest) |
void |
stream_write(stream, source, size) |
HRESULT |
stream_write_nothrow(stream, source, size) |
void |
stream_write(stream, const T* source) |
HRESULT |
stream_write_nothrow(stream, const T* source) |
unsigned long long |
stream_size(stream) |
HRESULT |
stream_size_nothrow(stream, unsigned long long* result) |
unsigned long long |
stream_seek(stream, distance, origin) |
HRESULT |
stream_seek_nothrow(stream, distance, origin, unsigned long long* result = nullptr) |
unsigned long long |
stream_set_position(stream, position) |
HRESULT |
stream_set_position_nothrow(stream, position, unsigned long long* result = nullptr) |
unsigned long long |
stream_seek_from_current_position(stream, distance) |
HRESULT |
stream_seek_from_current_position_nothrow(stream, distance, unsigned long long* result = nullptr) |
unsigned long long |
stream_get_position(stream) |
HRESULT |
stream_get_position_nothrow(stream, unsigned long long* result) |
void |
stream_reset(stream) |
HRESULT |
stream_reset_nothrow(stream) |
unsigned long long |
stream_copy_bytes(sourceStream, targetStream, amount) |
HRESULT |
stream_copy_bytes_nothrow(sourceStream, targetStream, amount, unsigned long long* result = nullptr) |
unsigned long long |
stream_copy_all(sourceStream, targetStream) |
HRESULT |
stream_copy_all_nothrow(sourceStream, targetStream, unsigned long long* result = nullptr) |
void |
stream_copy_exact(sourceStream, targetStream, amount) |
HRESULT |
stream_copy_exact_nothrow(sourceStream, targetStream, amount) |
ノート1:転送されたバイト数が要求されたバイト数と異なる場合、HRESULT_FROM_WIN32(ERROR_INVALID_DATA)
で失敗します。この失敗コードは不完全な書き込みでも発生して、書き込まれたデータに以上がなくても発生して誤解を招きます。問題はストリームがいっぱいであることです。
文字列ストリームヘルパー
戻り値 | 関数 |
---|---|
void |
stream_write_string(ISequentialStream* stream, const wchar_t sourceString, size_t characterCount) |
HRESULT |
stream_write_string_nothrow(ISequentialStream* stream, const wchar_t* sourceString, size_t characterCount) |
unique_cotaskmem_string |
stream_read_string(ISequentialStream* stream, options = returns_empty) |
HRESULT |
stream_read_string_nothrow(ISequentialStream* stream, PWSTR* result, options = returns_empty) |
stream_write_string
関数は数えた文字列をストリームへ書き込みます。書き込みフォーマットは多くが16ビット値であることから16ビット文字です。null終端は追加されません。これはIStream_WriteStr
関数で使われるのと同じ形式です。
characterCount
は典型的にwcslen(sourceString)
ですが、文字列の一部を書き込む場合はそれより小さくても構いません。
characterCount
が65,535を超えた場合、_nothrow
版であってもフェイルファスト例外が発生します。
stream_read_string
関数はstream_write_string
で書き込まれた文字列を読み込みます。返された文字列はCoTaskMemFree
で開放する必要があります。
オプションのoptions
引数は長さ0の文字列を返すかどうかを制御します。
オプション | 説明 |
---|---|
wil::empty_string_options::returns_empty (既定) |
長さ0の文字列は空の文字列を割り当てて返されます。 |
wil::empty_string_options::returns_null |
長さ0の文字列はnullptr として返されます。 |
stream_position_saver
stream_position_saver
クラスは作成時にオプションストリームの位置(position
)を保持して、破壊時にそれを復元します。
stream_position_saver
は位置を保持していない場合、空として扱われます。空のstream_position_saver
は破壊時に何もしません。
使用例:
// エラー時、ストリームの位置は開始時の位置に復元されます。 // 他の人もストリームから読み込めます。 auto saver = wil::stream_position_saver(stream); auto header = wil::stream_read<MY_HEADER>(stream); if (header.signature != MY_HEADER_SIGNATURE) { // ストリームが拒否された。「saver」はポジションを復元する。 THROW_HR(HRESULT_FROM_WIN32(ERROR_INVALID_DATA)); } // ストリームの処理が成功した。 // ストリームの位置の復元を取り消す。 saver.dismiss();
stream_position_saver
はムーブ可能、コピー不可能です。stream_position_saver
の移動はムーブ先のオブジェクトへストリームの位置の復元義務を転送します。ムーブ元のオブジェクトは空になります。
コンストラクタ
stream_position_saver(IStream* stream)
将来的にふくげんするストリームの位置をキャプチャします。ストリームの位置をキャプチャできない場合は例外を発生します。stream
はnullptr
も可能であり、その場合は位置をキャプチャしません。
デストラクタ
~stream_position_saver
空ではない場合は保存していたストリームの位置を復元します。復元に失敗した場合、エラーをログして実行を継続します。
メソッド
void update()
保存した位置をストリームの現在の位置に更新します。位置が取得できない場合は例外を発生します。空の場合はクラッシュします。unsigned long long position()
キャプチャした位置を返します。空の場合は無意味な値(garbage value)を返します。void reset()
ストリームの位置を復元します。復元失敗時は例外を発生します。stream_position_saver
はこの位置を保持して、破壊時に再度位置を復元します。void reset(IStream* newStream)
ストリームの位置を復元して、将来的な復元のためにnewStream
の現在位置をキャプチャします。位置の復元または新しい位置のキャプチャに失敗した場合は例外を発生します(現在の実装にはバグがあります。新しいストリームの位置を取得できない場合、ストリームの復元位置として元のストリームからキャプチャしていた位置が設定されます)。newStream
はnullptr
以外です。void dismiss()
保存したストリームの位置復元をキャンセルして、stream_position_saver
を空にします。
サイトヘルパー
wil::unique_set_site_null_call
`wil::unique_set_site_null_call
は破壊時にIObjectWithSite::SetSite(nullptr)を呼び出すRAII型です
。これはunique_com_call
パターンに従います。詳細はunique_com_callを参照してください。
このヘルパーは普通は明示的に作成されません。むしろサイトの設定、操作の実行、クリアのためにcom_set_site
で返されます。
明示的な使い方
// デモ目的限定。このパターンはcom_set_siteメソッドでカプセル化されます。 // com_set_siteは以下の3行を手書きする代わりに使えます。 auto objectWithSite = someObject.query<IObjectWithSite>(); objectWithSite->SetSite(someSite); auto cleanup = wil::unique_set_site_null_call(objectWithSite.get()); someObject->Execute(); // スコープから出るときにクリーンアップされます。サイトはnullptrが設定されます。
wil::com_set_site
wil::com_set_site
ヘルパーメソッドはオプションサイトにIObjectWithSite
をオプションで実装するオプションオブジェクトを設定します。これは破壊時にサイトにnullを設定するunique_set_site_null_call
を返します。以下はunique_set_site_null_call
の典型的な使い方です。
Gotcha:com_set_site
の結果の保存を忘れた場合、サイトは即座にリセットされて、com_set_site
が何もしていないように見えます。
unique_set_site_null_call com_set_site(_In_opt_ IUnknown* obj, _In_opt_ IUnknown* site);
obj
がnullかIObjectWithSite
を実装しない場合、空のunique_set_site_null_call
が返され、何も起きません。
obj
がIObjectWithSite
を実装する場合、そのサイトはsite
に設定され、返されたunique_set_site_ull_call
は破壊時にobj
のサイトをnullに設定します。
使用例:
auto obj = ...; auto cleanup = wil::com_set_site(obj.get(), site.get()); someObject->Execute(); // スコープから出るとき、サイトはnullptrに設定されます。
サイトの設定が目的で復元が不要な場合、以下のようにします。
auto obj = ...;
wil::com_set_site(obj.get(), site.get()).release();
wil::for_each_site
for_each_site
関数はサイトチェインの各サイトにコールバックを実行します。すべてのエラーは無視され、サイトチェインウォークは終了されます。これは典型的にデバッグで使用されます。
template<typename TLambda> void for_each_site(_In_opt_ IUnknown* obj, TLambda&& callback);
使用例:
void OutputDebugSiteChainWatchWindowText(IUnknown* site) { OutputDebugStringW(L"これらのエントリをVisual Studio ウォッチウィンドウへコピペします。\n"); wil::for_each_site(site, [](IUnknown* site) { wchar_t msg[64]; StringCchPrintfW(msg, ARRAYSIZE(msg), L"((IUnknown*)0x%p)->__vfptr[0]\n", site); OutputDebugStringW(msg); }); }
内部処理
query
、copy
メソッドファミリーの実装は「クエリポリシー」オブジェクトに依存しています。クエリポリシーは次の2メソッドをサポートすべきです。
static HRESULT query(T* ptr, REFIID riid, void** result)
static HRESULT query(T* ptr, TResult** result)
これらのメソッドはある型のポインタを別の型のポインタへ変換します。ptr
はnullptr
以外です。
最初のオーバーロードでは、対象インターフェイスはインターフェイスIDにより実行時に特定されます。次のオーバーロードでは、対象インターフェイスは関数テンプレート引数によりコンパイル時に特定されます。これらの実装は最適化に長所があります。例えば、default_query_policy
は与えられたポインタが戻り値と互換するか調査します。これにより、QueryInterface
の呼び出しを回避してAddRef
を呼び出すことができます。
次の3つのクエリポリシーが現在実装されています。
wil::details::agile_query_policy
forIAgileReference
。wil::details::weak_query_policy
forIWeakReference
。wil::details::default_query_policy
for その他すべてのCOMインターフェイス。
com_ptr_t
は特定のインターフェイスのwil::details::query_policy_helper
クラステンプレートの特殊化により上記の型を使用します。手動で特定することはできません(例:com_ptr_t
型のテンプレート引数を介して)。
加えて、これらの多様なquery
、copy
メソッドは部分的なコンストラクタの強制選択のためのタグ値を使用します。
タグ | 目的 | 何が起こるか |
---|---|---|
wil::details::tag_com_query |
query の作成 |
query の失敗時は例外発生またはフェイルファストします(リターンコードポリシーでは使いません)。 |
wil::details::tag_try_com_query |
try_query の作成 |
query の失敗時は空のラッパーを作成します。 |
wil::details::tag_com_copy |
copy の作成 |
copy の失敗時は例外発生またはフェイルファストします。ソースがnullの場合は空のラッパーを作成します。 |
wil::details::tag_try_com_copy |
try_copy の作成 |
copy の失敗またはソースがnull時は空のラッパーを作成します。 |
著作権表示
この記事は以下の著作物を使用しています。
Copyright (c) Microsoft Corporation. All rights reserved. https://github.com/microsoft/wil/blob/master/LICENSE