Flashを吉里吉里のレイヤとして表示するめどがだいたいつきました。おおざっぱに言うと、IOleInPlaceSiteWindowlessを実装して、FlashのActiveXコントロールには吉里吉里のレイヤに対して直接描画してもらいます。
初めてATLを使ってみました。数年前は「なんじゃこりゃ」だったのですが、実際にやってみると割と楽です。
CAxWindow Container;
とかしておいて、
RECT r;
r.left = r.top = 0;
r.right = ClientWidth; r.bottom = ClientHeight;
Container.Create(Handle, r, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
// コントロールを格納するためのウィンドウの作成
CComPtr<IAxWinHostWindow> spHost;
Container.QueryHost(&spHost);
spHost->CreateControl(L"{D27CDB6E-AE6D-11cf-96B8-444553540000}", Container, NULL);
// Shockwave Flash コントロールを作成
でとりあえず Shockwave Flashコントロールは作成できます。
ただ、こいつをWindowless(ウィンドウを作成せずにDCに直接描画するモード)にするためには、Flashのコントロールを作成する前に、
CComPtr<IDispatch> spDispatch;
Container.QueryHost(&spDispatch);
で得た IDispatchインターフェースでAllowWindowlessActivationプロパティをTRUEに設定しないとなりません。
しかし、それだけだとまだ駄目で、Shockwave FlashオブジェクトをWMode=Transparentの状態で作成しないとなりません。
Shockwave FlashコントロールのWModeプロパティはデフォルトで"Window"で、この状態ではウィンドウを作成して内容をそこに表示するモードです。これを"Transparent"に設定すると、親ウィンドウ(などのDC)に直接描画するようになります。
IEでFlashコンテンツを含んだページに対してトランジションをかけられるのもコレのおかげのようです。
これは、作成したあとからWModeプロパティをTransparentに設定しても効果が無く、作成時にWModeプロパティを"Transparent"にしなければなりません。
作成時にプロパティを設定するには、spHost->CreateControlの第三引数に、プロパティの詰まったIStreamインターフェースを渡します。ここから、作成時に必要なプロパティの情報を与えることができます。
プロパティの詰まった、と言っても、どういうデータを与えればいいのかしばらく分かりませんでした。
しばらく弄っていると、C++ BuilderでShockwave Flashをコントロールとして埋め込むと、フォームのデータ内にControlDataというのができます。どうやらこれのようです。
これは以下のようになってました。
000000: 66 55 66 55 64 EC 0A 00 46 57 53 05 64 EC 0A 00 fUfUd...FWS.d... (略) 0AEC60: 3F 03 02 00 00 00 07 00 40 00 00 00 00 03 00 00 ?.......@....... 0AEC70: C6 14 00 00 29 0E 00 00 08 00 02 00 00 00 00 00 ニ...)........... 0AEC80: 08 00 04 00 00 00 3F 00 00 00 08 00 04 00 00 00 ......?......... 0AEC90: 3F 00 00 00 08 00 18 00 00 00 54 00 72 00 61 00 ?.........T.r.a. 0AECA0: 6E 00 73 00 70 00 61 00 72 00 65 00 6E 00 74 00 n.s.p.a.r.e.n.t. 0AECB0: 00 00 0B 00 00 00 0B 00 FF FF 08 00 0A 00 00 00 ................ 0AECC0: 48 00 69 00 67 00 68 00 00 00 08 00 02 00 00 00 H.i.g.h......... 0AECD0: 00 00 0B 00 FF FF 08 00 02 00 00 00 00 00 08 00 ................ 0AECE0: 0E 00 00 00 61 00 6C 00 77 00 61 00 79 00 73 00 ....a.l.w.a.y.s. 0AECF0: 00 00 08 00 10 00 00 00 53 00 68 00 6F 00 77 00 ........S.h.o.w. 0AED00: 41 00 6C 00 6C 00 00 00 0B 00 00 00 0B 00 FF FF A.l.l........... 0AED10: 08 00 02 00 00 00 00 00
この例だと0x000008〜0x0AEC6BがFlashデータそのもの(.swfファイルの中身)で、0x000005〜0x000007がそのサイズとなっています。Flashデータの次にはプロパティが来ています(ここの中身はサッパリなのですが、Transparentという文字が見えます)。
これをIStreamにしてspHost->CreateControlの第三引数に渡してやるとうまくいきました。ついでにこの方法ならばFlashムービーをIStream経由で渡せるため、中間ファイルとしてswfファイルを作成したりせずに、吉里吉里内から直接Shockwave FlashコントロールにFlashムービーを渡せます。
ここまで来れば、ATL内のCAxHostWindow::OnPaint内でビットマップに対して描画を行っている場所がありますので、ここの処理を横取りすれば良いと言うことになります。あ、吉里吉里のレイヤとして動かすときはキーボードやマウスに反応できるようには作らないかもしれません。
清兵衛さんからパッド対応のナイスなコードをいただいているので、ありがたく組み込ませて頂きたいです。
第三回吉里吉里erオフ会inコミケ65が告知されました。幹事の秋人さん、毎度お疲れ様です。私自身はイベント会場の方にいけるかは分かりませんが、オフ会は出られそうです。