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

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

ただいまの
回答率

89.99%

子ウィンドウを閉じる方法

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 2,921

BeatStar

score 1613

C/C++ ( Windows API 実装あり ) でやっています。

DLLに ウィンドウ( ダイアログに相当? )を格納しておいて、
実行ファイルから動的リンクで(DLLの方の)ウィンドウを表示し、データを取得したいと思います。
格納するウィンドウはいくつかあり、

オリジナル? の バージョンダイアログ ( ウィンドウ ),
ウィンドウやコントロールの色と文字の色を取得するウィンドウ
etc.

です。

バージョンダイアログはなんとか成功したのですが、
コントロールの色&文字色 を取得する ウィンドウが...

ウィンドウを生成する場合は hInstance が必要なので、実行ファイル(呼び出し元) の hInstance を引数として渡します。

#include<Windows.h>
#include<string>


using namespace std;


// コントールID
const int ID_FORECOLOR = 102;
const int ID_BGCOLOR   = 103;
const int ID_OKBUTTON  = 104;


/*
 クラスのメンバにするのいいが、
WindowsAPIの ウィンドウプロシージャはstaticでないといけないらしいので、あまり意味がない...
*/
COLORREF g_foreColor, g_bgColor;


// チェックのため。
void MsgBox( const std::string str ){
      MessageBox( NULL, str.c_str(), NULL, MB_OK );
}


// 「Win32 API入門」(http://wisdom.sakura.ne.jp/system/winapi/)
// ->「コモンコントロール」
// ->「色の選択」
// 機能: ChooseColorダイアログを表示し、色を取得する
bool ShowChooseColor( HWND hWnd, COLORREF defaultColor, COLORREF *result ){
      BOOL bStatus;

      CHOOSECOLOR cc = { 0 };

      COLORREF    CustColors[16];

      cc.lStructSize = sizeof( CHOOSECOLOR );
      cc.hwndOwner = hWnd;
      cc.rgbResult = defaultColor;
      cc.lpCustColors = CustColors;
      cc.Flags = CC_PREVENTFULLOPEN | CC_RGBINIT;

      bStatus = ChooseColor( &cc );

      *result = cc.rgbResult;

      if( bStatus == TRUE ){
             return true;
      }else{
             return false;
      }
}



LRESULT CALLBACK WndProc2( HWND hWnd, UINT msg, WPARAM wp, LPARAM lp ){
    static HWND hStatic1, hStatic2;
    static HWND hBgColor, hForeColor, hOK;

    switch( msg ){
    case WM_CREATE:
                     hStatic1 = CreateWindow(
                                "STATIC",
                            EXT("ウィンドウの色:"),
                            WS_CHILD | WS_VISIBLE|SS_RIGHT,
                           60, 20,
                           110, 20,
                           hWnd,
                           NULL,
                           ((LPCREATESTRUCT)(lp))->hInstance,
                            NULL
              );
              
              hStatic2 = CreateWindow(
                              "STATIC",
                           TEXT("文字の色:"),
                           WS_CHILD | WS_VISIBLE|SS_RIGHT,
                            60, 20+21,
                            110, 20,
                            hWnd,
                            NULL,
                            ((LPCREATESTRUCT)(lp))->hInstance,
                            NULL
             );

             // 背景色選択
             hBgColor = CreateWindow(
                                     TEXT("BUTTON"),
                             TEXT("選択"),
                             WS_CHILD | WS_VISIBLE,
                             171+100, 20,
                             400, 20,
                             hWnd,
                             (HMENU)ID_BGCOLOR,
                             ((LPCREATESTRUCT)(lp))->hInstance,
                             NULL
             );
             
             // 文字の色選択
             hForeColor = CreateWindow(
                                TEXT("BUTTON"),
                            TEXT("選択"),
                            WS_CHILD | WS_VISIBLE,
                            171, 20+21,
                            400, 20,
                            hWnd,
                            (HMENU)ID_FORECOLOR,
                            ((LPCREATESTRUCT)(lp))->hInstance,
                            NULL
              );
              
              // "OK"ボタン。 これを押されたら結果を返して戻る。
                    hOK = CreateWindow(
                          TEXT("BUTTON"),
                        TEXT("OK"),
                        WS_CHILD | WS_VISIBLE,
                        171, 20+21+21+21,
                        400, 20,
                        hWnd,
                        (HMENU)ID_OKBUTTON,
                        ((LPCREATESTRUCT)(lp))->hInstance,
                         NULL
            );
            return 0;
    case WM_COMMAND:
                   switch( LOWORD(wp) ){
                   case ID_BGCOLOR:
                                    // グローバル変数の方に格納する
                                ShowChooseColor( hWnd, 0,  &g_foreColor );
                                break;
                   case ID_FORECOLOR:
                                    // グローバル変数の方に格納する
                                ShowChooseColor( hWnd, 0,  &g_bgColor );
                                break;
                   case ID_OKBUTTON:
                                SendMessage( hWnd, WM_DESTROY, 0, 0 );
                                break;
                   }
                   return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
return DefWindowProc( hWnd, msg, wp, lp );
}


extern "C" __declspec(dllexport)
bool ShowColorWindow( int x, int y, HINSTANCE hInstance, HICON hIcon, COLORREF *foreColor, COLORREF *bgColor ){
    MSG msg;
    WNDCLASSEX w;

    w.cbSize = sizeof(WNDCLASSEX);
    w.style = CS_HREDRAW | CS_VREDRAW;
    w.lpfnWndProc = WndProc2;
    w.cbWndExtra = w.cbClsExtra = 0;
    w.hInstance = hInstance;
    w.hIcon = hIcon;
    w.hIconSm = w.hIcon;
    w.hCursor = LoadCursor(NULL , IDC_ARROW);
    w.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(240,240,240));
    w.lpszClassName = TEXT( "Prog" );
    w.lpszMenuName = NULL;

    if( RegisterClassEx( &w ) == 0 ) return -1;

    HWND hWnd = CreateWindow( TEXT( "Prog" ), TEXT("色の設定"), WS_BORDER|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX, x, y, 600, 200-50+20, NULL, NULL, hInstance, NULL );

    if( hWnd == NULL ) return -2;

    ShowWindow( hWnd, SW_SHOW );

    while( true ){
        GetMessage( &msg, NULL, 0, 0 );
        DispatchMessage( &msg );
    }

    // グローバル変数 -> 引数 で戻り値扱いにする
    *foreColor = g_foreColor;
    *bgColor   = g_bgColor;

return 0;
}

