登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

面包会有的

... ...

 
 
 

日志

 
 

windows消息队列  

2011-03-08 19:53:29|  分类: VC++ |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
本节详细描述消息和消息队列以及如何在你的程序中使用他们。

关于消息和消息队列

与传统的应用程序不同,Microsoft Windows应用程序并不显式地用一个函数的调用(如c运行库)来获取输入,而是,等待windows系统把输入传给它们。

windows系统把应用程序的所有输入传给应用程序的窗口,每个窗口都有一个称之为窗口过程的函数.当窗口有输入时windows系统要调用它,窗口过程处理输入并把控制返回windows系统。有关窗口过程,参见 “窗口过程”。 这一章讲述消息及消息队列,并说明在应用程序中如何使用它们。

消息

windows系统以消息的形式把输入传给窗口过程,消息是由windows系统或应用程序产生的.windows系统对每一个输入事件都要产生消息,例如,用户按键盘、移动鼠标或单击一个滚动条控制框。windows系统为了响应应用程序给系统带来的变化也会产生消息,比如应用程序改变了系统字体资源池或是改变了一个窗门的大小。应用程序可通过产生消息指导它自己的窗口来完成某个任务,或是与其它应用程序的窗口进行通信。

windows系统把消息发送给窗口过程.窗口过程有四个参数:窗口句柄、消息标识以及两个叫做消息参数的32位值。窗口句柄决定消息将发送到哪—个窗口,windows系统则用它来确定向哪一个窗口过程发送消息。

消息标识是一个命名的常量,由它来标明消息的目的。如果窗口过程接收到一条消息,它就通过消息标识来决定如何处理这条消息。例如,消息标识WM_PAINT通知窗口过程,窗口的客户区被改变了,需要重画。

消息参数指定窗口过程在处理消息时所用的数据或数据的位置,消息的意图及数值取决了消息本身。消息参数可以是一个整数、紧缩的位标志、一个含有附加数据结构的指针等等。如果消息不使用消息参数,一般就都设置成NULL、窗口过程必须检查消息标识以确定如何解释消息参数。

消息路由

windows系统用两种方式向窗口过程发送消息:把消息投递到一个先进先出的消息队列中,它是一个系统定义的内存块用于临时存储消息;或是把消息直接发给窗口过程。

投递到消息队列中的消息叫排队消息,它们主要是用户通过鼠标或键盘的输入结果.如WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_KEYDOWN, and WM_CHAR消息。其它的排队消息包括定时器、绘制和退出消息:WM_TIMER, WM_PAINT, and WM_QUIT。所有直接发送到窗口过程的其它消息称之为非排队消息。

排队消息

windows系统在同一时间可显示多个窗口,要发送鼠标和键盘输入到相应的窗口,windows系统要用到消息队列,它要管理一个系统消息队列和任意数目线程消息队列,每一个队列对应于一个线程。

不管什么时候,只要用户移动鼠标或是敲键盘.鼠标或键盘的设备驱动器都要把输入转换成消息,并把它们放到系统消息队列中去。windows从系统队列中每次移走一条消息,确定目的窗口,再把它们投递到创建目的窗口的线程的消息队列中,线程消息队列接收所有由该线程创建的窗口的鼠标和键盘消息。线程从它的队列中移走消息并指导windows系统将它们发送到相应的窗口过程进行处理。有关线程,参见 “进程和线程”。

WM_PAINT消息有点特别,windows系统总是把这条消息放在消息队列的最后,这样可保证窗口按先进先出次序接收它的输入消息,WM_PAINT消息被保持在队列中,只有在队列中没有其它消息时才发送到窗口过程。同一个窗口的多个WM_PAINT消息被合并成一个WM_PAINT消息,把客户区所有无效部分合并成一个区域.合并WM_PAINT消息节约了窗口必须重画客户区内容的时间。

