POPUPウィンドウの消し方

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
たろ

POPUPウィンドウの消し方

#1

投稿記事 by たろ » 15年前

#以前「C言語です」という名前で投稿しましたが、名前変えました。

C言語+Win32APIで、GUIの画像処理ソフトを作ろうとしているのですが、ウィンドウ操作でわからない事があり、質問させてください。
OSはXP Home (SP3)、VC2008EEを使っています。MFCは使っていません。

種類としてはペイントやPhotoshopのような、画像を表示して加工を施すタイプのアプリケーションです。

動作中にユーザのクリックに反応して表示する、小さなポップアップウィンドウを消すタイミングがわかりません。
添付画像は問題のポップアップウィンドウ(赤枠)が出ている画面をキャプチャしたものです。

①ユーザが特定の場所("透明度○○%"の文字)をクリック
②小さなポップアップウィンドウ(TrackBarコントロールを乗せたWS_POPUPウィンドウ)を表示

その後、「このポップアップウィンドウ以外の場所をクリック(マウス押下)したタイミングでウィンドウを消したい」のですが、どう実装するのがよいのかわかりません。

一応、たぶんできそうだけど・・と思っている実装は、

・このポップアップウィンドウ以外の全てのウィンドウで WM_LBUTTONDOWN や WM_RBUTTONDOWN が来た時にポップアップウィンドウを消す処理を入れる。

というものですが、なんだか泥臭いというか・・「他にもっとうまいやり方があるのでは?」と思ってしまいます。

別のソフトでも、「バージョン表示ダイアログ」や「起動時のスプラッシュウィンドウ」などで、「そのウィンドウ(?)以外の場所をクリックしたら消えてくれる(閉じるボタン等を押す必要はない)」という感じのものを見かけることがあります。ああいう動作はどう実装されているのでしょうか・・?それと似たような感じに見えるのですが・・。検索しても解説してくれているサイトなどを見つけることができませんでした。

わかりにくかったらすみません。
ソースは大量になってしまうので載せていませんが、必要でしたらこの話に的を絞った小さなソースを提示させて頂きます。

よろしくお願いします。m(_ _)m

シエル

Re:POPUPウィンドウの消し方

#2

投稿記事 by シエル » 15年前

そのウィンドウがアクティブじゃなくなったら消すとかはどうですか?

GetActiveWindowで取得したウィンドウハンドルとそのポップアップウィンドウのハンドルが一致しなければ、
閉じるようにするのはどうでしょう。


追記:
すいません。↑のは却下でお願いします。 画像

palladium

Re:POPUPウィンドウの消し方

#3

投稿記事 by palladium » 15年前

もしかして、やりたいことは
ツールチップの表示でしょうか?

palladium

Re:POPUPウィンドウの消し方

#4

投稿記事 by palladium » 15年前

ツールチップじゃないですね。
ようやく意味が理解できました。
ShowWindow(hWndPopup, SW_HIDE);
ではだめでしょうか?

シエル

Re:POPUPウィンドウの消し方

#5

投稿記事 by シエル » 15年前

そのポップアップウィンドウでWM_KILLFOCUSのメッセージを受信したら、
閉じるようにしてはどうでしょうか。

無理かもしれませんが。

palladium

Re:POPUPウィンドウの消し方

#6

投稿記事 by palladium » 15年前

すみません、問題をよく理解してませんでした。

たとえば、トラックバーをサブクラス化して
トラックバーをダブルクリックしたら非表示とかどうでしょう?

たろ

Re:POPUPウィンドウの消し方

#7

投稿記事 by たろ » 15年前

コメントありがとうございます。
説明が乏しくてすみません。やりたい事は、

①クリックしたら独自のWS_POPUPスタイルのウィンドウを表示
②そのウィンドウ「以外の場所」をクリックしたらウィンドウを消す(それまでは出っぱなし)

ですが、②の実装方法で、よい方法がないでしょうか?という話です。

>シエルさん

GetActiveWindow()は使ったことがなかったです。何か応用できるか考えてみます。

>palladiumさん

はい、ShowWindow(hWndPopup, SW_HIDE); で消すことができるのは確かめました。ただ、今考えている方式だとShowWindow()を入れる箇所がかなり多くなり、すぐ考慮漏れが発生しそうで、他にうまいやり方がないのだろうか・・という相談でした。

今考えてる方式とは、ポップアップウィンドウ以外の、メインのウィンドウ他、常に表示されている全てのウィンドウの WindowProc で、WM_LBUTTONDOWN が来たら ShowWindow(SW_HIDE) を実行する、という方式です。右ボタンや中ボタンも含めるともっと増えるし、面倒だなあ・・と。

ShowWindow(SW_HIDE) を実行する箇所が、例えば1箇所だけになるようなよい方法があると嬉しいのですが、難しいででしょうか・・。

やはりソースがあった方がよい気がしてきました。小さなソースを、準備したいと思います。 画像

たろ

Re:POPUPウィンドウの消し方

#8

投稿記事 by たろ » 15年前

>シエルさん

WM_KILLFOCUS、こんなメッセージがあるんですね。フォーカスを失ったら来るメッセージでしょうか。ちょっと試してみます。ありがとうございます。

>palladiumさん

なるほど。ユーザインタフェースとしてはそういう方式もありですね。ありがとうございます。ちなみにサブクラス化は見よう見まねで使ってはいますがあまり理解できていません・・。(DefWindowProcを入れ替える=サブクラス化?みたいな・・)

palladium

Re:POPUPウィンドウの消し方

#9

投稿記事 by palladium » 15年前

サブクラス化についてですが、実行環境次第では
SetWindowSubclass関数が使えるかもしれません。

たろ

Re:POPUPウィンドウの消し方

#10

投稿記事 by たろ » 15年前

質問の内容に的を絞ったソースコードを作りました。
ちょっと長いですが最後に貼りつけます。。

・メインウィンドウ1つ、その中に子ウィンドウ1つ(操作パネル的な)
・小ウィンドウ上でクリックした地点にトラックバーを表示
・トラックバーは実際はWS_POPUPスタイルのウィンドウ上に乗っている

やりたいことは「トラックバー以外の場所をクリックしたらトラックバーを隠したい」です。トラックバーを隠す処理は、ShowWindow(hPopupWnd,SW_HIDE)でよいのですが、それを(できれば)1箇所だけ記述すれば済むような、簡単な方法はないものでしょうか。。

シエルさんに教えてもらった WM_KILLFOCUS を試してみました。が、あと一歩という感じでした。ポップアップウィンドウのイベントハンドラでShowWindow(SW_HIDE)したところ、「トラックバー以外の場所クリックで消える」はできたのですが、トラックバー自体を操作するためにクリックしても消えてしまいました(トラックバーが使えない)。これは、フォーカスがトラックバーコントロールに移ってしまい、その下地のウィンドウから外れてしまったからでしょうか(?)。トラックバーコントロールにフォーカスを移さないようにできればいいのかな?でもそれだとトラックバー操作できなくなるのかな・・うーん・・。
#include <windows.h>
#include <commctrl.h>

HWND    hPopupWnd=NULL; // ポップアップウィンドウハンドル

// ポップアップウィンドウプロシージャ
LRESULT CALLBACK PopupWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    switch( msg ) {
    case WM_HSCROLL:
        // トラックバーが変更された時の処理をする(省略)
        return 0;
    case WM_KILLFOCUS:
        // フォーカスを失った
        // ここで自分自身を隠すと、トラックバーを操作しても消えてしまう
        //ShowWindow( hwnd, SW_HIDE );
        return 0;
    }
    return DefWindowProc( hwnd, msg, wp, lp );
}

// 操作パネルウィンドウプロシージャ
LRESULT CALLBACK ChildWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    POINT po;

    switch( msg ) {
    case WM_LBUTTONDOWN:
        // パネル上でマウス押下した地点にトラックバーをポップアップ表示します
        po.x = LOWORD( lp );
        po.y = HIWORD( lp );
        ClientToScreen( hwnd, &po );
        MoveWindow( hPopupWnd, po.x, po.y, 150, 30, TRUE );
        ShowWindow( hPopupWnd, SW_SHOW );
        break;
    }
    return DefWindowProc( hwnd, msg, wp, lp );
}

// メインウィンドウプロシージャ
LRESULT CALLBACK MainWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    switch( msg ) {
    case WM_CREATE:
        // 操作パネル(子)ウィンドウ作成
        CreateWindowEx( 0, "ChildWindow", "操作パネルのようなもの", WS_CHILD|WS_OVERLAPPEDWINDOW|WS_VISIBLE,
                        0,0,300,200, hwnd, (HMENU)NULL, (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE), NULL );
        // ポップアップウィンドウ作成(親はメインウィンドウ)
        hPopupWnd = CreateWindowEx( 0, "PopupWindow", NULL, WS_POPUP, 0,0,0,0, hwnd, (HMENU)NULL,
                                    (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE), NULL );
        // トラックバー作成(ポップアップウィンドウに乗せる)
        CreateWindowEx( 0, TRACKBAR_CLASS, NULL, WS_CHILD|WS_VISIBLE, 0,0,150,30, hPopupWnd,
                        (HMENU)NULL, (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE), NULL );
        break;

    case WM_DESTROY:
        // アプリケーション終了
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc( hwnd, msg, wp, lp );
}


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow )
{
    MSG                     msg;
    WNDCLASSEX              wc;
    INITCOMMONCONTROLSEX    ic;

    // コモンコントロール初期化
    ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
    ic.dwICC  = ICC_BAR_CLASSES;
    InitCommonControlsEx( &ic );

    // メインウィンドウクラス登録
    ZeroMemory( &wc, sizeof(WNDCLASSEX) );
    wc.cbSize           = sizeof(WNDCLASSEX);
    wc.lpfnWndProc      = MainWindowProc;
    wc.hInstance        = hInstance;
    wc.hCursor          = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground    = (HBRUSH)( COLOR_APPWORKSPACE+1 );
    wc.lpszClassName    = "MainWindow";
    RegisterClassEx( &wc );
    // 子(操作パネル)ウィンドウクラス登録
    wc.lpfnWndProc      = ChildWindowProc;
    wc.lpszClassName    = "ChildWindow";
    RegisterClassEx( &wc );
    // ポップアップウィンドウクラス登録
    wc.lpfnWndProc      = PopupWindowProc;
    wc.lpszClassName    = "PopupWindow";
    RegisterClassEx( &wc );

    // メインウィンドウ作成
    CreateWindowEx( 0, "MainWindow", "メインウィンドウ", WS_OVERLAPPEDWINDOW|WS_VISIBLE,
                    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                    NULL, (HMENU)NULL, hInstance, NULL );

    // メッセージループ
    while( GetMessage( &msg, NULL, 0, 0 ) )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
    return msg.wParam;
}

