第一个手写Win32窗口程序
一 Windows编程基础
1 Win32应用程序的基本类型
1.1 控制台程序 不需要完善的Windows窗口,可以使用DOS窗口 的方式显示。 1.2 Win32窗口程序 包含窗口的程序。可以通过窗口与程序进行交互。 1.3 Win32库程序 提供已有的代码,供其他程序使用。 动态库:DLL 是在执行的时候可以加载的程序。 静态库:LIB 是在编译链接是使用的程序。 1.4 对比 1.4.1 程序的入口函数不同 控制台:main Win32窗口程序:WinMain 动态库DLL:DllMain 静态库LIB:无 1.4.2 编译链接后存在的形式不同 控制台和Win32窗口程序:EXE文件,可以执行 动态库DLL:DLL文件,无法执行 静态库LIB:LIB文件,无法执行 1.4.3 执行结果不同 控制台:使用DOS窗口,自己没有窗口。 Win32窗口程序:会产生自己的窗口, 可以将结果输出或者从窗口接受输入。 动态库DLL:自己无法执行,提供可以执行 的代码,当EXE等程序执行时,可以使用 这些代码.执行时,该库必须在指定的路径. 静态库LIB: 自己无法执行,提供给程序在 编译链接时使用,将库中的代码嵌入到 程序当中.执行时,不需要该库存在.二 Win32窗口程序和编译环境
2.1 开发和编译环境
VC1.5 - VC6.0(2008) - VC10.0(2010)2.1.1 编译器 CL.EXE(在VC安装目录的VC98/Bin目录下) 将原代码编译目标代码. OBJ文件. 2.1.2 链接器 Link.EXE(在VC安装目录的VC98/Bin目录下) 将OBJ文件和库函数链接.生成EXE. 2.1.3 资源编译器 rc.exe(在VC安装目录的MSDev98\Bin目录下) 将资源脚本编译成可以链接的文件(RES). 2.2 头文件和库 2.2.1 头文件 windows.h包含了windows 常用的定义等.其他,还包含了一些其他的 头文件:windef.h - 定义了各种的数据类型 winbase.h- 定义了kernel的相关函数 wingdi.h - 定义了绘图和文字 winuser.h- 窗口 控件等函数 winnt.h - 提供Unicode支持2.2.2 库
kernel32.lib - 提供进程/线程/内存等等 API函数支持 user32.lib - 包括窗户/界面等等. gdi32.lib - 提供绘图/文字等。 2.3 Hello World程序 2.3.1 入口函数 int WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pszCmdLine, int nShowCmd ) hInstance - 应用程序的实例句柄 hPrevInstance - 该应用程序的前一个实例句柄 pszCmdLine - 命令行参数 nShowCmd - 窗口的显示方式 2.3.2 MessageBox 2.4 编译环境的准备 在VC98的BIN目录下VCVARS32.BAT 2.5 编译CL.EXE CL的常用选项/c 只编译不链接 /TC 编译C文件 /TP 编译C++文件 如果不指定,CL会根据文件类型自动区分 /I 头文件所在路径 字符大小写敏感 2.6 链接LINK.EXE LINK常用选项: /out:文件名,链接成指定文件名的程序 /LIBPATH:LIB文件存放的路径, /LIBPATH:"E:\XXX" /SUBSYSTEM: CONSOLE/WINDOW 字符大小写不敏感 2.7 执行 正常执行或带参数执行三 第一个窗口程序3.1 入口函数WinMain
3.2 窗口处理函数 当窗口处理消息事件时,系统调用该函数 LRESULT CALLBACK WindowProc( HWND hwnd, // 窗口的句柄 UINT uMsg, // 消息的ID号 WPARAM wParam, // 消息所对应的参数 LPARAM lParam // 消息所对应的参数 ); 3.3 注册窗口类型 typedef struct _WNDCLASS { UINT style; //窗口类的风格 WNDPROC lpfnWndProc; //窗口处理函数 int cbClsExtra; //窗口类附加数据大小 int cbWndExtra; //窗口附加数据大小 HANDLE hInstance; //当前应用程序的实例句柄 HICON hIcon; //窗口图标 HCURSOR hCursor; //窗口的鼠标 HBRUSH hbrBackground; //窗口的背景画刷 LPCTSTR lpszMenuName; //菜单 LPCTSTR lpszClassName; //类型名称 } WNDCLASS; 注册函数 RegisterClass 3.4 创建窗口 HWND CreateWindow( LPCTSTR lpClassName, //窗口类型名称 LPCTSTR lpWindowName, //窗口名称 DWORD dwStyle, //窗口类型 int x, //窗口的左上角X坐边 int y, //窗口的左上角X坐边 int nWidth, //窗口的宽度 int nHeight, //窗口的高度 HWND hWndParent, //父窗口句柄 HMENU hMenu, //窗口菜单句柄 HANDLE hInstance, //应用程序的实例句柄 LPVOID lpParam //创建的参数,一般为NULL );3.5 显示窗口
ShowWindow 显示窗口 BOOL ShowWindow( HWND hWnd, //显示的窗口句柄 int nCmdShow //显示的方式 ); UpdateWindow 刷新窗口 3.6 消息处理 GetMessage 获取消息 DispatchMessage 派发消息 3.7 程序退出 窗口销毁时,退出程序。在WndProc中实现。 WM_DESTROY: 当窗口销毁时,会调用WndProc 传递给使用者。 PostQuitMessage:发送一个退出消息。四 资源的处理4.1 资源和资源脚本
资源:ICON/CUSRUR/BITMAP/MENU...... 资源脚本: 扩展名为rc文件。 4.2 编译资源 使用rc.exe编译资源,生成RES文件 4.3 链接资源 使用link.exe将RES文件链接到程序当中 4.4 ICON的使用 LoadIcon从指定程序中加载ICON资源。
HelloWorld.c代码如下:
1 #include2 3 4 // 2、窗口过程函数 5 LRESULT CALLBACK WindowProc( HWND hwnd, 6 UINT uMsg, 7 WPARAM wParam, 8 LPARAM lParam ) 9 { 10 //判断消息ID 11 switch (uMsg) 12 { 13 case WM_DESTROY: // 窗口销毁消息 14 PostQuitMessage( 0 ); // 发送退出消息 15 return 0; 16 } 17 // 其他的消息调用缺省的消息处理程序 18 return DefWindowProc( hwnd, uMsg, wParam, lParam ); 19 } 20 21 // 3、注册窗口类型 22 BOOL RegisterWindow( LPCSTR lpcWndName, HINSTANCE hInstance ) 23 { 24 ATOM nAtom = 0; 25 26 // 构造创建窗口参数 27 WNDCLASS wndClass = { 0 }; 28 29 wndClass.style = CS_HREDRAW | CS_VREDRAW; 30 wndClass.lpfnWndProc = WindowProc; // 指向窗口过程函数 31 wndClass.cbClsExtra = 0; 32 wndClass.cbWndExtra = 0; 33 wndClass.hInstance = hInstance; 34 wndClass.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE( 100 ) );// 100为在HelloWorld.rc文件中定义的ID号 35 wndClass.hCursor = NULL; 36 wndClass.hbrBackground = (HBRUSH)COLOR_GRAYTEXT; 37 wndClass.lpszMenuName = NULL; 38 wndClass.lpszClassName = lpcWndName; // 注册的窗口名称,并非标题,以后创建窗口根据此注册的名称创建 39 40 nAtom = RegisterClass( &wndClass ); 41 if( 0 == nAtom) 42 { 43 MessageBox( NULL, "Register Failed", 44 "Error", MB_OK|MB_ICONERROR ); 45 return FALSE; 46 } 47 else 48 { 49 MessageBox( NULL, "Register Successed", 50 "Sucessed", MB_OK ); 51 } 52 return TRUE; 53 } 54 55 // 4、创建窗口(lpClassName 一定是已经注册过的窗口类型) 56 HWND CreateMyWindow( LPCTSTR lpClassName, HINSTANCE hInstance ) 57 { 58 HWND hWnd = NULL; 59 // 创建窗口 60 hWnd = CreateWindow( lpClassName, "Hello World", 61 WS_OVERLAPPEDWINDOW, 62 0, 0, 500, 300, 63 NULL, NULL, hInstance, NULL ); 64 if( NULL == hWnd ) 65 { 66 MessageBox( NULL, "Create Window Failed", 67 "Error", MB_OK|MB_ICONERROR ); 68 return NULL; 69 } 70 else 71 { 72 MessageBox( NULL, "Create Window Successed", 73 "Sucessed", MB_OK ); 74 } 75 return hWnd; 76 } 77 78 // 5、 显示窗口 79 void DisplayMyWnd( HWND hWnd ) 80 { 81 ShowWindow( hWnd, SW_SHOW ); 82 UpdateWindow( hWnd ); 83 } 84 85 void doMessage() // 消息循环处理函数 86 { 87 MSG msg = { 0 }; 88 // 获取消息 89 while( GetMessage( &msg, NULL, 0, 0 ) ) // 当接收到WM_QIUT消息时,GetMessage函数返回0,结束循环 90 { 91 DispatchMessage( &msg ); // 派发消息,到WindowPro函数处理 92 } 93 } 94 95 96 // 1、 入口函数 97 int WINAPI WinMain( HINSTANCE hInstance, 98 HINSTANCE hPrevInstance, 99 LPWSTR lpCmdLine,100 int nShowCmd )101 {102 HWND hWnd = NULL;103 LPCTSTR lpClassName = "MyWnd"; // 注册窗口的名称104 RegisterWindow( lpClassName, hInstance );105 hWnd = CreateMyWindow( lpClassName, hInstance );106 107 DisplayMyWnd( hWnd );108 doMessage();109 110 return 0;111 }
HelloWorld.rc资源脚本如下:
其中 100:表示资源的ID号
ICON:表示资源的类型
”resources/ICO.ico“ 表示资源Ico图标的路径
1 100 ICON "resources/ICO.ico"
运行方法:(首先运行VC98/bin/VCVARS32.bat配置好运行环境)
1、在Cmd控制台中找到代码当前路径,使用CL HelloWorld.c /c 命令只编译不链接文件,会生成一个HelloWorld.obj的目标文件
2、使用 rc HelloWorld.rc 命令编译HelloWorld.rc 资源脚本文件,会生成一个HelloWorld.RES的编译过的资源脚本文件
3、使用 link HelloWorld.obj user32.lib HelloWorld.res 链接这几个文件,会生成一个带图标的HelloWorld.exe文件
4、可以在 cmd 窗口中继续使用 HelloWorld 命令运行该程序,也可以点击生成的HelloWorld.exe运行改程序
运行结果如下:
(1) (2)
(3)可以看到左上角的图标也改变了