デスクトップ・マスコットに挑戦してみる 


 Windowsプログラミングの練習がてらに サンプル的にデスクトップ・マスコットを作ってみる。 あくまでプログラムする取っ掛かり なんで、マスコットとしての出来は問わないで:-)。

 ところで、デスクトップ・マスコットという言い方でいいんだろうか。 ウィンドウ・マスコットとか言ってる場合もあるし。 ようは、マスコットキャラの形をしたデスクトップ・アクセサリの一形態 なんでしょうけど。

 とりあえずベクターの デスクトップ/マスコットとかにあるようなもの。  見ているとマスコットを作りたいだけならば、 すでにいくつか汎用なマスコット(デスクトップ・アクセサリ)プログラムがあるので データ(絵やスクリプト)を用意すれば、 わざわざ一からプログラムする必要ないのだけれど:-)

※以下は、模範解答にゃほど遠いだろう、 (間抜けな)悪あがきメモです:-)

あと、コンパイルは

で可能です。以下コンパイル環境が整っているものとしての話 (各コンパイラの実行ディレクトリをpathに設定して、と。bccの場合は 環境変数includeも設定してある、と。例はこちら)。


 STEP-1. マスコット以前 -- 四角くない窓を出す 

 mas_smp1.lzh

 どっかに作り方ないかと探してみると、 Win32 SDK/C&MFC Programming Tips に、そのものずばりのTipがあった。
  非四角形のウィンドウを作るには?(デスクトップにマスコットを表示させるには?)
でもって
  ビットマップの形をしたリージョンを作成するには?
  透過(透明)ウィンドウを作成するには?
とか。

 Winでは、マスコットは、四角くない窓(好きな形の窓)を表示する機能を使って実現している模様。 リージョンなる機能を使う、と。上記サンプル2つを組み合わせれば、 bmp一枚絵をデスクトップに表示するだけなら結構らくちんポイ……

で、とりあえず、上記サンプルの一つ(丸いウィンドウを出すだけ)をお試しする。 ほぼ完成のソースが載っているけれど必要なリソースは付属してないし、 何かちょっとでもいじりもって作業するのがサンプルお試しのコツ(と思ってる)なんで、 好みに手を加えて実行ファイルを作ってみる。 簡単。自分で一からだと到達できんもんなあ。ありがたい。


 STEP-2. BMP一枚をデスクトップに表示 

 mas_smp2.lzh

 次に、BMP一枚絵の形をしたウィンドウを出してみる。
上記 Tip の“ビットマップの形をしたリージョンを作成するには?”のCreateRgnFromBmp() をそのまんま利用して改造。 ソースはこうなった。

 ここまでは、すごく、楽チン。


 STEP-3. BMPをアニメさせてデスクトップに表示 

 mas_smp3-5.lzh

 問題は、こっから。うまくいかない。 リージョン関係の関数の説明みてて混沌。SetWindowRgn()の説明をみると

“オペレーティングシステムは、パラメータ hRgn で指定したリージョンを所有します。 リージョンのコピーは作りません。したがって、以後、このハンドルを使用したり 解放したりしないようにしてください。"
とかある。なんのことやらで暗中模索。 結局Vcのサンプルの中からリージョン関係の関数をgrep、
    SetWindowRgn(GetOuterWindow(), tempRgn, TRUE);
    if (m_hRgn != NULL)
        DeleteObject(m_hRgn);
    m_hRgn = tempRgn;
を見かけ真似る。 いいのかどうかわからないけれど、とりあえず、なんとかなりそう…… と、ましにはなるが、うまくアニメしてくれない。 リージョン生成や切り替えのタイミングがおかしいんか、で、 訳も分からず順番入れ替えたり……で、なんかつじつまが合ったかも。 とりあえず、こんな感じ (実はこの版のみ"やっつけ"たときのまま。 他はアップロードまでに手を加え直した。 キリが付いたのでソースを整理したり、 表に出せない素材(絵)を使ってしまってたため 絵を差し替えたり)。

どうも最初から欲張りすぎた(メモリ使いすぎる) 作りかなあ、と思い、もっと愚鈍に作り直して みたのがこれ(lzhは こっち)……だけれど、 これは見事に失敗。
 絵を差し替えたりしたのだけれど、動きの範囲が増えたせいか 結構チラつく……。

