嗯,本座又来了(咦?为什么说又?)。谁炼了本座推荐的《葵花宝典》[《Windows 核心编程》]的举手。我数数,0,……真是失望啊,一个都没有,还是有人偷偷练了却不说(嘿嘿,某人奸笑中)。

         算了,开始讲讲Windows消息。我们知道Windows的用户界面是由消息驱动的,比如你点击了某个按钮,那么这个按钮的主窗口将接收到一个鼠标消息,然后将鼠标消息翻译成按钮单击消息。

         那么我们怎么知道在哪里处理这些消息呢?不要急,听我慢慢来吹(住手,说好不打脸的……)。

         通常每一个句柄都属于某个窗口注册类,我们用VC的工具Spy++就可以看见,在该类的注册信息里有一个该类的默认处理过程。在RegisterClass 的传入参数里描述的很清楚的。

ATOM RegisterClass( CONST WNDCLASS  * lpWndClass);

typedef struct {
    UINT style;
    WNDPROC lpfnWndProc; 
// 这里就是默认注册的类处理过程
     int  cbClsExtra;
    
int  cbWndExtra;
    HINSTANCE hInstance;
    HICON hIcon;
    HCURSOR hCursor;
    HBRUSH hbrBackground;
    LPCTSTR lpszMenuName;
    LPCTSTR lpszClassName;
} WNDCLASS, 
* PWNDCLASS;

         但是很多时候,我们要的是自己处理该类的动作,比如Button类,我们要自己绘制它的样子,就像开始菜单按钮。
我们在Spy++里可以看见开始菜单按钮的处理过程后面有个描述Subclassed(中文译:子类化)。通常是我们用自己的处理过程替换了默认的处理过程。通常我们用SetWindowLong来改变处理过程。
m_lpfnOldWndProc = (WNDPROC) SetWindowLong(pThis->m_hAttachWnd,GWL_WNDPROC,(LONG)NewDefaultProc);

         我们先来看看一个默认的SDK是怎样建立窗口的。
#include <windows.h> 
// Global variable 
HINSTANCE hinst; 
// Function prototypes. 
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int); 
InitApplication(HINSTANCE); 
InitInstance(HINSTANCE, 
int); 
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); 
// Application entry point. 
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, 
    LPSTR lpCmdLine, 
int nCmdShow) 

    MSG msg; 
 
    
//注册窗口类
    if (!InitApplication(hinstance)) 
        
return FALSE; 
    
//创建窗口
    if (!InitInstance(hinstance, nCmdShow)) 
        
return FALSE; 
 
    BOOL fGotMessage;
    
while ((fGotMessage = GetMessage(&msg, (HWND) NULL, 00)) != 0 && fGotMessage != -1
    

        TranslateMessage(
&msg); 
        DispatchMessage(
&msg); 
    }
 
    
return msg.wParam; 
        UNREFERENCED_PARAMETER(lpCmdLine); 
}
 
 
BOOL InitApplication(HINSTANCE hinstance) 

    WNDCLASSEX wcx; 
 
    
// Fill in the window class structure with parameters 
    // that describe the main window. 
 
    wcx.cbSize 
= sizeof(wcx);          // size of structure 
    wcx.style = CS_HREDRAW | 
        CS_VREDRAW;                    
// redraw if size changes 
    wcx.lpfnWndProc = MainWndProc;     // points to window procedure 
    wcx.cbClsExtra = 0;                // no extra class memory 
    wcx.cbWndExtra = 0;                // no extra window memory 
    wcx.hInstance = hinstance;         // handle to instance 
    wcx.hIcon = LoadIcon(NULL, 
        IDI_APPLICATION);              
// predefined app. icon 
    wcx.hCursor = LoadCursor(NULL, 
        IDC_ARROW);                    
// predefined arrow 
    wcx.hbrBackground = GetStockObject( 
        WHITE_BRUSH);                  
