八宝书库 > 文学其他电子书 > C语言实例教程(PDF格式) >

第16部分

C语言实例教程(PDF格式)-第16部分

小说: C语言实例教程(PDF格式) 字数: 每页4000字

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




倾向于直接调用Win32   API,因为这有时候可以获得更高的效率,并 

且有着更大的自由度。而且,使用MFC编写的新风格的Windows应用程 

序的工作方式基本上与使用SDK编写的同一程序一样,它们往往有着 

很多的共同之处,只是使用MFC更加的方便,因为它隐藏了大量的复 

杂性。  


…………………………………………………………Page 122……………………………………………………………

前面提到过,面向对象的编程方式是当前最流行的程序设计方法,但 

是,Win32  API本身却是基于C语言的过程式编程的,SDK和MFC的最主 

要的不同之处也就是以C与C++之间的差别,使用MFC进行Windows应用 

程序设计需要面向对象的编程思想和方法,好在我们已经在前面这此 

进行了大量的铺垫。  



           第三节 使用SDK编写Windows应用程序  



传统的DOS程序以main函数作为进入程序的初始入口点,在Windows应 

用程序中,main函数被WinMain函数取而代之,WinMain函数的原型如 

下:  



int WINAPI WinMain (HINSTANCE hInstance; // 当前实例句柄  



HINSTANCE hPrevInstance; // 前一实例句柄  



LPSTR lpCmdLine; // 指向命令行参数的指针  



int nCmdShow) // 窗口的显示状态  



这里出现了一个新的名词 “句柄”(handle),所谓的句柄是一个标识 

对象的变量,或者是一个对操作系统资源的间接引用。  



在上面的函数原型中,我们看到了一些 “奇怪”的数据类型,如前面 

的HINSTANCE和LPSTR等,事实上,很多这样的数据类型只是一些基本 

数据类型的别名,表3。2列出了一些在Windows编程中常用的基本数据 

类型的别名,表3。3列出了常用的预定义句柄,它们的类型均为void  

*,即一个32位指针。  



                   表3。 2 Windows基本数据类型  



      Windows中 对应的基本数据   说明  

      所用的数    类型  

      据类型  



      BOOL    int        布尔值  



      BSTR    unsigned short   32位字符指针  

              *  



      BYTE    unsigned char   8位无符号整数  



      COLORREF   unsigned long   用作颜色值的32位值  



      DWORD   unsigned long   32位无符号整数,段地址和相关的偏移地 

                         址  


…………………………………………………………Page 123……………………………………………………………

LONG      long           32位带符号整数  



LPARAM    long           作为参数传递给窗口过程或回调函数的32 

                         位值  



LPCSTR    const char *   指向字符串常量的32位指针  



LPSTR     char *         指向字符串的32位指针  



LPCTSTR   const  char  * 指向可移植的Unicode和DBCS字符串常量 

           (注1)          的32位指针  



LPTSTR    char *(注1)     指向可移植为Unicode和DBCS字符串的32 

                         位指针  



LPVOID    void *         指向未定义类型的32位指针  



LRESULT   long           来自窗口过程或回调函数的32位返回值  



UINT      unsigned int   32位无符号整数  



WNDPROC   long           指向窗口过程的32位指针  

           (__stdcall  *) 

           (void  

          *;unsigned  

          int;unsigned  

          int;long)(注2)  



WORD      unsigned short  16位无符号整数  



WPARAM    unsigned int   当作参数传递给窗口过程或回调函数的32 

                         位值  



      注1:  这是在DBCS版本下的情况,在Unicode版本下LPCTSTR和LPTSTR将代表 

      其它的数据类型。  



      注2:   事实上,WNDPROC被定义为LRESULT        (CALLBACK*)(HWND;  UINT;  

      WPARAM; LPARAM),这个定义最终被编译器解释为long (__stdcall *)(void  

      *;unsigned int;unsigned int;long)。  



                 表3。 3 Windows公用句柄类型  



           句柄类型   说明  



           HBITMAP    保存位图信息的内存域的句柄  



           HBRUSH     画刷句柄  



           HCTR       子窗口控件句柄  



           HCURSOR    鼠标光标句柄  


