コンソールアプリケーションでのWIN32 APIメッセージ処理

このQ&Aのポイント
  • VisualStdio.NET 2005のC++で作成しているコンソールアプリケーションで、PostMessageでメッセージを送信しているのに、PeekMessageで検出できません。
  • ウィンドウハンドルの確認部分はパスしますが、PostMessageとPeekMessageの引数hWndをNULLに置き換えるとメッセージの検出はできるので、やはり、ウィンドウハンドルに問題があるのかもしれません。
  • ウィンドウハンドルが不正です
回答を見る
  • ベストアンサー

コンソールアプリケーションでのWIN32 APIメッセージ処理

コンソールアプリケーションでのWIN32 APIメッセージ処理 VisualStdio.NET 2005のC++で作成しているコンソールアプリケーションで、 PostMessageでメッセージを送信しているのに、PeekMessageで検出できません。 下のプログラムに誤った点があるのでしょうか? 尚、ウィンドウハンドルの確認部分はパスしますが、 PostMessageとPeekMessageの引数hWndをNULLに置き換えるとメッセージの検出はできるので、 やはり、ウィンドウハンドルに問題があるのかもしれません。 #include <windows.h> #include <stdio.h> void main( void ) {   char OldTitle[1024], NewTitle[1024];   char WindowText[1024], ConsoleTitle[1024];   HWND hWnd;   MSG Msg;   /*** ウィンドウハンドルの取得 ***/   GetConsoleTitle( OldTitle, 1024 );   wsprintf( NewTitle, "%d/%d", GetTickCount(), GetCurrentProcessId());   SetConsoleTitle( NewTitle );   Sleep(40);   hWnd = FindWindow( NULL, NewTitle );   SetConsoleTitle( OldTitle );   /*** ウィンドウハンドルの確認 ***/   GetWindowText( hWnd, WindowText, 1024 );   GetConsoleTitle( ConsoleTitle, 1024 );   if ( strcmp( WindowText, ConsoleTitle ) != 0 ){     printf( "ウィンドウハンドルが不正です" );     return;   }   /*** メッセージの送信と検出 ***/   PostMessage( hWnd, 1050, 0, 0 );   do{     while ( PeekMessage( &Msg, hWnd, 0, 0, PM_REMOVE )){       printf( "メッセージを検出しました" );       return;     }   } while( 1 ); }

質問者が選んだベストアンサー

  • ベストアンサー
  • Quant
  • ベストアンサー率18% (23/122)
回答No.3

ANo2のソースは勘違いでした。 FindWindowで0が返っています。 うまく行っていたように見えただけでした。 http://support.microsoft.com/kb/124103/jaの中に [FindWindowで]取得した HWND の値は、すべてのウィンドウハンドルを使用する処理において、適切なものであるとは保証されていません。 と書いてあります。 これが正しいのではないかと思います。

_hitoshi_
質問者

お礼

そう考えるしかなさそうです。 ありがとうございました。

その他の回答 (2)

  • Quant
  • ベストアンサー率18% (23/122)
回答No.2

http://support.microsoft.com/kb/124103/jaの中に [FindWindowで]取得した HWND の値は、すべてのウィンドウハンドルを使用する処理において、適切なものであるとは保証されていません。 と書いてあります。 しかし下のプログラムではメッセージを取得するようです。 http://support.microsoft.com/kb/124103/jaの情報自体が古いのか、何か問題があるような気がします。 原因不明です。 #pragma comment(lib,"user32.lib") #include <windows.h> #include <stdio.h> void main( void ) { char OldTitle[1024], NewTitle[1024]; char WindowText[1024], ConsoleTitle[1024]; HWND hWnd; MSG Msg; HANDLE CONSOLE; /*** ウィンドウハンドルの取得 ***/ GetConsoleTitle( OldTitle, 1024 ); wsprintf( NewTitle, "%d/%d", GetTickCount(), GetCurrentProcessId()); SetConsoleTitle( NewTitle ); Sleep(40); //hWnd = FindWindow( NULL, NewTitle ); <-- ここが失敗している。 hWnd = FindWindow( NULL, OldTitle ); // SetConsoleTitle( OldTitle ); /*** ウィンドウハンドルの確認 ***/ /* GetWindowText( hWnd, WindowText, 1024 ); GetConsoleTitle( ConsoleTitle, 1024 ); if ( strcmp( WindowText, ConsoleTitle ) != 0 ){ printf( "ウィンドウハンドルが不正です" ); return; } */ /*** メッセージの送信と検出 ***/ PostMessage( hWnd,1050, 0, 0 ); do{ while ( PeekMessage( &Msg, hWnd, 0, 0, PM_REMOVE )){ printf( "メッセージを検出しました" ); getch(); return; } } while( 1 ); }

回答No.1

FindWindowの第1引数にNULLが入ってますが、これが問題です。 クラス名を与えないといけません。 コンソールのクラス名が何なのか知りませんが、戻り値のウィンドウハンドルはNULL、つまり関数呼び出し失敗になっていませんか?

参考URL:
http://msdn.microsoft.com/ja-jp/library/cc364634.aspx
_hitoshi_
質問者

お礼

クラス名を指定してFindWindowを実行してもうまく動作しませんでした。 クラス名を指定してCreateWindowを実行して得たウィンドウハンドルでは動作しました。 ありがとうございました。

_hitoshi_
質問者

補足

回答ありがとうございます。 FindWindowの戻り値はNULLではなかったと思ったのですが、 再度確認すると、下記現象が確認できました。 ・パソコンの起動後、1回目のプログラム実行ではNULL ・パソコンの起動後、2回目以降のプログラム実行ではNULL以外 コンソールのクラス名を指定する方法で試してみようと思います。

関連するQ&A

  • BCCのコンソールアプリからウィンドウ表示

    BCCのコンソールアプリからウィンドウを表示したいのですが、うまくいきません。 なにが悪いのでしょうか・・・ どなたかお教えいただけると助かります。 よろしくお願いいたします。 コンパイラ: Borland C++ 5.5.1 bcc32 コンパイル方法: bcc32 -WC WindowTest.cpp (コンソールアプリにしているのは、標準入力を受け標準出力に出すフィルタ機能も持たせようと思っているからです。) *** ソース (WindowTest.cpp) *** #include <windows.h> LRESULT CALLBACK WndProc ( HWND hWnd, UINT msg, WPARAM wp, LPARAM lp ){ // とりあえず空 (void)hWnd; (void)msg; (void)wp; (void)lp; return 0; } int main (int argc, char**argv){ HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL); WNDCLASSEX wc; char className[] = "hoge"; memset( &wc, 0, sizeof( wc )); wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon( NULL, IDI_APPLICATION ); wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH ); wc.lpszMenuName = NULL; wc.lpszClassName = className; wc.hIconSm = NULL; if(! RegisterClassEx( &wc )) return 1; HWND hWnd = CreateWindow(className, "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, hInstance, NULL); // ← ここで失敗し、ウィンドウが表示されない if (!hWnd) return 2; ShowWindow(hWnd, NULL); UpdateWindow(hWnd); MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } (void)argc; (void)argv; return 0; }

  • win32apiにおける終了処理について

    下記のプログラムを実行してウィンドウを閉じるボタンで閉じると、 ウィンドウは消えるのですがなぜかプロセスが残ってしまいます。 正直、お手上げなので教えて頂けると幸いです。 よろしくお願いします。 #include<windows.h> #define APP_NAME TEXT("Sample_MainWindow") /*ウィンドウプロシージャ*/ LRESULT CALLBACK WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch(uMsg) { case WM_DESTROY: PostQuitMessage(0); return 0; } /*基本的なメッセージの処理*/ return DefWindowProc(hWnd, uMsg,wParam,lParam); } /*WinMain*/ int WINAPI WinMain( HINSTANCE hInstance , HINSTANCE hPrevInstance , PSTR lpCmdLine , int nCmdShow) { HWND hWnd; WNDCLASS wc; MSG msg; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = DefWindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL,IDI_APPLICATION); wc.hCursor = LoadCursor(NULL,IDC_ARROW); wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND + 1; wc.lpszMenuName = NULL; wc.lpszClassName = APP_NAME; if (!RegisterClass(&wc)){ MessageBox(NULL,TEXT("ウィンドウクラスの作成に失敗しました"),NULL,MB_OK); return 0; } hWnd = CreateWindow( APP_NAME, TEXT("Window Title"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL ); if(hWnd == NULL){ MessageBox(NULL,TEXT("ウィンドウの生成に失敗しました"),NULL,MB_OK); return 0; } /*メッセージループ*/ while(GetMessage(&msg, NULL,0,0)){ DispatchMessage(&msg); } return (int)msg.wParam; }

  • コンソールアプリケーションの空のプロジェクト

    VisualStudioでC++プロジェクトを作る際、 「コンソールアプリケーション、プロジェクト、空のプロジェクト、メイクファイルプロジェクト」 からプロジェクトの種類を選びますが、このとき 「コンソールアプリケーションを選び、「アプリケーションウィザードで「□空のプロジェクト」にチェックを入れて作った」プロジェクトと、 「空のプロジェクトを選択して作った」プロジェクトはどう違うのでしょうか? 先日プログラムを書いていたのですが、全く同じ文章であるにもかかわらず前者ではコンパイルエラーが起こり、後者は問題なく起動するということがありました。 プロジェクトの種類によってどのような動作をする際に差が出るのでしょうか? よろしくお願いします。 なお、上記の「全く同じ文章であるにもかかわらず前者ではコンパイルエラーが起こり、後者は問題なく起動した」プログラムは以下のもので、「58行目と63行目のCLASS_NAMEにご完成がないとエラーが出ました」。 #define WIN32_LEAN_AND_MEAN #include <Windows.h> int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int); bool CreateMainWindow(HINSTANCE, int); LRESULT WINAPI WinProc(HWND, UINT, WPARAM, LPARAM); HINSTANCE hinst; const char CLASS_NAME[] = "WinMain"; const char APP_TITLE[] = "Hello World"; const int WINDOW_WIDTH = 400; const int WINDOW_HEIGHT = 400; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLinc, int nCmdShow) { MSG msg; if (!CreateMainWindow(hInstance, nCmdShow)){ return false; } int done = 0; while (!done) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT){ done = 1; } TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; } LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, msg, wParam, lParam); } bool CreateMainWindow(HINSTANCE hInstance, int nCmdShow) { WNDCLASSEX wcx; HWND hwnd; wcx.cbSize = sizeof(wcx); wcx.style = CS_HREDRAW | CS_VREDRAW; wcx.lpfnWndProc = WinProc; wcx.cbClsExtra = 0; wcx.cbWndExtra = 0; wcx.hInstance = hInstance; wcx.hIcon = NULL; wcx.hCursor = LoadCursor(NULL, IDC_ARROW); wcx.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wcx.lpszMenuName = NULL; wcx.lpszClassName = CLASS_NAME; wcx.hIconSm = NULL; if (RegisterClassEx(&wcx) == 0){ return false; } hwnd = CreateWindow(CLASS_NAME, APP_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, (HWND)NULL, (HMENU)NULL, hInstance, (LPVOID)NULL); if (!hwnd){ return false; } ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); return true; }

  • win32apiでbmpを表示する関数についてです

    bmpを表示する関数と処理する関数を別々のファイルにしたいのですが、表示されません・・・。エラー、警告はありませんでした。VC++2008を使用しています。ソースは以下のようになっています。よろしくお願い致します。 ~ 処理部分 load_bmp.cpp ~ #include <windows.h> #include <stdio.h> #include <tchar.h> extern HINSTANCE hinst; extern HWND hwnd; int Load_Bmp( HDC hdc, char *f_name_of_BMP) { HBITMAP hbmp; HDC work_DC; hbmp=(HBITMAP)LoadImage(hinst,_T ("f_name_of_BMP"),IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION | LR_LOADFROMFILE); if( hbmp == NULL ){ MessageBox(hwnd, _T("ビットマップを表示できません"), _T("エラー"),MB_OK | MB_ICONWARNING); return 0; } work_DC = CreateCompatibleDC( hdc ); SelectObject( work_DC, hbmp ); BitBlt(hdc,0,0,640,480,work_DC,0,0,SRCCOPY); ReleaseDC( hwnd,work_DC ); DeleteObject( hbmp ); return 0; } ~ヘッダファイル load_bmp.h ~ int Load_Bmp( HDC hdc,char *f_name_of_BMP); ~処理部分 main.cpp ~ #include <windows.h> #include <tchar.h> #include "load_bmp.h" HWND hwnd; HDC win_hdc; HINSTANCE hinst; void init_game() { Load_Bmp( win_hdc,"test.bmp"); } LRESULT WndProc(HWND hwnd,UINT msg,WPARAM wprm,LPARAM lprm) { switch(msg){ case WM_CREATE: break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd,msg,wprm,lprm); } return 0; } int APIENTRY WinMain(HINSTANCE hIns,HINSTANCE hPI,LPSTR lpArg,int nCmdShow) { MSG msg; WNDCLASS wc; hinst=hIns; wc.hInstance=hIns; wc.lpszClassName=_T("test"); wc.lpfnWndProc=(WNDPROC)WndProc; wc.style=0; wc.hIcon=LoadIcon((HINSTANCE)NULL,IDI_APPLICATION); wc.hCursor=LoadCursor((HINSTANCE)NULL,IDC_ARROW); wc.lpszMenuName=0; wc.cbClsExtra=0; wc.cbWndExtra=0; wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); if(RegisterClass(&wc)==0)return 0; hwnd=CreateWindowEx( 0, wc.lpszClassName, _T("test"), WS_OVERLAPPEDWINDOW, 20,20,640,480, NULL, NULL, hIns, NULL     ); if(!hwnd) return 0; ShowWindow(hwnd,nCmdShow); UpdateWindow(hwnd); win_hdc=GetDC(hwnd); init_game(); while(1){  if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)){ (!GetMessage(&msg,(HWND)NULL,0,0));break; TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }

  • WM_CLEARなど使えないメッセージがある。

    WM_CLEARなど使えないメッセージがある。 外部ソフトからハンドルを取得して EditBox を操作しようとしています。 PostMessage/SendMessage で該当 EditBox にメッセージを送るのですが WM_PASTE, WM_CHAR などは期待通りの動きをするのですが WM_CLEAR, WM_SETTEXT など無反応です。 PostMessage( hwnd, WM_PASTE, 0, 0 ); // Operated PostMessage( hwnd, WM_CHAR, (int)msg[i], 0 ); // Operated PostMessage( hwnd, WM_CLEAR, 0, 0 ); // Not Operated PostMessage( hwnd, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)"ABC" ); // Not Operated よろしくお願いします。

  • メッセージループについて

    while(true) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(msg.message==WM_QUIT) break; DispatchMessage(&msg); if(!GetMessage(&msg,NULL,0,0)) { } } else { } これはpeekMessageがメッセージを取り出してメッセージがあったら if(msg.message==WM_QUIT) break; DispatchMessage(&msg); if(!GetMessage(&msg,NULL,0,0)) を実行して、GetMessage()で待機してもし、メッセージがWM_QUITならGetMessageにWM_QUITのメッセージを渡してメッセージが消えてPeekMessageはメッセージキューがないため、0を返し永遠にelseを繰り返すという認識でよろしいのですか? あと、while(true) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(!GetMessage(&msg,NULL,0,0)) { } if(msg.message==WM_QUIT) break; DispatchMessage(&msg); } else { } if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))がWM_QUITのメッセージで そしてメッセージが消えてGetMessageで待機状態になるということでよろしいのでしょうか?ご教授お願いします。

  • コンソールからのメッセージボックスをアクティブに

    Win32APIについて教えてください。 #include <iostream> #include <windows.h> int main() {   int i=0;   char mes[20]; // std::cin >> i;   std::sprintf(mes, "%dが入力されました", i);   MessageBox(NULL, mes, "test", MB_OK);   return 0; } をコンソールから実行するとメッセージボックスがアクティブになるのですが、コメントの部分を外してコンソールからの入力を受け取ると、コンソールがアクティブになってメッセージボックスがコンソールの下に隠れてしまいます。メッセージボックスをアクティブにすることはできるのでしょうか。 宜しくお願いします(WinXP、bcc32を使用しています)。

  • ウィンドウハンドルがメッセージ処理ループの後おかしくなる(?)

    下のコードをコンパイルしても、 WinMain KillTimer hr=ERROR_INVALID_WINDOW_HANDLE (0x00000578) というエラーメッセージが出てうまく通りません。 エラーを無視する意味でKillTimerをせずにやってしまえば、特に問題ないのですが、後々問題が出てきても怖いので、直したいです。 メッセージ処理ループの手前でKillTimerを行うと、エラーは出ませんし、 メッセージ処理ループのすぐ後でSetTimerを行うと、SetTimerでエラーが出るので、 ループでおかしくなるのかな、と思いました。 プログラムをシェイプアップしてもエラーがとれませんし、 もしかして根本的な間違いがあるのでしょうか・・・? #include <windows.h> #include <dxerr9.h> #define kWCLASS_NAME "WndClass" // ウィンドウクラス名 #define kWINDOW_NAME "Wnd" // ウィンドウ名 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow ) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInst; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName =NULL; wcex.lpszClassName = kWCLASS_NAME; wcex.hIconSm = NULL; RegisterClassEx(&wcex); /* --- メイン・ウィンドウの作成 --- */ HWND hWnd; hWnd = CreateWindow(kWCLASS_NAME, kWINDOW_NAME, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL); /* --- ウィンドウの表示 --- */ ShowWindow( hWnd, SW_SHOWDEFAULT ); UpdateWindow( hWnd ); /* --- タイマのセット --- */ if ( SetTimer( hWnd, 1, 1000, NULL ) == 0 ) // WM_TIMERはWndProcで処理 { DXTRACE_ERR( "WinMain SetTimer", GetLastError() ); return -1; } /* --- メッセージ処理ループ --- */ MSG msg; ZeroMemory( &msg, sizeof( msg ) ); while ( msg.message != WM_QUIT ) // PostQuitMessage()が呼ばれたら終了 { if ( !GetMessage( &msg, NULL, 0, 0 ) ) { msg.message = WM_QUIT; } else { TranslateMessage( &msg ); DispatchMessage( &msg ); } } /* --- タイマの破棄 --- */ if ( KillTimer( hWnd, 1 ) == 0 ) { DXTRACE_ERR( "WinMain KillTimer", GetLastError() ); return -1; } /* --- 終了処理 --- */ // ウィンドウクラスの登録解除 if ( UnregisterClass( kWCLASS_NAME, hInst ) == 0 ) { DXTRACE_ERR( "WinMain UnregisterClass", GetLastError() ); return -1; } return 0; }

  • メッセージループ

    while(true) { if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) { if(msg.message==WM_QUIT) break; DispatchMessage(&msg); if(!GetMessage(&msg,NULL,0,0)) { return (int)msg.wParam; } } } else { } このソースで実行して消したら終了しませんでした。 なぜ終了できなかったのでしょうか?

  • 子ウインドウの作成と破棄について

    CALLBACK のみを書きました。 メインウインドウを破棄したら 子ウインドウも破棄したいのですが、 うまく出来ません。 どうすればよろしいでしょうか? よろしくお願いします。 #include<windows.h> #include"ChildWindow.h" char MainWindowClassName[]="mainwindow"; LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { static HWND childWnd; switch(message) { case WM_ACTIVATEAPP: childWnd=Child_CreateWindow(hWnd,message,wParam,lParam); break; case WM_DESTROY: DestroyWindow(childWnd); PostQuitMessage(0); break; default: return DefWindowProc(hWnd,message,wParam,lParam); } } ///////////////////////////////////////////// #include<windows.h> char ChildWindowClassName[]="childwindow"; LRESULT CALLBACK ChildProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { switch(message) { case WM_LBUTTONDOWN: MessageBox(NULL,"","",MB_OK); break; default: return DefWindowProc(hWnd,message,wParam,lParam); } } ATOM Child_RegistWindow(HINSTANCE hInstance){} HWND Child_InitInstance(HWND hParentWnd,HINSTANCE hInst,int CmdShow){} HWND Child_CreateWindow(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { int CmdShow=1; Child_RegistWindow(NULL); HWND ChildWnd=Child_InitInstance(hWnd,NULL,CmdShow); MSG msg; while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return ChildWnd; }