palladium

Re:POPUPウィンドウの消し方

#11

投稿記事 by palladium » 15年前

フォーカスの問題は残りますが、ちょっとやってみました。
Windows XP sp3, VS2005 std sp2
#include <windows.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
LRESULT CALLBACK PopupWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp );
LRESULT CALLBACK ChildWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp );

HWND    hPopupWnd = NULL; // ポップアップウィンドウハンドル
static BOOL TrackBarVisible = FALSE;

void TrackBarState(HWND)
{
    if(!TrackBarVisible){
        ShowWindow( hPopupWnd, SW_SHOW );
        TrackBarVisible = !TrackBarVisible;
    } else {
        ShowWindow( hPopupWnd, SW_HIDE);
        TrackBarVisible = !TrackBarVisible;
    }
    return;
}


// ポップアップウィンドウプロシージャ
LRESULT CALLBACK PopupWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    switch( msg ) {
    case WM_HSCROLL:
        // トラックバーが変更された時の処理をする(省略)
        return 0;
    case WM_KILLFOCUS:
        // フォーカスを失った
        // ここで自分自身を隠すと、トラックバーを操作しても消えてしまう
        //ShowWindow( hwnd, SW_HIDE );
        return 0;
    }
    return DefWindowProc( hwnd, msg, wp, lp );
}

// 操作パネルウィンドウプロシージャ
LRESULT CALLBACK ChildWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    POINT po;

    switch( msg ) {
    case WM_LBUTTONDOWN:
        // パネル上でマウス押下した地点にトラックバーをポップアップ表示します
        po.x = LOWORD( lp );
        po.y = HIWORD( lp );
        ClientToScreen( hwnd, &po );
        MoveWindow( hPopupWnd, po.x, po.y, 150, 30, TRUE );
        TrackBarState( hPopupWnd );
        return 0;
    }
    return DefWindowProc( hwnd, msg, wp, lp );
}

// メインウィンドウプロシージャ
LRESULT CALLBACK MainWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    HINSTANCE hInst = GetModuleHandle(NULL);

    switch( msg ) {
    case WM_CREATE:
   
            // 操作パネル(子)ウィンドウ作成
        CreateWindowEx( 0, TEXT("ChildWindow"), TEXT("操作パネルのようなもの"), 
            WS_CHILD | WS_OVERLAPPEDWINDOW | WS_VISIBLE,
            0, 0, 300, 200, hwnd, (HMENU)NULL, hInst, NULL );

            // ポップアップウィンドウ作成(親はメインウィンドウ)
        hPopupWnd = CreateWindowEx( 0, TEXT("PopupWindow"), NULL, 
            WS_POPUP, 
            0, 0, 0, 0, hwnd, (HMENU)NULL, hInst, NULL );

            // トラックバー作成(ポップアップウィンドウに乗せる)
        CreateWindowEx( 0, TRACKBAR_CLASS, NULL, 
            WS_CHILD | WS_VISIBLE, 
            0, 0, 150, 30, hPopupWnd, (HMENU)NULL, hInst, NULL );

        return 0;

    case WM_LBUTTONDOWN:
        ShowWindow(hPopupWnd, SW_HIDE);
        return 0;
                   
    case WM_DESTROY:
        // アプリケーション終了
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc( hwnd, msg, wp, lp );
}


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int nShowCmd )
{
    MSG                     msg;
    HWND                    hwnd;
    WNDCLASSEX              wc;
    INITCOMMONCONTROLSEX    ic;

    // コモンコントロール初期化
    ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
    ic.dwICC  = ICC_BAR_CLASSES;
    InitCommonControlsEx( &ic );

    // メインウィンドウクラス登録
    SecureZeroMemory( &wc, sizeof(WNDCLASSEX) );
    wc.cbSize           = sizeof(WNDCLASSEX);
    wc.lpfnWndProc      = MainWindowProc;
    wc.hInstance        = hInstance;
    wc.hCursor          = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground    = (HBRUSH)( COLOR_APPWORKSPACE+1 );
    wc.lpszClassName    = TEXT("MainWindow");
    if(!RegisterClassEx( &wc )){ return -1; }
    // 子(操作パネル)ウィンドウクラス登録
    wc.lpfnWndProc      = ChildWindowProc;
    wc.lpszClassName    = TEXT("ChildWindow");
    if(!RegisterClassEx( &wc )){ return -2; }
    // ポップアップウィンドウクラス登録
    wc.lpfnWndProc      = PopupWindowProc;
    wc.lpszClassName    = TEXT("PopupWindow");
    if(!RegisterClassEx( &wc )){ return -3; }

    // メインウィンドウ作成
    hwnd = CreateWindowEx( 0, TEXT("MainWindow"), TEXT("メインウィンドウ"), WS_OVERLAPPEDWINDOW,
                    CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, (HMENU)NULL, hInstance, NULL );
    if(!hwnd){ return -4; }
    ShowWindow( hwnd, nShowCmd);
    UpdateWindow( hwnd );

    // メッセージループ
    while( GetMessage( &msg, NULL, 0, 0 ) > 0 )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
    return (int)msg.wParam;
}

たろ

Re:POPUPウィンドウの消し方

#12

投稿記事 by たろ » 15年前

WM_KILLFOCUS の処理変更と、コントロールのウィンドウプロシージャ差し替え(サブクラス化?)でなんとか自己解決しました。
シエルさん、palladiumさん、どうもありがとうございました。

・WM_KILLFOCUSはフォーカスを失う直前に来るようで、またwParamに次にフォーカスが移るウィンドウハンドルが入っている。
・そこで、次にフォーカスが移るウィンドウを調べてからShowWindow(SW_HIDE)するようにした。
・具体的には、下地のWS_POPUPウィンドウと、そこに乗るTrackBarコントロールとの両者で、共にWM_KILLFOCUSを捕まえて、相互にフォーカスが移動する場合は何もしない、その他のウィンドウにフォーカスが移る場合だけShowWindow(SW_HIDE)で隠す。

少々無理やり?感もありますが、他のウィンドウのWM_LBUTTONDOWNにShowWindow(SW_HIDE)を書きまくるのに比べれば、だいぶスマートに収まったと思っています。簡単な確認ですが動作も問題なさそうな感じです。

参考までに、先に提示したソースからの変更箇所を載せておきます。
HWND        hPopupWnd;          // ポップアップウィンドウハンドル
HWND        hTrackbar;          // トラックバーウィンドウハンドル
WNDPROC     DefTrackbarProc;    // トラックバー既定ウィンドウプロシージャ

// トラックバーコントロールウィンドウプロシージャ
LRESULT CALLBACK TrackbarProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    switch( msg ) {
    case WM_KILLFOCUS:
        // フォーカスを失う直前
        // 次にフォーカスが移るウィンドウ(wp)がポップアップウィンドウ(親)以外ならポップアップウィンドウ(親)を隠す
        if( (HWND)wp!=hPopupWnd ) ShowWindow( hPopupWnd, SW_HIDE );
        return 0;
    }
    return CallWindowProc( DefTrackbarProc, hwnd, msg, wp, lp );
}

// ポップアップウィンドウプロシージャ
LRESULT CALLBACK PopupWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    switch( msg ) {
          :
    case WM_KILLFOCUS:
        // フォーカスを失う直前
        // 次にフォーカスが移るウィンドウ(wp)がトラックバー(子)以外なら自分自身を隠す
        if( (HWND)wp!=hTrackbar ) ShowWindow( hwnd, SW_HIDE );
        return 0;
    }
    return DefWindowProc( hwnd, msg, wp, lp );
}
        :

