091021(星期三)MFC线程消息循环4,Using Messages and Message Queues的msdn描述

 

Msdn描述

Using Messages and Message Queues

--------------------------------------------------------------------------------

Creating a Message Loop

The system automatically creates a message queue for each thread系统自动给每个线程创建消息队列. If the thread creates one or more windows, a message loop must be provided如果有窗口存在,程序员需要提供一个“消息循环”; this message loop retrieves messages from the thread's message queue and dispatches them to the appropriate window procedures分发到合适的窗口过程函数.

Because the system directs messages to individual windows in an application系统派发消息的目的对象是窗口, a thread must create at least one window before starting its message loop. Most applications contain a single thread that creates windows. A typical application registers the window class for its main window, creates and shows the main window, and then starts its message loop — all in the WinMain function典型的win32程序实现.

You create a message loop by using the GetMessage and DispatchMessage functions一个消息循环其实很简单,循环的GetDispatchMessage就可以了. If your application must obtain character input from the user, include the TranslateMessage function in the loop. TranslateMessage translates virtual-key messages into character messages. The following example shows the message loop in the WinMain function of a simple Windows-based application.

 

HINSTANCE hinst;

HWND hwndMain;

 

int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

    LPSTR lpszCmdLine, int nCmdShow)

{

    MSG msg;

    BOOL bRet;

    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( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)

    {

        if (bRet == -1)

        {

            // handle the error and possibly exit 接口调用失败

        }

        else

        {

            TranslateMessage(&msg);

            DispatchMessage(&msg);

        }

    }

 

    // Return the exit code to the system.

     return msg.wParam;

}

The following example shows a message loop for a thread that uses accelerators and displays a modeless dialog box. When TranslateAccelerator or IsDialogMessage returns TRUE (indicating that the message has been processed), TranslateMessage and DispatchMessage are not called. The reason for this is that TranslateAccelerator and IsDialogMessage perform all necessary translating and dispatching of messages这两个函数已经处理/分发了消息.

 

HWND hwndMain;

HWND hwndDlgModeless = NULL;

MSG msg;

BOOL bRet;

HACCEL haccel;

//

// Perform initialization and create a main window.

//

 while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)

{

    if (bRet == -1)

    {

        // handle the error and possibly exit

    }

    else

    {

        if (

hwndDlgModeless == (HWND) NULL

||  !IsDialogMessage(hwndDlgModeless, &msg)

&& !TranslateAccelerator(hwndMain, haccel, &msg)

)

        {

            TranslateMessage(&msg);

            DispatchMessage(&msg);

        }

    }

}

Examining a Message Queue

Occasionally, an application needs to examine the contents of a thread's message queue from outside the thread's message loop. For example, if an application's window procedure performs a lengthy drawing operation, you may want the user to be able to interrupt the operation. Unless your application periodically examines the message queue during the operation for mouse and keyboard messages, it will not respond to user input until after the operation has completed. The reason for this is that the DispatchMessage function in the thread's message loop does not return until the window procedure finishes processing a message.

 

You can use the PeekMessage function to examine a message queue during a lengthy operation. PeekMessage is similar to the GetMessage function; both check a message queue for a message that matches the filter criteria and then copy the message to an MSG structure. The main difference between the two functions is that GetMessage does not return until a message matching the filter criteria is placed in the queue, whereas PeekMessage returns immediately regardless of whether a message is in the queue.

 

The following example shows how to use PeekMessage to examine a message queue for mouse clicks and keyboard input during a lengthy operation.

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;

        }

    }

}

Other functions, including GetQueueStatus and GetInputState, also allow you to examine the contents of a thread's message queue. GetQueueStatus returns an array of flags that indicates the types of messages in the queue; using it is the fastest way to discover whether the queue contains any messages. GetInputState returns TRUE if the queue contains mouse or keyboard messages. Both of these functions can be used to determine whether the queue contains messages that need to be processed.

 

Posting a Message

You can post a message to a message queue by using the PostMessage function使用PostMessage向消息队列加消息,从下面SendMessage的说明可以堪称,SendMessage的消息不加入队列. PostMessage places a message at the end of a thread's message queue 放在队列的最尾部and returns immediately, without waiting for the thread to process the message. The function's parameters include a window handle, a message identifier, and two message parameters. The system copies these parameters to an MSG structure系统拷贝MSG结构, fills the time and pt 填写时刻和鼠标位置members of the structure, and places the structure in the message queue.

The system uses the window handle passed with the PostMessage function to determine which thread message queue使用hWnd参数确定目标消息队列 should receive the message. If the handle is HWND_TOPMOST, the system posts the message to the thread message queues of all top-level windows.

You can use the PostThreadMessage function to post a message to a specific thread给指定线程的消息循环发消息 message queue. PostThreadMessage is similar to PostMessage, except the first parameter is a thread identifier rather than a window handle. You can retrieve the thread identifier by calling the GetCurrentThreadId function.

Use the PostQuitMessage function to exit a message loop. PostQuitMessage posts the WM_QUIT message to the currently executing thread. The thread's message loop terminates and returns control to the system when it encounters the WM_QUIT message. An application usually calls PostQuitMessage in response to the WM_DESTROY message收到销毁消息时PostQuitMessage以退出消息循环, as shown in the following example.

case WM_DESTROY:

     // Perform cleanup tasks.

     PostQuitMessage(0);

    break;

Sending a Message

The SendMessage function is used to send a message directly直接给窗口函数,而不入消息队列!! to a window procedure. SendMessage calls a window procedure and waits for that procedure to process the message and return a result等待窗口处理函数的执行和返回.

A message can be sent to any window in the system消息发给任何窗口,仅仅指定hWnd即可; all that is required is a window handle. The system uses the handle to determine which window procedure should receive the message.

Before processing a message that may have been sent from another thread, a window procedure should first call the InSendMessage function. If this function returns TRUE, the window procedure should call ReplyMessage before any function that causes the thread to yield control, as shown in the following example.

 

case WM_USER + 5:

    if (InSendMessage())

        ReplyMessage(TRUE);

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

    break;

A number of messages can be sent to controls in a dialog box这是重点. These control messages set the appearance, behavior, and content of controls or retrieve information about controls. For example, the CB_ADDSTRING message这个消息是否为“控件消息”是系统鉴定的吗? can add a string to a combo box, and the BM_SETCHECK message can set the check state of a check box or radio button.

 

Use the SendDlgItemMessage function to send a message to a control, specifying the identifier of the control and the handle of the dialog box window that contains the control依据控件父窗口的hWnd和控件自身ID来确定它. The following example, taken from a dialog box procedure, copies a string from a combo box's edit control into its list box. The example uses SendDlgItemMessage to send a CB_ADDSTRING message to the combo box.

 

以下代码在Dlg的窗口处理函数之中:

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)); //IDD_COMBO控件收到CB_ADDSTRING消息后,将pszMem中的字符串加到自己的list中,在自定义窗口中就可以利用给控件发生消息来控制它了。

                    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.

    //

 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值