ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

Win32APIコミュのSetDlgItemText() 等の表示がなぜかおかしい・・・

  • mixiチェック
  • このエントリーをはてなブックマークに追加
 MSDN 他、いろいろ探してみましたが、あまりに単純な問題のせいか、いまだ解決策が見つからず、もしかしたらここなら解決法を知ってらっしゃる方がいるのでは・・・と思いトピ立てします。

 Win32 の練習用プログラムとして、ファイルを指定して、その CRC32 と MD5 と SHA-1 を表示する、というのを C で作っています。
 ウインドウの基本制御とか、CRC とか SHA-1 とかの実装には、特に問題はありません。

 しかし、SetDlgItemText() もしくは SetWindowText() によるテキストボックス描画が、適用される時とされない時があり、その差がよく分からず困っています。

↓ソースはこれです。
http://www.h2.dion.ne.jp/~khurata/hashs.c
http://www.h2.dion.ne.jp/~khurata/hashs.zip
(↑hash.c や makefile 等を含む現状のソース一式)

 このソースの 806 行目で clear_crc32() しています。この関数は 989 行目にありますが、ここで SetDlgItemText() によりテキストボックスをクリアしています。
 808 行目で MessageBox() をコメントアウトしていますが、このままではテキストボックスがクリアされません(問題あり)。MessageBox() を生かすと、なぜかクリアされます。

 また、750 行目に proc_WM_DROPFILES() という関数があり、ウインドウへの DnD を受け付けていますが、ここでの clear_crc32() は、MessageBox() をしなくても、ちゃんと機能します(問題なし)。

 試しに、SetDlgItemText() を SetWindowText() に置き換えてみましたが、結果は当然ながら同じでした。
 なぜこのようになるのかが分かりません(汗)。MessageBox() を行えば、テキストボックスへの描画という目的は果たせるのですが・・・。

 処理系は、Windows XP Home SP2、Borland C++ 5.82 for Win32、および Borland Resource Compiler 5.40 です。

コメント(17)

試してみました

-環境-
Windows XP Professional Versin 2002 Service Pack 2
Visual Studio 2005 Standard Edition

-ロードされたDLL-
COMCTL32.DLL 5.82
SHLWAPI.DLL 6.0.2900.3020
KERNEL32.DLL 5.1.2600.2945
USER32.DLL 5.1.2600.2622
GDI32.DLL 5.1.2600.2818
COMDLG32.DLL 6.0.2900.2180
SHELL32.DLL 6.0.2900.2951
MSVCR80D.DLL 8.0.50727.42

-手順-
新規作成→プロジェクト→Win32→Win32プロジェクト
ライブラリにcomctl32.lib shlwapi.libを追加して
文字セット→マルチ バイト文字セットを使用するに変更し
デバッグビルド

ファイル(F)→開く(O)でファイルを選択し、CRC32値の算出ボタンを押下。
そのときすでにCRC32値のエディットボックス(IDC_EDIT_CRC32)に
値が入っているとクリアされる(はず)
ということでよろしいですか?

ちなみに消えるので現象を確認できていません。
> 808 行目で MessageBox() をコメントアウトしていますが、このままではテキストボックスがクリアされません(問題あり)。MessageBox() を生かすと、なぜかクリアされます。

ソース見ずに勘で答えますが、こういう不可思議な現象が出たときは、まるっきり関係ないところにバグがあって、それが影響していることが多いです。(たいていポインタがらみのバグです。)よって、問題が起きる場所だけをいくら見てもわからないと思います。プログラム全体を見直してみてください。
気になった点をコメントします。
SetDlgItemText() に渡しているハンドルはダイアログのハンドルではなくウィンドウのハンドルになっています。
ウィンドウのハンドルでも動作は保証されているんでしょうか?
「SetDlgItemText() を SetWindowText() に置き換えてみましたが」とありますが、SetWindowText() のハンドルにはエディトコントロール作成時の make_control 関数の戻り値のハンドルを指定されたでしょうか?
動作には影響しないけどソース見て気になった点

・DragFinish()呼んでない
・ステータスバーのハンドルをDeleteObject()に渡している
> まるっきり関係ないところにバグがあって、それが影響していることが多いです

私もそれを疑って見渡してみたものの
それらしいところはありませんでした。<ポインタがらみ

推測するに、問題はメッセージキュー絡みのような気がします。
無駄な時間を費やすだけかもしれませんが...
WM_PAINT メッセージ処理に BeginPaint と EndPaint がありません。
proc_WM_PAINT 関数に以下の3行を追加してみてください。
PAINTSTRUCT ps;
BeginPaint(wnd_h, &ps);
EndPaint(wnd_h, &ps);
また、これは少し別の視点からですが、
テキストボックスの内容を変更した後、
関数を抜ける前に即時画面に反映したいということならば、
SetDlgItemText 後すぐに UpdateWindow を呼んでください。

これを呼ばないと、テキストボックスの更新はキューに置かれ、
DispatchMessage でテキストボックスの
WM_PAINT が処理されるまで画面には反映されません。

MessageBox を呼ぶと反映される理由は、
MessageBox がモーダルダイアログボックスであり、
元のウィンドウに対して特別な処理が働き、
即時に画面更新用の WM_PAINT が発行されるからです。