コントロールの X座標,Y座標,高さ,幅 はでたらめです。
( コンパイルが通るかどうかや、動くかどうかを先にチェックするため。 )

ウィンドウは表示されたのですが、
挙動が...

ID_FORECOLOR, ID_BGCOLOR のコントロールはうまくいったのですが、

ID_OKBUTTON を押しても このウィンドウが表示されたままで、
システム(?) の "閉じる" ボタン ( "×" ) を押して消しました。

で、実行ファイルの方を再度コンパイル&移動すると、

「アクセス不可」のようなエラーに。

なので、タスクマネージャで見てみると
プロセスの欄に 実行ファイルの名前が...

"プロセスの終了" をして、再度コンパイルするとできました。

私が思うに、

実行ファイルから hInstance を渡す
-> hWnd が hInstace から作成される
-> 元の hWnd が同じであるためSendMessageでWM_DESTROYメッセージを送っても 呼び出し元の実行ファイルの方になる
-> DLLの方のウィンドウが残っているため、"プロセス"には 実行ファイルの方として"生存している"とみなされる

です。

(理由が)わかってはいても、どうすればいいか...

変数名を変えても中身が同じなら、同じデータとして扱われるし、
hInstance に でたらめな数値を入れて渡しても、 もし他のソフトで同じ値を使っている場合なら...

どうすれば回避できるでしょうか。

[環境等]
言語: C/C++
コンパイラ: (DLLは) VC++, (実行ファイルは) MinGW

宜しくお願い致します。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

プロセスが終了しなかった理由ですが、「文字通り」プログラムが終了していなかったからです。
ShowColorWindow関数をご覧ください。

while( true ){
    GetMessage( &msg, NULL, 0, 0 );
    DispatchMessage( &msg );
}

どのようなときにこのループは終了しますか?
というのが答えです。ウインドウが破棄されてもここから出られず、return文に到達しなかったため、プログラムが終了しなかったのです。
なので、メッセージIDをチェックしてループを抜ける処理を追加すると正しく動作するようになります。

int ret;
while( true ){
    ret = GetMessage( &msg, NULL, 0, 0 );
    if( ret == -1 ) break;
    DispatchMessage( &msg );
    if( ret == WM_DESTROY ) break; /* WM_QUITではない */
}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/10/19 15:50

    なるほど。
    そいう風にすればいいんですね。

    キャンセル

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

  • ただいまの回答率 89.99%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

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