創建Windows窗體 : WinMain() 與 WndProc()


#include <windows.h>
#include <mmsystem.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); //聲名消息處理函數(處理windows和接收windows消息)
//hInstance:系統為窗口分配的實例號,2和3忘了.4是顯示方式
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow)
{
    static TCHAR szAppName[] = TEXT ("HelloWin") ; //窗體名
    HWND hwnd;//句柄
    MSG msg;//消息體
    WNDCLASS wndclass;//這義一個窗體類實例
    //設置窗體參數
    wndclass.style = CS_HREDRAW | CS_VREDRAW ; //樣式
    wndclass.cbClsExtra   = 0 ;
    wndclass.cbWndExtra   = 0 ;
    wndclass.hInstance = hInstance ;//窗體實例名,由windows自動分發
    wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;//顯示上面的圖標titlte
    wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;//窗口光標
    wndclass.hbrBackground= (HBRUSH) GetStockObject (WHITE_BRUSH) ;//背景刷
    wndclass.lpszMenuName=NULL;
    wndclass.lpfnWndProc=WndProc;//設置窗體接收windws消息函數
    wndclass.lpszClassName= szAppName;//窗體類名
    if (!RegisterClass (&wndclass))//注冊窗體類
    {
        MessageBox ( NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ;
        return 0 ;
    };
    //創建一個窗體。已分配內存。返回一個窗體句柄
    hwnd = CreateWindow( szAppName,      // window class name
        TEXT ("The Hello Program"),   // window caption
        WS_OVERLAPPEDWINDOW, // window style
        CW_USEDEFAULT,// initial x position
        CW_USEDEFAULT,// initial y position
        CW_USEDEFAULT,// initial x size
        CW_USEDEFAULT,// initial y size
        NULL, // parent window handle
        NULL, // window menu handle
        hInstance, // program instance handle
        NULL) ;
    ShowWindow (hwnd,iCmdShow);//顯示窗口
    UpdateWindow (hwnd) ;//更新窗體
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage (&msg);//翻譯消息並發送到windows消息隊列
        DispatchMessage (&msg) ;//接收信息
    }
    return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)//消息的處理程序
{
    HDC         hdc ;
    PAINTSTRUCT ps ;
    RECT        rect ;

    switch (message)
    {

    case WM_CREATE:
        return 0 ;

    case   WM_PAINT:
        hdc = BeginPaint (hwnd, &ps) ;
        TextOut(hdc,0,0,"Hello",strlen("Hello"));
        EndPaint (hwnd, &ps) ;
        return 0 ;

    case   WM_DESTROY:
        PostQuitMessage (0) ;
        return 0 ;
    }

    return DefWindowProc (hwnd, message, wParam, lParam) ;
}

 

// GT_HelloWorldWin32.cpp
// compile with: /D_UNICODE /DUNICODE /DWIN32 /D_WINDOWS /c

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>

// Global variables

// The main window class name.
static TCHAR szWindowClass[] = _T("win32app");

// The string that appears in the application's title bar.
static TCHAR szTitle[] = _T("Win32 Guided Tour Application");

HINSTANCE hInst;

// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nCmdShow)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));

    if (!RegisterClassEx(&wcex))
    {
        MessageBox(NULL,
            _T("Call to RegisterClassEx failed!"),
            _T("Win32 Guided Tour"),
            NULL);

        return 1;
    }

    hInst = hInstance; // Store instance handle in our global variable

    // The parameters to CreateWindow explained:
    // szWindowClass: the name of the application
    // szTitle: the text that appears in the title bar
    // WS_OVERLAPPEDWINDOW: the type of window to create
    // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
    // 500, 100: initial size (width, length)
    // NULL: the parent of this window
    // NULL: this application does not have a menu bar
    // hInstance: the first parameter from WinMain
    // NULL: not used in this application
    HWND hWnd = CreateWindow(
        szWindowClass,
        szTitle,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        500, 100,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    if (!hWnd)
    {
        MessageBox(NULL,
            _T("Call to CreateWindow failed!"),
            _T("Win32 Guided Tour"),
            NULL);

        return 1;
    }

    // The parameters to ShowWindow explained:
    // hWnd: the value returned from CreateWindow
    // nCmdShow: the fourth parameter from WinMain
    ShowWindow(hWnd,
        nCmdShow);
    UpdateWindow(hWnd);

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

    return (int) msg.wParam;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR greeting[] = _T("Hello, World!");

    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);

        // Here your application is laid out.
        // For this introduction, we just print out "Hello, World!"
        // in the top left corner.
        TextOut(hdc,
            5, 5,
            greeting, _tcslen(greeting));
        // End application-specific layout section.

        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
        break;
    }

    return 0;
}

 

/* 

CreateWindow.cpp 


Tutorials and source code: www.danielloran.com

*/

#include <windows.h>