結局、元の仕組みに戻したりでこちら( lzhはこっち)。
マシにはなったけれど、やっぱりちらつく。動いたてるからよしとしたけれど、 リージョン関係の処理はまずいのはまずいだろうし……

 で、いろいろ悪戦苦闘。 ぜんぜん先にすすめん (ソース整理を除けば先の内容くらいまでが一日作業だったのだけれど……)。 未熟者ゆえWM_PAINT中にWM_TIMER来るのかと見当違いに勘ぐったり(濡れ衣)、さらに ほかの素材で試すともっとちらつき目だったり、もちろん マニュアル見直したりNETで何かヒントないかと検索したり……

 結局、リージョン生成/切替のタイミングが悪そう( 少なくとも、BeginPaint()〜EndPaint()の間とか、EndPaint()の後とか は、マズイだろう……ちょっと思えばそうだろうけれど……)。

修正したのが これ(lzhは上記)。

 だいぶマシになった、かな。とりあえず、よし、としとく。


※あがいている最中に知ったのだけれど、実は、 Teddy (Him氏作のデータ(スクリプト)差し替え型のデスクトップアクセサリ) のソースが公開されている模様。
 パラパラと覗いてみて、MFCだったり、己の読解力の足りないのだったりで、 今回直接反映はしなかったけれど。
 Teddyと見比べると、己のはまだ、リージョンの切り替えの仕方が 間抜けたことをやっているような気もする。
けれどTeddyの画面更新の仕組みは凝ったことしてるようで (自力で再描画範囲管理してるんだろうか)、 ちと簡単にはマネできそうにないし。


 STEP-4. マスコットを動かしてみる 

 mas_smp4.lzh

 先ので一旦よしとして、今度はマスコットをデスクトップ 上で動かしてみる。
 動かすといっても、揺らすだけ、なんだけど。 MoveWindowやSetWindowPosで試してすんなり。あとネットで見かけた Tipでタスクバーを除いた画面範囲の求め方を使って画面の中央に 表示してみる。
ソースはこれ


 STEP-5. アクティブ(カレント)な窓に付属してみる 

 mas_smp5b.lzh

 今度は、現在ユーザが使っている窓の上に乗っかるようにしてみる ……で、またしてもハマる。
 GetWindow と GetActiveWindow と戯れて……思いこんだらマニュアルで GetForegroundWindowを目の前にしてても気付けない。
 でもって GetForegroundWindow にしても、今度は、自分(マスコット)自身 がその場合どうすんねん状態。とりあえず安易に、直前の窓を記憶しといて 自分自身がそうだったら、それを用いる……けど、じゃあその窓がロストしてたら どないするんねんで、さらにGetWindowで適当に他の窓を選ぶようにしといて。
試してると何もないとこやアイコンをクリックすると画面全体が大きな窓なのか 猫の足が画面上にちらっと見えるよ、で、とりあえず窓座標みて 0以下なら 消しちゃうようにして(見えない座標へ移すだけ)。
 実は、マスコットをForegroundにした状態で足元(寄生先)の窓の×押して 消してみると…… なんでそんな何にも無いところに移んねん……て、状態だけれど もう、とりあえず仕様っ、てことであきらめる。

 できたソースは これ。だけど・・・

[2001-12追記]
と、水瀬たまき さんよりアクティブウィンドウの判定方法のソースをいただいてた ので(感謝)、それを参考に修正、できたソースは

これ

前のよりかはよくなった模様。


 (とりあえず)終わり 

 まだまだ、いろいろとマズイところ多そうだし、 当初の予定に到達してないけれど、マスコット作成は一旦おわり。 は、見直さないと駄目だろうな。
 vcのサンプルで見つけて真似たSetWindowRgnの直後で回DeleteObjectってのは マネする個所を間違えてるのか…… 他の方のソースみるかぎりはそんなことしてなさそうだし。

 WM_TIMER で、いろいろ処理しているけれど、 そうじゃなくて、メインのメッセージループのほうで、ゲームのループ の作りで作ったほうがよいかもしれない。タイマーの精度の問題もあるし。
 今回はビットマップやそれに対応するリージョンを最初にすべて用意して るけれど、絵の枚数を増やすならば、ダブルバッファにして毎回生成 するほうがよいようにも思う。
 データは、リソースで持つにしても、もう少し差し替えやすい 仕組みを用意しないと面倒。 といってマスコットの動きをどうするか でスクリプトとか用意しだすと手間増大、 やりたいこと自体は 2,3 なこと思えば 本末転倒だろうなあ。


2000-06-06


補足 2000-06-09
 mas_smp4.lzh, mas_smp5.lzh の猫の絵を、縁修正したバージョンに変更。
2000-06-12
 絵差し替えのおりmk.batが先祖帰りしてしまってたのを修正。
2001-12-16
 mas_smp5 の修整版を追加(プログラム修整自体は2月中に終わってたのに^^;)。
 ついでに各サンプルlzhに lcc, MinGW でのコンパイルバッチを追加。



[back]