İletileri ve İleti Kuyruklarını Kullanma

Aşağıdaki kod örnekleri, Windows iletileri ve ileti kuyruklarıyla ilişkilendirilmiş aşağıdaki görevlerin nasıl gerçekleştirileceklerini gösterir.

İleti Döngüsü Oluşturma

Sistem her iş parçacığı için otomatik olarak bir ileti kuyruğu oluşturmaz. Bunun yerine, sistem yalnızca ileti kuyruğu gerektiren işlemler gerçekleştiren iş parçacıkları için bir ileti kuyruğu oluşturur. İş parçacığı bir veya daha fazla pencere oluşturursa, bir ileti döngüsü sağlanmalıdır; bu ileti döngüsü, iletileri iş parçacığının ileti kuyruğundan alır ve uygun pencere yordamlarına gönderir.

Sistem iletileri bir uygulamadaki tek tek pencerelere yönlendirdiğinden, bir iş parçacığının ileti döngüsünü başlatmadan önce en az bir pencere oluşturması gerekir. Çoğu uygulama, pencere oluşturan tek bir iş parçacığı içerir. Tipik bir uygulama, pencere sınıfını ana penceresi için kaydeder, ana pencereyi oluşturup gösterir ve ardından ileti döngüsünü başlatır; tümü winmainişlevinde.

GetMessage ve DispatchMessage işlevlerini kullanarak bir ileti döngüsü oluşturursunuz. Uygulamanızın kullanıcıdan karakter girişi alması gerekiyorsa, TranslateMessage işlevini döngüye ekleyin. TranslateMessage sanal anahtar iletilerini karakter iletilerine çevirir. Aşağıdaki örnekte, basit bir Windows tabanlı uygulamanın WinMain işlevindeki ileti döngüsü gösterilmektedir.

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; 
} 

Aşağıdaki örnekte, hızlandırıcıları kullanan ve modsuz bir iletişim kutusu görüntüleyen bir iş parçacığı için ileti döngüsü gösterilmektedir. TranslateAccelerator veya IsDialogMessageTRUE döndürdüğünde (iletinin işlendiğini belirtir), TranslateMessage ve DispatchMessage çağrılmaz. Bunun nedeni, TranslateAccelerator ve IsDialogMessage tüm gerekli çeviri ve ileti gönderme işlemlerini gerçekleştirmesidir.

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); 
        }
    } 
} 

İleti Kuyruğu'nu inceleme

Bazen, bir uygulamanın iş parçacığının ileti döngüsünün dışından bir iş parçacığının ileti kuyruğunun içeriğini incelemesi gerekir. Örneğin, bir uygulamanın pencere yordamı uzun bir çizim işlemi gerçekleştiriyorsa, kullanıcının işlemi kesintiye uğratabilmesini isteyebilirsiniz. Uygulamanız fare ve klavye iletileri için işlem sırasında ileti kuyruğunu düzenli aralıklarla incelemediği sürece, işlem tamamlanana kadar kullanıcı girişine yanıt vermez. Bunun nedeni, iş parçacığının ileti döngüsündeki DispatchMessage işlevinin pencere yordamı mesajı işleyene kadar geri dönmemesidir.

Uzun bir işlem sırasında ileti kuyruğu incelemek için PeekMessage işlevini kullanabilirsiniz. PeekMessage, GetMessage işlevine benzer; her ikisi de filtre ölçütleri ile eşleşen bir ileti için ileti kuyruğuna bakın ve ardından iletiyi MSG yapısına kopyalayın. İki işlev arasındaki temel fark, getMessage filtre ölçütlerine uyan bir ileti kuyruğa alınana kadar döndürülmemesidir; PeekMessage ise iletinin kuyrukta olup olmamasına bakılmaksızın hemen döndürülmesidir.

Aşağıdaki örnekte, uzun bir işlem sırasında fare tıklamaları ve klavye girişi için ileti kuyruğu incelemek üzere PeekMessage nasıl kullanılacağı gösterilmektedir.

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; 
        } 
    } 
} 

GetQueueStatusve GetInputStategibi diğer işlevler de iş parçacığının ileti kuyruğunun içeriğini incelemenize olanak sağlar. GetQueueStatus, kuyruktaki ileti türlerini gösteren bir bayrak dizisi döndürür; bunu kullanmak, kuyruğun ileti içerip içermediğini bulmanın en hızlı yoludur. GetInputState, kuyrukta fare veya klavye iletileri varsa TRUE döndürür. Bu işlevlerin her ikisi de kuyruğun işlenmesi gereken iletiler içerip içermediğini belirlemek için kullanılabilir.