// メインウィンドウプロシージャ
LRESULT CALLBACK MainWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    switch( msg ) {
    case WM_CREATE:
              :
        // トラックバー作成(ポップアップウィンドウに乗せる)
        hTrackbar = CreateWindowEx( 0, TRACKBAR_CLASS, NULL, WS_CHILD|WS_VISIBLE, 0,0,150,30, hPopupWnd,
                                     (HMENU)NULL, (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE), NULL );
        // トラックバーウィンドウプロシージャ差し替え(サブクラス化?)
        DefTrackbarProc = (WNDPROC)GetWindowLong( hTrackbar, GWL_WNDPROC );
        SetWindowLong( hTrackbar, GWL_WNDPROC, (LONG)TrackbarProc );
        break;
         :

たろ

Re:POPUPウィンドウの消し方

#13

投稿記事 by たろ » 15年前

>palladiumさん

すみません、入れ違いになってしまったようです。
わざわざありがとうございました!試して頂いたソース、今から確認します。

ISLe

Re:POPUPウィンドウの消し方

#14

投稿記事 by ISLe » 15年前

トラックバーを操作した時点でSetCaptureしてウインドウ外メッセージを監視する方法は使えないでしょうか。
ツールチップ使っていると相性が悪いかもしれません。

たろ

Re:POPUPウィンドウの消し方

#15

投稿記事 by たろ » 15年前

>palladiumさん

なるほど、「Show/Hideの状態を保持しておいて交互に切り替える」「メインウィンドウのWM_LBUTTONDOWNで常に隠す」の2点でしょうか。

手元の環境で実行したところ、タイトルバーをクリックした時はトラックバー消えず残ったままになってしまうようでした。クライアント領域外のマウス押下もつかまえてShowWindow(SW_HIDE)を実行すればよさそうかな。

あと、他にもいろいろ手直しありがとうございます。勉強になりました。

・hInstanceって、GetModuleHandle(NULL)で取得できるんですね。知りませんでした。
・MSDNを見たら、while(GetMessage(..)) という書き方はダメよと確かに書いてありました・・。
・nShowCmdってそうやって使うんですね・・知りませんでした。。

身近に相談できる人がいないのですごく助かります!
本当にありがとうございました!

たろ

Re:POPUPウィンドウの消し方

#16

投稿記事 by たろ » 15年前

>ISLeさん

コメントありがとうございます。
ツールチップは現在使っていませんので相性は大丈夫そうですが、すみません、試してみたいのですが、具体的な実装がすぐイメージできないので、調べてみます。

・トラックバー操作時点でSetCaptureするとは、トラックバーをサブクラス化した?差し替えウィンドウプロシージャで WM_LBUTTONDON/WM_LBUTTONUP を捕まえて実行するのでしょうか・・。

・そしてSetCaptureした後、ウィンドウ外メッセージを監視するというのは・・どこで何をすれば・・すみません・・。SetCaptureはドラッグ操作の処理で使っていますが、「SetCaptureしておけばウィンドウ外に出てもドラッグが続けられる」というくらいの認識しかありませんでした。

とりあえずSetCaptureを調べてきます。

ISLe

Re:POPUPウィンドウの消し方

#17

投稿記事 by ISLe » 15年前

SetCaptureだと下のウインドウにメッセージを投げる透過処理が必要なので面倒臭いですね。

No:59981のソースをもう一度詳しく見てみたのですが、

1) ポップアップウインドウを開くのはWM_LBUTTONDOWNではなくWM_LBUTTONUPで行う。

2) ポップアップウインドウのウインドウプロシージャに以下のメッセージ処理コードを追加。
case WM_ACTIVATE:
        {
            WORD fActive = LOWORD(wp);
            if (fActive == WA_INACTIVE) {
                ShowWindow(hwnd, SW_HIDE);
            }
        }
        break;
ではどうでしょう。

シエル

Re:POPUPウィンドウの消し方

#18

投稿記事 by シエル » 15年前

これってMDIじゃないんですね。

palladium

Re:POPUPウィンドウの消し方

#19

投稿記事 by palladium » 15年前

前回の修正とツールチップの動作確認です。
以下抜粋です。
#include <windows.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
LRESULT CALLBACK PopupWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp );
LRESULT CALLBACK ChildWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp );

#define IDTT_TRACKBAR   1   // ToolTip control ID

HWND    hPopupWnd = NULL;   // ポップアップウィンドウハンドル
HWND    hTrackBar = NULL;
static BOOL TrackBarVisible = FALSE;


void TrackBarState(HWND hPopupWnd, PBOOL pTrackBarVisible) // 非グローバル対策
{
    if(! *pTrackBarVisible){
        ShowWindow( hPopupWnd, SW_SHOW );
    } else {
        ShowWindow( hPopupWnd, SW_HIDE);
    }
    *pTrackBarVisible = ! *pTrackBarVisible;
    return;
}

BOOL AddToolTip(HWND hOwnerWnd, LPTSTR lpText, UINT_PTR uId)
{
    TOOLINFO ti;
    HWND hToolTip = CreateWindowEx(
        WS_EX_TOPMOST,      // タクスバーとの競合を避ける 
        TOOLTIPS_CLASS,     // ツールチップクラス
        NULL,               // ウィンドウタイトルは不要
        TTS_ALWAYSTIP |     // 対象のアクティブ・非アクティブにかかわらず常に表示する 
        TTS_NOPREFIX ,      // &文字を有効にする(表示される)
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, hOwnerWnd, NULL, GetModuleHandle(NULL), NULL);
    if(!hToolTip){ return FALSE; }
    
    GetClientRect(hOwnerWnd, &ti.rect);
    ti.cbSize   = sizeof(TOOLINFO);
    ti.uFlags   = TTF_SUBCLASS;
    ti.hwnd     = hOwnerWnd;
    ti.uId      = uId;
    ti.hinst    = NULL;
    ti.lpszText = lpText;
        // 初期化したTOOLINFO構造体データを登録する
    if(!SendMessage(hToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti)){ return FALSE; }

        // ToolTipが表示されるまでの時間指定(ms)
    SendMessage(hToolTip, TTM_SETDELAYTIME, TTDT_INITIAL, 100);
    return TRUE;
}

// 操作パネルウィンドウプロシージャ
LRESULT CALLBACK ChildWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    POINT po;

    switch( msg ) {
    case WM_LBUTTONDOWN:
        // パネル上でマウス押下した地点にトラックバーをポップアップ表示します
        po.x = LOWORD( lp );
        po.y = HIWORD( lp );
        ClientToScreen( hwnd, &po );
        MoveWindow( hPopupWnd, po.x, po.y, 150, 30, TRUE );
        TrackBarState( hPopupWnd, &TrackBarVisible );  // ■
        return 0;
    }
    return DefWindowProc( hwnd, msg, wp, lp );
}

// メインウィンドウプロシージャ
LRESULT CALLBACK MainWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    HINSTANCE hInst = GetModuleHandle(NULL);
    
    switch( msg ) {
    case WM_CREATE:
   
            // 操作パネル(子)ウィンドウ作成
        CreateWindowEx( 0, TEXT("ChildWindow"), TEXT("操作パネルのようなもの"), 
            WS_CHILD | WS_OVERLAPPEDWINDOW | WS_VISIBLE,    
            0, 0, 300, 200, hwnd, (HMENU)NULL, hInst, NULL );

            // ポップアップウィンドウ作成(親はメインウィンドウ)
        hPopupWnd = CreateWindowEx( 0, TEXT("PopupWindow"), NULL, 
            WS_POPUP, 
            0, 0, 0, 0, hwnd, (HMENU)NULL, hInst, NULL );

            // トラックバー作成(ポップアップウィンドウに乗せる)
        hTrackBar = CreateWindowEx( 0, TRACKBAR_CLASS, NULL, 
            WS_CHILD | WS_VISIBLE, 
            0, 0, 150, 30, hPopupWnd, (HMENU)NULL, hInst, NULL );

        AddToolTip( hTrackBar, TEXT("some text"), IDTT_TRACKBAR );    // ■
        return 0;

    case WM_LBUTTONDOWN:
        ShowWindow(hPopupWnd, SW_HIDE);
        return 0;
                   
    case WM_DESTROY:
        // アプリケーション終了
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc( hwnd, msg, wp, lp );
}

たろ

Re:POPUPウィンドウの消し方

#20

投稿記事 by たろ » 15年前

>ISLeさん

すみません、SetCaptureを考えてるうちに寝てしまいました。。
MSDNを読みまして、「SetCaptureしたウィンドウは、(自身以外も含めて)以降のマウス操作をすべて拾うことができる」という感じで、「なるほど」と思いました。そして

①トラックバー出現と共にSetCapture(hTrackBar)する
②以降のマウスダウン/アップ等のイベントが、
  ・自身のウィンドウ上ならトラックバー処理
  ・自身のウィンドウ上でなければウィンドウ隠してReleaseCaptureして終わり

の発想までいきましたが、具体的にどこにどう実装するか・・まるっと違う方式になるな・・というところでした。仕事おそくてすみません・・。ただ、なるほどこんな考え方もあるか!という感じでとても参考になりました!ありがとうございました。

そして WM_ACTIVATE を使った方式ですが、これ動きました!すごいっ、ShowWindow(SW_HIDE)も1回だけだし、かなりスマートです。こんなやり方があったのか~。

ちなみに、ポップアップの表示は WM_LBUTTONUP と WM_LBUTTONDOWN とどちらも試してみましたが、特にどっちでも大丈夫そうに見えます・・。何か違うのでしょうか・・。

あと、細かい話ですが、トラックバー表示状態のままメインウィンドウの大きさを変更しようとしてウィンドウ境界部分(矢印カーソル状態)をドラッグしようとすると、なぜか一発目はできません(ドラッグ操作が無視されてしまう感じ)。トラックバーが消えていれば問題ないですが。なぜそんなところの動作に影響があるのだろう・・?まあ気にするほどの事でもないかな・・。

それにしても目から鱗です。ありがとうございました!


>シエルさん

貼り付けたソースはMDIではありませんが、実際作ろうとしている画像処理アプリはMDIです。

MDIの子ウィンドウ(任意数)と、操作パネルのようなウィンドウがいくつかあって、さらに操作パネル上には部品用のウィンドウもたくさんあって・・という感じで、それら全てのウィンドウに「トラックバーを消す」処理を入れるなんて・・、かなり大変だし、もっといい方法ないのかな?ということで質問させて頂きました。 画像

palladium

Re:POPUPウィンドウの消し方

#21

投稿記事 by palladium » 15年前

私もWM_ACTIVATE方式をやってみました。
素晴らしい!

勉強になりました。

たろ

Re:POPUPウィンドウの消し方

#22

投稿記事 by たろ » 15年前

>palladiumさん

たびたびありがとうございます!
おお・・ツールチップの実装コードはじめて見ました。こうやって作るんですね。

これいいですね。いい感じに勝手に出現して勝手に消えてくれます。

ソフトがもっとまともに動くようになったらそのうち入れてみよう・・と何となく考えていましたが、1つ2つ入れてみようかなぁ。これは hToolTip はアプリケーション全体で1つだけで、中身のテキストを変えて使い回せばいいんですよね・・って、やってみればわかるか。

ありがとうございました~。

シエル

Re:POPUPウィンドウの消し方

#23

投稿記事 by シエル » 15年前

WM_ACTIVATEって非アクティブのときもこのメッセージで受け取るんですね。
知らなかったので、すごい勉強になりました。

ツールチップも私は使ったことなかったので、非常に勉強になりました。
この掲示板は見てるだけですごい勉強になりますね^^

なんか質問者じゃないですけど、ありがとうございますw

たろ

Re:POPUPウィンドウの消し方

#24

投稿記事 by たろ » 15年前

皆様ありがとうございました。おかげさまで問題は解決し、それ以外でもとても勉強になりました。

ちょっと補足を最後に・・しつこくてすみません。WM_ACTIVATE方式で、「なぜかウィンドウの大きさ変更が(一発目だけ)できない」という細かい話を書きました。原因はよくわかりませんが、それを回避する実装を考えました。(無理やり感たっぷりですが・・)

「非アクティブになって次のウィンドウもアクティブ化された後」でポップアップウィンドウ隠すようにしたつもりです。メッセージの到着順序とかあまり詳しく調べておらず不安は残りますが、手元(WinXP Home SP3)では動いているようです。

・非アクティブになった後で来る(つもりの)独自メッセージを定義。

  #define WM_APP_INACTIVATED WM_APP

・ポップアップウィンドウプロシージャで、
 ・非アクティブになる直前(WM_ACTIVATE)に WM_APP_INACTIVATED を PostMessage()。
   case WM_ACTIVATE:
     {
      WORD fActive = LOWORD(wp);
      if (fActive == WA_INACTIVE) {
        // (これから)非アクティブになります
        // 「アクティブになった後」の独自メッセージをポストして終了。
        PostMessage( hwnd, WM_APP_INACTIVATED, 0, 0 );
      }
    }
    break;

 ・WM_APP_INACTIVATED(非アクティブになった後)でウィンドウを隠す。
   case WM_APP_INACTIVATED:
     // 非アクティブになりました
     ShowWindow(hwnd, SW_HIDE); // ウィンドウ隠す
     return 0;

質問の内容自体は既に解決していますので、解決マークとさせて頂きます。
ありがとうございました。m(_ _)m 画像

ISLe

Re:POPUPウィンドウの消し方

#25

投稿記事 by ISLe » 15年前

> ちなみに、ポップアップの表示は WM_LBUTTONUP と WM_LBUTTONDOWN とどちらも試してみましたが、特にどっちでも大丈夫そうに見えます・・。何か違うのでしょうか・・。

トラックバーのポップアップウインドウが表示されているときに、操作パネルのようなものウインドウのクライアント領域をクリックした時の挙動が違います。

WM_LBUTTONUPで表示しているときは、クリック一回でポップアップウインドウが移動します。
WM_LBUTTONDOWNだとクリックして非表示になり、もう一回クリックすると表示されます。

WM_LBUTTONUPのほうが元の挙動と同じだというのもありますが、WM_LBUTTONDOWNの挙動はたまたまそうなっているという意図しない挙動なのでお勧めしません。


> あと、細かい話ですが、トラックバー表示状態のままメインウィンドウの大きさを変更しようとしてウィンドウ境界部分(矢印カーソル状態)をドラッグしようとすると、なぜか一発目はできません(ドラッグ操作が無視されてしまう感じ)。トラックバーが消えていれば問題ないですが。なぜそんなところの動作に影響があるのだろう・・?まあ気にするほどの事でもないかな・・。

こちら、解決されたようですが、実はShowWindowのポスト版というAPIがあります。
No:60006で紹介したコードの場合
ShowWindow(hwnd, SW_HIDE);

ShowWindowAsync(hwnd, SW_HIDE); /* メッセージポスト版 */
に変更してみてください。

palladium

Re:POPUPウィンドウの消し方

#26

投稿記事 by palladium » 15年前

ShowWindowAsync関数はMSDNによると
The ShowWindowAsync function sets the show state of a window created by a different thread.
とあるので、動作保障が無いかもしれません。

たろ

Re:POPUPウィンドウの消し方

#27

投稿記事 by たろ » 15年前

>ISLeさん、palladiumさん

細かい話にコメントありがとうございます!実はけっこう気になってました。

>WM_LBUTTONUPで表示しているときは、クリック一回でポップアップウインドウが移動します。
>WM_LBUTTONDOWNだとクリックして非表示になり、もう一回クリックすると表示されます。

おお、本当ですね。気づきませんでした。なるほど。これは、メッセージの到着順による違いでしょうか。
0) 表示されてる状態から、

1) WM_LBUTTONDOWN で表示
2) WM_ACTIVATE で隠す



1) WM_ACTIVATE で隠す
2) WM_LBUTTONUP で表示

の違いかな?ちゃんと確認してみたいと思いますが、ここまで考慮して頂いていたとは・・感服しました。


そして ShowWindowAsync 関数!!試してみたら期待通り動きました!うおお・・こんなものがあったとは。すごい、よくご存知ですね。MSDNのShowWindowのページにもなぜかリンクがないし。左側の関数ツリーには出てきたけど・・。う~んこういうところで差が出るなぁと改めて痛感します。

palladiumさんご指摘の、MSDN説明文「別のスレッドによって作成されたウィンドウの表示状態を設定」は確かに気にかかります。「同じスレッドで作ったウィンドウに使っちゃダメなの?」と。でも下の解説には「イベントをポストします」とあるだけで、スレッドについては触れられていません。なんなの?スレッド関係ないんじゃ?とも思ってしまいますが、ウィンドウとスレッドの結びつき具合をよく知らないし・・謎だ・・。こういう時にどちら側に倒すか・・難しいです。

ひとまず手元の XP Home SP3 では特に問題なさそうな感触です。
できれば ShowWindowAsync が一番スマートなので使いたい。
問題があったら No:60040 (独自メッセージ版)に戻す。

という方針でいこうかなと思ってます。

いろいろ教えていただき本当にありがとうございました!

ISLe

Re:POPUPウィンドウの消し方

#28

投稿記事 by ISLe » 15年前

"(a window created by) a different thread"というのは、ShowWindowAsyncを呼び出すスレッドから見て異なるスレッドという意味ではなく「(ウインドウを作成した)それぞれのスレッド」という意味だと思います。
#日本語サイトは直訳ですけど。

--追記
ウインドウはスレッドと関連付けられメッセージキューもスレッドごとに独立しているので、メッセージのポスト先はそれぞれのスレッドというふうに表現できます。
画像

たろ

Re:POPUPウィンドウの消し方

#29

投稿記事 by たろ » 15年前

>ISLeさん

なるほど・・! 深いご見識と洞察に脱帽です・・。よろしければもう少し食いつかせてください。

「different thread」という表現。確かにMSDNはShowWindowAsyncの特徴を「他のアプリケーションに対して安全に使える」と書いてます。元々、"別のアプリケーションプロセスに対して使うもの" という感じでしょうか。ググっても、そういった用途の話しか見つかりませんでした。その点を強調した表現かもしれないと思いました。

裏を返すと「単一アプリケーション内で使うのは?」→「そんな意味もないし必要ないだろう?」という感じでしょうか。

でもそれなら、今回の件で辿り着いたこの一番スマートな方式(WM_ACTIVATE+ShowWindowAsync)は何なんだろう・・やりたい機能は、別にそんな独創的な話ではない。でもトリッキーな実装になってしまってるんでしょうか?できれば定石的な実装でいきたいですが・・。


>ウインドウはスレッドと関連付けられメッセージキューもスレッドごとに独立しているので、

このあたりのWindows内部の話、興味深いです。OS側でウィンドウやスレッドがどう管理されているのか?イメージしながらAPIを使えるといいのですが、なかなか難しいです・・。

ウィンドウは、生成したスレッドと紐付いてるんですね。
メッセージキューはウィンドウに1つ存在する、ウィンドウが持ってる感じをイメージしてます。

もっと突っ込んで、ウィンドウの実体=ウィンドウハンドルの先にある構造体かクラスのインスタンス?と、プロセスやスレッドの関係、という話になるともうダメです(笑)プロセス・スレッドの実体も構造体かクラスのインスタンスなのかな・・メモリ上どうなってるのか・・CPUの割り当てとか・・難しいです・・。


>メッセージのポスト先はそれぞれのスレッドというふうに表現できます。

なるほど・・「スレッドにウィンドウメッセージをポスト」というのは、わかるような、わからないような・・。

でもそういえば不思議です。「ShowWindowAsync がメッセージキューにポストする "a show-window event"」って何だ?と。WM_SHOWWINDOW とは違うようですし、WM_XXX 系のウィンドウメッセージとは違うものでしょうか。同じだけど、WM_XXX の名前で公開されてない秘密メッセージ、とかかな。謎です・・。 画像

palladium

Re:POPUPウィンドウの消し方

#30

投稿記事 by palladium » 15年前

>もっと突っ込んで、ウィンドウの実体...
この辺りはやっぱり押さえておきたいですよね。

私は「Advanced Windows 改訂第4版 Jeffrey Richter著」を
参考にしました。(ISBN4-7561-3805-5)

たとえば
PostMessageはメッセージをポストするとすぐに制御を返しますが、
呼出し元スレッドからは、メッセージが送り先で処理されたかどうかわかりません。
(処理完了のエラーチェックができない)

もし、送り先での処理完了通知を受け取るとなると問題があります。
送り先がハングアップしていた場合、処理完了通知を受け取れないので
呼出し元スレッドもハングアップしてしまいます。

ShowWindowAsyncはハングアップの連鎖を防ぐために使われるのだと思います。

ISLe

Re:POPUPウィンドウの消し方

#31