…………………………………………………………Page 124……………………………………………………………

             HDC    设备描述表句柄  



             HDLG   对话框句柄  



             HFONT  字体句柄  



             HICON   图标句柄  



             HINSTANCE  应用程序的实例句柄  



             HMENU  菜单句柄  



             HMODULE  模块句柄  



             HPALETTE   颜色调色板句柄  



             HPEN   在设备上画图时用于指明线型 

                     的笔的句柄  



             HRGN   剪贴区域句柄  



             HTASK  独立于已执行任务的句柄  



             HWND    窗口句柄  



查看Win32  SDK文档或者浏览Windows头文件 (如windef。h、ctype。h以 

及winnt。h等)可以获得关于其它数据类型的定义,这些定义往往使用 

了#define和typedef等关键字。  



这里解释什么是应用程序的一个实例 (instance)。最简单的理解可以 

用下面的例子来说明:比如说已经在Windows中打开了一个 “写字 

板”(可以在 “开始”菜单中的 “程序 |附件”下面找到它的快捷方 

式),现在你需要从另一篇文章里复制一部分内容到你正在写的这篇 

文章中,那么,你可以再打开一个 “写字板”(注意写字板不是一个 

多文档应用程序,不能像在Word中那样打开多个不同的文件),然后 

从该写字板中复制文件的内容到在前一个写字板内打开的文章中。这 

里,我们多次运行了同一个应用程序,在这个例子中,我们将所打开 

的两个写字板叫做该应用程序的两个实例。对于实例的更精确 (当然 

也要比上面的例子要更难懂得多)的定义,在Win32  SDK中是这样给出 

的:实例就是类中一特定对象类型的一个实例化对象 

(instantiation),如一个特定的进程或线程,在多任务操作系统 

中,一个实例指所加载的应用程序或动态链接库的一份拷贝。刚开始 

时我们也许看不懂这一定义,不过没有关系,慢慢的就理解了。   



  l 注意:  


…………………………………………………………Page 125……………………………………………………………

l 尽管在前面给出的WinMain函数的原型中包括了一个名为 

 hPrevInstance的HINSTANCE类型的参数,按照其字面上的意义, 

  它所传递的是应用程序的前一个实例的句柄,但是,在Win32平台 

 下,该参数的值总是为NULL,而不管是否有当前应用程序的实例 

 在运行。在过去的Windows 3。x环境下编程,我们常常使用下面的 

 代码来检查应用程序是否已有一个实例在运行:  



l if (!hPrevInstance)  



l {  



l // 在此添加没有应用程序实例在运行时的所需执行的代码。  



l // 对于大多数应用程序,我们常在这里注册窗口类。  



l }  



     然而,在Win32操作系统——Windows 95、Windows NT 以及其 

     后续版本中,上面的if条件体中的代码总会被执行,因为 

     hPrevInstance总是为NULL,因此!hPrevInstance恒为真。  



     之所以这样,是因为在Win32环境下,每一个应用程序的实例 

     都有自已独立的地址空间,因此,它们之间互相独立,互不 

     干涉。但是,对于一些应用程序,只需要而且只应该有一个 

     实例在运行。什么情况下会是这样呢?假设我们编写了一个 

     应用程序,在默认情况下,该应用程序将在后台运行,通过 

     按下程序所定义的某一个热键,应用程序将被激活。对于这 

     样的应用程序,在同一时该只应该有一个实例在运行。另 

     外,像Windows  NT下在任务管理器,在同一时刻也只可以有 

     一个实例在运行。  



     使用下面的技巧可以保证在同一时刻只有应用程序的一个实 

     例:  



l #include 〃windows。h〃  



l   



l #define VK_X 0x58  



l   



l int WINAPI WinMain (HINSTANCE hInstance;  


…………………………………………………………Page 126……………………………………………………………

l HINSTANCE hPrevInstance;  



l LPSTR lpCmdLine;  



l int nCmdShow)  



