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

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

ただいまの
回答率

90.52%

  • C

    4370questions

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

  • C++

    4295questions

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

  • Win32 API

    283questions

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

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

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 1,690

BeatStar

score 1212

趣味で 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用エントリーポイントが呼ばれる

-> この DllMainDLL_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++ )

宜しくお願い致します。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • yohhoy

    2017/02/14 12:08 編集

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

    キャンセル

  • BeatStar

    2017/02/14 16:31

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

    キャンセル

  • PineMatsu

    2017/02/14 17:21

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

    キャンセル

回答 3

+2

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

+1

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

問題1-1

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

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

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

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

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

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

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

struct VersionViewInfo{
.....
};

void ShowVersionDialogImpl(VersionViewInfo* info){
    //略

    HWND hwnd = CreateWindow(
     //略
     ,(LPVOID)info //引数の最後
    )
    //略ShowWindowとか
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg) {

    case WM_CREATE:
        LPCREATESTRUCT lpData = (LPCREATESTRUCT)lParam;
        VersionViewInfo* info = (VersionViewInfo*) lpData->lpCreateParams;
        break;

    default:
        break;

    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • C

    4370questions

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

  • C++

    4295questions

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

  • Win32 API

    283questions

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