1999年10月のエントリ

どうでもいいが,VC のアウトプットウィンドウのスクロールバーを操作している最中にキーを押すと文字が書き込めることを発見。って本当にどうでもいいけど。


印刷に挑戦。デフォルトの印刷処理ではダメなので,まず CView::OnBeginPrinting に処理を加えるが呼び出されない。ここで数分悩んだが,原因判明。結局派生クラスを作ったときに勝手に CView::OnBeginPrinting オーバーライドされていたからだった。印刷処理を基底クラス(CEditorView)で記述していたのに,実際には派生クラス(CXXXView)の仮想関数が呼ばれていたのだ。


フォントダイアログ。@ 付きのフォントを選択させない方法。CFontDialog のコンストラクタの第 2 引数に CF_SCREENFONTS | CF_NOVERTFONTS を指定する。

MFC でドキュメントを保存するかを聞くダイアログボックスを出す方法。CDocument::SaveModified を呼び出す。

だったが,その後 CWinApp::OpenDocumentFile を直接呼び出すことでファイルを開くという目的は達せられたので使わなかった。


エディタ。SHIFT を押していないのに選択されてしまうというバグにずっと悩んでいたが,問題らしき箇所がやっと見つかった。

if(::GetAsyncKeyState(VK_SHIFT))

となっていたのだが,正しくは

if(::GetAsyncKeyState(VK_SHIFT) < 0)

というか今まで正しく使っていたのだが,何故か今回はこうなっていた。これで直るといいんだが,必ず再現する方法が見つからないため確かめられない。

# でいいようだ。


ユーザー定義メッセージ。コンボボックス内のエディットコントロールをサブクラス化し,WM_KILLFOCUS をユーザー定義メッセージでコンボボックスに通知しようとする。が,メッセージが流れてこない。でいろいろ調べてみると,ユーザー定義メッセージの WM_USER + n は MFC がいくつか使用しているとのこと。これをバーンと WM_USER + 1000 にしたら無事動いた。でも前作ったやつは WM_USER + 1 で動いてたんだけど。まあいいか。

# ::RegisterWindowMessage を使用した方がよい。

STL。copy アルゴリズムを使おうとして落ちる。copy アルゴリズムとかは勝手に要素数を拡張してくれるわけではないのか。

copy(l.begin(), l.end(), back_inserter(v));

のように back_inserter を使うことで解決。

DVIOUT を新しいキヤノンプリンタ用に設定。設定の解像度を 360dpi にし,見つからないフォントをそれぞれ生成。通常勝手に生成してくれるはずだが,なんかできなかったので手動。

  • dvi ファイルを開く。
  • DOS プロンプトで C:texsharetexmffontspkcxpubliccm に移動。
  • DVI ファイルを開いたときにできる Gen_font.bat の内容を実行。できた tfm ファイルを C:texsharetexmffontstfmptex に移動

これをエラーがなくなるまで繰り返せばよい。

時刻のチェックで,1 <= hour <= 23 としていた。これでは 0 時を表せない。正しくは 0 <= hour <= 23。


TeX。A・B のような点(かけ算)を入れる方法。すぐ忘れるので書いておく。cdot

# でいいと思うんですが。


TeX の section にラベルをはって他のところに埋め込む方法。section の下に label{aaa} を作り,ref{aaa},またはpageref{aaa} でアクセスする。

Visual Studio の DLL 等再配布情報を探す。Visual Studio ディレクトリの redist.txt に書いてあった。

メモリリークで,行番号が分からないときに問題箇所を発見する方法。C Magazine(ソフトバンク)1999.3 天元広海「VisualC++6.0 デバッギングテクニック」より

デバッガのクイックウォッチに,以下を追加

{,,msvcrtd.dll}_crtBreakAlloc=XXX

ここで XXX はメモリリーク検出時に出るアロケート回数。


コンボボックスのエディットボックスの取得。

combo.GetTopWindow();

以下のコードでメモリリーク。

struct A
{
};

struct B : public A
{
string b;
};

A *p = new B;
delete p;

原因は B のデストラクタが呼ばれないためで,A に仮想デストラクタを用意することで解決。

エディットコントロールなどをウィンドウに直接置く方法。

たまにハマるが,コントロールはメンバに持つようにする。スタックに作ると関数を抜けた瞬間にデストラクトされてしまう。必要なときに Create で作成すればよい。

m_edit.Create(WS_VISIBLE | WS_CHILD, rect, pParent, 0);

コールバック関数の定義。

typedef void (* CallBack)(void *pParam);
virtual void SetCallBack(callBack callBack, void *pParam);

のようにする。

