创建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.
When it is received the window is destroyed by calling the DestroyWindow(hwnd) method.
The DestroyWindow() method also generates a WM_DESTROY message.
This is achieved by calling the PostQuitMessage(0) method.
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).
After the window was registered we create it by passing the title, widht and height among other parameters.
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 ;
(全文完)