• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:SendMessage中のメッセージ・ループについて)

SendMessage中のメッセージ・ループについて

このQ&Aのポイント
  • SendMessage中のメッセージ・ループについて私は今まで、SendMessageを行うと、受信側の処理が終わるまで送信側は一切のメッセージ処理を受け付けない(処理が終了するまで待ち状態)と信じていました。がしかし・・・実際には待っている間に自分のメッセージを処理することがあるようなのです。
  • 環境:VisualStudio2005 C/C++ 状況:IntelliPointMouseのドライバ?であるipoint.exeを組み込んでいる場合、SendMessage中にウィンドウの更新が発生します。例)SendMessage(hwnd, msg, 0, 0) <--- SendMessageから制御が返ってきていない状態で、メインスレットのOnPaintが呼び出されることがある・・・(コールスタックで確認・・・)
  • 対応策として、SendMessageTimeout(hwnd, msg, 0, 0, SMTO_BLOCK, 10000, ret);を使用し、SMTO_BLOCK属性を指定して、SendMessageを行うことで、特定のドライバが起因する不可解な現象を避けることができます。しかし、実際にはSendMessage中になんらかのメッセージ処理が発生することも考えられるため、恒久的な対応が必要です。

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

  • ベストアンサー
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.1

こちらに書いてありますが、 http://yokohama.cool.ne.jp/chokuto/urawaza/api/SendMessage.html 引用「受信側スレッドがメッセージを処理するまで送信側スレッドの実行は停止されます。ただし、メッセージ処理を待つ間でも、送信側スレッドは自身に送られてきたキューイングされないメッセージは処理されます。これを防ぐには SendMessageTimeout 関数呼び出しで SMTO_BLOCK フラグを指定します。」 と言うことで、対処されたSMTO_BLOCKでWM_PAINTメッセージをブロックできていると思います。 ただし、恒久的にはWM_PAINTメッセージをブロックするのではなく、SendMessage中でも画面更新できるのが望ましいです。

kuni-gogo
質問者

お礼

ご教授ありがとうございます。 そうですか、やはりこういう事象を考慮してプログラミングすべき なんですね。 今回はどうもご回答ありがとうございました。 m(__)m

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • SendMessageについて

    VERSION:VB6.0 SendMessageを使用しSQLPlusに対して文字列を送りたいのですが巧くいきません。 ↓が自身が作成したSendMessageを使用しているプログラムの一部なのですが、おかしな点や別な方法があればご教授お願いします。 '別アプリにメッセージを送る Declare Function SendMessageStr Lib "user32.dll" _ Alias "SendMessageA" (ByVal hWnd As Long, ByVal MSG As Long, _ ByVal wParam As Long, ByVal lParam As String) As Long Dim pId As Long 'プロセスID pId = Shell("SQLPlusのアドレス" & " /nolog", 1) SendMessageStr pId, WM_SETTEXT, 0, "送信する文字列" というプログラムです。 SQLPlusは起動するのですが文字列がSQLPlus側に送れず困っています。 どうかよろしくお願いします。

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

    下のコードをコンパイルしても、 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; }

  • excelVBAからC#へsendmessage

    excelのVBAから文字列をsendmessageで C#のプログラムに文字列を渡せないかと考えています。 ネットで調べつつなんとか作ってみたのですが、 どうしてもうまく動作しません。 変な文字列が表示されてしまいます。 どこがおかしいか教えて頂けないでしょうか。 windows7、Excel2010、.netFramework4になります。 ※※※excel VBA側プログラム※※※※※※※※※※※※ //外部functionを使いますよ Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _ (ByVal hwd As Long, ByVal Msg As Long, ByVal wpara As Long, lpara As COPYDATASTRUCT) As Long //構造体 Public Type COPYDATASTRUCT dwData As Long cbData As Long lpData As String End Type //メッセージを送信するsub Public Sub sousin() Dim result As Longv Dim hWnd As Long Dim cds As COPYDATASTRUCT Dim str As String Dim strby() As Byte Dim length As Long  ~ ウィンドウハンドルの取得 ~ str = "test" strby = StrConv(str, vbFromUnicode) length = UBound(strby) - LBound(strby) + 1 cds.dwData = 0 cds.lpData = str cds.cbData = length result = SendMessage(hWnd, WM_COPYDATA, 0, cds) End Sub ※※※C#側プログラム※※※※※※※※※※※※※※※ //構造体 public struct COPYDATASTRUCT { public long dwData; public long cbData; public string lpData; } //WndProc関数 protected override void WndProc(ref Message m) { switch (m.Msg) { case WM_COPYDATA: COPYDATASTRUCT mystr = new COPYDATASTRUCT(); Type mytype = mystr.GetType(); mystr = (COPYDATASTRUCT)m.GetLParam(mytype); label1.Text = mystr.lpData;           ←※無茶苦茶な文字列になります break; } base.WndProc(ref m); }

  • ウィンドウメッセージについて

    Visual C++ で初歩のプログラミングをさせていただいてますが、 実現できない点があるのでご回答いただけると幸いです。 環境は以下になります。 SDK: Visual C++ 6.0 OS: Windows XP 今やっているのは、他のウィンドウの動きを監視するというものです。 対象のウィンドウがリサイズされたら、サイズがいくつに変更されたかメッセージボックスを出します。 以下の手順でプログラミングしました。 MSG msg; RECT r; HWND hWnd = FindWindow("Notepad", "無題 - メモ帳"); if(hWnd != NULL) { return 0; } while( GetMessage(&msg, hWnd, 0, 0) ) { if(msg.message == WM_SIZE) { GetClientRect(hWnd, &r) ... } } このように書くと、コンパイルも通ったのですが、 リサイズどころかウィンドウを動かすこともできなくなってしまいました。 こういうのって力技でしょうか・・・。 フリーソフトなどでも多いですが、ウィンドウを監視するプログラム のコアな部分はどのように書かれているものなのでしょう? よい例があればご教授よろしくお願いします。

  • 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 よろしくお願いします。

  • VC++ メインループでのイベント監視方法

    こんにちは。 VC++2008Expressでプログラムをしようと思っている初心者です。 以下、変な疑問があり、お尋ねしたいと思います。 よろしくお願いします。 Windowsアプリケーション Win32API クラスで別スレッドを作成して、そのスレッドからのイベントを WinMainループで受け取る方法ですが 通常皆様はどういう風にするのでしょうか? クラスは、その他のプログラムでも流用可能で様々なアプリに対応しやすいようにしあげたいのですが。。 別スレッドでイベント発生時にWinMainにどのように教えるのが普通のやり方なんでしょうか? 僕の考えでは、WinMain関数内のループ内で常時イベント発生していないか 以下のように監視させるか eventloop el; while(GetMessage(&msg,NULL,0,0)) {   TranslateMessage(&msg);   DispatchMessage(&msg);      if(el::boolEvent){     イベント処理へ   } } とするのが良いか? これだとクラスの関数、変数の使い方さえ分かるようにしておけば流用は簡単 なのかなと思いますが。。 メインのループ内にこんな監視を入れるようなプログラムをみたことないので ナンセンスなのではと思います。 次に考えられるのは、クラスのイベント発生で作成したSendMessageを送って メッセージ処理でイベント処理をさせるのが良いのかなって思いますが これだと、流用するときに対応したMessage(キュー?ですかね)を作成しないといけなく 私的に分かりにくいなーって思います。。。 変なことで悩んで先に進まないのですが、皆様はどのようにコーディングされるのでしょうか? ちなみにイベントというのは、RS232Cで受信があって、そのデータを加工したあとで メモリに格納して格納しましたよってイベントです。 どうかよろしくお願いします。

  • Windowsプログラムでのメッセージループ

    Microsoft Visual C++6.0でWin32ApplicationでWindowsプログラムを作る勉強を始めました。 『Visual C++ 1 はじめてのWindowsプログラミング』(山本信雄 著) という本で勉強しています。 WinMain函數の中に次のような「メッセージループ」というものがあるんですね。 while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } 本の説明では 「メッセージループとは、GetMessageでメッセージの有無を常に確認しつづけるループです。Windowsプログラムは、何もしていないように見えるときでも常にメッセージループをじっこうしているのです。」 ということです。 また 「もしもメッセージがなければ、GetMessageは他のアプリケーションに処理を讓ります。これによってWindowsのマルチタスクがじつげんされています。」 ともありました。 私が思ったのは、 他のアプリケーションに処理を讓ってしまったら、上の説明にあるような「常にメッセージループをじっこうしている」ことにはならないんではないか、 ということです。 逆に、メッセージがあり續けたら、他のアプリケーションに処理を讓らないのでしょうか。 WindowsのマルチタスクはGetMessageが行っているのではなくて、WindowsというOSが行っているのではないでしょうか。 GetMessageが他のアプリケーションに処理を讓っている間の状態というのは、GetMessage函數がじっこうされている状態なのでしょうか。それとも、その間プログラムは停止しているのでしょうか。停止しているのだとしたら、再開するのはGetMessageの次のTranslateMessageからでしょうか。 編集部に質問を送ったのですが、返事はありません。 初級者ゆえ何か勘違いしているのかもしれません。 よろしくお願いいたします。

  • visualstudioについて

    visual studio2008 c++ を使用しています. ダイアログ形式でアプリケーションを作成しています. ボタンを押すと画像のようなアプリケーションを起動してenterキーを送るようにしたいのですがうまく出来ません. void CMy6Dlg::OnBnClickedButton1() { // TODO: ここにコントロール通知ハンドラ コードを追加します。 HINSTANCE ret = ShellExecute(m_hWnd, "open", "---Release\\scip_20_gd.exe", NULL, NULL, SW_SHOW); HWND hWnd = ::FindWindowEx(NULL, NULL, NULL, "---Release\scip_20_gd.exe"); ::SendMessage(hWnd,WM_SETFOCUS,0,0); ::SendMessage(hEdit, WM_KEYDOWN, VK_RETURN,0); if (ret <= (HINSTANCE)32) AfxMessageBox("シェル処理ができません.", MB_OK); } よろしくお願いします.

  • Modalダイアログを他のThreadから閉じたい

    VC++6.0のMFCプロジェクトで、Modalダイアログを他のThreadから閉じる処理を行いたいと考えています。 以下のようなことを実行しているのですが、3.で"MyDialog"にメッセージが送信されません。 1.あるFormView上で、他のスレッド("WorkerThread"とします)を起動する。 2.上記FormView上で、Modalダイアログ("DialogTest"とします)を開く。 3."WorkerThread"にて、一定の処理後にSendMessageを実行して、"MyDialog"にメッセージを送り、EndDialog()を実行させる。 /*----- WorkerThread関数内-----*/ //"TestDialog"のハンドルを取得する。 HWND hWnd = ::FindWindowEx(NULL, NULL, _T("#32770"), NULL); if (hWnd) { CWnd* pWnd = FromHandle(hWnd); if (pWnd) { //処理がここに入っていることは確認できます。 pWnd->SendMessage(WM_MESSAGE_CLOSEDIALOG, 0, 0); } } /*-----定義用ヘッダーファイル------*/ const UINT WM_MESSAGE_CLOSEDIALOG =::RegisterWindowMessage(_T("UWM_MESSAGE_CLOSEDIALOG")); /*-----DialogTest.h------*/ //{{AFX_MSG(CWaitingSearchDialog) //}}AFX_MSG afx_msg void OnCloseDialog(WPARAM wParam,LPARAM lParam); DECLARE_MESSAGE_MAP() /*-----DialogTest.cpp------*/ void DialogTest::OnCloseDialog() { EndDialog(IDOK); } BEGIN_MESSAGE_MAP(DialogTest, CDialog) //{{AFX_MSG_MAP(DialogTest) //}}AFX_MSG_MAP ON_REGISTERED_MESSAGE(WM_MESSAGE_CLOSEDIALOG, OnCloseDialog) END_MESSAGE_MAP() 間違いありましたら、ご指摘いただけないでしょうか。よろしくお願いいたします。 (ところで、私が同カテゴリに先日投稿した「"複数プロジェクトをビルドしたとき、DLLに新しく追加したClassのみがリンクエラーになる "」は、自己解決できました。 もしどなたか適当な回答を投稿してもらえれば、その旨を書けます。お暇な方、お願いできないでしょうか)

  • コンソールアプリケーションでの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 ); }