(なお、SetDlgItemText は HWND にも使えますよ)
8: kes さん
>(なお、SetDlgItemText は HWND にも使えますよ)
HWND は型ですが...
Handle to the dialog box だけでなく Handle to the window にも使えるという意味でしょうか?
であれば、その根拠を教えていただけないでしょうか?
MSDN Library の SetDlgItemText を見る限りは、Handle to the dialog box にしか使えないように読めます。
残念ながら昔に知った話なので出典は忘れてしまいましたが、
少なくとも Windows 95 の時代よりサポートはされていました。
以前、GetDlgItemInt をよく使ってましたので。

SetDlgItemText(hDlg, nIDDlgItem, lpString) は、
SetWindowText(GetDlgItem(hDlg, nIDDlgItem), lpString) と
内部的に等価なコードになっています。

GetDlgItem も HWND (handle to the window) に使えますので、
結果的に SetDlgItemText も使えるということのようですね。
// そもそもダイアログだってウィンドウ

子ウィンドウにIDさえふってあれば、
親をCreateWindow(Ex)で作成しても使えます。
根拠なんてありません。

ちなみにIsDialogMessage()を使ったコードもたまに見かけますね。
それこそMSDNには

> 指定されたメッセージが指定されたダイアログボックス宛のものかどうかを判断し

と記述してあるので、ウィンドウで使えないと判断されるのでしょうけど。
残念ながらドキュメントあるいはそれに順ずるものはないのですね。
現在の MSDN Library で Handle to the window を対象としていない理由は何なんでしょうね。
どちらにしても MSDN Library ぐらいしか情報がない私にはこれにしたがったコードを書くぐらいです。
確かに文書がどこにも見当たりませんね。

Sahmaro さんの言われるとおり、
ウィンドウに対しては使わない方が、
行儀がよいプログラミングになるは思います。

なぜか GetDlgItem の文書には使えると明記してありますので、
ID から子ウィンドウの HWND を取得する事はできますね。
khurata さんのコードはコントロール ID を使っているため、
これが保障されているだけでも少しは楽になりそうです。
>備考
>IsDialogMessageはモードレス ダイアログ ボックス用ですが、 ダイアログ ボックスと同じキーボード選択を実現することにより、 コントロールを含むウィンドウに対しても使用できます。

Borland C++ 4.0に付属していた「Microsoft Win32 API プログラマーズ リファレンス」(API31WH.HLPファイル)より。
 すいません、4日間自宅を留守にせざるを得ず、放置してしまいました・・・。

 勉強中とは言え、きれいとも言えないソースをお忙しいなか見てくださって、皆さん、本当にありがとうございます! 1つ1つ、ゆっくり確認させていただきます!
m(_ _)m
> 1: てる 様

> そのときすでにCRC32値のエディットボックス(IDC_EDIT_CRC32)に
> 値が入っているとクリアされる(はず)
 そうです、それが期待している動作です。CRC32 算出に時間がかかる大きなファイルを再計算する場合に、算出開始の時点で CRC32 の表示が消えるつもりで作りました。小さなファイルの場合は、動作が速いので分かりません。

> ちなみに消えるので現象を確認できていません。
 Visual Studio だと大丈夫、という事は、Borland 製品との差異がある、という事でしょうか・・・。

> 2: のぐー 様
 アドヴァイスありがとうございます。自分では正しい構造にしたつもりではあるのですが、「自分では正しいと思って(思い込んで)作っている」ため、なかなか自分の目では間違いが見つけられない、という事は往々にしてあると思います(汗)。
 関数の分離などは、自分で勝手にやってますが、それなりに整理したつもりではあります。

> 3: Sahmaro 様
 SetDlgItemText( HWND hDlg, int nIDDlgItem, LPCTSTR lpString) は、SetWindowText( GetDlgItem( HWND hWnd, int nIDDlgItem ), LPCTSTR lpString) と等価だ・・・と私は思っているのですが、確信してはおりません。
 と思ったら、すでに 10: で kes 様が書いてらっしゃいました・・・(汗)。

> 4: てる 様
 ご指摘ありがとうございます、DragFinish() は全然知りませんでした(汗)。早速追加しました。
 ステータスバーは、CreateStatusWindow() を使って「後付け」で作っているので、終了時に DeleteObject() しているのですが、マズいでしょうか・・・。

> 6: Sahmaro 様
 これは、単に私の怠慢と言いますか、後で書くつもりでした・・・行儀悪いソースで申し訳ないです。ちなみにこれを書いても結果は変わりませんでした・・・。

> 7:
 あれっ・・・?

> 8: kes 様
 おそらくは WM_PAINT をなんとかすべきなのでは・・・と思ってはおりましたが、UpdateWindow() は知りませんでした。御陰様で期待通りの動作を得ました。ありがとうございます。

>ダイアログにもウインドウにも・・・
 すでに 13: で kes 様が書かれていますが、私の唯一の「拠り所」は、下記の記述でした。
http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/jpwinui/html/_win32_setdlgitemtext.asp
 ここの「解説」に記載されていることを信じて作りました。
 皆様の御蔭で、期待通りの動作を得ることができ、また、知らなかった事もいろいろ教えていただきまして、本当にありがとうございました!
 私も、他の方がもし困っていたら、自分の出来る範囲で、なんとか手助けしたい・・・と思います。

ログインすると、残り1件のコメントが見れるよ

mixiユーザー
ログインしてコメントしよう!

Win32API 更新情報

Win32APIのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング