プログラマのつれづれなるままにプログラマのつれづれなるままに音宮志久が思ったことなどをネタにします。プログラムネタ・数学ネタがメインです。[IStreamを実装してみよう(2)]コメントを残す記事のためおきってできるんですね・・。使い方が微妙ですが・・・。ちなみに、ファイル名からIStreamを開くだけならSHCreateStreamOnFileを使った方が早いです。これはあくまで実装をやってみるときどうなるか、とCUnknownの使い方を示すものですので。コンストラクタコンストラクタの実装は普通にファイルを開けばいいだけです。二つ宣言がありましたが、両方示しておきます。m_hFile(hFile){}CUnknownを継承すると、CUnknownのコンストラクタに引数を2つ渡す必要があるいます。親となるべきIUnknownのオブジェクト(NULLなら自分自身を親とする)NAMEマクロはデバッグ時にはその文字コード環境に合わせた文字列となり、リリース時には空文字列となります。ファイル名をとる普通のコンストラクタではHRESULTをどう渡すのかの一例が出ています。ファイルに開くことに失敗したときにはエラーコードE_FAILを渡して失敗した、と連絡しています。ちなみに、CUnknownを継承すると、コンストラクタが終了したときの参照カウントは「0」で初期化されます。デストラクタデストラクタです。このオブジェクトが解体されるときに呼び出されます。このオブジェクトが解体されるときってどんなとき?というのはもちろんReleaseを呼び出して参照カウントが0になったときですが、ここで疑問が一つ。このオブジェクトはどうやって「自身のメモリを解放する」のか(連動して、どうやってメモリを確保してコンストラクタを呼び出すのか)?CUnknownを使うとこの処理は自動的にdeleteを使う、と決まります。CStreamのメモリは常にnew~deleteを使用することになります。IUnknownの処理を自前で実装すると、「その部分はメモリ解放を何で行うかによってやり方が変わる」ので注意してください。Releaseを呼び出して参照カウントが0になるんですから開かれているファイルを閉じればいいわけです。INVALID_HANDLE_VALUE;}}ファイルが開かれていない(コンストラクタでE_FAILを返したパターン)もちゃんと考慮に入れないとだめですね。QueryInterfaceの実装CUnknownを継承するとQueryInterfaceの機能を持たせるときはNonDelegatingQueryInterfaceという関数で記述することになります。説明なしですが、とりあえず見てみましょう。CUnknown::NonDelegatingQueryInterface(refiid,lplpInterface);}COMオブジェクトにはすべてInterfaceIDがあり、それを使ってインターフェイスを指定します。今の場合はIStreamなので、それはIID_IStreamという定数値となります。CUnknown側(つまり自分が継承している上位側)のNonDelegatingQueryInterfaceに任せるです。一応説明しておきますが、IsEqualGUIDの処理は二つのGUIDが同じGUIDかどうを判定する関数(あるいはマクロ)です。*>(this),lplpInterface);と書いても間違いではありません(構造体同士の比較演算子は構造体のメモリ自体の比較に変換される)が、こちらを使うのが本来は正しいです。GetInterfaceはインターフェイスを返すときに対象のインターフェイスの参照カウントを一つあげて(つまり共有数を増やして)返す、という機能を持つ関数で、これはQueryInterfaceではよく使う関数です。GetInterfaceはDirectShowを開発するときしか使えない関数ですので自分で使いたいときは同機能の関数を実装してください。ここで処理できないものはCUnknown側の処理に任せることで解決しています。実はここがこの関数を仮想継承をしない理由で、つまり、CUnknown(系)を継承したときのQueryInterfaceの動作はIUnknownのQueryInterfaceの呼び出し呼び出しがCStreamのNonDelegatingQueryInterfaceの呼び出しとなって呼び出される処理されなければ上位のCUnknownのNonDelegatingQueryInterfaceの呼び出しになるという風に継承の子供から親方向への呼び出しの連鎖を作ることでこの処理を正しく処理するようにできています。(実際にはこれは仮想関数なのですが、説明がわかりやすいようにと)実際に開いて閉じてみる今までの説明からCStreamを使用するときのやり方も決まります。以下のようなコードになるわけです。NULL;開くときはnewで作ればいいわけですが、開くのに失敗したときはReleaseではなく即座にdeleteを使ってC++のクラスとしてメモリを解放してしまうのが正しいです。開くことに成功すれば参照カウントを1にしてやって、以降はIUnknownのオブジェクト的な扱いを許されることになります。CStreamからIStreamを取得するには、継承しているので単純にアップキャストしてもいいといえばいいですが、COMの礼儀に従ってQueryInterfaceでIStreamを取得します。取得に成功すればlpFileStreamはいらなくなるのでReleaseして使用しないようにします。ちなみに、参照カウントの動きはこんな感じになります。CStreamのデストラクタが呼び出されてファイルが閉じられる次回は残りの関数を実装してみます。今回のネタがCOMやDirectShowでのベースとなる動きですのでよく覚えましょう。コメントをキャンセルメールアドレスが公開されることはありません。気になるプログラムネタや数学ネタがあったら書き込みたいのだが残業が長すぎて眠気が全くとれず体調があまりよくない。過労などでぶっ倒れるかもしれない。あと、さすがに独り身が寂しいのでなんとかしたいと考えてはいるのだが...。アクセスカウンタアクセス数:スポンサーリンクモバイルバージョンに。