const char    MAIN_WINDOW_TITLE[] = "© danielloran.com",
            MAIN_WINDOW_CLASS_NAME[] = "myWindowClass";

const int    MAIN_WINDOW_WIDTH  = 340,
            MAIN_WINDOW_HEIGHT = 240;


LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_CLOSE:
            DestroyWindow(hwnd);
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX w;
    HWND hwnd;
    MSG msg;

    //Register window class
    w.cbSize = sizeof(WNDCLASSEX);
    w.style = 0;
    w.lpfnWndProc = WndProc;
    w.cbClsExtra = 0;
    w.cbWndExtra = 0;
    w.hInstance = hInstance;
    w.hIcon = LoadIcon(NULL, IDI_APPLICATION); // large icon (Alt+Tab)
    w.hCursor = LoadCursor(NULL, IDC_ARROW);
    w.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    w.lpszMenuName = NULL;
    w.lpszClassName = MAIN_WINDOW_CLASS_NAME;
    w.hIconSm = LoadIcon(NULL, IDI_APPLICATION); // small icon (title bar)

    if(!RegisterClassEx(&w)){
        MessageBox(NULL, "RegisterClassEx() failed", "System error",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Create window
    hwnd = CreateWindowEx(
        NULL,
        MAIN_WINDOW_CLASS_NAME,
        MAIN_WINDOW_TITLE,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 
        MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT,
        NULL, NULL, hInstance, NULL);

    if(hwnd == NULL){
        MessageBox(NULL, "CreateWindowEx() failed", "System error", 
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Show window
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Message loop
    while(GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

If you already have some experience with developing applications for Windows, the source code above should be familiar to you.

There are only 2 standard functions involved: WinMain() and WndProc().

The WinMain() function includes window definition and the main message loop.

The WndProc() function processing the messages as long as application is running.

As you probably already know Windows operating system is working with messages in order to make things happen.
So to keep it simple, if you want something to happen you send a message.
After the message has been received it is processed according to the logic you specify.

In this example only a very limited number of messages is being processed by the WndProc() function.
Those messages are: WM_CLOSE and WM_DESTROY.
 
The WM_CLOSE message is sent when user closes the window.
When it is received the window is destroyed by calling the DestroyWindow(hwnd) method.
The DestroyWindow() method also generates a WM_DESTROY message.
 
The WM_DESTROY message is causing the application to exit.
This is achieved by calling the PostQuitMessage(0) method.
 
Inside the WinMain() function we use WNDCLASSEX to specify the kind of window we want to create.
In this project we use the extended window class. The hwnd is a handle to the window and msg is the message we are going to send.
We then register the window class and set all the desired parameters inclusive the window icon, background color etc
(please advise the Microsoft MSDN documentation for additional information about this subject).
 
We check if the window was registered succesfully, if not we show an error message in the MessageBox.
After the window was registered we create it by passing the title, widht and height among other parameters.
 
In the next step we show and update the window.
Finally we enter the message loop which is constantly checking if there are messages in the queue by calling the GetMessage() method.
If yes those are translated and dispatched so they could be processed by the WndProc() function.
 
 
//**************************************
//INCLUDE files for :A simple window
//**************************************
#include <windows.h>
//**************************************
// Name: A simple window
// Description:It's a simple blank window that you can resize.
// By: kenshin
//
#include <windows.h>
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
char szClassName[ ] = "WindowsApp";
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
HWND hwnd;
MSG messages;
WNDCLASSEX wincl;
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; 
wincl.style = CS_DBLCLKS;
wincl.cbSize = sizeof (WNDCLASSEX);
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0; 
wincl.cbWndExtra = 0;
 
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
if (!RegisterClassEx (&wincl))
return 0;
 
hwnd = CreateWindowEx (
0, 
szClassName,
"Windows App", 
WS_OVERLAPPEDWINDOW, 
CW_USEDEFAULT,
CW_USEDEFAULT, 
544,
375,
HWND_DESKTOP,
NULL,
hThisInstance,
NULL
);
ShowWindow (hwnd, nFunsterStil);
while (GetMessage (&messages, NULL, 0, 0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
 
return messages.wParam;
}
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage (0); 
break;
default: 
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}

 http://www.cppblog.com/Lee7/archive/2008/11/07/66226.html

Windows SDK筆記()Windows程序基本結構

一、概述

Windows程序具有相對固定的結構,對編寫者而言,不需要書寫整個過程,大部分過程由系統完成。
程序中只要按一定的格式填寫系統留給客戶的那一小部分。
所需要完成的有:
窗口類的定義、窗口的建立、消息函數的書寫、消息循環。

 

二、消息處理函數

Windows程序是事件驅動的,對於一個窗口,它的大部分例行維護是由系統維護的。沒個窗口都有一個消息處理函數。
在消息處理函數中,對傳入的消息進行處理。系統內還有它自己的缺省消息處理函數。

客戶寫一個消息處理函數,在窗口建立前,將消息處理函數與窗口關聯。這樣,每當有消息產生時,就會去調用這個消息處理函數。
通常情況下,客戶都不會處理全部的消息,而是只處理自己感興趣的消息,其他的,則送回到系統的缺省消息處理函數中去。

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{

     switch (message)

     {

     case ...

         ...

     case ...

         ...

 

     }

     return DefWindowProc (hwnd, message, wParam, lParam) ;

}

 

三、窗口的建立 

客戶需要自己建立窗口,建立后會得到系統返回的窗口句柄(HWND),后繼的針對窗口的操作都針對句柄進行。
1.注冊窗口類
建立窗口前,需要制定好這個窗口的相關屬性,最主要的就是將自己定義的消息處理函數與窗口關聯,其他的屬性還包括:菜單、圖標等等。
這個屬性指定步驟是通過指定"窗口類"來完成的。
對於自己建立的窗口,這個"窗口類"需要自己制定,也即自己填充一個WNDCLASS結構,然后向系統注冊。
對於一些特殊窗口,如按鈕等控件,他們的行為是系統制定好了的,所以不需要自己注冊,直接使用對應的“窗口類”名稱就行了。
2.建立窗口
建立窗口時,注冊的"窗口類"名稱作為參數傳入。
這樣,當有針對該窗口的消息時,將調用“窗口類”中指定的消息處理函數,在其中得到處理。 

四、消息循環

系統會將針對這個程序的消息依次放到程序的“消息隊列”中,由程序自己依次取出消息,在分發到對應的窗口中去。
因此,建立窗口后,將進入一個循環。
在循環中,取出消息、派發消息,循環往復,直到取得的消息是退出消息。
循環退出后,程序即結束。

#include "stdafx.h"

#include <windows.h>

 

//一、消息處理函數

//參數:窗口句柄,消息,消息參數,消息參數

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{

     //處理感興趣的消息

     switch (message)

     {

     case WM_DESTROY:

         //當用戶關閉窗口,窗口銷毀,程序需結束,發退出消息,以退出消息循環

         PostQuitMessage (0) ;

         return 0 ;

     }

     //其他消息交給由系統提供的缺省處理函數

     return ::DefWindowProc (hwnd, message, wParam, lParam) ;

}

 

 

二、應用程序主函數

//參數:實例句柄、前一個實例的句柄、命令行參數、窗口顯示方式

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

                    PSTR szCmdLine, int iCmdShow)

{

     //1.注冊窗口類

     static TCHAR szAppName[] = TEXT ("HelloWin") ;     //窗口類名稱

     //定制"窗口類"結構

     WNDCLASS     wndclass ;

     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;

     wndclass.lpfnWndProc   = WndProc ;                 //關聯消息處理函數

     wndclass.cbClsExtra    = 0 ;

     wndclass.cbWndExtra    = 0 ;

     wndclass.hInstance     = hInstance ;           //實例句柄

     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;  //圖標

     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;      //光標

     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);  //畫刷

     wndclass.lpszMenuName  = NULL ;

     wndclass.lpszClassName = szAppName;                 //類名稱

     //注冊

     if (!RegisterClass (&wndclass))

     {

         MessageBox (NULL, TEXT ("RegisterClass Fail!"),

              szAppName, MB_ICONERROR) ;

         return 0 ;

     }

    

     //建立窗口

     HWND hwnd ;

     hwnd = CreateWindow (szAppName,      //窗口類名稱

         TEXT ("The Hello Program"),      //窗口標題

         WS_OVERLAPPEDWINDOW,        //窗口風格

         CW_USEDEFAULT,

         CW_USEDEFAULT,

         CW_USEDEFAULT,

         CW_USEDEFAULT,

         NULL,

         NULL,

         hInstance,             //實例句柄

         NULL);

    

     ShowWindow (hwnd, iCmdShow) ;

     UpdateWindow (hwnd) ;

    

     //消息循環

     MSG          msg ;

     while (GetMessage (&msg, NULL, 0, 0)) //從消息隊列中取消息

     {

         TranslateMessage (&msg) ;        //轉換消息

         DispatchMessage (&msg) ;         //派發消息

     }

     return msg.wParam ;

}

 

 

Windows SDK筆記():在窗口上建立控件

一、概述

控件是子窗口,它們是系統已經定義好的窗口類,因此不需要注冊、
也不需要寫消息處理函數。
在主窗口得到WM_CREATE消息時,建立子窗口即可。


二、實例

//參數:窗口句柄,消息,消息參數,消息參數

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{

     //處理感興趣的消息

     switch (message)

     {

     case WM_CREATE:

         CreateWindow(TEXT("BUTTON"),         //控件"類名稱"

                   TEXT("按鈕(&A)"),

                   WS_CHILD | WS_VISIBLE |BS_PUSHBUTTON,

                   10,

                   10,

                   100,

                   100,

                   hwnd,

                   (HMENU)1000,           //控件ID

                   ((LPCREATESTRUCT) lParam)->hInstance, //實例句柄

                   NULL);

 

         return 0;

     case WM_DESTROY:

         //當用戶關閉窗口,窗口銷毀,程序需結束,發退出消息,以退出消息循環

         PostQuitMessage (0) ;

         return 0 ;

     }

     //其他消息交給由系統提供的缺省處理函數

     return ::DefWindowProc (hwnd, message, wParam, lParam) ;

}

 

三、關於WM_CREATE消息

WM_CREATE 的lParam參數將會傳入一個建立時信息結構指針(LPCREATESTRUCT)。
結構中包含了一些有用信息(窗口建立時的參數)。

typedef struct tagCREATESTRUCT {

    LPVOID    lpCreateParams;

    HINSTANCE hInstance;         //實例句柄

    HMENU     hMenu;            

    HWND      hwndParent;

    int       cy;

    int       cx;

    int       y;

    int       x;

    LONG      style;

    LPCTSTR   lpszName;

    LPCTSTR   lpszClass;

    DWORD     dwExStyle;

} CREATESTRUCT, *LPCREATESTRUCT;

 

四、控件與父窗口的協作

1.控件上發生動作時,將向父窗口發送通知消息WM_COMMAND。
WM_COMMAND:
HIWORD(wParam):通知碼(notification code)
LOWORD(wParam):控件ID
(HWND)lParam: 控件句柄

除了WM_COMMAND外,每種控件還有可能有其他的通知消息(如WM_DRAWITEM)。

2.父窗口需要控制控件時,向控件發控件消息。
事先應記錄下控件句柄,或由ID獲取控件句柄

3.備注:
各種控件的通知消碼和控制消息可由
MSDN-> Platform SDK-> User Interface Services->Windows User Interface->Controls
查得。

五、控件"類名稱"

1.標准控件
BUTTON :按鈕
COMBOBOX :復合框 
EDIT :編輯 
LISTBOX :列表 
RichEdit :Rich Edit version 1.0
RICHEDIT_CLASS :Rich Edit version 2.0
SCROLLBAR :滾動條
STATIC :靜態

2.外殼附帶的公用控件
注:建立前需要用InitCommonControlsEx進行初始化

INITCOMMONCONTROLSEX icex;// Ensure that the common control DLL is loaded.

icex.dwSize = sizeof(INITCOMMONCONTROLSEX);

icex.dwICC  = ICC_LISTVIEW_CLASSES;

InitCommonControlsEx(&icex);

 

HWND hWndListView =CreateWindowEx(0,WC_LISTVIEW,  //WC_LISTVIEW不需要加引號

     TEXT(""),

     WS_CHILD | WS_VISIBLE|WS_BORDER | LVS_ICON | LVS_EDITLABELS | WS_EX_CLIENTEDGE ,

     10,

     10,

     100,

     100,

     hwnd,

     (HMENU)1000,       //控件ID

     ((LPCREATESTRUCT) lParam)->hInstance, //實例句柄

     NULL);

}

 

ANIMATE_CLASS

DATETIMEPICK_CLASS

HOTKEY_CLASS

MONTHCAL_CLASS

PROGRESS_CLASS

REBARCLASSNAME

STATUSCLASSNAME

TOOLBARCLASSNAME

TOOLTIPS_CLASS

TRACKBAR_CLASS

UPDOWN_CLASS

WC_COMBOBOXEX

WC_HEADER

WC_IPADDRESS

WC_LISTVIEW

WC_PAGESCROLLER

WC_TABCONTROL

WC_TREEVIEW

3.特殊窗口


MDIClient :MDI客戶區窗口
ComboLBox :The class for the list box contained in a combo box. 
DDEMLEvent :Windows NT/2000: The class for DDEML events. 
Message :Windows 2000: The class for a message-only window. 
#32768 :The class for a menu. 
#32769 :The class for the desktop window. 
#32770 :The class for a dialog box. 
#32771 :The class for the task switch window. 
#32772 :Windows NT/2000: The class for icon titles.

Windows SDK筆記():定制控件消息處理函數

一、概述
控件的消息處理函數是由系統定義好了的,通常情況下,不需要自己提供。
但當需要對控件進行特殊控制時,可以提供一個消息處理函數,替換原來的消息處理函數。
自己的處理完成后,再調用控件的缺省消息處理。


二、相關函數
1.窗口類的屬性可以通過GetWindowLong和SetWindowLong進行讀取和設置

LONG GetWindowLong(

     HWND hWnd,  // handle to window

     int nIndex  // offset of value to retrieve

     );

    

LONG SetWindowLong(

  HWND hWnd,       // handle to window

  int nIndex,      // offset of value to set

  LONG dwNewLong   // new value

);

 

可以返回或設置以下內容:
nIndex值 意義
GWL_EXSTYLE 擴展風格
GWL_STYLE 風格
GWL_WNDPROC 消息處理函數
GWL_HINSTANCE 實例
GWL_ID 窗口ID
GWL_USERDATA 用戶數據
DWL_DLGPROC 對話框消息處理函數
DWL_MSGRESULT
DWL_USER


所以使用

OldMsgProc = (WNDPROC)SetWindowLong (hControlWnd, GWL_WNDPROC, (LONG)MyMsgProc);

將控件消息處理函數替換成MyMsgProc,原處理函數被OldMsgProc記錄。

2.調用消息處理函數

LRESULT CallWindowProc(

     WNDPROC lpPrevWndFunc,  // pointer to previous procedure

     HWND hWnd,              // handle to window

     UINT Msg,               // message

     WPARAM wParam,          // first message parameter

     LPARAM lParam           // second message parameter

);

 

三、示例
1.提供新處理函數

//記錄原來處理函數的全局變量

WNDPROC OldMsgProc;

 

//新消息處理函數

LRESULT MyMsgProc(HWND hwnd,UINT message, WPARAM wParam, LPARAM lParam)

{

     switch(message)

     {

     case WM_LBUTTONDOWN:

         ::MessageBox(NULL,"click!","",MB_OK);

     }

     //調用控件原來的消息處理函數

     return CallWindowProc(OldMsgProc,hwnd,message,wParam,lParam);

}

 


2.建立窗口后,更改消息處理函數

case WM_CREATE:

{

     HWND hControlWnd = CreateWindowEx(0,"BUTTON",

         TEXT("按鈕(&A)"),

         WS_CHILD | WS_VISIBLE|BS_PUSHBUTTON,

         10,

         10,

         100,

         100,

         hwnd,

         (HMENU)1000,  //控件ID

         ((LPCREATESTRUCT) lParam)->hInstance, //實例句柄

         NULL);

 

     //嵌入新的消息處理函數

     OldMsgProc = (WNDPROC) SetWindowLong (hControlWnd, GWL_WNDPROC, (LONG)MyMsgProc);

}

return 0;

 

 

Windows SDK筆記():模式對話框

一、概述

對話框是一種特殊的窗口,它依據對話框模板資源而建立。
它與一般的窗口有些不同,很多過程由系統完成了,雖然用戶還是要提供一個消息處理函數,但在此消息處理函數中,不需要將不關心的消息交由缺省消息處理函數。
實際上,調用缺省處理的過程又系統完成。

二、對話框消息處理函數

對話框也需要用戶提供一個消息處理函數,但這個處理函數沒有普通窗口的消息處理函數"權利大"。
對話框是一種系統定義的“窗口類”,它已經定義好了對應的消息處理函數。客戶所作的消息處理函數,並不是直接與窗口連接,而是對對話框消息處理函數的一種補充,或者說“嵌入”。
因此,對話框處理函數不需要調用“缺省消息處理函數”。
當有消息被處理時,返回TRUE,沒有消息需要處理時,返回FALSE,此時退出用戶消息處理函數后,系統會去調缺省消息處理函數。

//對話框消息處理函數

//返回值類型為BOOL,與普通窗口處理函數不同。

BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)

{

 

     switch (message)

     {

     case WM_INITDIALOG :

          return TRUE ; //返回真,表示消息被處理了。

         

     case WM_COMMAND :

          switch (LOWORD (wParam))

          {

          case IDOK :

          case IDCANCEL :

               EndDialog (hDlg, 0) ; //使用EndDialog關閉對話框

               return TRUE ; //返回真,表示消息被處理了。

          }

          break ;

     }

     return FALSE ; ////返回假,表示消息未被用戶處理,又缺省消息處理函數去處理。

}

 

三、模式對話框建立

使用DialogBox。

INT_PTR DialogBox(

     HINSTANCE hInstance,  // handle to module

     LPCTSTR lpTemplate,   // dialog box template

     HWND hWndParent,      // handle to owner window

     DLGPROC lpDialogFunc  // dialog box procedure

);

例:

case WM_COMMAND:

switch(LOWORD(wParam))

{

         case ID_ABOUT:

               DialogBox (hinst, MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDlgProc) ;

              break;

}

return 0;

 

四、模式對話框與程序的交互

模式對話框中,可以對程序中的數據進行更改。
結束對話框時,在EndDialog第二個參數中傳入退出參數
這個參數將被DialogBox作為返回值,然后對話框的用戶根據此返回值作相應的操作。

1.初始化
對話框消息處理函數中,在接到WM_INITDIALOG消息時,作一些初始化工作。
如從全局變量讀取初始值來設置各控件狀態。

2.退出時
若退出時,更改需要生效,(如按了“確定”),則根據控件狀態設置全局變量,並相應的在EndDialg中使用一個表示成功的值(如TRUE)。
若更改不需要生效(如按了“取消”),則不保存結果,並相應的在EndDialg中使用一個表示取消的值(如FALSE)。

3.對話框用戶作出反應
根據DialogBox的返回值不同,而進行不同的操作
如,返回TRUE時,重繪窗口:

if (DialogBox (hInstance, TEXT ("AboutBox"), hwnd, AboutDlgProc))

     InvalidateRect (hwnd, NULL, TRUE) ;

 

 

Windows SDK筆記():非模式對話框

一、概述

使用DialgBox建立的對話框是“模式對話框”,只有關閉對話框后,程序的其他窗口才能進行操作。
與此相對應,存在“非模式對話框”,對話框建立后,並不強制要求用戶立即反應,而是與其他窗口同時接受用戶操作。

二、建立

非模式對話框使用CreateDialg建立。
可以在WinMain中建立主窗口后建立,對話框句柄保存備用。

hDlgModeless = CreateDialog (

         hInstance,

         TEXT ("ColorScrDlg"),  //對話框模板

         hwnd,

         ColorScrDlg        //對話框消息處理函數

         );

 

三、消息循環添加針對非模式對話框的處理

“非模式對話框”與“模式對話框”不同,模式對話框工作的時候,有其內部的消息泵機制。
而非模式對話框則象普通窗口一樣,由WinMain中書寫的消息循環驅動。
但由於是對話框,它對一些消息有特殊的處理,例如用於在對話框中各子控件間導航的"TAB"鍵、"ENTER"鍵等等。
因此,在消息循環中,需要先給對話框提供截獲消息的機會。

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

{

     if (hDlgModeless == 0 || !IsDialogMessage (hDlgModeless, &msg))

     {

         TranslateMessage (&msg) ;

         DispatchMessage  (&msg) ;

     }

}

 


如果當前取得的消息是對話框消息的話,IsDialgMessage將它交由對話消息處理函數處理,並返回TRUE。
不需要在派發了。

四、非模式對話框的銷毀

使用:

DestroyWindow (hDlg);

用戶關閉對話框時,對話框消息處理函數將收到WM_CLOSE消息,接到后調用DestroyWindow以銷毀非模式對話框。

 

Windows SDK筆記():使用對話框資源建立窗口

 

一、概述
在Charles Petzold的書中,介紹了一種直接利用對話框資源建立主窗口的方法。
使用這種方法,可以方便的在主窗口中安排子控件,而代碼的其他部分跟用普通窗口時一樣。

我們知道,對話框是系統預先定義的“窗口類”,它有自己的窗口處理函數,我們自己寫的對話框消息處理函數並不是真正的窗口消息處理函數。
但我們可以在對話框模板腳本中,指定這個對話框使用我們自己定義的窗口類,而不是系統的對話框類,這樣,就將對話框的消息處理函數“嫁接”成我們自己定義的消息處理函數了。

二、書寫一個“真正的”窗口消息處理函數
按照普通窗口的方式書寫好消息處理函數。
(不要漏掉了DefWindowProc)

三、注冊窗口類
用書寫的消息處理函數注冊一個窗口類。

四、建立對話框資源,指定窗口類為自定的窗口類。
手工書寫一個對話框資源,存為單獨文件,然后包含到資源文件中去。
(使用菜單View->Resource Includes彈出對話框,將文件名填入到Compile-time derective一欄,這將在rc文件中添加一行:"#include ""Some.dlg"" ")
例:
建立文件Some.dlg
書寫:

HexCalc DIALOG -1, -1, 102, 122

STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX

CLASS "HexCalc"    //填寫上自己注冊的類名稱

CAPTION "Hex Calculator"

{

     PUSHBUTTON "D",       68,  8,  24, 14, 14

     PUSHBUTTON "A",       65,  8,  40, 14, 14

     //各種控件

}

五、使用非模式對話框方式建立主窗口
建立主窗口的時候,使用CreateDialog。

hwnd = CreateDialog (

              hInstance,

              szAppName,    //對話框模板

              0,

              NULL) ;

     ShowWindow (hwnd, iCmdShow) ;

其他各部分,都與普通窗口時相同(注冊窗口類、消息循環等)。

 

Ⅱ.在對話框中建立自定義子窗口

 

可以自己定義控件,然后在對話框模板中使用

一、定義"窗口類"與消息處理函數
在WinMain中
除了注冊主窗口類外,
另外注冊用於對話框的類,指明類對應的消息處理函數

wndclass.style         = CS_HREDRAW | CS_VREDRAW ;

wndclass.lpfnWndProc   = SomeWndProc ;  //對應的消息處理函數

wndclass.cbClsExtra    = 0 ;

wndclass.cbWndExtra    = 0 ;

wndclass.hInstance     = hInstance ;

wndclass.hIcon         = NULL ;

wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;

wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1) ;