系统向线程消息队列投递消息是通过填充一个MSG结构,再把它复制到消息队列中,MSG结构中的信息包括接收消息的窗口句柄、消息标识、两个消息参数、消息时间以及鼠标的位置,线程可把消息投递到它自己的消息队列中或是通过函数 PostMessagePostThreadMessage把消息投递到其它线程的队列中去。

应用程序可通过函数GetMessage从它的队列中移走一条消息,应用程序还可用函数PeekMessage来检查队列中的某个消息但并不移走它,这个函数用有关这条消息的信息填充MSG结构。

把一条消息从它的队列中移走后.应用程序可用函数DispatchMessage指导windows系统把这条消息发送到窗口过程进行处理。DispatchMessage利用前面调用函数GetMessagePeekMessage时填充的MSG结构的指针,把窗口句柄、消息标识及两个消息参数传给窗口过程,但它并不传送时间或鼠标光标的位置.应用程序可以在处理一条消息时,通过调用函数GetMessageTimeGetMessagePos来获取这些信息。

一个线程可以用函数WaitMessage当他没有其他消息在其队列里时,产生对其他线程的控制。此函数将终止线程,直到一个新消息被放入该线程的消息队列里,然后返回。

你可以调用函数SetMessageExtraInfo来设置当前线程消息队列的附加信息。是和当前线程的消息队列联系的32位值。用户可以用函数GetMessageExtraInfo来获得附加信息,该信息将会保留到下次调用函数GetMessagePeekMessage之前。

非排队消息

非排队消息是直接发送到目标窗口过程的,而不通过系统消息队列和线程消息队列。windows系统一般通过发送非排队消息把影响某窗口的事件通知窗口。例如,如果用户激活一个新的应用程序窗口.windows系统就会向该窗口发送一系列的消息,包括:WM_ACTIVATEWM_SETFOCUSWM_SETCURSOR,这些消息分别通知窗口:它被激活了;将通过这个窗口进行键盘输入;鼠标已移到这个窗口边框的里面了。非排队消息也有可能发生在应用程序调用一个windows系统函数时,例如,在应用程序用函数SetWindowPos来移动一个窗口之后,windows系统发送一条WM_WINDOWPOSCHANGED消息。

应用程序是调用函数SendMessageSendNotifyMessageSendDlgItemMessage发送消息的。

消息处理

应用程序必须删除和处理投递到它的线程消息队列中的消息,单一线程的应用程序一般是在它的WinMain函数中使用一个消息环来删除消息,并把消息发送到相应的窗口过程进行处理。具有多重线程的应用程序在创建窗口的每一个线程中使用一个消息环,下一节将讲述消息环是如何工作的,另外还解释了窗口过程的一般规则

消息环

一个简单的消息环含有一个对下列函数的调用:GetMessage, TranslateMessage和DispatchMessage。函数GetMessage从队列中检取一条消息并把它复制到一个MSG结构中.GetMessage应返回TRUE,但如果它得到的是WM_QUIT消息,它就返回FALSE并结束循环。在单一线程的应用程序中,结束消息循环通常是关闭应用程序的第一步。一般在应用程序主窗口的窗口过程中响应WM_DESTROY消息时,应用程序通过函数PostQuitMessage关闭它自己的消息环。

如果在GetMessage中指定窗口句柄,那么从队列中检取的只是指定窗口的消息。GetMessage 也能过滤队列中的消息,这种情况下检取的只是指定范围内的消息。有关过滤消息,参见 “消息过滤”。

如果某个线程想接收键盘的字符输入,那么线程消息环中必须含有TranslateMessage。Windows系统在用户每按一次键时会产生一个虚键消息(WM_KEYDOWN和WM_KEYUP),虚键消息含有一个标识哪一个键被按过的虚键码,但不是它的字符值,要得到这个值,消息环中必须含有TranslateMessage,由它来把虚键消息翻译成字符消息(WM_CHAR),再把它放回到应用程序的消息队列中去.这样字符消息才能在消息环的下一轮循环中被发送到窗口过程。

函数DispatchMessage把消息发送到与MSG结构中指定的窗口句柄相应的窗口过程,如果窗口句柄是HWND_TOPMOST ,DispatchMessage就把消息发送到系统中所有顶层窗口的窗口过程。如果窗口句柄是NULL,对于这条消息DispatchMessage则什么也不做。

应用程序的主线程在初始化应用程序并且至少创建了一个窗口之后就开始了消息循环,一旦开始,消息环就连续不断地从线程的消息队列中校取消息并把它们分发到相应的窗口,函数GetMessage从消息队列中检取到WM_QUIT消息时,消息环就结束了。

一个消息队列只需要有一个消息环,而不管应用程序有多少个窗口,因为队列中的每一条消息是一个MSG结构,其中含有接收消息的窗口句柄,DispatchMessage总能把消息发送到相应的窗口。

应用程序可以有多种方法修改它的消息环,例如,它可以从队列中检取消息但并不发送到任何窗口,这对那些投递不指定窗口的消息的应用程序是很有用的,(这些消息是提供给应用程序的,而不是某个窗口,因为它们含有NULL窗口句柄)。应用程序也能指导GetMessage来搜索队列中一个特定的消息,而不管其它消息,这对那些有时不按消息队列先进先出次序检取消息的应用程序来说是很有用的。

使用键盘加速键的应用程序必须能够把键盘消息转换成命令消息,要这样做,应用程序的消息环必须调用函数TranslateAccelerator有关加速键,参见 “键盘加速键”。

窗口过程

窗口过程是一个函数,用来接收和处理所有发送到该窗口的消息,每个窗口类都有一个窗口过程,同一窗口类所创建的窗口共用同一个窗口过程来响应消息。

系统通过把消息数据作为过程的参数来向窗口过程发送消息,再由窗口过程完成与消息相应的活动。它需要检查消息的标识,在处理消息时要使用由消息参数指定的这个信息。

窗口过程一般不会忽略—条消息,如果它不处理某条消息,它就必须把这条消息传回系统进行默认处理,窗口过程是调用函数DefWindowProc来完成的,由它完成一个默认的操作并返回消息结果。绝大多数窗口过程只处理几种类型的消息,其它的则通过调用DefWindowProc传给了系统。

因为窗口过程是由所有属于同类窗口共享的,所以它能处理几个不同窗口的消息,要识别受消息影响的某个窗口,窗口过程可以检查消息所带的窗口句柄。有关窗口过程,参见 “窗口过程”。

传递和发送消息

任何应用程序都能投递和发送消息,就跟系统一样,应用程序投递一条消息是通过把它复制到消息队列,发送消息则是通过把消息数据作为窗门过程的参数。要投递消息,应用程序需要用到函数PostMessage,要发送消息,程序使用函数SendMessage, BroadcastSystemMessage, SendMessageCallback, SendMessageTimeout, SendNotifyMessageSendDlgItemMessage

应用程序通常投递—条消息来通知某个窗口去完成一个任务。PostMessage为消息创建一个MSG结构并把消息拷到消息队列中,最后由应用程序的消息环检取这条消息再把它发送到相应的窗口过程。

应用程序一般是通过发送一条消息通知窗口过程立即完成某项任务,函数SendMessage把消息发送到与给定窗口相应的窗口过程,这个函数要等待窗口过程完成处理井返回消息的结果。父窗口与子窗口之间也是通过发送消息来进行相互间的通信,例如,某个父窗口有一个编辑控制框作为它的子窗口,就可通过向它发送消息设置控制框的正文,这个控制框则通过向父窗口发送消息来把用户对正文的改变通知其父窗口。

函数SendMessageCallback也能发送消息到指定窗口的窗口过程里,但是,这函数是立即返回,当窗口过程函数处理完消息后,系统调用指定的回调函数,有关更多回调函数信息,参考函数SendAsyncProc

