8ドット絵エディタ「EDGE2」、MIDI音楽編集ソフト「Domino」、楽曲などを配布している個人サイトです。忙しくなりそうな予感なのでドミノ更新しておきます。更新内容はダウンロードページの下にありますので、そちらをどうぞ。昼休みゲオにダッシュで行ったんですが、スマブラ売り切れでした。2005(MFC)を使っているのですが、印刷周りでいくつかバグを見つけましたので、情報として出しておきます。印刷可能範囲が1~10だとして、印刷画面で2~3ページを印刷しようとした場合、実際には2~10ページが印刷されてしまう。→回避策:http://codezine.jp/forum/message.aspx?thid=472海外のサイトではOnPrint内で印刷範囲を書き換えて回避するコードもありました。《その2》リリースでMFCをスタティックリンクすると、印刷プレビュー画面の上のボタン類が英語になる。“l.jpn/afxprint.rc”にすればOK。“l.jpn/afxprint.rc”の代わりに別名保存したファイルをインクルードすればOKです。《その3》A4縦用紙の印刷プレビュー画面にて、一段階拡大したときに、マウスカーソル(ルーペ)と用紙の当たり判定がおかしい(紙の右側をクリックしても、もう一段階拡大しない)こちらは検索しても回避策が出てきませんでしたので自前でなんとかしました。CPreviewViewの派生クラスを作成して、マウスカーソルの当たり判定部分を修正すればOKです。.NETもいいですがVS2005でせっかくMFCもバージョンアップするなら、こういう初歩的なバグは直してからリリースしてほしいです(というか未チェックなんじゃ・・・)。あと、クラスウィザードは復活させてほしいです(イベントハンドラの追加が面倒)。あと、ラジオボタンかなんかの変数を追加したときにBOOL型にしようとするのは止めてほしいです。あと、インテリセンスの更新をVC6並にちょっぱやにしてほしいです。あと、CFile系の処理でブレークポイント貼ると落ちることがあるのをなんとかしてほしいです。pHoge」の「CHogeHoge*」だけをCtrl+左ドラッグで選択出来るようにしてほしいです(VC6ではできた)そんな事を挙げていくとキリがないですが・・・。́・ω・`)ショボーン何か、改善策などをご存じの方がいらっしゃいましたら、こっそり教えてくださると助かります。MFC)MFC,ProgrammingTips,日記(一応解決しました。例によってシンプルなプロジェクトファイルと実行ファイルを用意しましたので、もし通りすがった方で良い解決策などをご存知の方がいらっしゃれば、私まで連絡をお願いいたします(という他力本願な日記です)。興味のある方向けに実行ファイルも用意しました。今回の不具合は、アクセラレータキー(Ctrl+Zでアンドゥが効くような機構・・・ショートカットキーと呼ぶのが一般的?)が場合によって効かなくなるというものです。起動する「↑(矢印)」キーが「浅い」というコマンドに割り当てられ、「↓」キーが「深い」というコマンドに割り当てられています。「↑」キーを押せば「浅い」が実行され、「↓」キーを押せば「深い」が実行されるというわけです。試しに「↑」「↓」キーを押してみてください。どちらもコマンドが実行されるとメッセージボックスが表示され、「実行された」という事が目で見て解るようにしてあります。どちらのキーでも処理が実行されることを確認してみてください。ここで、ツールボタン「ONで有効」の凹んでる状態を解除します(OFFになります)すると、「浅い」や「深い」が無効状態になります(無効状態にしています)。メニューを表示し、各コマンドが両方とも使えなくなっていル事を確認してください(必須)さて、ここで「↑」「↓」キーを押してみてください。「浅い」や「深い」は使えない状態ですので、もちろん処理は実行されません。ツールボタン「ONで有効」をもう一度凹まし、ONの状態にしてください。これで内部的には「浅い」も「深い」も実行可能状態になります。(メニューは開かないでください。)このまま、「↑」「↓」キーを押してみてください。「浅い」は処理されますが、「深い」が処理されません。「深い」位置にあるコマンド(サブメニュー?)は使えないのです。これが今回の不具合です。ちなみに、このあとメニューを開き、「深い」が有効状態になっているのを確認してから「↓」キーを押せば処理されるようになります。選択範囲が無い時点でメニューを見に行き、座標微調整コマンドが無効状態になっているのを確認してから、画像を選択し、矢印キーを押してみると、キーが効かなくなるという不具合が発生します。APIを通ってコマンド(WM_COMMAND)に変換されるようなのです。その際にTranslateAcceleratorは、対応するメニューコマンドが無効だとコマンドを送信しない仕様らしいんです(MSDNの資料はこちら)。MFCのフレームワークで深い位置にあるメニューコマンド状態が更新されないのかなぁなどと推測しています(あんまりWindowsSDKとかメッセージ処理とか詳しくないのでどっかかん違いしていたらごめんなさい)。土曜日に書いたツールバードッキングで嫌な感じ事件ですが、無事(?)に解決いたしました。当初は闘う前から負けていた(だってドッキング部分はいろいろなサイトで難解と言われていましたから)のですが、きよのさんの協力もあってやる気が出まして(笑)、駄目元でデバッグをしていったところ、それっぽい原因を見つけ出すことができました。VC6.0を使ってどうやって問題を解決したかなどを簡単に書き記しておこうと思います。ドッキングしているツールバーをドラッグ&ドロップした際、ドロップした位置より下側にずれてドッキングしていまう、というのが今回の不具合です(詳しくは12日の日記を参照してください)。なんとなく「ドロップしたあとのツールバー位置を決める処理」に不具合があるんだろうなぁとは予想出来ましたので、その辺をさぐろうと思ったのですが、ソースを見るに当たってまずは大体どんなかんじでドッキングしたツールバーなどを管理しているのか、データ構造を探ることにしました(その方がソース見ていて解りやすくなると思いまして)。CToolBarやCStatusBarのヘルプを見たときに、それらがCControlBarというクラスから派生していたのを何度か目にしていたため、「きっとメインフレームがCControlBarの一覧を持ってるんだろう」という憶測はしていました。m_listControlBars;という名前がそのままの変数を見つけました。ためしに一つずつポインタを取得してみてGetWindowRectでウィンドウ座標を取り、その位置に四角形を描画してみたのですが、思ったとおり、全てのツールバーやステータスバーが格納されていました。実際にはそれだけでなく、謎のクラスCDockBarというクラス(これもCControlBarの派生クラス)が上下左右に1つずつ存在していました。このCDockBarというのがツールバーのドッキングを受け入れるバーのようです(受け入れるバーと受け入れられるツールバーが同じリスト内に存在している、というのも不思議な気がしますが)。上下左右の4つだけでなく、ツールバーを浮かせた状態にした際にも生成されるようです。CControlBarという怪しいポインタ配列を見つけたので、例によって一つずつポインタを取得してみてGetWindowRectでウィンドウ座標を取り、その位置に四角形を描画してみましたが、またも思ったとおり、ドッキングされているツールバーなどが格納されていました。ところが、中にはNULLという情報も含まれており、どういったルールでこの配列の中身が決まっているかが気になりました。そこで、ツールバーのドッキング状態をいろいろ変えながらm_arrBarsがどのように変化するか試したところ、上の行から順番にコントロールバーのポインタが格納されており、NULLは「コントロールバーの改行」を意味するようでした。NULL;このような配列状態になりました。「・・・ということは、ツールバーをドロップした際、この配列への挿入場所を導き出す処理がうまくいかず、こちらが期待する位置にツールバーが配置されず、下の段にドッキングしてしまうのではないか」、というような考えにいきつきました。データ構造は大体解りましたので(?)ようやくここからドッキング部分のソースを追うことにします。・・・どうやって追うのか?10秒ぐらい悩みましたが、ドッキング後には、メインフレームのRecalLayoutが呼び出されると思い、ここにブレークポイントを設置し、実際にツールバーをドラッグ&ドロップしてみたところ、見事にひっかかりました。そこからコールスタックウィンドウを駆使して呼び出し元を辿り、CDockContext::EndDrag()という関数の最初の方でまたブレークポイントを設置し、また実行してドラッグ&ドロップして停止させて、今度はステップ実行でひとつずつ怪しいところが無いか見ていきました。m_arrBars;」というポインタ配列へバーを挿入している事が判明しました。今度は変数ウォッチに、この関数内で使用している変数を表示させ、変数の変化を見ながらステップ実行していきました。配列の先頭(=一番上のコントロールバー)から順番に座標を照らし合わせながら、ドッキングしたいコントロールバーの「順番(配列番号)」を求め、ポインタを挿入している関数だと思われます。nPosInsAfter+1;}この関数でどんな処理が行われているか、私の解釈で簡単に説明しますと・・・コントロールバーというのは種類によってバーの高さが異なりますので、行の中で一番高いサイズをnWidthという変数で記憶しておいて、改行(=NULL)または表示されていないバーが来たら「高さの合計」を示すnTotalWidth変数にnWidthを足す、というような処理が入っています。この高さ合計と、ドッキングしたい場所のY座標(中央)を比較し、条件が合えばその位置にバーを挿入、というような感じです。afxData.cyBorder2;という処理が実行されると、nTotalWidthが減るという事です。nWidthは0ですが、afxData.cyBorder2は0ではないため(2だったかな?)改行&表示されていないバーが来るたびにnTotalWidthの値がどんどん減っていきました。・・・これってバグじゃないの?この部分の不具合疑惑が浮上し、ここをなんとか書き換えて実行しようと思いました。書き換えたい気持ちは山々なのですが、ここはMFCソース内部、変えるのが困難な部分です。̄|○しょうがないので自分でやることに(^^;まず、CDockBar::Insertという関数はvirtual関数ではないため、オーバーライドさせることが出来ません。そんなわけで、virtual関数が出てくるまで呼び出し元をたどりました。pt);という関数が仮想関数であることがわかったため、この関数からCDockBar::Insertまでのすべての呼び出し処理を変更すればCDockBar::Insert処理を別のものに変えられそうでした。́・ω・`)ショボーンクラス別に見てCDockContextCFrameWndCDockBarこれら3つがありますで、これらから新たにクラスを派生させ、そこで別関数を用意すれば良いという事です。(CFrameWndに関してはCMainFrameという関数がありますので、クラスを新しく用意する必要はありませんね。)で、これらのクラスから新たにCDockContext→CMyDockContextCDockBar→CMyDockBarというクラスを作るのはまぁ出来るだろうとは思うのですが、いままでCDockContextクラスをnewしていた部分を今度はCMyDockContextクラスをnewさせるようにしないといけないわけで、それが出来るかどうかの実験から始めました。CDockContextのコンストラクタにブレークポイントを設定して生成タイミングなどを調査した結果、CControlBar::EnableDocking();関数内でnewされている事が解りました。CDockBar部分を書き換えました。これでクラスのインスタンスをごっそり変える事が出来ましたので、CMyDockContextや、CMyDockBarのメンバ変数をコピペしたりして各関数を実装します。→CMyDockBar::InsertDebug()というように呼ばれるわけです。呼び出す際の型キャストも必要です。例の「高さの合計を示すnTotalWidth変数にnWidth足す」という部分に修正を試みます。afxData.cyBorder2;#endifこれで実行してみたところ、ドッキング不具合は発生しなくなりました!・・・長かった。そんなわけで治ったっぽいプロジェクトはこちらです。今後同じような問題にぶちあたった人のお役に立てられれば幸いです・・・。私まで連絡をお願いします。C++6.0が必要です)VisualC持ってないけど見てみたいという方はこちらをどうぞ。プロジェクトの主な作成手順は次の通りです。TRUE);で非表示するまた、症状がわかり易くなるように、ここでダイアログバーを一つ作成しています。(無くても症状は発生します)ビルドし、実行します。症状の再現方法は次の通りです。ツールバー5個中、2個が表示されています。上のツールバーを、ダイアログバーの下へドラッグ&ドロップしてドッキングさせます。すると、普通にドッキングします。