wndclass.lpszMenuName  = NULL ;

wndclass.lpszClassName = TEXT ("SomeControl") ;

 

ReGISterClass (&wndclass) ;

 


同時,還要書寫好消息處理函數SomeWndProc。

二、在對話框模板中添加自定義控件窗口
在對話框模板上放上"Custom Control",然后設置屬性,並填寫自己定義的類名稱SomeControl。

Windows SDK筆記():創建MDI窗口

一、概述
MDI窗口包含一個框架窗口和若干子窗口。
實際上,框架窗口本身是一個普通主窗口,不過它的客戶去被一個特殊窗口覆蓋。
這個特殊窗口是系統預定義的“窗口類”,類名稱為:"MDICLIENT"。它負責各個MDI子窗口的管理。


二、窗口建立
1.注冊一個MDI框架窗口類,提供MDI框架窗口消息處理函數
MDI框架窗口消息處理函數中,將未處理消息交由DefFrameProc處理

//MDI框架窗口消息處理函數

LRESULT CALLBACK MDIFrameWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{

     //...

    

     //其他消息交給由系統提供的缺省框架處理函數DefFrameProc

     //其中,第二個參數是客戶區窗口句柄

     return ::DefFrameProc (hwnd,hwndClient, message, wParam, lParam) ;

}

 

2.注冊多個MDI子窗口類、對應提供各MDI子窗口的消息處理函數
子窗口消息處理函數中,將未處理消息交由MDIDefMDIChildProc處理

//MDI子窗口消息處理函數

LRESULT CALLBACK MDIChildWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{

     //...

     //...

    

     //其他消息交給由系統提供的缺省MDI子窗口處理函數

     return ::DefMDIChildProc (hwnd, message, wParam, lParam) ;

}

 

3.在框架窗口的客戶區建立MDI管理子窗口
MDI子窗口的管理實際上是由框架窗口客戶區的"MDILIENT"窗口完成的。
這是一個系統預定義的窗口。

在主窗口收到WM_CREATE消息后:

case WM_CREATE:

{

     hinst=((LPCREATESTRUCT) lParam)->hInstance;

             

     //填充CLIENTCREATESTRUCT結構

     CLIENTCREATESTRUCT clientcreate ;

     clientcreate.hWindowMenu  = hMenuInitWindow ;   //用於添加窗口列表的菜單句柄

     clientcreate.idFirstChild = 50000 ;  //起始ID

 

     hwndClient =CreateWindowEx(0,

         "MDICLIENT",  //類名稱為"MDICLIENT"

         NULL,

         WS_CHILD |WS_CLIPCHILDREN| WS_VISIBLE,

         0,

         0,

         0,

         0,

         hwnd,

         (HMENU)1,//ID

         hinst,   //實例句柄

         &clientcreate);    //參數

}