有时,应用程序也有可能要求向系统中的所有顶层窗口发送或投递一条消息,例如,如果应用程序改变了系统的时间,它必须通过发送WM_TIMECHANGE消息来通知所有顶层窗口,应用程序向所有顶层窗口发送或投递一条消息是调用函数SendMessagePostMessage,并在hwnd参数中指定HWND_TOPMOST。你同样通过函数BroadcastSystemMessage指定参数lpdwRecipients的值为BSM_APPLICATIONS广播消息给所有程序

应用程序能够投递一条消息而不指定窗口,在调用PostMessage时应用程序提供NULL窗口句柄,这条消息就被投递到与当前线程相应的队列中。因为没有指定窗口句柄,应用程序就必须在处理消息环中的这条消息,这也是一种创建消息的方法.此类消息适用于整个应用程序,而不只是指某个窗口。

使用函数InSendMessage窗口过程能够确定它所处理的消息是从另一个线程发来的,这种能力在需要根据消息源进行消息处理时是很有用的。

经常出现的一个编程错误是假设函数PostMessage总能成功地投递一条消息,这在消息队列是满的时候是不对的,应用程序应该检查函数PostMessage的返回值以确认消息是否已经被投递,否则要重新投递这条消息。

消息种类

这部分将两种类型windows消息;系统定义的消息,程序定义的消息

系统消息

系统使用系统定义的消息来控制应用程序的操作,并给应用程序提供输入或其他信息进行处理。系统在与应用程序进行通信是时是发送系统消息的。应用程序也能发送或投递系统消息,应用程序通常用这些消息来控制预注册类创建的控制窗口的操作。

每条系统消息都有一个唯一的消息标识,对应于一个符号常量(在Windows系统头文件中定义),它表明了消息的目的,例如,常量WM_PAINT要求窗口绘制它的内容。

符号常量指定了系统消息所属的类别,常量的前缀标识能够解释和处理消息的亩口的类型。下表列出了前缀及相应的消息类别:

前缀 消息类

ABM Application desktop toolbar

BM Button control

CB Combo box control

CDM Common dialog box

DBT Device

DL Drag list box

DM Default push button control

EM Edit control

HDM Header control

LB List box control

LVM List view control

PBM Progress bar

PSM Property sheet

SB Status bar window

SBM Scroll bar control

STM Static control

TB Toolbar

TBM Trackbar

TCM Tab control

TTM Tooltip control

TVM Tree-view control

UDM Up-down control

WM General window

通用窗口消息覆盖了—个较大范围的信息和请求,包括鼠标和键盘输入消息、菜单和对话框输入消息、窗口创建和管理消息及动态数据交换消息(DDL)。

应用程序定义消息

应用程序可创建用在它自己的窗口中的消息,或是与其它进程中的窗口进行通信的消息。如果应用程序创建了它自己的消息,接收它们的窗口过程必须能够对消息进行翻译,并提供相应的处理。 ’

windows系统保留用于系统定义的消息的标识值的范围从0x0000到0x03FF(等于WM_USER—1)和0x8000到0xBFFF应用程序不能把这些值用于私有消息。

从0x0400(WM_USER的值)到0x7FFF之间的值是可用于应用程序定义的用于它自己的消息标识,而从0xC000到0xFFFF之间的值是应用程序为了与其它应用程序中的窗口进行通信所定义的消息标识。

应用程序用函数RegisterWindowMessage注册一条消息时,windows系统返回的消息标识在0xC000到0xFFFF之间,这个函数所返回的消息标识应保证在整个系统中是唯一的。如果应用程序要创建与其它应用程序中的窗口进行通信的消息,则使用RegisterWindowMessage来对它进行注册,这个函数可防止由于其它的应用程序基于不同的目的使用了相同的消息标识所产生的冲突。

消息过滤

应用程序可使用函数GetMessagePeekMessage来指定一个消息过滤器,从消息队列中检取指定的消息[忽略其它的消息),这是一个消息标识的范围(由第一个和最后一个标识指定)、一个窗口句柄或者两者都是GetMessagePeekMessage利用消息过滤器有选择地检取队列中的某条消息。如果某个应用程序必须检索消息队列中的排在后面的消息,消息过滤则是很有用的。

