リリースモード時に落ちます。
・使用環境
VC++、MFC、Windows2000
リリースモードでデバッグしながら製作しています。
①イベントをレンジで取得するとき呼び出す関数に引数がない場合落ちる。
②ポストメッセージをすると落ちる。
①については、解決しましたが、②は、原因の特定ができません。
ある個所をコメントアウトするとOKになるが、組み合わせによっては
落ちたりします。そのため、原因の特定はできませんでした。
今まで、デバッグモードで製作していたのですが、リリースモードで
始めてから急に落ち始めたことや、それが、数箇所あるポストメッセージ
の周辺で落ちていること、ポストメッセージがなければ、確実にOKであること
から、ポストメッセージが原因だと思います。
しかし、①も②もなぜ落ちるのか理由がわかりません。
メモリの不正なアクセスはしていないと思うので、これが原因とは考えられません。
というより、調べるのに飽きました。
どなたかご存知な方教えてください。
あまりにも漠然とした内容で、正直回答が難しいパターンですが・・・。
以下を確認してみては?
・Lib等のディレクトリ指定は正しいか?
・OutputDebugStringで実際に落ちている場所を厳密に特定
・リビルド(笑)
ここからスタートしましょう。
はずしてるかもしれないですけど、
メッセージを受ける関数の宣言によって、リリースモードだと落ちてしまうという現象があった
と思います。
既に調査はされていると思いますが、
PostMessageとSendMessageが錯綜しているケースは無いでしょうか?
PostMessageは単にキューにつまれるだけなので、Postした後で
Postされたメッセージが処理されているつもりでSendしてしまうと
不整合が起こり得ると思います。
ああ、デバッグでは落ちないんですよね。
外してましたすいません。
これかな?
メッセージの受け取る側のON_MESSAGEマクロに指定する関数の実装が違う場合
○ afx_msg LRESULT OnMessage( WPARAM wParam,LPARAM lParam );
× afx_msg LRESULT OnMessage();
× afx_msg LRESULT OnMessage( WPARAM wParam );
いちもぃさん、ありがとうございます。
ヘルプを読んでみたものの、OutputDebugStringの使い方がよくわかりませんでした。
滝沢さん、不良PGさんありがとうございます。
宣言は、正しいようで、問題なさそうです。勉強になります。
PATIOさんありがとうございます。
SendMessageとPostMessageが錯綜していると、ダメなのですか?
たくさんのスレッドが立ち上がっている環境で、あるスレッドの中で、
ある処理をしたいためにPostMessageしています。ある処理とは、
画面の制御です。スレッドの処理とPostMessageでするある処理とは、
まったくかかわりのない処理です。
未だに解決しないので困っています。仕方ないので、タイマーによって
代用しています。
ところで、気になった点がありました。
・自分のクラスで定義(プライベート)したIDを使って
PostMessage(MY_ID, NULL, NULL);
というふうに使っています。IDの定義は、
private:
enum{ MY_ID = WM_USER + 1};
としています。これって問題あります?
最近はWM_USERは使わなくなっています。
WM_APPを使いましょう。
>SendMessageとPostMessageが錯綜していると、ダメなのですか?
>たくさんのスレッドが立ち上がっている環境で、あるスレッドの中で、
>ある処理をしたいためにPostMessageしています。ある処理とは、
>画面の制御です。スレッドの処理とPostMessageでするある処理とは、
>まったくかかわりのない処理です。
いえ、ごく普通に考えればいいだけです。
既に説明の中で書いているはずですが、先にPostした結果を期待してSendすると
アプリケーション内の状態に不整合が出る可能性があると言う話です。
特にマルチスレッドの場合、PostとSendが錯綜すれば、そういう状況は
用意に想像できると思います。だから、「既に調査はされていると思いますが」と書きました。
全くかかわりが無いのであれば別に問題は無いはずです。
あと、ON_MESSAGEマクロに指定する関数の実装が違う件ですが、
これは関数の呼び出しに関するメカニズムを理解すれば、それがまずい事は
わかると思います。引数の関係がおかしいとスタック内部のデータを破壊した挙句
もとの関数に戻れないなんて事にもなりかねません。
WM_USERは一部のコントールで拡張された機能のコントロール用に既に使われています。
特にWM_USERの前半についてはかなり怪しいです。
MFCの既存のコントロールの派生を全く含まないものに対して使う場合は大丈夫だと
思いますが、何らかのコントロールの派生に送りつけるメッセージに使うのは危険です。
いもちぃさんが言われていますが、WM_APPを使った方がいいと思います。
リリースモードのコンパイルの最適化の指定をいろいろ変えてみるとか
postしてる先のダイアログ?のポインタを吐き出させてみるとか
まあ、思いつきで適当に書いてるだけですが・・・
しかし、大変そうですね
がんばってください
WM_APP以外に
::RegisterWindowMessage を使う手もありますね
解決しました。
滝沢さん、不良PGさん、ありがとうございます。
この前は、意味を取り違えていました。
どうやら、メッセージを受け取った時に呼ばれる関数の引数が間違っていました。
BOOL RcvMsg( WPARAM wParam, LPARAM lParam );
のように、引数を追加しないといけないみたいですね。
>不良PGさん
afx_msg LRESULT OnMessage( WPARAM wParam,LPARAM lParam );
は、なぜ、戻り値に LRESULTを指定しているのですか?
また、関数を定義する場所は、普通のprivateととかではダメなのですか?
>これは関数の呼び出しに関するメカニズムを理解すれば、それがまずい事は
>わかると思います。引数の関係がおかしいとスタック内部のデータを破壊した挙句
>もとの関数に戻れないなんて事にもなりかねません。
うーむ、難しいです。リリースモードでダメな理由とかもあるのでしょうが、
もっと勉強します。ありがとうございます。
WM_APP???
コントロールの派生はたくさんしてます。かなり危険だったかもしれません。
privateでもダメなんですか?
とにかくこれを使ってみます。
ありがとうございます。
IDが使用されているかチェックできるといいのですが、、、
>afx_msg LRESULT OnMessage( WPARAM wParam,LPARAM lParam );
>は、なぜ、戻り値に LRESULTを指定しているのですか?
↓ここからMSDNより
LRESULT
ウィンドウプロシージャまたはコールバック関数から返される 32 ビット値。
WPARAM
ウィンドウプロシージャまたはコールバック関数への引数として渡される値。
Windows Versions 3.0 と 3.1 では 16 ビット値、Win32 では 32 ビット値。
LPARAM
ウィンドウプロシージャまたはコールバック関数の引数として渡される 32 ビット値。
↑ここまでMSDNより
いわゆるSDKから来たものですね
>また、関数を定義する場所は、普通のprivateととかではダメなのですか?
別に駄目ではないでしょうが・・、普通は、派生を考えてprotectedですね
最後まで、ありがとうございました。
よく勉強する必要がありますね。