return 0;

 

窗口的大小沒有關系,缺省的框架窗口消息處理函數為讓它覆蓋整個客戶區。 
MDI客戶區窗口建立后,通過向它發送消息管理子窗口的建立、銷毀、排列等等。


4.MDI子窗口的建立
可以在菜單中添加命令項,以建立子窗口。
框架窗口的消息處理函數收到命令后,向MDI客戶區窗口發建立命令。

case ID_NEW:

{

     MDICREATESTRUCT mdicreate;

     mdicreate.szClass = szMDIChildName ; //MDI子窗口的類名稱

     mdicreate.szTitle = TEXT ("Hello") ;

     mdicreate.hOwner  = hinst ;

     mdicreate.x       = CW_USEDEFAULT ;

     mdicreate.y       = CW_USEDEFAULT ;

     mdicreate.cx      = CW_USEDEFAULT ;

     mdicreate.cy      = CW_USEDEFAULT ;

     mdicreate.style   = 0 ;

     mdicreate.lParam  = 0 ;

     SendMessage (

         hwndClient, //MDI客戶區窗口句柄

         WM_MDICREATE, //創建MDI子窗口

         0,

         (LPARAM) (LPMDICREATESTRUCT) &mdicreate //創建參數

         ) ;

 

}

break;

 