过滤消息的应用程序必须保证满足消息过滤器的消息是能被投递的,例如,如果某个应用程序的过滤器用于一个并不接收键盘输入的窗口中的WM_CHAR消息,函数GetMessage就不能返回,这样就会“挂起”这个应用程序。

要过滤键盘、鼠标和DDE消息,应用程序可以便用下列常量WM_KEYFIRST WM_KEYLAST, WM_MOUSEFIRST WM_MOUSELAST messages, WM_DDE_FIRST WM_DDE_LAST

消息死锁

调用函数SendMessage的线程向另一个线程发送一条消息,要等待接收消息的窗口过程返回,如果接收消息的线程在处理消息时放弃了控制,发送消息的线程就不能继续执行下去,因为它正等待SendMessage返回,这种情况就叫做死锁。接收消息的线程无须直接地放弃控制,调用下列函数其个的一个就能让线程放弃控制。

DialogBox

DialogBoxIndirect

DialogBoxIndirectParam

DialogBoxParam

GetMessage

MessageBox

PeekMessage

窗口过程可以确定它所接收的消息是不是另一个线程通过调用函数InSendMessage发来的。在处理一条消息时调用前面所列出的任一个函数之前,窗口过程应首先调用InSendMessage,如果函数返回TRUE,窗口过程就必须在调用任何能使线程放弃控制的函数之前调用函数ReplyMessage

使用消息和消息队列

这节描述如何完成下面的工作

创建消息环

检查消息队列

投递消息

发送消息

创建消息环

windows系统为每一个线程自动创建消息队列,如果线程创建了一个或多个窗口,就必须提供从线程消息队列中检取消息,并把它们发送至相应窗口过程的消息环。

因为windows系统指导向应用程序中的某个窗口发送消息,线程就必须在启动它的消息环之前至少要创建—个窗口,绝大多数windows应用程序含有一个创建窗口的线程。一个典型的应用程序是在函数WinMain中注册它主窗口的窗口类。创建和显示主窗口.然后启动消息环。

函数GetMessage DispatchMessage用来创建消息环,如果应用程序必须从用户得到字符输入,那么在消息环中应包含函数TranslateMessageTranslateMessage把虚键消转换成字符消息。下面的范例说明了一个简单的windows应用程序的WinMain函数中的消息环

HINSTANCE hinst;

HWND hwndMain;

int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpszCmdLine, int nCmdShow)

{

MSG msg;

WNDCLASS wc;

UNREFERENCED_PARAMETER(lpszCmdLine);

// Register the window class for the main window.

if (!hPrevInstance)

{

wc.style = 0;

wc.lpfnWndProc = (WNDPROC) WndProc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

wc.hInstance = hInstance;

wc.hIcon = LoadIcon((HINSTANCE) NULL, IDI_APPLICATION);

wc.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW);

wc.hbrBackground = GetStockObject(WHITE_BRUSH);

wc.lpszMenuName = "MainMenu";

wc.lpszClassName = "MainWndClass";

if (!RegisterClass(&wc))

return FALSE;

}

hinst = hInstance; // save instance handle

// Create the main window.

hwndMain = CreateWindow("MainWndClass", "Sample", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT, (HWND) NULL, (HMENU) NULL, hinst, (LPVOID) NULL);

// If the main window cannot be created, terminate

// the application.

if (!hwndMain)

return FALSE;

// Show the window and paint its contents.

ShowWindow(hwndMain, nCmdShow);

UpdateWindow(hwndMain);

// Start the message loop.

while (GetMessage(&msg, (HWND) NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

// Return the exit code to Windows.

return msg.wParam;

}

函数GetMessage,TranslateMessage以及DispatchMessageMSG结构的指针当作一个参数。如果有消息,GetMessage把它复制到MSG结构中,如果这个消息是一条虚键消息(如WM_KEYDOWNWM_SYSKEYDOWN),TranslateMessage产生一个字符消息(WM_CHARWM_SYSCHAR),并把它放到消息队列中去。DispatchMessage也使用MSG结构的成员用作窗口过程的参数.但要等到窗口过程完成处理后才返回。

如果某个线程支持加速键,那么它的消息环必须含有函数TranslateAccelerator。这个函数检查与线程加速键表中的一个入口相匹配的组合键,如果它找到一个匹配值.TranslateAccelerator就把组合键翻译成一条WM_COMMAND消息,并把它发送到窗口过程。

如果某个线程使用模式对话框,消息环中必须含有函数IsDialogMessage以便于对话框能够接收键盘输入。

有关对话框,参见“对话框”。

下面的范例说明了一个使用加速键的线程的消息环,其中显示了一个模式对话框。

如果TranslateAcceleratorIsDialogMessage返回TRUE(指示消息已被处理),就不再调用TranslateMessage DispatchMessage原因是TranslateAcceleratorIsDialogMessage完成所有对消息的翻译和发送工作。

HWND hwndMain;

HWND hwndDlgModeless = NULL;

MSG msg;

HACCEL haccel;

// Perform initialization and create a main window.

while (GetMessage(&msg, (HWND) NULL, 0, 0))

{

if (hwndDlgModeless == (HWND) NULL ||

!IsDialogMessage(hwndDlgModeless, &msg) &&

!TranslateAccelerator(hwndMain, haccel,

&msg))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

检消息队列

有时,应用程序需要在线程消息环的外面检查线程消息队列的内容,例如,如果某个应用程序的窗口过程进行一个较长的绘画操作,就可能允许用户中断这个操作。除非应用程序在处理鼠标和键盘消息的操作过程中不停地检查消息队列,否则在操作结束之前就不再会响应用户的输入.原因是线程消息环中的函数DispatchMessage在窗口过程处理完消息之前是不会返回的。

对于一个较长时间的操作,可使用函数PeekMessage来检查消息队列,PeekMessage与函数GetMessage是很相似的,都可用来检查消息队列中与过滤器标准相匹配的消息,再把这个消息复制到一个MSG结构中。它们之间主要的不同就是GetMessage要等待队列中出现一条与过滤器标准相匹配的消息,而PeekMessage 会立即返回,不管队列中是否有某条消息。

下面的范例说明了如何使用PeekMessage在一个长操作期间,检查消息队列中的一条单击鼠标或键盘输入消息。

HWND hwnd;

BOOL fDone;

MSG msg;

// Begin the operation and continue until it is complete

// or until the user clicks the mouse or presses a key.

fDone = FALSE;

while (!fDone)

{

fDone = DoLengthyOperation(); // application-defined function

// Remove any messages that may be in the queue. If the

// queue contains any mouse or keyboard

// messages, end the operation.

while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE))

{

switch(msg.message)

{

case WM_LBUTTONDOWN:

case WM_RBUTTONDOWN:

case WM_KEYDOWN:

// Perform any required cleanup.

fDone = TRUE;

}

}

}

其它的函数如GetQueueStatusGetInputState也能用来检查线程消息队列中的内容,GetQueueStatus返回一组标志,用来指明队列中消息的类型,这是一个最快的办法来确定队列中是否有消息,如果队列中台有鼠标或键盘消息,GetInputState就返回TRUE,这两个函数都能用来确定队列中是否有需要处理的消息。

投递消息

使用函数PostMessage把一条消息投递到消息队列中,PostMessage在线程消息队列的最后放置消息并立即返回,它不等待线程处理这条消息。函数的参数包括窗口句柄、消息标识相两个消息参数,windows系统把这些参数复制到一个MSG结构中,填充结构的timept成员,再把这个结构放到消息队列中。

windows系统用函数PostMessage所带的窗口句柄来决定哪一个线程消息队列接收消息.如果句柄是HWND_TOPMOST,windows系统就把这条消息投递到所有顶层窗口的线程消息队列中。

函数PostThreadMessage可用来向一个指定的线程消息队列投递消息,PostThreadMessagePostMessage也很相似.只是它的第一个参数是线程标识而不是窗口句柄,可通过调用函数GetCurrentThreadId检取这个线程标识。