l {  



l if (!CreateMutex(NULL;TRUE;〃No Previous Instance!〃))  



l {  



l MessageBox(NULL;〃创建Mutex失败!〃;〃NoPrev〃;MB_OK|MB_SYSTEMMODAL);  



l return FALSE;  



l }  



l if (GetLastError()==ERROR_ALREADY_EXISTS)  



l {  



l MessageBox(NULL;〃已有NoPrev的一个实例在运行; 当前实例将被终止!〃;  



l 〃NoPrev〃;MB_OK|MB_SYSTEMMODAL);  



l return FALSE;  



l }  



l if(!RegisterHotKey(NULL;0x0001;MOD_CONTROL|MOD_SHIFT;VK_X))  



l {  



l MessageBox(NULL;〃注册热键Ctrl+Shift+X失败!〃;  



l 〃NoPrev〃;MB_OK|MB_SYSTEMMODAL);  



l return FALSE;  



l }  



l MessageBox(NULL;〃NoPrev已启动!nn按下热键Ctrl+Shift+X将终止NoPrev。〃;  



l 〃NoPrev〃;MB_OK|MB_SYSTEMMODAL);  


…………………………………………………………Page 127……………………………………………………………

l MSG msg;  



l while (GetMessage(&msg;NULL;0;0))  



l {  



l switch (msg。message)  



l {  



l case WM_HOTKEY:  



l if (int(msg。wParam)==0x0001)  



l if (MessageBox(NULL;〃终止NoPrev?〃;  



l 〃NoPrev〃;MB_YESNO|MB_SYSTEMMODAL)==IDYES)  



l return TRUE;  



l }  



l }  



l return TRUE;  



l }  



      上面的代码是一个功能完整的Windows应用程序,其中用到了 

      一些到目前为止我们还未讲述到的内容。程序定义了热键 

      Ctrl+Shift+X,当按下该热键时将终止该程序。由于程序中 

       没有包括任何窗口,因此这是唯一的一种正常终止应用程序 

       的方法。当程序NoPrev正在后台运行时,如果用户按下了组 

      合键Ctrl+Shift+X,Windows将向程序主线程的消息队列中发 

      送一条称为WM_HOTKEY的消息,当程序收到这条消息时,即弹 

       出了消息框询问是否终止NoPrev。上面的说明将有助于你理 

      解以上代码,但是我们 目前对止并不做要求。这里,只需要 

       注意下面的代码 :  



l if (!CreateMutex(NULL;TRUE;〃No Previous Instance!〃))  



l {  


…………………………………………………………Page 128……………………………………………………………

  l MessageBox(NULL;〃创建Mutex失败!〃;〃NoPrev〃;MB_OK|MB_SYSTEMMODAL);  



  l return FALSE;  



  l }  



  l if (GetLastError()==ERROR_ALREADY_EXISTS)  



  l {  



  l MessageBox(NULL;〃已有NoPrev的一个实例在运行; 当前实例将被终止!〃;  



  l 〃NoPrev〃;MB_OK|MB_SYSTEMMODAL);  



  l return FALSE;  



  l }  



       在上面的代码 中,我们先调用CreateMutex创建一个名为 “ 

                                                          No  

       Previous     Instance”的命名互斥对象(named             mutex  

       object),如果该对象名已存在(注意这时函数CreateMutex仍 

       返回真值TRUE),则随后调用的GetLastError函数将返回 

       ERROR_ALREADY_EXISTS,由此得知已有一个应用程序的实例 

       正在运行。从而弹出消息框提醒用户,然后终止应用程序的 

        当前实例。  



在上面的WinMain函数原型中的另一个奇怪的标识符为WINAPI,这是 

一个在windef。h头文件中定义的宏,在当前版本Win32                       SDK中, 

WINAPI被定义为FAR PASCAL,因此,使用FAR PASCAL同使用WINAPI具 

有同样的效果,但是,我们强烈建议你使用WINAPI来代替以前常用的 

FAR PASCAL,因为Microsoft不保证FAR PASCAL能够在将来的Windows 

版本中正常工作。在目前情况下,和FAR                    PASCAL等价的标识符还有 

CALLBACK       (用在如窗口过程或对话框过程之类的回调函数前)和 

APIENTRY等。它们对编译器而言都是一回事,最终将被解释为 

__stdcall。在Windows环境下编程,会遇到很多这

返回目录 上一页 下一页 回到顶部 0 0

你可能喜欢的