三、消息循環中處理針對MDI的熱鍵
在消息循環中,用TranslateMDISysAccel處理針對MDI的熱鍵。

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

{

     if (!TranslateMDISysAccel (hwndClient, &msg) &&

         !TranslateAccelerator (hwndFrame, hAccel, &msg))

     {

          TranslateMessage (&msg) ;

          DispatchMessage (&msg) ;

     }

}

 

四、命令的流向
框架窗口在收到WM_COMMAND等通知消息后,應該給當前激活的MDI窗口提供處理機會。

case WM_COMMAND:

switch (LOWORD (wParam))

{

     //針對框架的命令

     case ID_ONE:      

         //...

         return 0;

     //針對MDI子窗口管理的命令       

     case IDM_WINDOW_TILE:

         SendMessage (hwndClient, WM_MDITILE, 0, 0) ;

         return 0 ;

 

     //針對子窗口的命令又子窗口去處理              

     default:

         hwndChild = (HWND) SendMessage (hwndClient,

                                               WM_MDIGETACTIVE, 0, 0) ;

         if (IsWindow (hwndChild))

              SendMessage (hwndChild, WM_COMMAND, wParam, lParam) ;

              

               break ;        //..and then to DefFrameProc

}

break ;  //跳出針對WM_COMMAND的case分支,又DefFrameProc處理剩下的命令

 