// white background brush 
    wcx.lpszMenuName =  "MainMenu";    // name of menu resource 
    wcx.lpszClassName = "MainWClass";  // name of window class 
    wcx.hIconSm = LoadImage(hinstance, // small class icon 
        MAKEINTRESOURCE(5),
        IMAGE_ICON, 
        GetSystemMetrics(SM_CXSMICON), 
        GetSystemMetrics(SM_CYSMICON), 
        LR_DEFAULTCOLOR); 
 
    
// Register the window class. 
 
    
return RegisterClassEx(&wcx); 
}
 
 
BOOL InitInstance(HINSTANCE hinstance, 
int nCmdShow) 

    HWND hwnd; 
 
    
// Save the application-instance handle. 
 
    hinst 
= hinstance; 
 
    
// Create the main window. 
 
    hwnd 
= CreateWindow( 
        
"MainWClass",        // name of window class 
        "Sample",            // title-bar string 
        WS_OVERLAPPEDWINDOW, // top-level window 
        CW_USEDEFAULT,       // default horizontal position 
        CW_USEDEFAULT,       // default vertical position 
        CW_USEDEFAULT,       // default width 
        CW_USEDEFAULT,       // default height 
        (HWND) NULL,         // no owner window 
        (HMENU) NULL,        // use class menu 
        hinstance,           // handle to application instance 
        (LPVOID) NULL);      // no window-creation data 
 
    
if (!hwnd) 
        
return FALSE; 
 
    
// Show the window and send a WM_PAINT message to the window 
    // procedure. 
 
    ShowWindow(hwnd, nCmdShow); 
    UpdateWindow(hwnd); 
    
return TRUE; 
 
}

 
LRESULT CALLBACK MainWndProc(
    HWND hwnd,        
// handle to window
    UINT uMsg,        // message identifier
    WPARAM wParam,    // first message parameter
    LPARAM lParam)    // second message parameter

    
    
//这里响应窗口消息
    switch (uMsg) 
    

        
case WM_CREATE: 
            
// Initialize the window. 
            return 0
 
        
case WM_PAINT: 
            
// Paint the window's client area. 
            return 0
 
        
case WM_SIZE: 
            
// Set the size and position of the window. 
            return 0
 
        
case WM_DESTROY: 
            
// Clean up window-specific data objects. 
            return 0
 
        
// 
        // Process other messages. 
        // 
 
        
default
            
return DefWindowProc(hwnd, uMsg, wParam, lParam); 
    }
 
    
return 0
}
 

        我们看到通常建立了窗口后,还要建立消息循环才能响应消息。
         我们来总结一下如何创建窗口的几中方式(对话框是一种特殊的窗口):
            使用Windows默认提供的类创建窗口(CreateWindow[Ex]、CreateDialog[Ex]等) 
            定义处理过程的窗口(RegisterClass后再CreateWindow) 
            子类化处理窗口(CreateWindow后SubClassWindow) 

  • int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, 
        LPSTR lpCmdLine, 
    int nCmdShow) 

        MSG msg; 
     
        
    if (!InitApplication(hinstance)) 
            
    return FALSE; 
     
        
    if (!InitInstance(hinstance, nCmdShow)) 
            
    return FALSE; 
        
    //这里建立消息循环
        BOOL fGotMessage;
        
    while ((fGotMessage = GetMessage(&msg, (HWND) NULL, 00)) != 0 && fGotMessage != -1
        { 
            TranslateMessage(
    &msg); 
            DispatchMessage(
    &msg); 
        } 
        
    return msg.wParam; 
      
         
          这样窗口就能响应消息了,可以等待Windows的消息通知,我们的消息通知,和其他用户的消息通知。至于怎么通知下次再说喽。(某人从背后抽出一把剑,然后大喝一声:御剑飞仙,然后往下一跳。不一会儿传来凄厉的惨叫~ 。小朋友切勿模仿)
  • posted on 2006-09-29 11:28 孤独的夜 阅读(873) 评论(0)  编辑 收藏 引用 所属分类: My VC Study
    只有注册用户登录后才能发表评论。