投稿記事 by ISLe » 15年前

> 「different thread」という表現。

palladiumさんがおっしゃっているハングアップの連鎖、いわゆるデッドロックは単一スレッドでも発生します。
デッドロックを避けるためにSendMessageとPostMessageを使い分けることは特別なことではないです。
今回のメインウインドウ枠のコントロールが一回目のクリックで効かないというのはShowWindowの副作用が原因ですのである種のデッドロックと考えられなくもないような気がします(弱気)。
ならばSendMessageの代わりにPostMessageを使うようにShowWindowAsyncを使って後回ししてもらうというのは常識の範囲というかしばしば使う手だと思います。
もちろん場合によってはメッセージ処理が遅延することによる影響を考慮する必要があります。

> ウィンドウは、生成したスレッドと紐付いてるんですね。
> メッセージキューはウィンドウに1つ存在する、ウィンドウが持ってる感じをイメージしてます。

後半は違いますよ。
メッセージキューもスレッドに対して1つです。
メッセージキューに溜まったメッセージをウインドウ(プロシージャ)に投げているのはメッセージループにあるDispatchMessage APIです。

> でもそういえば不思議です。「ShowWindowAsync がメッセージキューにポストする "a show-window event"」って何だ?と。WM_SHOWWINDOW とは違うようですし、(後略)

調べたところちゃんとWM_SHOWWINDOWがポストされていましたよ。

たろ

Re:POPUPウィンドウの消し方

#32

投稿記事 by たろ » 15年前

>palladiumさん

今までWindowsプログラミングの本は読んだことありませんでした。
MSDNとグーグル先生で何とかなるかな?と思ってて・・。
紹介いただいた本、amazonや紹介ブログなども見てみましたが高評価でした。
やはりネットだけでは得られないような情報がまとまっているのでしょうか。

他にも、GUIなら「プログラミングWindows」、Windowsの実装を追求したいなら
「インサイド Microsoft Windows」も揃えておくべき、なんていう人もいて・・。

こんど本屋さんで中身を見てみたいと思います。そして財布と相談します。(^^;
ありがとうございました!


>ISLeさん

なるほど・・。なんだか、単に自分が知らなかったから大げさに考えてしまった気もしてきました。
「デッドロックを避けるためにSendMessageとPostMessageを使い分け」は今まで遭遇したことがありませんし、
ShowWindowAsync も知らなかったし・・。今回 ShowWindowAsync を使う事は、別にトリッキーでもない、
APIを知ってればまあ普通、と思っておきたいと思います。

>メッセージキューもスレッドに対して1つです。
>メッセージキューに溜まったメッセージをウインドウ(プロシージャ)に投げているのはメッセージループにあるDispatchMessage APIです。

なんと、知りませんでした・・orz お恥ずかしい。ありがとうございました(><)
勘違いしたままおかしなコードを書いてきたかも、と思うと恐ろしいです。ひぇ。

>調べたところちゃんとWM_SHOWWINDOWがポストされていましたよ。

ぎゃーすみませんっ(><)
Web検索してチラッと見かけた「WM_SHOWWINDOWで消えないからShowWindowAsync使った」という話から
勝手に違うと思い込んでました。ダメですねちゃんと自分で確認しないと・・。

WM_SHOWWINDOW がポストされること確かめました。お手数おかけしました。m(_ _)m

ふと思い立ちやってみたのですが、

ShowWindow(hwnd,SW_HIDE) の代わりに SendMessage(hwnd,WM_SHOWWINDOW,0,1) を使ってもほぼ同じ。
ShowWindowAsync(hwnd,SW_HIDE) の代わりに PostMessage(hwnd,WM_SHOWWINDOW,0,1) を使ってもほぼ同じ。
※最後の引数1はよくわからないので適当

という結果になりました。

ただ、見た目の挙動は同じですが、ポップアップウィンドウに来るメッセージが微妙に異なりました。
SendMessage/PostMessageの方が、無駄に多くメッセージが来る?ような感じでした。

ふーん・・。いえ、だからどうという話もないです。
ShowWindow/ShowWindowAsyncを使っておきます。

それにしても、今回のスレッドでは本当に勉強させてもらいました!ありがとうございました!

palladium

Re:POPUPウィンドウの消し方

#33

投稿記事 by palladium » 15年前

一応コード載せておきます。
#include <windows.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
LRESULT CALLBACK PopupWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp );
LRESULT CALLBACK ChildWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp );

HWND    hPopupWnd = NULL;   // ポップアップウィンドウハンドル
HWND    hTrackbar = NULL;
WNDPROC DefTrackbarProc;    // トラックバー既定ウィンドウプロシージャ

// ポップアップウィンドウプロシージャ
LRESULT CALLBACK PopupWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    switch( msg ) {
    case WM_ACTIVATE:
        {
            WORD fActive = LOWORD(wp);
            if (fActive == WA_INACTIVE) {
                ShowWindow(hwnd, SW_HIDE);
            } 
        }
        return 0;
    }
    return DefWindowProc( hwnd, msg, wp, lp );
}

// 操作パネルウィンドウプロシージャ
LRESULT CALLBACK ChildWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    POINT po;
    
    switch( msg ) {
    case WM_LBUTTONDOWN:
        // パネル上でマウス押下した地点にトラックバーをポップアップ表示します
        po.x = LOWORD( lp );
        po.y = HIWORD( lp );
        ClientToScreen( hwnd, &po );
        MoveWindow( hPopupWnd, po.x, po.y, 150, 30, TRUE );
        ShowWindow( hPopupWnd, SW_SHOW );
        return 0;
    }
    return DefWindowProc( hwnd, msg, wp, lp );
}

// メインウィンドウプロシージャ
LRESULT CALLBACK MainWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    HINSTANCE hInst = GetModuleHandle(NULL);
    
    switch( msg ) {
    case WM_CREATE: 
   
            // 操作パネル(子)ウィンドウ作成
        CreateWindowEx( 0, TEXT("ChildWindow"), TEXT("操作パネルのようなもの"), 
            WS_CHILD | WS_OVERLAPPEDWINDOW | WS_VISIBLE,    
            0, 0, 300, 200, hwnd, (HMENU)NULL, hInst, NULL );

            // ポップアップウィンドウ作成(親はメインウィンドウ)
        hPopupWnd = CreateWindowEx( 0, TEXT("PopupWindow"), NULL, 
            WS_POPUP, 
            0, 0, 0, 0, hwnd, (HMENU)NULL, hInst, NULL );
       
            // トラックバー作成(ポップアップウィンドウに乗せる)
        hTrackbar = CreateWindowEx( 0, TRACKBAR_CLASS, NULL, 
            WS_CHILD | WS_VISIBLE, 
            0, 0, 150, 30, hPopupWnd, (HMENU)NULL, GetModuleHandle(NULL), NULL );
        return 0;
               
    case WM_DESTROY:
        // アプリケーション終了
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc( hwnd, msg, wp, lp );
}


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int nShowCmd )
{
    MSG                     msg;
    HWND                    hwnd;
    WNDCLASSEX              wc;
    INITCOMMONCONTROLSEX    ic;

    // コモンコントロール初期化
    ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
    ic.dwICC  = ICC_BAR_CLASSES | ICC_TREEVIEW_CLASSES; // for ToolTip
    InitCommonControlsEx( &ic );

    // メインウィンドウクラス登録
    SecureZeroMemory( &wc, sizeof(WNDCLASSEX) );
    wc.cbSize           = sizeof(WNDCLASSEX);
    wc.lpfnWndProc      = MainWindowProc;
    wc.hInstance        = hInstance;
    wc.hCursor          = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground    = (HBRUSH)( COLOR_APPWORKSPACE+1 );
    wc.lpszClassName    = TEXT("MainWindow");
    if(!RegisterClassEx( &wc )){ return -1; }
    // 子(操作パネル)ウィンドウクラス登録
    wc.lpfnWndProc      = ChildWindowProc;
    wc.lpszClassName    = TEXT("ChildWindow");
    if(!RegisterClassEx( &wc )){ return -2; }
    // ポップアップウィンドウクラス登録
    wc.lpfnWndProc      = PopupWindowProc;
    wc.lpszClassName    = TEXT("PopupWindow");
    if(!RegisterClassEx( &wc )){ return -3; }

    // メインウィンドウ作成
    hwnd = CreateWindowEx( 0, TEXT("MainWindow"), TEXT("メインウィンドウ"), WS_OVERLAPPEDWINDOW,
                    CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, (HMENU)NULL, hInstance, NULL );
    if(!hwnd){ return -4; }
    ShowWindow( hwnd, nShowCmd );
    UpdateWindow( hwnd );

    // メッセージループ
    while( GetMessage( &msg, NULL, 0, 0 ) > 0 )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
    return (int)msg.wParam;
}

たろ

Re:POPUPウィンドウの消し方

#34

投稿記事 by たろ » 15年前

これは・・No:60025 のコード、ということでしょうか?

palladium

Re:POPUPウィンドウの消し方

#35

投稿記事 by palladium » 15年前

すみません貼り間違えました。
#include <windows.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
LRESULT CALLBACK PopupWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp );
LRESULT CALLBACK ChildWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp );

HWND    hPopupWnd = NULL;   // ポップアップウィンドウハンドル
HWND    hTrackbar = NULL;
WNDPROC DefTrackbarProc;    // トラックバー既定ウィンドウプロシージャ

// ポップアップウィンドウプロシージャ
LRESULT CALLBACK PopupWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    switch( msg ) {
    case WM_ACTIVATE:
        {
            WORD fActive = LOWORD(wp);
            if (fActive == WA_INACTIVE) {
                ShowWindowAsync( hwnd, SW_HIDE );   // ■ ここ! ■
            } 
        }
        return 0;
    }
    return DefWindowProc( hwnd, msg, wp, lp );
}

