« 落ちるのは別の原因 | メイン | Direct3Dを自前で…… »

2005年11月04日

吉里吉里 ムービー拡張日誌2:: ウィンドウを列挙する

    

EnumWindowsでトップレベルウィンドウを列挙できる。
EnumChildWindowsで指定した親ウィンドウに属する子ウィンドウを列挙できる。
GetWindowで指定したウィンドウと指定した関係にあるウィンドウのハンドルを取得できる。

EnumChildWindowsで、VideoOverlayに渡されるOwnerWindowを調べてみると、フルスクリーンモードとウィンドウモードで子が変わっている。
ScrollBoxとPaintBoxかと思いきや、GetClassNameで調べると両方TScrollBoxだった。
ウィンドウ時 : TForm - TScrollBox - TPaintBox
フルスクリーン時 : TForm - TPaintBox
だと思っていたのだが……

GetWindowで調べると――
自分 : TTVPWindowForm
Ownerは常にTAplication
Childも常にTScrollBox

ウィンドウ時
Next : TTVPMainForm
Next Next : TAplication
その次は関係のないもの

フルスクリーン時
Next : 関係のないもの

となっている。

Delphiのウィドウの関係については、Owned Window を使いたいApplication 変数が詳しい。
C++Builderも同じVCLを使っているので、たぶん同じ構造を持つと思われる。(上述の関係を見るとそうなっている)
また、オーナーウィンドウなどの関係については、Win32 Window Hierarchy and Stylesに書かれている。

と、ここまでのことをいろいろと考えてみると、ウィンドウの関係などが原因ではない気がしてきた。

フルスクリーン前と後で渡されるOwnerWindowはいつも同じ。
Ownerは常にTAplication。
OwnerWindowの子はTScrollBoxだけど、ハンドルは変わる。
ウィンドウモード時に再生が開始され、フルスクリーン時にOwnerWindowで作った子ウィンドウをSetVideoClippingWindowに渡すとエラーになる。
フルスクリーンになった時に、非表示のウィンドウをSetVideoClippingWindowに渡し、ウィンドウモードに戻った時に子ウィンドウをSetVideoClippingWindowに渡すと復活する。
初めからフルスクリーンモードの時は、OwnerWindowで作った子ウィンドウをSetVideoClippingWindowに渡しても問題ない。また、その後ウィンドウモードになった時にOwnerWindowで作った子ウィンドウをSetVideoClippingWindowに渡しても問題ない。でも、その次は失敗する。
他のアプリケーションがフルスクリーンにするのは問題ない。

『DirectDraw 排他モード』が原因では?

VMRには、次のようなインターフェイスとメソッドがある。
《 IVMRSurface9 インターフェイスは、Video Mixing Renderer フィルタ 9 で使われるメディア サンプルに実装される。フィルタはこのインターフェイスを使って、メディア サンプルに必要な DirectDraw サーフェイスにアクセスできる。 》
《 IVMRSurfaceAllocatorNotify9::ChangeD3DDevice メソッドは、VMR に Direct3D デバイスが変更されたことを通知する。 》

VMR9は、Direct3D 9を使っている。
Direct3D 9を使っている状態で、DirectDrawを使い排他モードへ切り替えた場合、Direct3D デバイスはロストするのではないか?
もしくは、そのデバイスによって作られたサーフェイスは排他モード中使えなくなるのでは?
以前気まぐれで作った吉里吉里用のDirect3Dプラグインで実際に試してみた。
予想通り、フルスクリーンモードに切り替えた後のIDirect3DDevice9::Presentは失敗し、D3DERR_DEVICELOST と言うエラーを返す。
そこで、IDirect3DDevice9::TestCooperativeLevelをコールすると、ラッキーなことにD3DERR_DEVICENOTRESETが返ってきた。
これはヘルプによると《デバイスは、消失しているが、現在リセットできる。》 とある。
そこで、GetAdapterDisplayModeでディスプレイの解像度などを取得し、、IDirect3DDevice9::Resetをコールしてやると復活した。

つまり、IDirect3DDevice9を自前で作り、IVMRSurfaceAllocatorNotify9::SetD3DDeviceでVMRに設定し、フルスクリーン切り替わり時にResetをコールしてやると復活するのでは?
ただ、フォーマットの変更やサーフェイスの再生成が必要になるから失敗する可能性はある。
また今度試そう。


ちょっと関係ないけどメモ
古いWindowsへの対応
ウィンドウクラスを作るには



投稿者 Takenori : 2005年11月04日 00:25




comments powered by Disqus
Total : Today : Yesterday : なかのひと