質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

6119閲覧

DLLに複数のウィンドウを込める

BeatStar

総合スコア4958

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2017/02/14 02:57

趣味で 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++ )

宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yohhoy

2017/02/14 03:10 編集

それで、何を知りたいのでしょうか?思いついた順に文章を並べるのではなく、質問の本質を絞られた方が良いと思います。なぜ「汎用的なバージョンダイアログを DLL化したい」のでしょう。あなたのイメージする、汎用的とはどういう意味ですか?(端的に言えば、そのような単調な機能を汎化・共通化したい目的を理解できませんでした)
BeatStar

2017/02/14 07:31

MessageBox等のように、毎回実装せずに DLLにリンクするだけで MessageBoxのような感じで気軽にダイアログを出せたらなと思ってです。
PineMatsu

2017/02/14 08:21

質問が長すぎて読む気になれません。他の人も書いてますが問題を絞ってください。
guest

回答3

0

すでに書かれていることですが、質問は絞った方が回答しやすいです。あれもこれもと知りたい気持ちは伝わってきますが、それでは回答する側が困ってしまいます。一つ一つ順番にクリアしていくことが結果的には一番の近道です。

それと、MinGWで作っているようですが、それでないと困る理由が何かあるのでしょうか? マルチプラットフォームなGUIツールキットを利用するならともかく、Windows SDKを使ったGUIアプリ作成にMinGWは向きません(できないことはありませんが、難易度が跳ね上がります)。もしMinGWを使う特段の理由がないのなら、Visual Studioの利用を強くお勧めします。巷に溢れかえっているWindows向けのC/C++情報のほとんどはVisual Studio(Visual C++)を前提としています。

一つだけ指摘しておくとすると、ダイアログの表示はCreateWindowではなく、通常DialogBox系API関数で行います。これはMessageBox関数と同様に、呼び出すとダイアログが閉じられるまで戻ってきません。内部でメッセージループを回しているからです。したがって、自分でメッセージループを用意する必要はありませんし、WNDCLSの登録も不要です。いくつかの準備段階が端折れて、しかもダイアログテンプレートによるデザインも可能ということで、簡単なアプリならダイアログとして実装するということはよくやります。実際、Visual StudioにはダイアログベースでGUIアプリを作成するテンプレートが用意されています。

投稿2017/02/15 02:48

編集2017/02/15 02:50
catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

問題1-1

DLLMainの引数を受け取ってグローバル変数にするサンプルが多いです。
もしくはGetModuleHandleExにGET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESSを指定して取得します。

問題2. ウィンドウのメッセージループはどうするか

DLL内でメッセージループの別スレッドを作ってもいいですし、
EXE側のメッセージループを使用してもいいです。
普通はDLL内でメッセージループを作る必要性はないのでEXE側の
メッセージループをそのまま使用すればいいんじゃないでしょうか。

問題2: 問題2-1 の状態のとき、メインウィンドウが閉じられた場合にプロセスが残らないようにするにはどうすればいいか

これはメインウィンドウでPostQuitMessageを実行してないからじゃないでしょうか?

問題3. ウィンドウから情報を取得する場合やデータを渡す場合はどうするか

CreateWindowの最後の引数にポインタを渡してWM_CREATEで受け取れます。

c++

1struct VersionViewInfo{ 2..... 3}; 4 5void ShowVersionDialogImpl(VersionViewInfo* info){ 6 //略 7 8 HWND hwnd = CreateWindow( 9 //略 10 ,(LPVOID)info //引数の最後 11 ) 12 //略ShowWindowとか 13} 14 15LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 16{ 17 switch (uMsg) { 18 19 case WM_CREATE: 20 LPCREATESTRUCT lpData = (LPCREATESTRUCT)lParam; 21 VersionViewInfo* info = (VersionViewInfo*) lpData->lpCreateParams; 22 break; 23 24 default: 25 break; 26 27 } 28 29 return DefWindowProc(hwnd, uMsg, wParam, lParam); 30}

問題4. 「閉じる」ボタンが押された等でウィンドウが閉じる場合はどうするか

これは質問の意味がよくわかりませんね。
バージョンダイアログを開くときにメインウィンドウを非表示にして、
バージョンダイアログを閉じるときにメインウィンドウを表示したいということでしょうか?

投稿2017/02/14 03:43

hmmm

総合スコア818

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

まず、質問内容を分割したほうが回答がつきやすいですよ。このQ&Aをあとから参照する第三者の方のためにもテーマを絞ってほしいです。

全般的に...猫でもわかるプログラミング - kumeiさん のWEBサイトはご存知かもしれませんが、今一度ご参考にされてはいかがでしょう?WindowsSDK編から、ウインドウの取り扱いについて、とても丁寧に書かれています。

投稿2017/02/14 03:21

hsk

総合スコア728

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問