// 操作パネルウィンドウプロシージャ
LRESULT CALLBACK ChildWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    POINT po;
    
    switch( msg ) {
    case WM_LBUTTONDOWN:
        // パネル上でマウス押下した地点にトラックバーをポップアップ表示します
        po.x = LOWORD( lp );
        po.y = HIWORD( lp );
        ClientToScreen( hwnd, &po );
        MoveWindow( hPopupWnd, po.x, po.y, 150, 30, TRUE );
        ShowWindow( hPopupWnd, SW_SHOW );
        return 0;
    }
    return DefWindowProc( hwnd, msg, wp, lp );
}

// メインウィンドウプロシージャ
LRESULT CALLBACK MainWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    HINSTANCE hInst = GetModuleHandle(NULL);
    
    switch( msg ) {
    case WM_CREATE: 
   
            // 操作パネル(子)ウィンドウ作成
        CreateWindowEx( 0, TEXT("ChildWindow"), TEXT("操作パネルのようなもの"), 
            WS_CHILD | WS_OVERLAPPEDWINDOW | WS_VISIBLE,    
            0, 0, 300, 200, hwnd, (HMENU)NULL, hInst, NULL );

            // ポップアップウィンドウ作成(親はメインウィンドウ)
        hPopupWnd = CreateWindowEx( 0, TEXT("PopupWindow"), NULL, 
            WS_POPUP, 
            0, 0, 0, 0, hwnd, (HMENU)NULL, hInst, NULL );
       
            // トラックバー作成(ポップアップウィンドウに乗せる)
        hTrackbar = CreateWindowEx( 0, TRACKBAR_CLASS, NULL, 
            WS_CHILD | WS_VISIBLE, 
            0, 0, 150, 30, hPopupWnd, (HMENU)NULL, GetModuleHandle(NULL), NULL );
        return 0;
               
    case WM_DESTROY:
        // アプリケーション終了
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc( hwnd, msg, wp, lp );
}


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int nShowCmd )
{
    MSG                     msg;
    HWND                    hwnd;
    WNDCLASSEX              wc;
    INITCOMMONCONTROLSEX    ic;

    // コモンコントロール初期化
    ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
    ic.dwICC  = ICC_BAR_CLASSES | ICC_TREEVIEW_CLASSES; // for ToolTip
    InitCommonControlsEx( &ic );

    // メインウィンドウクラス登録
    SecureZeroMemory( &wc, sizeof(WNDCLASSEX) );
    wc.cbSize           = sizeof(WNDCLASSEX);
    wc.lpfnWndProc      = MainWindowProc;
    wc.hInstance        = hInstance;
    wc.hCursor          = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground    = (HBRUSH)( COLOR_APPWORKSPACE+1 );
    wc.lpszClassName    = TEXT("MainWindow");
    if(!RegisterClassEx( &wc )){ return -1; }
    // 子(操作パネル)ウィンドウクラス登録
    wc.lpfnWndProc      = ChildWindowProc;
    wc.lpszClassName    = TEXT("ChildWindow");
    if(!RegisterClassEx( &wc )){ return -2; }
    // ポップアップウィンドウクラス登録
    wc.lpfnWndProc      = PopupWindowProc;
    wc.lpszClassName    = TEXT("PopupWindow");
    if(!RegisterClassEx( &wc )){ return -3; }

    // メインウィンドウ作成
    hwnd = CreateWindowEx( 0, TEXT("MainWindow"), TEXT("メインウィンドウ"), WS_OVERLAPPEDWINDOW,
                    CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, (HMENU)NULL, hInstance, NULL );
    if(!hwnd){ return -4; }
    ShowWindow( hwnd, nShowCmd );
    UpdateWindow( hwnd );

    // メッセージループ
    while( GetMessage( &msg, NULL, 0, 0 ) > 0 )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
    return (int)msg.wParam;
}

たろ

Re:POPUPウィンドウの消し方

#36

投稿記事 by たろ » 15年前

あ、最終的なコードですね。すみません私が貼るべきだったかも・・。ありがとうございました!

ISLe

Re:POPUPウィンドウの消し方

#37

投稿記事 by ISLe » 15年前

> case WM_LBUTTONDOWN:
> // パネル上でマウス押下した地点にトラックバーをポップアップ表示します

WM_LBUTTONDOWN→WM_LBUTTONUPをお勧めします。


あと余談ですが、MSのガイドラインではメッセージループに辿り着く前にプログラムを終了するときは戻り値を0にすべきとなっています。
#古い書籍のサンプルコードを見るとFALSEを返していたりしますが結果的に同じでも意味合いが違う。
特に不具合はないと思いますが、Windows7では互換性アシスタントが動き出したりするかもしれません。

WinMain
http://msdn.microsoft.com/ja-jp/library/cc364870.aspx
戻り値の欄を見てください。

DXライブラリのサンプルプログラムとか-1を返しているものを良く見かけますね。

palladium

Re:POPUPウィンドウの消し方

#38

投稿記事 by palladium » 15年前

PeekMessage
指定されたウィンドウを作成したスレッドに関連付けられているメッセージキューに、
1 つのメッセージをポストします

ShowWindowAsync
別のスレッドによって作成されたウィンドウの表示状態を設定します。

ShowWindowAsyncに関しては
「指定されたウィンドウ」ではなく
「別のスレッドによって作成されたウィンドウ」とはっきり書いてあるので
やはり使い方が適切でないと思います。
今まで問題なく作動していたとしても、それはたまたまそうなだけかもしれませんし、
今後ShowWindowAsyncの内部仕様が変更されないとも限りません。

なので私なら以下のようにします。

// ポップアップウィンドウプロシージャ
LRESULT CALLBACK PopupWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
switch( msg ) {
case WM_ACTIVATE:
{
WORD fActive = LOWORD(wp);
if ( fActive == WA_INACTIVE ) {
PostMessage( hwnd, WM_APP, 0, 0 );
}
}
return 0;

case WM_APP:
ShowWindow( hwnd, SW_HIDE );
return 0;
}
return DefWindowProc( hwnd, msg, wp, lp );
}

palladium

Re:POPUPウィンドウの消し方

#39

投稿記事 by palladium » 15年前

WinMainの戻り値についてですが0を返した場合
正常終了したことをシステムに伝えることになります。
a return code of zero means that the program completed successfully.
なのでプログラムが正常終了しない場合は0を返してはいけません。

palladium

Re:POPUPウィンドウの消し方

#40

投稿記事 by palladium » 15年前

WM_LBUTTONDOWNとWM_LBUTTONUPについては
WM_LBUTTONUPですとマウスを下押ししたまま
マウスをウィンドウの外へ移動した場合動作しません。

WM_LBUTTONUPにする場合はこの辺りを考慮すべきかもしれません。

たろ

Re:POPUPウィンドウの消し方

#41

投稿記事 by たろ » 15年前