İleti Gönderme

PostMessage işlevini kullanarak ileti kuyruğuna ileti gönderebilirsiniz. PostMessage bir iletiyi iş parçacığının ileti kuyruğunun sonuna yerleştirir ve iş parçacığının iletiyi işlemesini beklemeden hemen döndürür. İşlevin parametreleri bir pencere tutamacı, bir ileti tanımlayıcısı ve iki ileti parametresi içerir. Sistem bu parametreleri bir MSG yapısına kopyalar, zaman ve pt yapı üyelerini doldurur ve yapıyı ileti kuyruğuna yerleştirir.

Sistem, hangi iş parçacığı ileti kuyruğunun iletiyi alması gerektiğini belirlemek için PostMessage işleviyle geçirilen pencere tutamacını kullanır. Eğer imaç HWND_TOPMOSTise, sistem, iletiyi tüm üst düzey pencerelerin iş parçacığı ileti kuyruklarına gönderir.

Belirtilmiş bir iş parçacığı ileti kuyruğuna ileti göndermek için PostThreadMessage işlevini kullanabilirsiniz. PostThreadMessage, PostMessageile benzerdir, ancak ilk parametre pencere tutamacı yerine iş parçacığı tanımlayıcısıdır. GetCurrentThreadId işlevini çağırarak iş parçacığı tanımlayıcısını alabilirsiniz.

İleti döngüsünden çıkmak için PostQuitMessage işlevini kullanın. PostQuitMessage, WM_QUIT iletisini o anda yürütülmekte olan iş parçacığına postalar. İş parçacığının ileti döngüsü sonlandırılır ve WM_QUIT iletisiyle karşılaştığında denetimi sisteme döndürür. Bir uygulama genellikle aşağıdaki örnekte gösterildiği gibi WM_DESTROY iletisine yanıt olarak PostQuitMessage çağırır.

case WM_DESTROY: 
 
    // Perform cleanup tasks. 
 
    PostQuitMessage(0); 
    break; 

İleti Gönderme

SendMessage işlevi, doğrudan bir pencere yordamına ileti göndermek için kullanılır. SendMessage bir pencere yordamı çağırır ve bu yordamın iletiyi işlemesini ve bir sonuç döndürmesini bekler.

İleti sistemdeki herhangi bir pencereye gönderilebilir; gereken tek şey bir pencere tutamacıdır. Sistem, hangi pencere prosedürünün iletiyi alması gerektiğini belirlemek için tanıtıcıyı kullanır.

Başka bir iş parçacığından gönderilmiş olabilecek bir iletiyi işlemeden önce, bir pencere yordamının önce InSendMessage işlevini çağırması gerekir. Eğer bu işlev TRUEdöndürürse, pencere prosedürü, iş parçacığının kontrolü devretmesine neden olacak herhangi bir işlevden önce ReplyMessage çağırmalıdır, aşağıdaki örnekte gösterildiği gibi.

case WM_USER + 5: 
    if (InSendMessage()) 
        ReplyMessage(TRUE); 
 
    DialogBox(hInst, "MyDialogBox", hwndMain, (DLGPROC) MyDlgProc); 
    break; 

bir iletişim kutusundaki denetimlere bir dizi ileti gönderilebilir. Bu denetim iletileri denetimlerin görünümünü, davranışını ve içeriğini ayarlar veya denetimler hakkında bilgi alır. Örneğin, CB_ADDSTRING iletisi birleşik giriş kutusuna bir dize ekleyebilir ve BM_SETCHECK iletisi onay kutusunun veya radyo düğmesinin onay durumunu ayarlayabilir.

Denetimin tanımlayıcısını ve denetimi içeren iletişim kutusu penceresinin tutamacını belirterek bir denetime ileti göndermek için SendDlgItemMessage işlevini kullanın. Bir iletişim kutusu prosedüründen alınan aşağıdaki örnek, kombinasyon kutusunun yazı alanındaki bir dizeyi liste kutusunun içine kopyalar. Örnek, birleşik giriş kutusuna SendDlgItemMessage kullanarak CB_ADDSTRING mesajını gönderir.

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. 
    // 
 
}