五、子窗口的管理
1.概述
給MDI客戶區窗口發控制消息即可
如:

case WM_COMMAND:

switch (LOWORD (wParam))

{

     case IDM_WINDOW_TILE:

         SendMessage (hwndClient, WM_MDITILE, 0, 0) ;

         return 0 ;

              

     case IDM_WINDOW_CASCADE:

         SendMessage (hwndClient, WM_MDICASCADE, 0, 0) ;

         return 0 ;

              

     case IDM_WINDOW_ARRANGE:

         SendMessage (hwndClient, WM_MDIICONARRANGE, 0, 0) ;         

         return 0;

               

        //...

        //...

}

break;

 

2.當前子窗口的關閉
關閉當前激活窗口時,先向該窗口發送查詢消息:WM_QUERYENDSESSION。
子窗口的消息處理循環中響應此消息,作關閉前的一些處理,若能關閉,返回真
否則返回假。
框架窗口中根據此返回值決定是否關閉窗口。

如果用戶直接按下子窗口的關閉按鈕,則WM_CLOSE消息直接發送到了子窗口消息處理函數。

例如:
框架窗口命令處理中:

case IDM_FILE_CLOSE:         

//獲得當前激活窗口

hwndChild = (HWND) SendMessage (hwndClient, WM_MDIGETACTIVE, 0, 0);

