INASOFT 管理人のひとこと


フリーソフトダウンロードサイト「INASOFT」の管理人 矢吹拓也 が日々の「ひとこと」を語るページです。
2021年1月1日より、旧ブログ(blog.inasoft.org)からお引越ししました。
・INASOFT Webサイト: https://www.inasoft.org/
・管理人のふたこと(長文記事/寄稿文): https://www.inasoft.org/talk/
2022年7月下旬より再び本業多忙化してきているため、更新頻度は落ちます。 [2022/7/24 19:32]

目次 | ←前へ / 2014-10-23 00:00 / 次へ→ / 最新へ⇒

■SetClipboardViewerの戻り値が変?引数と戻り値が一緒!?

2014年10月23日(木) 0:00:00 [さくらのブログから転記]



RSSRSS配信中
https://www.inasoft.org/



先日、「コピペテキスト修飾除去」に関するユーザーからのフィードバックで、突然無言で本ソフトが終了するというものがありました。

本ソフトは公開から4年半ほど経過しますが、自分のところでそんな現象は起きたことはないし、他のユーザーからもそういった声は聞きません。いつもの固有環境問題かな?とも思ったのですが、本ソフトはクリップボードを監視するという使命の都合上、「クリップボードチェーン」という、環境上の他のソフトに大きく影響される仕掛けを採用しているため、固有環境問題が起きやすいソフトであるとも考えられます。

というわけで、本腰を入れて調べてみることにしました。

ちなみに本ソフトが無言で終了するためには、WM_DESTROYか、WM_QUERYENDSESSIONを受け取らなければなりません。つまりは通常終了です。通常終了以外で終了する場合は、何かしらのダイアログが出ますし、少なくともOSが異常終了させた旨のメッセージを出すはずです。とはいえ、他のソフトからの悪影響を受けた状態では、何がどうなっているかなんて想像も付きません。

まずは落ちている箇所を特定するために、全てのウィンドウメッセージを受け取ったところで、デバッグ用のログファイルへ記録メッセージを残すようにしました。すると、WM_CHANGECBCHAINとWM_DRAWCLIPBOARDの2カ所で、突然死をしていることがわかりました。

こんなところでWM_DESTROYか、WM_QUERYENDSESSIONへ繋がるルートはありませんから、明らかに異常動作です。しかし、OSが異常終了させた旨のメッセージを出すことはないみたい。

(ちなみに、イベントログには、アプリケーションエラーである旨のログが出力されていたようでした)

WM_CHANGECBCHAINとWM_DRAWCLIPBOARDは、クリップボードチェーンのために、他のクリップボード監視ソフトから呼び出されたり、他のクリップボード監視ソフトを呼び出したりする可能性のある部分です。詳細は、「クリップボードチェーン」とか「ビューアチェーン」などの言葉でググっていただければわかりますが、Windowsがクリップボード監視ソフトに順番に(排他的に)アクセスさせるために生み出した苦肉の策です。なので、このあたりでトラブルが起きているというのは、ありそうなこと。

(ちなみに、Windows Vista以降でのみ動作させるソフトであれば、AddClipboardFormatListener() を使う別の方法があるのですが、今回は割愛)

次に異常が起きたとき、WM_CHANGECBCHAINとWM_DRAWCLIPBOARDの処理ルーチンがどんな動きをしているか、調べてみました。すると、WM_CHANGECBCHAINとWM_DRAWCLIPBOARDがチェーンの次のソフトを呼び出す(SendMessage()する)ところで、引数に自分自身のウィンドウハンドルを渡していることがわかりました。

SendMessage()が自分自身に同じメッセージを投げた場合、全く同じメッセージ処理が入れ子で実行され続けることになりますから、いずれスタックを使い果たし、プログラムはメモリ不足で死亡します。死亡する際、メモリが不足しすぎれば、エラーダイアログを出すことすらできなくなりますから、OSが出力するはずのエラーダイアログすら出てこなかった直接的原因は、これだったと考えられます。

さて、SendMessage()が自分自身に同じメッセージを投げてしまうようになった原因を調べてみました。

チェーンで次のソフトを呼び出すためのウィンドウハンドルを得る箇所は、SetClipboardViewer() APIを呼び出している箇所です。ここで、自分自身のウィンドウハンドルを登録した際の戻り値として、自分が次にどのウィンドウハンドルにメッセージを伝えるべきかをOSから教えてもらいます。ここしかありません。


実際、ここの戻り値を調べてみたら、引数と全く値が返ってきておりました

SetClipboardViewer(A) と実行したら、戻り値も A だったというわけですね。

SetClipboardViewerが引数と同じ値を戻り値として返すことなんか、ありえるんでしょうか?

普通はないはずです。というか、今回フィードバックを頂いたユーザさんの環境以外では、起きたことはありません。少なくとも私の所では起きていません。

というわけで、SetClipboardViewer() が引数と同じ値を戻り値として返すような場合は、チェーン切れ覚悟の上で、次のウィンドウへの伝達の処理をスキップするようにしようかと思います。これで少なくとも、フィードバックを頂いたユーザさんの環境での謎事象は解決するはず・・・。

時間が取れるようになったら、Windows Vista以降の場合は、AddClipboardFormatListener() を使う実装についても研究してみようかと思います。



目次 | ←前へ / 2014-10-23 00:00 / 次へ→ / 最新へ⇒


目次の表示:


ブログではないので、コメント機能とトラックバック機能は提供していません。ご質問・ご意見等はメールフィードバックまたはTwitter等からお願いします。いただいたご質問・ご意見などは、この「管理人のひとこと」の記事に追加、あるいは新規の記事にする形で一部または全文をそのまま、あるいは加工させていただいた上で、ご紹介させていただく場合があります。
当サイトでは掲載内容による不具合等に関する責任を持ちません。また、内容の正確性についての保証もありませんので、情報をご利用の際は、利用者の自己責任で確認をお願いします。本ページは公開から1年半後の任意のタイミングで削除される予定です。


- 最近の更新 -



3212517 (+0214)[+0214]

Copyright© 2010-2024 INASOFT