程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> 在非主線程中創建窗口

在非主線程中創建窗口

編輯:.NET實例教程

//========================================================================
//TITLE:
//    在非主線程中創建窗口
//AUTHOR:
//    norains
//DATE:
//    Saturday  29-December-2007
//Environment:
//    VS2005 + SDK-WINCE5.0-MIPSII  
//========================================================================

   很多朋友都會有過這樣的經歷,為什麼在主線程中創建窗口且窗口工作很正常,但一移到非主線程(有的朋友喜歡叫它為工作線程),卻無法正常工作.本文就這個問題和各位探討,可能無法做到盡善盡美,但能拋磚引玉也算是欣慰了.
  
   在主線程中創建一個能夠正常工作的窗口,估計地球人都知道.
  
   這是一段工作正常的代碼: 




#include "Windows.h"

HWND g_hWnd = NULL;
HINSTANCE g_hInst;


LRESULT WndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
{
    return DefWindowProc(hWnd,wMsg,wParam,lParam);
}

void CreateWnd(void)
{    

    WNDCLASS wc = {0};
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = $False$

: #000000">0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = g_hInst;
    wc.hIcon         = NULL; 
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = TEXT("SimpleWindow");

    RegisterClass(&wc);

    g_hWnd = CreateWindowEx(0,
                TEXT("SimpleWindow"),
                TEXT("SimpleWindow"),
                WS_VISIBLE,
                0,
                0,
                200,
                200,
                NULL, 
                NULL, 
                g_hInst, 
                0);
}



int WINAPI WinMain(    HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPTSTR    lpCmdLine,
                    int       nCmdShow)
{
     // TODO: Place code here.

an>    
    g_hInst = hInstance;

    CreateWnd();

    //The message loop    
    MSG msg;
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}
    如果我們創建一個線程,然後在這個線程中創建窗口,看看帶給我們的是什麼:


 
#include "Windows.h"

HWND g_hWnd = NULL;
HINSTANCE g_hInst;


LRESULT WndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
{
    return DefWindowProc(hWnd,wMsg,wParam,lParam);
}

void CreateWnd(void</span>)
{    
WNDCLASS wc = {0};
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = g_hInst;
    wc.hIcon         = NULL; 
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = TEXT("SimpleWindow");

   &nbsp;RegisterClass(&wc);

    g_hWnd = CreateWindowEx(0,
                TEXT("SimpleWindow"),
                TEXT("SimpleWindow"),
                WS_VISIBLE,
                0,
                0,
                200,
                200,
                NULL, 
                NULL, 
                g_hInst, 
                0);
}


DWord CreateThread(PVOID pArg)
{
  &nbsp; CreateWnd();
    return 0;
}


int WINAPI WinMain(    HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPTSTR    lpCmdLine,
                    int       nCmdShow)
{
     // TODO: Place code here.
    
    g_hInst = hInstance;

    HANDLE hThrd = CreateThread(NULL,0,CreateThread,NULL,0,NULL);
    CloseHandle(hThrd);

    //The message loop    
    MSG msg;
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}


    我們似乎什麼都沒見到,只是窗口一閃,啥都沒了.因為g_hWnd為全局變量,我們的理智告訴我們,在主線程沒有退出之前,g_hWnd是不會銷毀的.而用斷點調試,將會發現在WndProc函數中只能接收WM_CREATE及以後一些消息,之後的再也收不到了,特別是WM_PAINT似乎就憑空消失了!那麼,代碼什麼都沒變更,只是移動到了分線程中,為何會出現這個問題呢?
   
    一切似乎很簡單,在MSDN中我們找到了答案(原文見:http://support.microsoft.com/kb/90975/en-us):
   
    In a multithreaded application, any thread can call the CreateWindow() API to create a window. There are no restrictions on which thread(s) can create Windows.

It is important to note that the message loop and window procedure for the window must be in the thread that created the window. If a different thread creates the window, the window won''t get messages from DispatchMessage(), but will get messages from other sources. Therefore, the window will appear but won''t show activation or repaint, cannot be moved, won''t receive mouse messages, and so on.

    該段話大意是:窗口在任何線程中都可以創建,但消息循環必須要和創建窗口在同一線程,否則窗口將無法從DispatchMessage()獲取任何消息!
   
    原來如此,最重要是這麼一句:It is important to note that the message loop and window procedure for the window must be in the thread that created the window.
   
    好吧,那麼我們在支線程中放置消息循環代碼,看看是什麼結果吧:




#include "Windows.h"

HWND g_hWnd =1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13]

"> NULL;
HINSTANCE g_hInst;


LRESULT WndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
{
    return DefWindowProc(hWnd,wMsg,wParam,lParam);
}

void CreateWnd(void)
{    

    WNDCLASS wc = {0};
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = g_hInst;
    wc.hIcon         = NULL; 
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);
  &nbsp; wc.lpszMenuName  = NULL;
    wc.lpszClassName = TEXT("SimpleWindow");

    RegisterClass(&wc);

    g_hWnd = CreateWindowEx(0,
                TEXT("SimpleWindow"),
                TEXT("SimpleWindow"),
                WS_VISIBLE,
                0,
                0,
                200,
                200,
                NULL,
                NULL, 
                g_hInst, 
                0);
}


DWord CreateThread(PVOID pArg)
{
    CreateWnd();

    //The message loop    
    MSG msg;
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }


    return 0;
}


int WINAPI WinMain(    HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPTSTR    lpCmdLine,
            &nbsp;       int       nCmdShow)
{
     // TODO: Place code here.
    
    g_hInst = hInstance;

    HANDLE hThrd = CreateThread(NULL,0,CreateThread,NULL,0,NULL);
    CloseHandle(hThrd);


    MSG msg;
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}
    一切正常,如同在主線程創建一樣!
   
    當然了,還有點需要注意的,在這個例子中,由於消息循環在主線程和分線程都分別存在,如果在WndProc()調用PostQuitMessage(),那麼退出的也僅僅是分線程,而主線程還是會不停地在等待消息,從而導致程序無法正常退出.不過倒不用過分擔心,和這個示例代碼不同,在實際代碼編寫中,在主線程往往都會創建主窗口,而在這個主窗口消息處理函數調用PostQuitMessage()則完全可以讓主線程正常退出.
   
    事實告訴我們,非主線程創建窗口也能工作正常,

只要我們注意一點:消息循環必須要和創建窗口在同一線程!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved