質問: 趣味で C/C++ ( Window API あり ) でやっています。 ( ※ イメージしてやりながらなのでめちゃくちゃな文になっていると思いますが... ) GUI でやっているのですが、ちょっと質問があります。 WinAPIでデフォルト提供の バージョンダイアログ はあまり個人的に好きではないので、 汎用的なバージョンダイアログを DLL化したいと思っています。 ですが、ここでいくつか問題があります。 問題セット1{ 問題1. HINSTANCE hInstance はどうするか 問題2. ウィンドウのメッセージループはどうするか 問題3. ウィンドウから情報を取得する場合やデータを渡す場合はどうするか 問題4. 「閉じる」ボタンが押された等でウィンドウが閉じる場合はどうするか } または 問題セット2{ 問題1: もし実行ファイルに複数のウィンドウがあるような場合、どこでウィンドウを生成すべきか 問題2: 問題2-1 の状態のとき、メインウィンドウが閉じられた場合にプロセスが残らないようにするにはどうすればいいか 問題3: 問題2-1, 問題2-2 の係ることですが、これをDLL化することは可能でしょうか 問題4: 問題2-3 で「可能」である場合、どのようにすべきか } です。 ※ "問題" といっても、課題ではないです。問題がある の問題。です。 問題1-1について: まず普通に DLL内で バージョンダイアログ用に WNDCLS を定義し、登録。 その後ウィンドウを CreateWIndow関数でウィンドウを生成... のようにして、 バージョンダイアログ用の自作ウィンドウプロシージャ ( VersionDialogProc ) を定義... という風にしようとしたのですが、 WNDCLS のメンバ hInstance でインスタンスハンドル を指定しないといけないし、 CreateWindow関数にもそのインスタンスハンドルを渡さないといけません。 なので どうすべきなのか... DLL作成関係 ( C/C++ ) の資料を漁っていると "DLLのエントリーポイント" があったので、 もしかしてそれでやるのでしょうか。 ですが、この場合ってグローバル変数の使用は避けられないのでしょうか? 問題1-2について: メッセージループのやつって、ただ登録の意味ではなくて WM_DESTROYメッセージがあるまで ループし続けるやつですよね。 バージョンダイアログは用途的にすぐ閉じるやつなのでまだいいですが、 複数のウィンドウが同時に動いている ( 厳密には交互にだと思いますが。 ) ような場合もありますよね。 そういう場合はどうすればいいのでしょうか。 もし ウィンドウが生成できなかった等のエラーにより表示不可 -> false を返す 表示成功 -> true を返す とするような場合もありますよね。 この場合はどのようにすればいいのでしょうか。 問題1-3 について: たとえばバージョンダイアログを作るとして、汎用的にするために * ファイル名 + バージョン を表示する部分 * 製作者 ( author ) を表示する部分 * 製作者の 連絡先 ( メールアドレス ) を表示する部分 のようなのがあり、そこをDLLがオープンにしている関数の引数で受け取るとします。 この元引数はどうすればいいのでしょうか。 その関数で収まるならいいですが、実際にはウィンドウプロシージャの WM_CREATE メッセージのところで コントロール生成したりしますよね。 ですが、このウィンドウプロシージャは クラスの普通のメンバ関数にすることもできないし、 引数が固定されていて、それぞれ意味があるため追加が不可能ですね。 たとえば マルチスレッドで 開始スレッドに渡す引数を void* で受け取る... みたいなのがないし... そのため グローバル変数を使わないといけないと思いますが、 シングルスレッドならこれでも問題ないですが、マルチスレッドで複数のスレッドから呼び出される可能性があったり、 DLLなので 他の実行ファイルから呼ばれたりする場合もあり得ます。 その場合は HINSTANCEも変更されたりするのでは? グローバル変数として確保していたデータが書き換わるのでは? と思っています。 こういう場合はどのようにすればいいのでしょうか。 問題1-4について: (これは以前質問したような気が...?) 以前自分でやってみたのですが、DLLは普通に組んで、実行ファイルはテストプログラムとして最低限の書式に、 WM_CREATE のところで そのDLL内の ウィンドウを表示する関数で呼び出したのですが、 「閉じる」ボタンを押したらウィンドウが消えたのですが、メインウィンドウとなるウィンドウが表示されませんでした。 試しに "タスクマネージャー" で確認したところ、その実行ファイルは動いているようでした。 うまく動かなかったので(そのソースコードを)削除してしまいました。 なので手元にないのでコードを提示できませんが、 この場合ってどのようにすればいいのでしょうか。 ( 「閉じる」ボタンが押された等で サブウィンドウが 閉じるが、メインウィンドウとなるウィンドウは開いたままにする方法です。 ) もしかして、サブウィンドウ側の ウィンドウプロシージャの WM_DESTROYを削除して DefWindowでしたっけ? デフォルト用のプロシージャに任せるといった感じにするべきなのでしょうか。 確かにやってみればいいことなのですが、一応自分なりにやってみたのですが、 うまくいきません。 特に 問題3, 問題4 で引っかかります。 問題1 は マルチスレッドや 複数の実行ファイルからのアクセスに対応できるようにすると考えると... 一応、現在取り組んでいるのですが、途中のためソースコードは載せられません。 ( 載せてもかなりスカスカな状態であまり意味が... ) 現在やっている方法 ( 考えている方法 ) は ``` /* ShowVersionDialog関数 : バージョンダイアログ ( ウィンドウ ) を表示する関数 ShowInputBox関数 : JavaScriptの Prompt のような 文字列や数値を入力させて受け取るダイアログ ( ウィンドウ ) を表示して 戻り値扱いの引数にセットして返す とします。 */ DLLがリンクされた -> DllMainという DLL用エントリーポイントが呼ばれる -> この DllMainの DLL_PROCESS_ATTACHメッセージを受け取ったときに 引数の一つ HINSTANCE hinstDll を グローバル変数 HINSTANCE g_hinstDll にコピー -> ShowVersionDialog関数, ShowInputBox関数 といった DLLにある 関数が呼ばれたときに グローバル変数 HINSTANCE g_hinstDll を使って 関数内で 生成&表示及び メッセージループ -> ShowInputBox関数のように ダイアログ ( または ウィンドウ ) に入力された値をグローバル変数やグローバル配列に代入 -> ShowInputBox関数のような場合は グローバル変数/配列 から値を取り出して 戻り値 ( または 戻り値扱いの引数 ) として返す ``` です。 ですが、この方法だと まだ実験はしていないのですが、複数の実行ファイルからアクセスされて ShowVersionDialog関数 や ShowInputBox関数のように グローバル変数にアクセスし書き換えたりする 関数にアクセスしていた場合、データが書き換わるおそれがありますよね。 グローバル変数・配列はなるべく使いたくないのですが、 グローバルは使わずにやることは不可能なのでしょうか? それとももっといい方法があるのでしょうか? 今はまだ ShowVersionDialog関数という バージョンダイアログのようなものを表示する関数しかできていません ( しかも未完。 ) が、ShowInputBox関数なる Promptや InputBox のような データ一個受け取るだけのウィンドウ, 色選択ダイアログ を使って 「ウィンドウの色( 背景色 )」と 「コントロールの表示文字列の色 ( 文字色 )」を取得できる ダイアログ ( というよりウィンドウですが。 )を作ろうと思っています。 ですが、質問にある通り、マルチスレッドでの使用や、複数の実行ファイルからのアクセスといった場合、 グローバル変数を使っているので データが書き換わる ( あるいは破壊される? ) おそれがあるような気がするのですが... また、CUIのときは うまくいくのですが、GUIで WM_LBUTTONDOWNメッセージを受け取ったときに 呼び出すと その(えせ)VersionDialogが閉じられて、実行ファイルも終了させても、タスクマネージャーで見ると その実行ファイルのプロセスが動いているようなのです。 最初は WM_CREATEメッセージのところで ShowVersionDialog関数を呼んだのですが、 その バージョンダイアログ ( ウィンドウ ) を閉じても メインウィンドウが表示されなかったので、 WM_LBUTTONDOWNメッセージのところで呼び出してみると、一応 メインウィンドウも表示されたのですが、 バージョンダイアログを閉じた後に メインウィンドウを閉じても タスクマネージャーで見ると、 実行ファイルのプロセスが動いていました。 実行ファイル自体は普通のGUIウィンドウ ( Windows APIでゴリゴリ書くやつ ) です。 どうすればいいのでしょうか? 以降は問題2関係: 問題2-1の"実行ファイルに複数のウィンドウ... "というのは、 たとえば、起動と同時に複数のウィンドウを表示するタイプであれば、 「Windows API 複数 ウィンドウ」だったかな? で検索するとヒットはするのですが、 私が最低限知りたいのは、起動時はメインウィンドウ一つで、たとえば 動画の拡張子を変更 ( wmv -> mp4 etc.) のようにするソフトがあるとします。 メインウィンドウで 「どの拡張子からどの拡張子に変換するか」、 変更前のファイルパス, 変更後に格納するディレクトリ...等の情報をセットして、 "変換!" というボタンを押すと 別ウィンドウが開いて プログレスバー ( ProgressBar ) や、 どこまで完了した等の情報がコンソールのように表示されるとか... のように、最初はメインウィンドウのみで、ある条件 ( "開始" ボタンが押された, "メニューバー" の "バージョン" が押された etc. ) のときだけ表示して、それが終わったら消える.... という感じにしたいのです。 これができれば DLL化ができそうなのですが... 問題2-2 は DLL化したときは なぜか 実行ファイルのプロセスが動いていたので、 TASKKILL を使わずに プログラムのみで終了できたらなぁと... 問題2-3, と 問題2-4 は それのDLL化について。 ※ コードを張ろうとしましたが、字数制限のため投稿不可になりましたので、割愛させていただきます。 [環境等] 言 語: C/C++ WindowsAPI: あり コンパイラ: MinGW ( g++ ) 宜しくお願い致します。
回答: まず、質問内容を分割したほうが回答がつきやすいですよ。このQ&Aをあとから参照する第三者の方のためにもテーマを絞ってほしいです。 全般的に...猫でもわかるプログラミング - kumeiさん のWEBサイトはご存知かもしれませんが、今一度ご参考にされてはいかがでしょう?WindowsSDK編から、ウインドウの取り扱いについて、とても丁寧に書かれています。