WinMainの戻り値はあんまり深く考えたことがなかったです。
それくらいの、まあ大した問題でもないという面はあるでしょうか。(^^;

main関数のCUIコマンドのようなプログラムなら、OS側への通知と共に、戻り値を使った
他のプログラムとの連携という(プロセス間通信的な)わかりやすい用途がありますが、
WinMainの場合はそれは特にないですよねぇ・・よく知りませんが。

そうすると、OS側でWinMainの戻り値はどう扱われるのか?だけがポイントとなり、
その答えがMSDNの「メッセージループ前ならゼロを返せ」というガイドラインでしょうか。
エラーはMessageBox等で表示して、戻り値としてはゼロでよいと・・。

palladium

Re:POPUPウィンドウの消し方

#42

投稿記事 by palladium » 15年前

crtexe.c
に戻り値の扱いが書いてあります。
おそらく最終的には
crt0dat.c
の中の
ExitProcess(status); // status がWinMainの戻り値
で終了するのだと思います。

たろ

Re:POPUPウィンドウの消し方

#43

投稿記事 by たろ » 15年前

WM_LBUTTONDOWN と WM_LBUTTONUP の違いについては、好みの問題ですかね・・。
どっちのインタフェースが好きか?マウス押下する地点に何があるか?とか。

ただし WM_LBUTTONDOWN の「ポップアップ表示状態でクリックすると消える」動作は、
メッセージ発生到着順により「意図せずこうなった挙動」というのは覚えておかない
といかんなーと思ってます。ちゃんとコメント書いておく必要がありそうです。

事の発端となった私のへぼアプリでは、今のところ、WM_LBUTTONDOWN 相当の動作で
満足しています。というか、実は WM_LBUTTONDOWN では使っておらず、スタティック
テキストコントロールの WM_COMMAND 通知で使っており、どうも WM_LBUTTONDOWN 相当
の動作になってしまうようなのです・・。

たろ

Re:POPUPウィンドウの消し方

#44

投稿記事 by たろ » 15年前

WinMain の呼び出し部分のソースがあるんですね。ぜんぜん知りませんでした。。

crtexe.c や crt0dat.c って、検索しても私のPCには見当たらないのですが、
ひょっとして VC2008 Express Edition には入ってない代物でしょうか。

softya

Re:POPUPウィンドウの消し方

#45

投稿記事 by softya » 15年前

>crtexe.c や crt0dat.c って、検索しても私のPCには見当たらないのですが、
>ひょっとして VC2008 Express Edition には入ってない代物でしょうか。
C:\Program Files\Microsoft Visual Studio 9.0\VC\crt\src
にソースコードがあるはずですが、Express Editionには無いかも知れません。
画像

palladium

Re:POPUPウィンドウの消し方

#46

投稿記事 by palladium » 15年前

あといわゆる「常識」ですが
本件の場合はともかく
巷には間違った常識がまかり通っている場合があるようです。
たとえばこれですが
http://www.kijineko.co.jp/tech/superstitions
はじめて読んだときはいくつか引っかかりました。

ファイルの存在についてはVC2008 が手元に無いので確認できませんでした。

たろ

Re:POPUPウィンドウの消し方

#47

投稿記事 by たろ » 15年前

VC フォルダの中に crt フォルダが見当たりません。
crtexe で検索しても何もヒットしないし、無さそうです。うーん残念。

伝聞を鵜呑みにしてしまわないよう気を付けたいです。上でポカしてますが。(^^;

ISLe

Re:POPUPウィンドウの消し方

#48

投稿記事 by ISLe » 15年前

わたしの解釈はNo:60127に書いたとおりです。

> PeekMessage
> 指定されたウィンドウを作成したスレッドに関連付けられているメッセージキューに、
> 1 つのメッセージをポストします

PostMessage
http://msdn.microsoft.com/en-us/library/ms644944(VS.85).aspx
"Places (posts) a message in the message queue associated with the thread that created the
specified window and returns without waiting for the thread to process the message."

> ShowWindowAsync
> 別のスレッドによって作成されたウィンドウの表示状態を設定します。

ShowWindowAsync
http://msdn.microsoft.com/en-us/library/ms633549(VS.85).aspx
Sets the show state of a window created by a different thread.

PostMessageの表現をそのまま使うと"window"が被ってしまうのでそれを避けたために思いっ切り省略される形になったと推測します。

Remarksに同一スレッドからポストしたときの挙動について何も書いてないですし。
こんな古いAPIで挙動が不安定だったらかなり問題ですよね。


ShowWindowAsyncを嫌うにしてもたろさんがNo:60205で書いているようにWM_SHOWWINDOWをPostMessageで投げれば良いと思います。

--編集
横に長くなるので英文の途中に改行を入れました。 画像

ISLe

Re:POPUPウィンドウの消し方

#49

投稿記事 by ISLe » 15年前

> WinMainの戻り値についてですが0を返した場合
> 正常終了したことをシステムに伝えることになります。
> a return code of zero means that the program completed successfully.
> なのでプログラムが正常終了しない場合は0を返してはいけません。

WinMainから始まるプログラムをホスト環境とみなすのは無理があると思います。

WinMain Function
http://msdn.microsoft.com/en-us/library/ms633559(VS.85).aspx
WinMain
http://msdn.microsoft.com/ja-jp/library/cc364870.aspx
(引用開始)
戻り値
関数が WM_QUIT メッセージを受け取って正常に終了する場合は、メッセージの wParam パラメータに格納されている終了コードを返してください。関数がメッセージループに入る前に終了する場合は、0 を返してください。
(引用終了)

実験してみたのですが、WinMainでどんな戻り値を返そうとコマンドプロンプトには終了コードが0と返るようです。
WinMainから始まるプログラムの終了コードはCreateProcessして(WaitForSingleObjectで終了を待って)GetExitCodeProcessで取得する必要があると思います。

ISLe

Re:POPUPウィンドウの消し方

#50

投稿記事 by ISLe » 15年前

> WM_LBUTTONUPですとマウスを下押ししたまま
> マウスをウィンドウの外へ移動した場合動作しません。
>
> WM_LBUTTONUPにする場合はこの辺りを考慮すべきかもしれません。

ウインドウズのUIではそれがふつうですけど。

WM_LBUTTONDOWN→WM_LBUTTONUPのあいだにフォーカスが移動すると不具合が発生することがあるというのは既知なので避けたほうが無難だと思います。
例えばポップアップメニューを表示するTrackPopupMenuはデッドロックすることがあるのでWM_RBUTTONUPで表示すべきとされています。

どうしても押した瞬間に反応して欲しいというのであればメッセージをポストすれば良いかもしれません。
--追記
WM_LBUTTONDOWNでクリックした座標を記憶しておいてSetCapture、WM_LBUTTONUPで記憶しておいた場所に表示…というUIはかなり変ですね。 画像

palladium

Re:POPUPウィンドウの消し方

#51

投稿記事 by palladium » 15年前

>WinMainから始まるプログラムの終了コードはCreateProcessして(WaitForSingleObjectで終了を待って)GetExitCodeProcessで取得する必要があると思います。

MS自体が公開している終了処理コードではそのようなことはしていないようです。

palladium

Re:POPUPウィンドウの消し方

#52

投稿記事 by palladium » 15年前

というか、これはもう本件と直接関係ない話になってますね。
まさかWinMainの戻り値でUIがデッドロック起こすわけでもないでしょう。
自分の本音ですとWinMainの戻り値なんかどうでもよいと思ってます。
もちろんMSDNや自分なりにMSの終了処理コードなどを見た上でのことです。
SDKで開発している人にとってはWinMainの戻り値が0なんてことは常識ですが、
可読性の上でも0以外の値なら異常終了とすぐにわかると思います。
他のサイトの説明用コードでもよくあることですし、
スーパークラス系の書き方のところをチェックするには一番簡単な書き方かもしれません。
まあご存知でしょうがVCの出力ウィンドウをみれば自分の決めた戻り値が表示されるので
デバッグ作業も楽だと思いますよ。(コンソールの人、ごめんなさい)
それでも「絶対0にしろ」ってことであれば私はハングアップです。

ISLe

Re:POPUPウィンドウの消し方

#53

投稿記事 by ISLe » 15年前

> >WinMainから始まるプログラムの終了コードはCreateProcessして(WaitForSingleObjectで終了を待って)GetExitCodeProcessで取得する必要があると思います。
>
> MS自体が公開している終了処理コードではそのようなことはしていないようです。

ごめんなさい。
終了処理コードには違いがないようですね。
ウインドウアプリ(WinMain)とコンソールアプリ(main)では起動の仕方が違っていました。
実験手順が不足していたために偏った結論になってしまいました。

拡張機能(既定で有効)が有効なコマンドプロンプトのプロンプトからウインドウアプリを直接起動するとき、あるいはWAITオプション無しのstartコマンドからウインドウアプリ/コンソールアプリを起動するときはアプリの終了を待たずにプロンプトが復帰します。
このとき終了コードが取得できません(反映されません)でした。

アプリが終了するまで待たない呼び出し方をすると終了コードが取得できず(反映されず)、アプリが終了するまで待つ呼び出し方をすれば終了コードは取得できる(反映される)という至極当然の結果でした。


実験してて気付いたのですが、Visual C++って前から終了コードに8ビットのマスク掛けてませんでしたっけ。
#またまた余談ですみません。
exit、_exit
http://msdn.microsoft.com/ja-jp/library/6wdz5232.aspx
(引用開始)
status の下位バイトを利用できます。
(引用終了)
下位バイトって書いてあるのに32ビットまるまる返しているみたいなんですけど。
プログラムで-1を返しているのがバッチファイルでそのまま-1取れるとかダメじゃん。
#自分はもうずっとマイナス使わないようにしてたから気が付かなかっただけですか。

ISLe

Re:POPUPウィンドウの消し方

#54

投稿記事 by ISLe » 15年前

> というか、これはもう本件と直接関係ない話になってますね。

そうですね。最初に余談と断ってましたしね。
最初にMSDNのWinMainのページをリンクしてたんですが「正常終了しない場合は0を返してはいけません 」と断定されていたので再度引用したのが気に触りましたか。
気に触ったのなら申し訳ないです。

> まさかWinMainの戻り値でUIがデッドロック起こすわけでもないでしょう。

これはわざとミスリードしているのですか?
そんなことはどこにも書かれていませんね。

> 自分の本音ですとWinMainの戻り値なんかどうでもよいと思ってます。
> もちろんMSDNや自分なりにMSの終了処理コードなどを見た上でのことです。
> SDKで開発している人にとってはWinMainの戻り値が0なんてことは常識ですが、
> 可読性の上でも0以外の値なら異常終了とすぐにわかると思います。
> 他のサイトの説明用コードでもよくあることですし、

そのとおりで、余談として、良く見かけますね、と書きました。

> それでも「絶対0にしろ」ってことであれば私はハングアップです。

わたしが何か主張しましたでしょうか。
特に不具合は無いと思いますとも書いていますけども。

わたしが関知することではないですからpalladiumさんはご自由にWinMainの戻り値を決められれば良いと思います。
そのかわりではないですがわたしはShowWindowAsyncをShowWindowのポスト版として同一スレッドからも使い続けます。

たろ

Re:POPUPウィンドウの消し方

#55

投稿記事 by たろ » 15年前

もはや私の知恵ではまったく及びません。

興味深い余談でした。「あとは作る人がそれぞれ自分で決めればよい」という領域ですかね・・。

ちなみに私は「WM_LBUTTONDOWN→WM_LBUTTONUPのあいだにフォーカスが移動すると不具合が発生することがある」という話が気になりました。今回のポップアップ話は、確かに TrackPopupMenu と似てます。中身が違うだけみたいな。

どちらでもいけるようにしておきたいけど、STATICコントロールSS_NOTIFY+親WM_COMMAND だと、WM_LBUTTONUP 相当の検知は不可能・・。やりたかったらサブクラス化などで対応しましょうって話かな。うーんメッセージハンドラがどんどん増えていく・・そういうものなのか・・。

palladium

Re:POPUPウィンドウの消し方

#56

投稿記事 by palladium » 15年前

>わたしが何か主張しましたでしょうか。
まぁあれだけWinMainのリンク貼り付ければイヤミでしょ。

それはさておき
MSDNの場合はドキュメントと実際の動作が違うことはままありますよね。
(PostQuitMessageでWM_QUITが実際にはポストされていないなど)
それでここからはそのプログラマの判断になる場合もあるかと思いますが
建前のMSDNをとるか、実際の動作を利用するかになると思います。
ただ、何か問題が起きたときにはMSは建前を出してくる(使用法として)でしょうから
そこさえクリアできれば別に問題ないという考えもあるかもしれませんね。

palladium

Re:POPUPウィンドウの消し方

#57

投稿記事 by palladium » 15年前

本当は全部貼りたいですが著作権とかありそうなので雰囲気だけです
int WinMainCRTStartup(void)
{
    .
    .
    .

    static int mainret = WinMain(...)
        if ( !managedapp )
            exit(mainret); //a return code of zero means that the program completed successfully.

    .
}
----------------------------------------------
void __cdecl exit( int code )
{
    doexit( code, 0, 0 );
}
----------------------------------------------
static void __cdecl doexit( int code, int quick, int retcaller )
{
    .
    .
    .
    __crtExitProcess(code);
}
----------------------------------------------
void __cdecl __crtExitProcess( int status )
{
    .
    .
    .
//プロセスの終了コードを取得するには、GetExitCodeProcess 関数を使います。
//スレッドの終了コードを取得するには、GetExitCodeThread function 関数を使います。

// んなことはMSやっちゃいない
    ExitProcess(status);
}

palladium

Re:POPUPウィンドウの消し方

#58

投稿記事 by palladium » 15年前

>実験してて気付いたのですが、Visual C++って前から終了コードに8ビットのマスク掛けてませんでしたっけ。
#またまた余談ですみません。
exit、_exit
http://msdn.microsoft.com/ja-jp/library/6wdz5232.aspx
(引用開始)
status の下位バイトを利用できます。
(引用終了)
下位バイトって書いてあるのに32ビットまるまる返しているみたいなんですけど。
プログラムで-1を返しているのがバッチファイルでそのまま-1取れるとかダメじゃん。
#自分はもうずっとマイナス使わないようにしてたから気が付かなかっただけですか。

何かご不明な点があるようですが開発環境、実験内容等を明記の上、別スレでご質問なさったらいかがですか。

ISLe

Re:POPUPウィンドウの消し方

#59

投稿記事 by ISLe » 15年前

> >わたしが何か主張しましたでしょうか。
> まぁあれだけWinMainのリンク貼り付ければイヤミでしょ。

二回目の投稿をするのが「あれだけ」と言われるほどひどいことなのですね。
palladiumさんのNo:60397の投稿を見て完全にスルーされたと思いました。
かなりショックだったので読み易く投稿し直したつもりでした。
#わたしもスルー力を鍛える必要がありますね。

> それはさておき
> MSDNの場合はドキュメントと実際の動作が違うことはままありますよね。
> (PostQuitMessageでWM_QUITが実際にはポストされていないなど)

ウインドウプロシージャに届いかないからポストされていないということですか?
GetMessageやPeekMessageでメッセージキューからWM_QUITを取り出したらメッセージループを抜けるようにコーディングしてますよね。
DispatchMessageが実行されないのでウインドウプロシージャには投げられないですけど、GetMessageやPeekMessageに与えたMSG構造体の引数にはWM_QUITが入ってきますけど。
解説願えますか?

--誤字とちょっと表現を訂正 画像

ISLe

Re:POPUPウィンドウの消し方

#60

投稿記事 by ISLe » 15年前

> 何かご不明な点があるようですが開発環境、実験内容等を明記の上、別スレでご質問なさったらいかがですか。

リンク先がVisual C++ 2010のページなので、開発環境は明示しなくても良いと思ってしまいました。
開発環境はVisual C++ 2010です。2008でも確認しました。

> #自分はもうずっとマイナス使わないようにしてたから気が付かなかっただけですか。
と書いたようにわたし自身は既に何も困っていません。
ホスト環境で負の数(正確には下位8ビット以外のビットが有効な値)を戻り値としたときに移植性が損なわれる要因が見付かったことを紹介させていただきました。

はっきり言いますとpalladiumさんのソースファイルをVCでコンパイルしたときとgccでコンパイルしたときで実行ファイルの戻り値が変化してしまうということです。
余計なことでしたね。

--編集
WinMainから始まるウインドウズアプリでもgcc(cygwin版)でコンパイルすると戻り値が下位8ビットでマスクされるのを確認。
画像

palladium

Re:POPUPウィンドウの消し方

#61

投稿記事 by palladium » 15年前

>解説願えますか?
Advanced Windows 改訂第4版 Jeffrey Richter著の第26章をお調べください。

palladium

Re:POPUPウィンドウの消し方

#62

投稿記事 by palladium » 15年前

補足
アプリケーションのメッセージキューにはもちろんポストされています。
システムキューにはポストされないということです。

palladium

Re:POPUPウィンドウの消し方

#63

投稿記事 by palladium » 15年前

「余談」から本件に直接関係ない「実験」とかに発展してしまうと
本件がだんだんぼけてくるので差し控えていただけませんか。
何かテーマをお持ちでしたら別スレでお願いしたいものです。

(PostQuitMessageでWM_QUITが実際にはポストされていないなど)
これについてはまた発展しちゃうといけないのでお忘れください。

ISLe

Re:POPUPウィンドウの消し方

#64

投稿記事 by ISLe » 15年前

> 「余談」から本件に直接関係ない「実験」とかに発展してしまうと
> 本件がだんだんぼけてくるので差し控えていただけませんか。

自分が投稿する内容や他の方が書いたコードは勉強のために検証して気になることがあればコメントしてきました。
#検証の仕方をミスることが少なくないのは申し訳ないです。

> (PostQuitMessageでWM_QUITが実際にはポストされていないなど)
> これについてはまた発展しちゃうといけないのでお忘れください。

検証した内容は既にNo:60650に書いてますので。
ふるまいはMSDNに書かれているとおりのような気がします。


余談も実験も禁止ということは、ルートの質問に回答だけしてろということですね。
了解しました。

本件がぼけるということであればプログラミングの質問にそのジャンルのゲーム関連ネタを振るのも禁止ですよね。
他のスレですがひとつだけネタふりさせてください。
それで最後にします。

palladium

Re:POPUPウィンドウの消し方

#65

投稿記事 by palladium » 15年前

>たろさまへ
>実は WM_LBUTTONDOWN では使っておらず、スタティック
テキストコントロールの WM_COMMAND 通知で使っており、どうも WM_LBUTTONDOWN 相当
の動作になってしまうようなのです・・。

このあたりですが、もうすこし詳しい仕様をお願いできますか。

たろ

Re:POPUPウィンドウの消し方

#66

投稿記事 by たろ » 15年前

えっと・・なんだか残念で悲しい気持ちでいっぱいです・・。

私のコメント方法にも要因があるのか・・わかりませんが、
ネットのコミュニケーションの難しさを改めて感じます。

できるだけ言葉を選びながら書きます。

余談について、今回コメント頂いたくらいの内容なら私は全く気になりません。
むしろ有り難かったです。余談で盛り上がるのも楽しいし、得ることは多いと思います。

問題は、「自分の考えの表現方法」と「自分と対立する考えの受け流し」ですかね・・。

私はコメント書く時「事実以外に断定的な表現を使わない」ように気をつけます。
例えば、MSDNからの引用は「事実」として断定的に書きますが、「だからこうすべき」
という"解釈"には、必ず「~と思う・~と考える」等を付けるようにします。

そして人のコメントを読む時、「この人は事実じゃない事を断定して書いている」と
判断した場合は、脳内で勝手に「~と思う」を付け加えて読みます。
尖ったものが少し丸くなる感覚があります。

自分と対立する考え方の受け流し、まあいわゆる「スルー」ですが、難しいですね・・
我慢できるかどうか、無視できるかどうか、しかないのかな・・。

私は、スルーするのはけっこう得意です・・というか、臆病なのですぐ逃げます。(^^;

なんだか取り留めのない独り言になってきた。。


ISLeさん、palladiumさん、本題から余談までとても勉強になりました。お世話になりました。
お2人とも博識ですね。今後のご活躍も期待しております。


続きで失礼しますが、

>>実は WM_LBUTTONDOWN では使っておらず、スタティック
>>テキストコントロールの WM_COMMAND 通知で使っており、どうも WM_LBUTTONDOWN 相当
>>の動作になってしまうようなのです・・。

>このあたりですが、もうすこし詳しい仕様をお願いできますか。

お気遣いありがとうございます。m(_ _)m
ええと・・実はこの話を出したのは、何かちょっと危険な空気を感じたからかも知れません。。

まだ自分でいろいろ試したり確認しておらず、中途半端な状態です。
いろいろやってみて、どうしてもダメだったら、また新しく質問させて頂きたいと思います。
ひとまずお忘れください。

「POPUPウィンドウの消し方」としては、私は解決終了と思ってます。ありがとうございました。 画像

softya

Re:POPUPウィンドウの消し方

#67

投稿記事 by softya » 15年前

横から失礼しますね。
とりあえず、たろさんに落ち度はないですよ。
管理人さんの規約と注意事項にあります通り「目指すはアットホームで温かい」がスローガンですのでその趣旨に沿っていただけるとありがたいです。
多少雑談が交じるのはこの掲示板の常ですので質問者さんが困らない&混乱しない限り、そして質問者さんが止めて欲しいとお願いしない限り、質問者さんの経験とプラスに成るなら問題ないと私は考えます。
もし、別スレ分けが必要だとお感じでしたら穏やかに提案なさってください。

palladium

Re:POPUPウィンドウの消し方

#68

投稿記事 by palladium » 15年前

1質問1トピと思い、
必要に応じ他にスレを立てることをお勧めしたつもりですが、
私に非があるようなら御容赦下さい。
申し訳ございませんでした。

ISLe

Re:POPUPウィンドウの消し方

#69

投稿記事 by ISLe » 15年前

たろさんへ
表示するときもPost系APIを使うと幸せになれるかもしれません。
WM_LBUTTONDOWNでの動作確認は取れてます。

気にしないでください。

たろ

Re:POPUPウィンドウの消し方

#70

投稿記事 by たろ » 15年前

あ、はい、実はすでに試してみました。お気遣いありがとうございます。

閉鎖

“C言語何でも質問掲示板” へ戻る