第4讲 Windows编程基础 此为封面页,需列出课程编码、课程名称和课程开发室名称。 要求:每个子课程(6位编码的课程)要求做一个这样的胶片,胶片文件命名为“课程编码 课程名称.ppt”。 此页胶片仅在授课时使用,胶片+注释中不使用。 封面页按产品分为4个,各产品使用自己的封面,把其他封面直接删除即可。
编程的基本概念 与Windows系统密切相关的八个基本概念: 窗口、程序 进程、线程 消息、事件 句柄、API与SDK。
1、窗口 窗口是Windows本身以及Windows 环境下的应用程序的基本界面单位,但是很多人都误以为只有具有标题栏、状态栏、最大化、最小化按钮这样标准的方框才叫窗口。 其实窗口的概念很广,例如按钮和对话框等也是窗口,只不过是一种特殊的窗口罢了。
2、程序 通常说的程序都是指一个能让计算机识别的文件。 接触最多的是以exe或者com作为扩展名的文件。 注意:程序是静态的,进程是动态的。
3、进程 进程就是应用程序的执行实例(或称一个执行程序),进程是程序动态的描述。 一个exe文件,在没有被执行的时候称之为应用程序,当被执行以后,就被操作系统作为一个进程执行了。 当关机或退出,进程便消亡彻底结束了生命。 进程经历了由“创建”到“消亡”的生命期,而程序自始至终存在于你的硬盘上,不管计算机是否启动。
4、线程 线程是进程的一个执行单元,同一个进程中的各个线程对应于一组CPU指令、一组CPU寄存器以及一个堆栈。 进程的动态性,是通过线程来体现的。
5、消息 消息是应用程序和计算机交互的途径,在计算机上几乎做每一个动作都会产生一个消息 鼠标被移动会产生WM_MOUSEMOVE消息,鼠标左键被按下会产生WM_LBUTTONDOWN的消息,鼠标右键按下便产生WM_RBUTTONDOWN消息等等。
关于消息及消息队列 操作系统能够将输入设备的变化上传给应用程序。如用户在某个程序活动时按了一下键盘,操作系统马上能够感知到这一事件,并且能够知道用户按下的是哪一个键,操作系统并不决定对这一事件如何作出反应,而是将这一事件转交给应用程序,由应用程序决定如何对这一事件作出反应。 (好比有个蚊子叮了我们一口,我们的神经末梢(相当于操作系统)马上感知到这一事件,并传递给了我们的大脑(相当于应用程序),我们的大脑最终决定如何对这一事件作出反应,如将蚊子赶走,或是将蚊子拍死。) 对事件作出反应的过程就是消息响应。
在程序运行的过程中改变窗口的大小或者移动窗口等,都会触发相应的“事件”,从而调用相关的事件处理函数。 6、事件 事件是程序对外界动作的反应。 在程序运行的过程中改变窗口的大小或者移动窗口等,都会触发相应的“事件”,从而调用相关的事件处理函数。
7 、句柄 句柄是一个指针,通过句柄就可以控制该句柄指向的对象。 句柄是系统用来标识不同对象类型的工具。 如窗口、菜单等,这些东西在系统中被视为不同类型的对象,用不同的句柄将他们区分开来。
关于句柄 句柄(HANDLE),资源的标识。操作系统要管理和操作这些资源,都是通过句柄来找到对应的资源。 按资源的类型,又可将句柄细分成图标句柄(HICON)、光标句柄(HCURSOR)、窗口句柄(HWND)、应用程序实例句柄(HINSTANCE)等。 操作系统给每一个窗口指定的一个唯一的标识号即窗口句柄。
8、API与SDK API(Application Programming Interface),即应用程序接口,泛指系统为应用程序提供的一系列函数接口。 在编程的时候可以直接调用,而不必知道其内部实现的过程,只知道它的原型和返回值就可以了。 SDK(Software Development Kit),即软件开发工具包,微软提供了许多专门的SDK开发包,比如DirectX开发包和语音识别开发包等等。
学习Windows下编程 比较流行的是VC++6.0英文企业版 学习语言,选择语言和工具是第一步,而且是非常重要的一步工作,目前的编程语言那么多,有C、C++、C#、Java和汇编语言等等。 虽然有很多语言,只要精通一门就够了。从实用的角度来讲,C/C++是最好的选择,而微软公司的Visual C++和Insprise公司(原Borland公司)的C++ Builder是其相应开发工具的两大主流。 比较流行的是VC++6.0英文企业版
学习编程需要经历三大步 1、读程序 语言基础知识、查相关的资料,补充基础知识 2、写程序 编程贵在动手!要规范、循序渐进。 3、积累功能代码 语言基础知识、查相关的资料,补充基础知识 2、写程序 编程贵在动手!要规范、循序渐进。 3、积累功能代码 分类保存、代码库、效率及正确率。
C语言发展的四个阶段 1、面向过程的C语言 2、面向对象的C++语言 3、SDK编程 4、MFC编程
面向过程的C语言 C和C++的最主要区别是:C语言中没有类的概念,C++在C的语法基础上引入了类,所以C++和C的语法是基本相同的。 #include <stdio.h> void main() { printf("Hello DOS\n"); }
#include <stdio.h> int main(int argc, char *argv[ ]) { int i; 读取命令行参数 参数内容 #include <stdio.h> int main(int argc, char *argv[ ]) { int i; for (i = 1; i < argc; i++) printf("%s\n", argv[i]); } return 0; 参数个数
面向对象的C++语言 面向对象程序设计语言可以将一些变量和函数封装到类中,当变量被类封装后,称之为属性或者数据成员,当函数被类封装后,称之为方法或者成员函数。 定义好的一个类,然后定义一个类的实例,这个实例就叫做对象,在C++中可以用类定义对象.
在C++中使用类 #include <iostream.h> class person { public: int heart; char *name; int run() { heart=heart+20; return heart; } }; void main() int iRunStop; person ZhangSan; ZhangSan.name = "张三"; ZhangSan.heart = 72; cout<<"姓名:"<<ZhangSan.name <<endl; cout<<"跑步前心跳"<< ZhangSan.heart<<endl; iRunStop = ZhangSan.run(); cout<<"跑步后心跳"<<iRunStop<<endl; }
SDK编程 C库提供了许多函数,可以直接使用。如DeleteFile函数来删除一个文件。 #include <stdio.h> #include <stdio.h> #include <windows.h> int main() { DeleteFile("C:\\test.txt"); printf("删除成功\n"); return 0; }
Windows内部机制 Windows是一个“基于事件的,消息驱动的”操作系统。在Windows下执行一个程序,只要用户进行了影响窗口的动作(如改变窗口大小或移动、单击鼠标等)该动作就会触发一个相应的“事件”。 系统每次检测到一个事件时,就会给程序发送一个“消息”,从而使程序可以处理该事件。 每次检测到一个用户事件,程序就对该事件做出响应,处理完以后,再等待下一个事件的发生。
Windows应用程序、操作系统、计算机硬件之间的相互关系
关于消息及消息队列 操作系统是怎样将感知到的事件传递给应用程序的呢?这是通过消息机制(Message)来实现的。操作系统将每个事件都包装成消息的结构体MSG来传递给应用程序,MSG结构定义如下: typedef struct tagMSG { HWND hWnd; // 目标窗口句柄 UINT message; // 消息标识 WPARAM wParam; // 消息参数1(附加信息,16位) LPARAM lParam; // 消息参数2(附加信息,32位) DWORD time; // 消息发送时间 POINT pt; // 消息发送时鼠标的屏幕坐标 } MSG;
从变量类型区分变量用途 int x,y; x=30; y=30; typedef int WIDTH typedef int HEIGHT WIDTH x; HEIGHT y; //好处:我们从变量的类型上就可以知道x和y是用来表示宽度和高度。
在project中选Win32 Application 编写窗口应用程序 #include <windows.h> int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { MessageBox (NULL, "Hello, Windows!", "HelloMsg", MB_OK) ; return 0 ; } 在project中选Win32 Application 示例1
WinMain函数 Windows程序的入口函数 int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line int nCmdShow // window show state );
编写窗口应用程序 hInstance :是当前实例的句柄,表示应用程序本身; hPrevInstance:总是为NULL。 lpCmdLine:用于接受并存放程序运行时所需的参数 nCmdShow:用于指定程序窗口最初的显示模式 可以正常显示,也可以在初始化就最大化或者最小化。
窗口的创建 创建一个完整的窗口需要经过下面四个操作步骤: 设计一个窗口类; 注册窗口类; 创建窗口; 显示及更新窗口。
1、设计窗口类 typedef struct _WNDCLASS { UINT style; //窗口样式 WNDPROC lpfnWndProc; //指向窗口过程函数 int cbClsExtra; //窗口类的附加内存空间(0) int cbWndExtra; //窗口的附加内存空间(0) HANDLE hInstance; //指向程序的实例句柄 HICON hIcon; //指向图标的句柄 HCURSOR hCursor; //指向光标的句柄 HBRUSH hbrBackground; //背景画刷句柄 LPCTSTR lpszMenuName; //菜单资源名 LPCTSTR lpszClassName; //指定窗口类的名称 } WNDCLASS;
----窗口类的类型 补充知识: 在程序中经常要用到一类变量,这个变量里的每一位(bit)都对应某一种特性。当该变量的某位为1时,表示有该位对应的那种特性,当该位为0时,即没有该位所对应的特性。当变量中的某几位同时为1时,就表示同时具有几种特性的组合。一个变量中的哪一位代表哪种意义,不容易记忆,所以我们经常根据特征的英文拼写的大写去定义一些宏,该宏所对应的数值中仅有与该特征相对应的那一位(bit)为1,其余的bit都为0。
----窗口类的类型 使用goto definition,发现CS_VREDRAW=0x0001,CS_HREDRAW=0x0002,CS_DBLCLKS =0x0008,CS_NOCLOSE=0x0200。共同点就是只有一位为1,其余位都为0。 如果希望某一变量的值既有CS_VREDRAW又有CS_HREDRAW特性,可使用或运算,如:style=CS_VREDRAW | CS_HREDRAW ; 如果希望在某一变量原有的几个特征上去掉其中一个特征,用取反(~)之后再进行与(&)运算。如在刚才的style的基础上去掉CS_NOCLOSE特征,可以用: style=style& ~CS_NOCLOSE;
----窗口过程函数 lpfnWndProc:窗口的过程函数,也称回调函数。 作用:当应用程序收到给某一窗口的消息时,就应该调用某一函数来处理这条消息。这一调用过程不用应用程序自己来实施,而由操作系统来完成,但是,回调函数本身的代码必须由应用程序自己完成。对于一条消息,操作系统到底调用应用程序中的哪个函数(回调函数)来处理呢?操作系统调用的就是接受消息的窗口所属的类型中的lpfnWndProc成员指定的函数。每一种不同类型的窗口都有自己专用的回调函数,该函数就是通过lpfnWndProc成员指定的。
----窗口过程函数 举例:汽车厂家生产汽车好比应用程序创建窗口,用户使用汽车好比操作系统管理窗口,某种汽车在销售前就指定好了修理站(类似回调函数),当用户的汽车出现故障后(类似窗口收到消息),汽车用户(类似操作系统)自己直接找到修理站去修理,不用厂家(类似应用程序)亲自将车送到修理站去修理,但修理站还得由厂家事先建造好。
----设计窗口类的示例代码 WNDCLASS wndcls; wndcls.style=CS_HREDRAW | CS_VREDRAW; wndcls.cbClsExtra=0; wndcls.cbWndExtra=0; wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); wndcls.hCursor=LoadCursor(NULL,IDC_CROSS); wndcls.hIcon=LoadIcon(NULL,IDI_ERROR); wndcls.hInstance=hInstance; wndcls.lpfnWndProc=WindowProc; wndcls.lpszClassName="xiexin2011"; wndcls.lpszMenuName=NULL;
2、注册窗口类 ATOM RegisterClass( CONST WNDCLASS *lpWndClass); 刚才有: WNDCLASS wndcls; 所以: RegisterClass(&wndcls);
3、创建窗口 HWND CreateWindow( LPCTSTR lpClassName, // 1.pointer to registered class name LPCTSTR lpWindowName, //2. pointer to window name DWORD dwStyle, // 3.window style int x, // 4.horizontal position of window int y, //5. vertical position of window int nWidth, //6. window width int nHeight, // 7.window height HWND hWndParent, //8. handle to parent or owner window HMENU hMenu, // 9.handle to menu or child-window identifier HANDLE hInstance, // 10.handle to application instance LPVOID lpParam //11. pointer to window-creation data );
--创建窗口的示例代码 HWND hwnd; hwnd=CreateWindow("xiexin2011","My window", WS_OVERLAPPEDWINDOW, 0,0,600,400,NULL,NULL,hInstance,NULL); 注:创建成功后,返回系统分配给窗口句柄,否则返回NULL。因此要用一个句柄变量(如hwnd)来保存 WS_OVERLAPPEDWINDOW类型的窗口具有: Creates an overlapped window with the WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, and WS_MAXIMIZEBOX styles.
4、显示及更新窗口 BOOL ShowWindow( HWND hWnd, //窗口创建成功后的句柄 int nCmdShow // 窗口显示状态 ); BOOL UpdateWindow( HWND hWnd // 窗口创建成功后的句柄 ); ShowWindow(hwnd ,SW_SHOWNORMAL); UpdateWindow(hwnd); 还有:SW_MAXIMIZE , SW_SHOWMAXIMIZED SW_SHOWMINIMIZED SW_SHOWDEFAULT 等
--创建窗口的示例代码 HWND hwnd; hwnd=CreateWindow("xiexin2011","My window", WS_OVERLAPPEDWINDOW, 0,0,600,400,NULL,NULL,hInstance,NULL); WS_OVERLAPPEDWINDOW类型的窗口具有: Creates an overlapped window with the WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, and WS_MAXIMIZEBOX styles.
Windows消息循环 消息队列和在应用程序中的轮询处理
Windows消息循环 BOOL GetMessage( LPMSG lpMsg, // 指向消息结构体的地址 HWND hWnd, // 接收消息的窗口句柄 UINT wMsgFilterMin, // 消息的最小值(一般取0) UINT wMsgFilterMax //消息的最大值(一般取0) ); 后两个参数若都设为0,则接收所有消息; 接收到除WM_QUIT 外的消息均返回非0值; 对于WM_QUIT返回0,出现错误返回-1。
Windows消息循环 MSG msg; while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; TranslateMessage(&msg):将虚拟键消息转换为字符消息 DispatchMessage(&msg ):把消息投递到窗口过程
窗口过程函数 LRESULT CALLBACK WindowProc( HWND hwnd, // 消息的窗口句柄 UINT uMsg, // 消息代码 WPARAM wParam, // 消息的附加参数1 LPARAM lParam //消息的附加参数2 ); 该函数内部主要通过switch-case来确定窗口接收的是什么消息,以及如何处理这些消息。
窗口过程函数示例代码 LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg, WPARAM wParam,LPARAM lParam) { switch(uMsg) { case WM_LBUTTONDOWN: MessageBox(hwnd,"mouse clicked","message",0); break; case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd,uMsg,wParam,lParam); } return 0;
总结:SDK开发程序的步骤 1、包含相关头文件,如window.h及stdio.h等 2、写WinMain(……)入口函数 A、设计一个窗口类(WNDCLASS) B、注册窗口类(RegisterClass) C、创建窗口(CreateWindow) D、显示及更新窗口(ShowWindow UpdateWindow) E、消息循环(获取、转换、投递消息函数) 3、写窗口过程函数 用switch来接收各类消息并作相应处理 示例2
利用SDK函数创建窗口 #include <windows.h> #include <stdio.h> WNDCLASS wc; HWND h_wnd; MSG msg; /* 消息处理函数wndProc的声明*/ long WINAPI WindowProc(HWND,UINT,WPARAM,LPARAM); /* winMain 函数*/ int PASCAL WinMain(HINSTANCE h_CurInstance,HINSTANCE h_PrevInstance,LPSTR p_CmdLine,int m_Show) { wc.lpfnWndProc =WindowProc; wc.hInstance =h_CurInstance; wc.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszClassName ="ECJTU";
利用SDK函数创建窗口 { TranslateMessage(&msg); DispatchMessage(&msg); } RegisterClass(&wc); //注册窗口类 h_wnd=CreateWindow("ECJTU","My Window", WS_OVERLAPPEDWINDOW,0,0,400,500, 0,0,h_CurInstance,0); //创建窗口 //显示窗口 ShowWindow(h_wnd,SW_SHOWMAXIMIZED); UpdateWindow(h_wnd); //更新窗口 //消息循环 while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (msg.wParam ); }
利用SDK函数创建窗口 示例3 LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg, WPARAM wParam,LPARAM lParam) { switch(uMsg) { case WM_LBUTTONDOWN: MessageBox(hwnd,"mouse clicked","message",0); break; case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd,uMsg,wParam,lParam); } return 0; 示例3
MFC编程 SDK的功能非常强大,需要记很多的函数,当面向对象编程成为主流的时候,微软将SDK的函数分类进行封装,这就是MFC(Microsoft Foundation Class) MFC中,函数名及其用法与SDK中基本一致。可多参考MSDN。
MFC编程基础 #include<afxwin.h> class sample:public CFrameWnd { Create(NULL,"My Window"); MessageBox("My Window","CFrame constructor"); } }; class App:public CWinApp { public: BOOL InitInstance(); BOOL ExitInstance(); }; BOOL App ::InitInstance() //InitInstance函数的定义// { MessageBox(0,"My Window","InitInstance", MB_OK|MB_ICONASTERISK);
MFC编程基础 示例4 sample *obj; obj=new sample; m_pMainWnd=obj; obj->ShowWindow(SW_SHOWMAXIMIZED); return TRUE; } BOOL App::ExitInstance() //ExitInstance函数定义 { MessageBox(0,"My Window","ExitInstance", MB_OK|MB_ICONHAND); //创建应用程序对象 App appobject; 示例4
MFC编程基础
MFC事件处理机制 示例5 #include<afxwin.h> class sample:public CFrameWnd { Create(NULL, "My Window"); } void OnLButtonDown(UINT,CPoint) { MessageBox("Left Button", "Hello",0); } DECLARE_MESSAGE_MAP() }; BEGIN_MESSAGE_MAP(sample,CFrameWnd) ON_WM_LBUTTONDOWN( ) END_MESSAGE_MAP( ) //消息映射 示例5