1.第一个程序:Hello,world!
1 #include<windows.h> 2 3 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow ) 4 { 5 MessageBox( NULL, TEXT("Hello,world!"), TEXT("MessageBox"), 0 ); 6 7 return 0; 8 }
WinMain()函数
WINAPI为WinMain函数的调用规则, 在WINDEF.H对"WINAPI"作出了如下宏定义:
#define WINAPI __stdcall
WinMain函数的调用规则为"__stdcall"方式, 对于"__stdcall"调用规则, 具体用法待查。
WinMain函数的参数: 1.HINSTANCE hInstance:实例句柄 2.HINSTANCE hPrevInstance:前一个的实例句柄,历史原因,已无实际意义,总为NULL。 3.LPSTR lpCmdLine:PSTR:运行程序的命令行。PSTR来指向一个字符串的指针类型, szCmdLine, sz:表示以0结尾的字符串;
目的是通过命令行方式运行程序并向主函数中传入参数, 应该就像给main函数传入参数一样。暂未遇到具体命令程序,待学习。 4.程序(窗口)最初如何被显示, 例如最小化?最大化?全屏?暂未遇到具体命令程序,待学习。
MessageBox函数:
int MessageBox(
HWND hWnd, // handle of owner window, 窗口的一个句柄
LPCTSTR lpText, // address of text in message box, 一个文本(字符串)的指针
LPCTSTR lpCaption, // address of title of message box, 标题字符串的指针
UINT uType // style of message box, 对话框的风格
);
MessageBox( NULL, TEXT("Hello,world!"), TEXT("MessageBox"), 0 );
第一个参数窗口的句柄的实参为NULL, 意思为不属于任何窗口.
第二个参数为对话框的内容,
第三个参数为对话框的标题, 但是这两个参数都使用了一个TEXT()的函数,
当使用wchar_t类型的宽字符时, 使用"令牌粘贴", 使用TEXT宏时就避免了在字符串前面加上一个大写字母'L'了。
#define __T(x) L ## x #define _TEXT(x) __T(x) #define __TEXT(quote) L##quote #define TEXT(quote) __TEXT(quote)
第四个参数为对话框的风格, 一些以MB_开头的一些常量的组合, 可以使用OR(|)运算进行组合, 这些常量定义在WINUSER.H中, 例如常用的有: 1>.对话框按钮类型: #define MB_OK 0x00000000L //仅有一个"确定"按钮 #define MB_OKCANCEL 0x00000001L //"确定" + "取消" #define MB_ABORTRETRYIGNORE 0x00000002L //"终止" + "重试" + "忽略" #define MB_YESNOCANCEL 0x00000003L //"是" + "否" + "取消" #define MB_YESNO 0x00000004L //"是" + "否" #define MB_RETRYCANCEL 0x00000005L //"重试" + "取消" 2>.对话框中的图标类型: #define MB_ICONHAND 0x00000010L //一个红X的错误/停止图标
#define MB_ICONQUESTION 0x00000020L //一个问号的询问图标
#define MB_ICONEXCLAMATION 0x00000030L //一个黄色感叹号的警告图标
#define MB_ICONASTERISK 0x00000040L //一个带有i的信息提示图标 同时, 在这些图标中有的还可以用其他名称代替, 这些别名在WINUSER.H的定义如下: #define MB_ICONWARNING MB_ICONEXCLAMATION //警告
#define MB_ICONERROR MB_ICONHAND //错误
#define MB_ICONINFORMATION MB_ICONASTERISK //信息
#define MB_ICONSTOP MB_ICONHAND //停止
2.创建自己的窗口
1 #include <windows.h> 2 3 LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ) ; //声明用来处理消息的函 4 5 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow ) 6 { 7 static TCHAR szAppName[] = TEXT("MyWindow") ; 8 HWND hwnd ; 9 MSG msg ; 10 WNDCLASS wndclass ; //声明一个窗口类对象 11 12 //以下为窗口类对象wndclass的属性 13 wndclass.style = CS_HREDRAW | CS_VREDRAW ; //窗口样式 14 wndclass.lpszClassName = szAppName ; //窗口类名 15 wndclass.lpszMenuName = NULL ; //窗口菜单:无 16 wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH) ; //窗口背景颜色 17 wndclass.lpfnWndProc = WndProc ; //窗口处理函数 18 wndclass.cbWndExtra = 0 ; //窗口实例扩展:无 19 wndclass.cbClsExtra = 0 ; //窗口类扩展:无 20 wndclass.hInstance = hInstance ; //窗口实例句柄 21 wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION ) ; //窗口最小化图标:使用缺省图标 22 wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ) ; //窗口采用箭头光标 23 24 if( !RegisterClass( &wndclass ) ) 25 { //注册窗口类, 如果注册失败弹出错误提示 26 MessageBox( NULL, TEXT("窗口注册失败!"), TEXT("错误"), MB_OK | MB_ICONERROR ) ; 27 return 0 ; 28 } 29 30 hwnd = CreateWindow( //创建窗口 31 szAppName, //窗口类名 32 TEXT("我的窗口"), //窗口标题 33 WS_OVERLAPPEDWINDOW, //窗口的风格 34 CW_USEDEFAULT, //窗口初始显示位置x:使用缺省值 35 CW_USEDEFAULT, //窗口初始显示位置y:使用缺省值 36 CW_USEDEFAULT, //窗口的宽度:使用缺省值 37 CW_USEDEFAULT, //窗口的高度:使用缺省值 38 NULL, //父窗口:无 39 NULL, //子菜单:无 40 hInstance, //该窗口应用程序的实例句柄 41 NULL // 42 ) ; 43 44 ShowWindow( hwnd, iCmdShow ) ; //显示窗口 45 UpdateWindow( hwnd ) ; //更新窗口 46 47 while( GetMessage( &msg, NULL, 0, 0 ) ) //从消息队列中获取消息 48 { 49 TranslateMessage( &msg ) ; //将虚拟键消息转换为字符消息 50 DispatchMessage( &msg ) ; //分发到回调函数(过程函数) 51 } 52 return msg.wParam ; 53 } 54 55 LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) 56 { 57 HDC hdc ; //设备环境句柄 58 PAINTSTRUCT ps ; //绘制结构 59 RECT rect; //矩形结构 60 61 switch( message ) //处理得到的消息 62 { 63 case WM_CREATE: //窗口创建完成时发来的消息 64 MessageBox( hwnd, TEXT("窗口已创建完成!"), TEXT("我的窗口"), MB_OK | MB_ICONINFORMATION ) ; 65 return 0; 66 67 case WM_PAINT: //处理窗口区域无效时发来的消息 68 hdc = BeginPaint( hwnd, &ps ) ; 69 GetClientRect( hwnd, &rect ) ; 70 DrawText( hdc, TEXT( "Hello, 这是我自己的窗口!" ), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ; 71 EndPaint( hwnd, &ps ) ; 72 return 0 ; 73 74 case WM_LBUTTONDOWN: //处理鼠标左键被按下的消息 75 MessageBox( hwnd, TEXT("鼠标左键被按下。"), TEXT("单击"), MB_OK | MB_ICONINFORMATION ) ; 76 return 0; 77 78 case WM_DESTROY: //处理窗口关闭时的消息 79 MessageBox( hwnd, TEXT("关闭程序!"), TEXT("结束"), MB_OK | MB_ICONINFORMATION ) ; 80 PostQuitMessage( 0 ) ; 81 return 0; 82 } 83 return DefWindowProc( hwnd, message, wParam, lParam ) ; //DefWindowProc处理我们自定义的消息处理函数没有处理到的消息 84 }
(1)窗口类对象wndclass的属性
wndclass.style = CS_HREDRAW | CS_VREDRAW ; //窗口样式 wndclass.lpszClassName = szAppName ; //窗口类名 wndclass.lpszMenuName = NULL ; //窗口菜单:无 wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH) ; //窗口背景颜色 wndclass.lpfnWndProc = WndProc ; //窗口消息处理函数 wndclass.cbWndExtra = 0 ; //窗口实例扩展:无 wndclass.cbClsExtra = 0 ; //窗口类扩展:无 wndclass.hInstance = hInstance ; //窗口实例句柄 wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION ) ; //窗口最小化图标:使用缺省图标 wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ) ; //窗口采用箭头光标
1>. wndclass.style = CS_HREDRAW | CS_VREDRAW ; style属性决定着窗口的风格, 可以通过C语言的或运算组合出不同风格类型的窗口, 在WINUSER.H头文件中定义着这些标识符以及其值, 所有的前缀为CS_的标识符如下: * Class styles #define CS_VREDRAW 0x0001 #define CS_HREDRAW 0x0002 #define CS_DBLCLKS 0x0008 #define CS_OWNDC 0x0020 #define CS_CLASSDC 0x0040 #define CS_PARENTDC 0x0080 #define CS_NOCLOSE 0x0200 #define CS_SAVEBITS 0x0800 #define CS_BYTEALIGNCLIENT 0x1000 #define CS_BYTEALIGNWINDOW 0x2000 #define CS_GLOBALCLASS 0x4000 #define CS_IME 0x00010000 2>. wndclass.lpszClassName = szAppName ; 赋予窗口一个名称, 可以使用ASCII版本的字符串也可以使用Unicode版本的字符串, 需要注意的是, 这里的窗口名称并不是指窗口标题。 3>. wndclass.lpszMenuName = NULL ; 指定窗口类的菜单, 由于我们这个窗口没有使用菜单, 所以为NULL, 4>. wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH) ; 窗口的背景颜色, 这里使用的是以白色作为填充, 填充白色这是常见的做法, 如果你愿意, 也可以填充为其他的一些样式, 这里是一些样式的标识符: #define WHITE_BRUSH 0 #define LTGRAY_BRUSH 1 #define GRAY_BRUSH 2 #define DKGRAY_BRUSH 3 #define BLACK_BRUSH 4 #define NULL_BRUSH 5 #define HOLLOW_BRUSH NULL_BRUSH #define WHITE_PEN 6 #define BLACK_PEN 7 #define NULL_PEN 8 #define OEM_FIXED_FONT 10 #define ANSI_FIXED_FONT 11 #define ANSI_VAR_FONT 12 #define SYSTEM_FONT 13 #define DEVICE_DEFAULT_FONT 14 #define DEFAULT_PALETTE 15 #define SYSTEM_FIXED_FONT 16 5>. wndclass.lpfnWndProc = WndProc ; 将窗口的消息处理函数设置为我们自定义的WndProc函数。 6>. wndclass.cbWndExtra = 0 ; 7>. wndclass.cbClsExtra = 0 ; 这两个属性用来维护结构中预留的一些额外空间, 程序可以根据需要要使用这些额外空间, 通过匈牙利命名的cbClsExtra、cbWndExtra中的cb可以知道, 这些成员表示一个"字节数", 由于我们这个窗口没有使用到额外空间, 所以将这个两个属性赋值为0; 8>. wndclass.hInstance = hInstance ; 表示应用程序的实例句柄, hInstance的来源是WinMain的一个参数; 9>. wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION ) ; 加载一个位图作为程序标题栏最左侧的小图标, 我们这里加载了一个系统的默认图标, 后面的学习这将会学习到如何从磁盘加载我们自定义的图标. 10>. wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ) ; 与LoadIcon类似, 加载鼠标的指针位图;
(2)注册窗口
if( !RegisterClass( &wndclass ) ) { //注册窗口类, 如果注册失败弹出错误提示 MessageBox( NULL, TEXT("窗口注册失败!"), TEXT("错误"), MB_OK | MB_ICONERROR ) ; return 0 ; }
(3)创建窗口
hwnd = CreateWindow( //创建窗口 szAppName, //窗口类名 TEXT("我的窗口"), //窗口标题 WS_OVERLAPPEDWINDOW, //窗口的风格 CW_USEDEFAULT, //窗口初始显示位置x:使用缺省值 CW_USEDEFAULT, //窗口初始显示位置y:使用缺省值 CW_USEDEFAULT, //窗口的宽度:使用缺省值 CW_USEDEFAULT, //窗口的高度:使用缺省值 NULL, //父窗口:无 NULL, //子菜单:无 hInstance, //该窗口应用程序的实例句柄 NULL // ) ;
1>.参数一: LPCTSTR lpClassName 参数LPCTSTR lpClassName,为窗口的名称, 我们需要传入的参数就是刚才我们在窗口类注册的窗口类名称, 这样使用CreateWindow建立的窗口就能与注册的窗口进行关联。 2>. 参数三: DWORD dwStyle 参数三为窗口的样式, 示例中创建的是一个普通的层叠窗口样式, WS_OVERLAPPEDWINDOW, 打开WINUSER.H头文件, 对于WS_OVERLAPPEDWINDOW是这样定义的: #define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) 可以看出, WS_OVERLAPPEDWINDOW样式实际上是通过一些标识符通过或的组合, 此外我们还可以通过组合设计我们自己的样式, 这些标识符在WINUSER.H的定义如下: #define WS_OVERLAPPED 0x00000000L //产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。与WS_TILED风格相同。 #define WS_POPUP 0x80000000L //创建一个弹出式窗口。该风格不能与WS_CHLD风格同时使用。 #define WS_CHILD 0x40000000L //创建一个子窗口。这个风格不能与WS_POPUP风格合用。 #define WS_MINIMIZE 0x20000000L //创建一个初始状态为最小化的窗口。仅与WS_OVERLAPPED风格一起使用。 #define WS_VISIBLE 0x10000000L //创建一个最初可见的窗口。 #define WS_DISABLED 0x08000000L //创建一个初始状态为禁止的窗口。 #define WS_CLIPSIBLINGS 0x04000000L //排除子窗口之间的相对区域。 #define WS_CLIPCHILDREN 0x02000000L //创建一个初始状态为禁止的子窗口。一个禁止状态的窗口不能接受来自用户的输入信息。 #define WS_MAXIMIZE 0x01000000L //创建一个初始状态为最大化状态的窗口。 #define WS_CAPTION 0x00C00000L //创建一个有标题框的窗口(包括WS_BODER风格)。 #define WS_BORDER 0x00800000L //创建一个单边框的窗口。 #define WS_DLGFRAME 0x00400000L //创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条。 #define WS_VSCROLL 0x00200000L //创建一个有垂直滚动条的窗口。 #define WS_HSCROLL 0x00100000L //创建一个有水平滚动条的窗口。 #define WS_SYSMENU 0x00080000L //创建一个在标题条上带有窗口菜单的窗口,必须同时设定WS_CAPTION风格。 #define WS_THICKFRAME 0x00040000L //创建一个具有可调边框的窗口,与WS_SIZEBOX风格相同。 #define WS_GROUP 0x00020000L //指定一组控制的第一个控制。 #define WS_TABSTOP 0x00010000L //创建一个控制,这个控制在用户按下Tab键时可以获得键盘焦点。按下Tab键后使键盘焦点转移到下一具有WS_TABSTOP风格的控制。 #define WS_MINIMIZEBOX 0x00020000L //创建一个具有最小化按钮的窗口。 #define WS_MAXIMIZEBOX 0x00010000L //创建一个具有最大化按钮的窗口。 #define WS_TILED WS_OVERLAPPED //产生一个层叠的窗口。一个层叠的窗口有一个标题和一个边框。与WS_OVERLAPPED风格相同。 #define WS_ICONIC WS_MINIMIZE //创建一个初始状态为最小化的窗口。仅与WS_OVERLAPPED风格一起使用。 #define WS_SIZEBOX WS_THICKFRAME //创建一个具有厚边框的窗口,可以通过厚边框来改变窗口大小。 #define WS_TILEDWINDOW WS_OVERLAPPEDWINDOW //创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU,WS_THICKFRAME,WS_MINIMIZEBOX和WS_MAXIMIZEBOX风格的重叠式窗口。
(4)窗口的显示、更新
ShowWindow( hwnd, iCmdShow ) ; //显示窗口 UpdateWindow( hwnd ) ; //更新窗口
ShowWindow函数的原型如下: BOOL ShowWindow( HWND hWnd, int iCmdShow ); 参数一为刚才通过CreateWindow函数窗口出的窗口句柄, 参数二为窗口的显示方式, 由WinMain函数的int iCmdShow接收该值, 常用的显示方式有: SW_HIDE //隐藏窗口并激活其他窗口; SW_MAXIMIZE //最大化; SW_MINIMIZE //最小化指定的窗口并且激活在Z序中的下一个顶层窗口; SW_RESTORE //激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置; SW_SHOW //在窗口原来的位置以原来的尺寸激活和显示窗口; SW_SHOWMAXIMIZED //激活窗口并将其最大化; SW_SHOWMINIMIZED //激活窗口并将其最小化; SW_SHOWMINNOACTIVE //窗口最小化,激活窗口仍然维持激活状态; SW_SHOWNA //以窗口原来的状态显示窗口。激活窗口仍然维持激活状态; SW_SHOWNOACTIVATE //以窗口最近一次的大小和状态显示窗口。激活窗口仍然维持激活状态; SW_SHOWNORMAL //激活并显示一个窗口。如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小;
UpdateWindow函数的原型如下: BOOL UpdateWindow( HWND hWnd ); 该函数只有一个参数, 参数为需要更新的窗口句柄; 函数调用成功返回值为非0, 调用失败时返回值为0。
(5)消息的转换、分发
while( GetMessage( &msg, NULL, 0, 0 ) ) //从消息队列中获取消息 { TranslateMessage( &msg ) ; //将虚拟键消息转换为字符消息 DispatchMessage( &msg ) ; //分发到回调函数(过程函数) } return msg.wParam ; }
(6)消息处理函数
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { HDC hdc ; //设备环境句柄 PAINTSTRUCT ps ; //绘制结构 RECT rect; //矩形结构 switch( message ) //处理得到的消息 { case WM_CREATE: //窗口创建完成时发来的消息 MessageBox( hwnd, TEXT("窗口已创建完成!"), TEXT("我的窗口"), MB_OK | MB_ICONINFORMATION ) ; return 0; case WM_PAINT: //处理窗口区域无效时发来的消息 hdc = BeginPaint( hwnd, &ps ) ; GetClientRect( hwnd, &rect ) ; DrawText( hdc, TEXT( "Hello, 这是我自己的窗口!" ), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ; EndPaint( hwnd, &ps ) ; return 0 ; case WM_LBUTTONDOWN: //处理鼠标左键被按下的消息 MessageBox( hwnd, TEXT("鼠标左键被按下。"), TEXT("单击"), MB_OK | MB_ICONINFORMATION ) ; return 0; case WM_DESTROY: //处理窗口关闭时的消息 MessageBox( hwnd, TEXT("关闭程序!"), TEXT("结束"), MB_OK | MB_ICONINFORMATION ) ; PostQuitMessage( 0 ) ; return 0; } return DefWindowProc( hwnd, message, wParam, lParam ) ; //DefWindowProc处理我们自定义的消息处理函数没有处理到的消息 }