函数PostQuitMessage用来退出消息环,PostQuitMessage向当前正在执行的线程发送WM_QUIT消息,如果线程消息环接收到WM_QUIT消息,就结束消息环并把控制返回给windows系统。应用程序通常调用PostQuitMessage响应WM_DESTROY消息,

用法如下

case WM_DESTROY:

// Perform cleanup tasks.

PostQuitMessage(0);

break;

发送消息

函数SendMessage是用来直接向一个窗口过程发送消息,SendMessage调用一个窗口过程,并等待过程对消息的处理和返回结果。 一条消息可以被发往系统中的任何一个窗口,而仅要求有一个窗口句柄,windows系统用这个句柄决定哪一个窗口过程应该接收这条消息。 如果窗口过程在处理由另一个线程发来的消息时放弃控制,就会出现消息死锁(有关消息死锁,参见 “消息死锁”)。在处理一个可能是发自另一个线程的消息之前,窗口过程应首先调用函数InSendMessage,如果这个函数返回TRUE,那么窗口过程就应在调用任何可以使线程放弃控制的函数之前调用ReplyMessage,做法如下:

case WM_USER + 5:

if (InSendMessage())

ReplyMessage(TRUE);

DialogBox(hInst, "MyDialogBox", hwndMain, (DLGPROC) MyDlgProc);

break;

有一些消息可以发给对话框中的控制框,这些控制框消息设置控制框的外观、特性和内容或是检取有关控制框的信息。例如,CB_ADDSTRING消息可以向组合框添加字串,BM_SETCHECK消息能够设置复选框或单选按钮的选择状态。

使用函数SendDlgItemMessage向一个控制框发送一条消息,要指定控制框的标识,含有这个控制框的对话框窗口的句柄。下面的范例用在对话框过程中的,把一个字串从组合框的编辑控制框拷到它的列表框,这个例子用SendDlgItemMessage向组合框发送一条CB_ADDSTRING消息.

HWND hwndCombo;

int cTxtLen;

PSTR pszMem;

switch (uMsg)

{

case WM_COMMAND:

switch (LOWORD(wParam))

{

case IDD_ADDCBITEM:

// Get the handle of the combo box and the

// length of the string in the edit control

// of the combo box.

hwndCombo = GetDlgItem(hwndDlg, IDD_COMBO);

cTxtLen = GetWindowTextLength(hwndCombo);

// Allocate memory for the string and copy

// the string into the memory.

pszMem=(PSTR)VirtualAlloc((LPVOID)NULL,(DWORD)(cTxtLen+1),MEM_COMMIT, PAGE_READWRITE);

GetWindowText(hwndCombo, pszMem, cTxtLen + 1);

// Add the string to the list box of the

// combo box and remove the string from the

// edit control of the combo box.

if (*pszMem != NULL)

{

SendDlgItemMessage(hwndDlg, IDD_COMBO, CB_ADDSTRING, 0, (DWORD) ((LPSTR) pszMem));

SetWindowText(hwndCombo, (LPSTR) NULL);

}

// Free the memory and return.

VirtualFree(pszMem, 0, MEM_RELEASE);

return TRUE;

// Process other dialog box commands.

}

// Process other dialog box messages.

}

消息及消息队列参考

下列函数函数用于消息和消息队列

BroadcastSystemMessage

DefWindowProc

DispatchMessage

GetInputState

GetMessage

GetMessageExtraInfo

GetMessagePos

GetMessageTime

GetQueueStatus

InSendMessage

PeekMessage

PostMessage

PostQuitMessage

PostThreadMessage

RegisterWindowMessage

ReplyMessage

SendAsyncProc

SendMessage

SendMessageCallback

SendMessageTimeout

SendNotifyMessage

SetMessageExtraInfo

TranslateMessage

WaitMessage

Obsolete Functions

PostAppMessage

SetMessageQueue

WM_USER

  评论这张
 
阅读(5159)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018