今なら関数オブジェクトを使うが。

VC のリリース版でデバッグする方法。プロジェクトの設定で,C/C++ デバッグ情報-行番号のみ,リンク-デバッグ情報を生成する。で ok。もちろんエディットコンティニューはできないが。

ファイルオープンダイアログのカスタマイズ。まずダイアログテンプレートを作成し,stc32=0x45f の不可視グループボックスを作成。ダイアログはチャイルド,境界線なし,兄弟ウィンドウをクリップ,可視で作成。その後 CFileDialog 派生のクラスを作り,class wizard でテンプレートと結合。コンストラクタで

m_ofn.Flags |= OFN_ENABLETEMPLATE;
m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILE_DIALOG_EX);

とする。


コンボボックスのプルダウン幅の変更。リソースエディタでコンボボックスの矢印をクリックする。

太字にした時の文字の太さが GetTextExtent と違う。これは TEXTMETRIC の tmOverHang を加えればいい。が,選択したときに背景を反転させて描画するとその大きさまで反転してくれないので,自分で背景を描くことにする。


DrawText と TextOut を比較。TextOut の方が大分早いみたいだ。こっちを使うことにした。

フォーカス矩形,どうしてもうまい具合に表示されなかったんだが,スクロールを CScrollView に任せずに自分で処理したらうまく表示された。CScrollView がなんか処理しているらしい。

VC6.0 を入れてからだが,どうもデバッグしてるとエクスプローラ関連が落ちる。デバッグ中のツールバーにマウスカーソルが重なると落ちるし,エクスプローラのメニューに触れると落ちる。何故だろう。


オフスクリーンバッファ,バッファ再作成の時にビットマップの Detach を行っていたが,リソースがどんどんなくなっていく。結局バッファの初期化,解放時に new,delete し,転送時にデバイスコンテキストに選択するようにした。

アイテムなどを選択したときの矩形の描画。通常の方法では細かい点線が書けないので悩んだが,DrawFocusRect で解決。

システム色の取得方法

::GetSysColor();

ビューの背景を変える方法。OnDraw で描画してしまうとその前に白で描画されるのでちらついてしまう。これを回避するには WM_ERASEBKGND メッセージで背景を描画し,TRUE を返す。

エディタ,マウスがクライアント外にある時のスクロールを実装する。メッセージは送られてこないのでタイマーで実装する。OnLButtonDown でタイマーを発生させ,その中で WM_MOUSE_MOVE メッセージを送る(クライアント座標で送ることに注意)。で OnLbuttonUp でタイマーを解放して,完成。

hr みたいな線をダイアログに置く方法。static コントロールに置いて,スタイルで「くぼみ」をチェックする。

日記 2000/01/05 にもう少しいい方法が。


ボタンのオーナードローをする方法。ボタンのオーナー描画をチェックし,ダイアログの WM_DRAWITEM をハンドルする。で nIDCtl がオーナードローしたいコントロールだったら lpDrawItemStruct->rcItem に,pDrawItemStruct->hDC を使って描画する。


メモ帳のバージョン情報のようにフリーリソースを表示しようとしてハマる。Windows3.1 のときは GetFreeSystemResources というのがあったようだが,Windows95 ではなくなっている。よってサンクを使って 16 ビットのコードを呼び出さなくてはならないらしいが,サンクコンパイラが必要だったりアセンブラで記述しなければならないなど非常に面倒。しかもできたとしても WindowsNT では動かない(メモ帳でも表示されない)。で手間に比べて得るものが少ないので中止。

クリップボードからのコピー。他のアプリからのペーストができなくて困ったが,FORMATETC を作って GetData に渡すことで解決。

STGMEDIUM stg;
FORMATETC fmt =
{
CF_TEXT,
NULL, 
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL,
};

if(!pDataObject->IsDataAvailable(CF_TEXT))
{
return false;
}

pDataObject->GetData(CF_TEXT, &stg, &fmt);
HGLOBAL hData = stg.hGlobal;
char *pText = (char *)::GlobalLock(hData);
…
::GlobalUnlock(hData);

VC,コンパイル中にプロジェクトのフォルダを新規作成すると落ちるのを発見。

ワイルドカード *.* をログで検索したら (*.*) という顔文字がヒット。ウーム。


カレットについて。カレットが突然消えるという現象が起こった。調べると,カレットは通常 WM_SETFOCUS で作成し,WM_KILLFOCUS で破棄するらしいので,そうやってみたら解決した。

string の == が使えなくて困る。でいろいろ調べると,

#include <string>

#include <string.h>

と書いていた。何故か string は使えたが,オペレータが見つからなかったようだ。