//詢問通過后,銷毀窗口

if (SendMessage (hwndChild, WM_QUERYENDSESSION, 0, 0))

     SendMessage (hwndClient, WM_MDIDESTROY, (WPARAM) hwndChild, 0);

return 0;

 

子窗口的消息處理函數中:

LRESULT CALLBACK HelloWndProc (HWND hwnd, UINT message,

                               WPARAM wParam, LPARAM lParam)

{

     switch (message)

     {

     //...

     //...

 

     case WM_QUERYENDSESSION:

     case WM_CLOSE:

          if (IDOK != MessageBox (hwnd, TEXT ("OK to close window?"),

                                  TEXT ("Hello"),

                                  MB_ICONQUESTION | MB_OKCANCEL))

               return 0 ;

              

          break ;   // i.e., call DefMDIChildProc

     }

     return DefMDIChildProc (hwnd, message, wParam, lParam) ;

}

 

3.關閉所有子窗口
當使用命令方式關閉所有子窗口時,需要枚舉所有子窗口進行關閉。
例:
框架窗口響應命令:

case IDM_WINDOW_CLOSEALL:   

     //針對所有子窗口執行CloseEnumProc

     EnumChildWindows (hwndClient, CloseEnumProc, 0) ;

     return 0 ;

 

枚舉函數:

BOOL CALLBACK CloseEnumProc (HWND hwnd, LPARAM lParam)

{

     if (GetWindow (hwnd, GW_OWNER))         // Check for icon title

          return TRUE ;

    

     SendMessage (GetParent (hwnd), WM_MDIRESTORE, (WPARAM) hwnd, 0) ;

    

     if (!SendMessage (hwnd, WM_QUERYENDSESSION, 0, 0))

          return TRUE ;

    

     SendMessage (GetParent (hwnd), WM_MDIDESTROY, (WPARAM) hwnd, 0) ;

     return TRUE ;

}

 

六、菜單控制
在MDI程序中,可以根據激活的子窗口而切換框架窗口的菜單。
並且,可以將窗口列表添加到菜單中去。所添加的菜單項命令是又框架對應的缺省消息處理函數完成的。
1.為每種窗口類准備一套菜單資源
2.裝載菜單,得到菜單句柄
3.框架在建立時,使用框架菜單的句柄作為參數。
4.子窗口在激活時,加載自己菜單到框架窗口
失去焦點時,還原框架菜單。
使用向MDI客戶區窗口發送WM_MDISETMENU或WM_MDISETMENU消息。
wParam為菜單句柄,lParam為欲添加窗口列表的子菜單句柄

case WM_MDIACTIVATE:

         //激活時,設置框架菜單

         if (lParam == (LPARAM) hwnd)

               SendMessage (hwndClient, WM_MDISETMENU,

                            (WPARAM) hMenuHello, (LPARAM) hMenuHelloWindow) ;

              

              

          //失去焦點時,將框架菜單還原

         if (lParam != (LPARAM) hwnd)

               SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) hMenuInit,

                            (LPARAM) hMenuInitWindow) ;

              

          DrawMenuBar (hwndFrame) ;

         

          //注: hwndFrame的得到方法:

          //hwndClient = GetParent (hwnd) ;

          //hwndFrame  = GetParent (hwndClient) ;

         

          return 0 ;

 

 (全文完)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM