Delphi处理Windows消息

来源:互联网 发布:ping 使用的端口 编辑:程序博客网 时间:2024/04/28 15:58

一、PeekMessage()函数。下面是它的原形: BOOL PeekMessage( LPMSG lpMsg, // pointer to structure for message HWND hWnd, // handle to window UINT wMsgFilterMin, // first message UINT wMsgFilterMax, // last message UINT wRemoveMsg // removal flags ); 这是一个布尔类型,也就是一个int型,不过只有两个值,TRUE和FALSE,如果有一条消息在队列中等待,函数返回TRUE,否则,返回FALSE。它的参数很简单: LPMSG lpMsg:这是一个MSG类型的指针变量。如果有消息在等待,消息信息将被填入该变量。 HWND hWnd:你所要检查的消息队列的窗口的句柄。 UINT wMsgFilterMin,wMsgFilterMax:索引第一个和最后一个消息,一般你都从第一个消息开始检索,所以把它们都设置为0好了。 UINT wRemoveMsg:一般来说,它有两个值,PM_REMOVE或者PM_NOREMOVE。使用前者会在消息被读取后从队列中移除,后者是继续保留。通常,我们选择前者PM_REMOVE。二、PeekMessage和GetMessage的区别 他俩的区别与SendMessage和PostMessage的区别有类似之处,都是等待与不等待的关系,如果消息队列里没有消息,PeekMessage不会等待,返回0,而GetMessage则会等待消息队列里面有消息才返回... Getmessage是阻塞的,调用Getmessage后整个程序将处于休眠状态。三、消息处理 真正处理消息时,你需要做两件事,很简单,第一件是TranslateMessage(),第二件是DispatchMessage()。它们的原形很相似: BOOL TranslateMessage(CONST MSG *lpmsg); 是将虚拟键消息转换为字符消息并加到调用线程的队列。(应该就是把WM_KEYDOWN消息转成合适的WM_CHAR消息再放到本线程消息队列中) LONG DispatchMessage(CONST MSG *lpmsg); 从MSG结构中调用相应的信息。DispatchMessage将处理后的消息发回Windows,由Windows自己处理,它所完成的工作就是把当前消息分发到相关的窗口过程。然后窗口过程根据消息的类型对不同的消息进行相关处理。四、PostMessage()与SendMessage() PostMessage()被经常用来向消息队列中加入消息,成功,返回TRUE,否则,返回FALSE。它只是简单的把消息加入到队列中,然后返回。多数情况下,调用它将返回TRUE。 SendMessage()则有些不同,它并不是把消息加入到队列里,而是直接翻译消息和调用消息处理,直到消息处理完成后才返回。五、消息队列 消息队列由可以分成系统消息队列和线程消息队列。系统消息队列由Windows维护,线程消息队列则由每个GUI线程自己进行维护,为避免给非GUI线程创建消息队列,所有线程产生时并没有消息队列,仅当线程第一次调用GDI函数后系统给线程创建一个消息队列。队列消息送到系统消息队列,然后到线程消息队列。 对于队列消息,最常见的是鼠标和键盘触发的消息,例如WM_MOUSERMOVE,WM_CHAR等消息,还有一些其它的消息,例如:WM_PAINT、WM_TIMER和WM_QUIT。当鼠标、键盘事件被触发后,相应的鼠标或键盘驱动程序就会把这些事件转换成相应的消息,然后输送到系统消息队列,由Windows系统去进行处理。Windows系统则在适当的时机,从系统消息队列中取出一个消息,根据前面我们所说的MSG消息结构确定消息是要被送往那个窗口,然后把取出的消息送往创建窗口的线程的相应队列,下面的事情就该由线程消息队列操心了,Windows开始忙自己的事情去了。线程看到自己的消息队列中有消息,就从队列中取出来,通过操作系统发送到合适的窗口过程去处理。 一般来讲,系统总是将消息Post在消息队列的末尾。这样保证窗口以先进先出的顺序接受消息。然而,WM_PAINT是一个例外,同一个窗口的多个 WM_PAINT被合并成一个 WM_PAINT 消息, 合并所有的无效区域到一个无效区域。合并WM_PAIN的目的是为了减少刷新窗口的次数。 例子一: // 该函数使程序进入一个消息循环,只有在鼠标左键在窗体客户区域 // 单击后才会退出循环,在循环退出前用户不能改变窗体大小和移动窗体 procedure TForm1.Button1Click(Sender: TObject); var TheMessage: TMSG; // 保持消息信息 MouseClicked: boolean; // 循环控制变量 begin {初始化循环控制变量} MouseClicked := FALSE; {在进入之前清空消息队列,有个干净的环境} while PeekMessage(TheMessage, Handle, 0, 0, PM_REMOVE) do; {该函数将程序置于一个消息循环中,直到单击鼠标才退出} while not MouseClicked do begin {挂起线程直到一个新消息被放入消息队列} WaitMessage(); {获得放入消息队列的消息} while PeekMessage(TheMessage, Handle, 0, 0, PM_REMOVE) do begin if TheMessage.message=WM_PAINT then DispatchMessage(TheMessage) else if TheMessage.Message=WM_LBUTTONDOWN then begin MouseClicked := TRUE; ShowMessage('A message was received, resume execution'); end; end; end; end; 例子二: function TApplication.ProcessMessage(var Msg: TMsg): Boolean; var Handled: Boolean; begin Result := False; if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then begin Result := True; if Msg.Message <> WM_QUIT then begin Handled := False; if Assigned(FOnMessage) then FOnMessage(Msg, Handled); if not IsHintMsg(Msg) and not Handled and not IsMDIMsg(Msg) and not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then begin TranslateMessage(Msg); DispatchMessage(Msg); end; end else FTerminate := True; end; end; 例子三: //等待响应当前进程的所有消息,Message指定不进行处理的消息 void ProcessMessages(int Message) { MSG msg; bool Result; do { Result = false; if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { Result = true; if(msg.message != WM_QUIT || msg.message != Message) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } } }while(Result); }