zoukankan      html  css  js  c++  java
  • Programming Windows 第五版读书笔记 第一章 开始

    Programming Windows 5th Edition - Chapter 1 Getting Started

    1. 第一个windows程序,如下:

    Code: Select all
    /*------------------------------------------------------------
        HelloMsg.cpp -- Display "Hello, Windows!" in
                       a message box
       Eric Zhang 2007
    --------------------------------------------------------------*/

    #include <windows.h>

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   PSTR szCmdLine, int iCmdShow)
    {
       MessageBox(NULL, TEXT("Hello, Windows!"), TEXT("HelloMsg"), 0);

       return 0;
    }


    在这个程序中,就有很多需要说明的东西。首先,include windows.h,windows.h是一个集大成的头文件,他里面include了很多必需的东西,最重要和最基本的有:

    WINDEF.H 基本类型定义。
    WINNT.H 支持Unicode的型态定义。
    WINBASE.H Kernel函数。
    WINUSER.H 使用者接口函数。
    WINGDI.H 图形设备接口函数。

    windows 自从发展开始以来,核心的东西一直没有变过,主要有三个:kernel,user,gdi,kernel(在windows很多地方这个kernel也叫 base,所以就有winbase.h这样的头文件)是windows的核心,负责内存管理,文件,进程等;user是使用者接口,比如键盘等;gdi是 图形设备接口。

    再往下看代码,看到的是WinMain函数,这就相当于一个C程序的main函数。WinMain的原型定义在WINBASE.H中,如下:

    Code: Select all
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine, int nShowCmd);


    这 里我们做了一些改动,首先是第三个参数,我们把类型改成了PSTR,PSTR其实就是char *,第二章中讲Unicode的时候会很详细清楚的讲windows中有关字符,字符串的数据类型系列,这里我们讲LPSTR改成了PSTR,其实效果一 样,带LP的指针表示long型指针,这是16位windows的遗留产物,在16位下,带L的指针表示占用4个字节,现在都是32位的windows 了,所以这个L加不加无所谓了,后面我们会看到很多16位windows下的数据类型和函数,这些都是遗留问题,事实上,windows从16位转成32 位的时候,API,数据类型膨胀的非常厉害,因为要兼容原来的16位程序,同时针对32位,又新加了大量的数据类型和函数。

    其他就没什么变化了,只是我们将变量的名字改了一下,比如将lpCmdLine改成了szCmdLine,这是匈牙利变量的命名法,以前学过的,sz表示string terminaed with zero。

    然后看到的就是WinMain申明中的WINAPI,这是给编译器看的一个编译参数,定义在WINDEF.h:

    #define WINAPI __stdcall

    __stdcall, __cdel, __fastcall这些都是指示编译器的指令,叫做呼叫约定(call convention),这些指令告诉编译器在编译function的时候,将function的名字如何命名(在真正二进制程序中,function的 name不是我们现在写的,需要做一些变化),函数的参数如何进栈和出栈(是将参数从右往左压入堆栈还是反之)...... 。有关这些东西我会在后面的文章中专门介绍,事实上,这些东西很重要,一旦写错会导致程序无法链接或执行期出现莫明其妙的错误,因为很多第三方的库,他的 Call Convention可能和我们的不一样,为了能调用他们,必须将我们的代码改成和他一致的,否则参数入栈出栈不同,会导致取出的参数不对;也有可能我们 将来的代码里面含有C++的代码,那么C++代码针对函数的呼叫约定又有不同;再有可能不同的编译器也不一样,情况很多,所以对呼叫约定还是需要透彻了解 的。

    然后我们看到WinMain函数中的参数,第一个参数是我们这个程序实例(instance)的句柄,其实就是一个数字,用来标识我 们这个程序实例,第二个参数也是历史产物,在早期的windows中,如果我们将一个程序执行多次,那么,就会出现多个该程序的instance,此时, 我们的程序就可以通过check这个hPrevInstance来判定我们的程序是否已经被launch了,从而可以选择少做一些工作(比如一些只需要做 一次的工作)。不过这个参数目前已经被废弃了,所以目前的32位的windows,这个参数永远是NULL。

    第三个参数是执行此程序时候的命令行,从中我们可以取到命令行选项和参数设定。第四个参数指定程序最初显示的方式,是最大化窗口,还是最小化窗口等等。

    再 往下我们就看到MessageBox函数了,第一个参数是窗口句柄,将在第三章中介绍。第二个参数MessageBox对话框主体中显示的文字;第三个参 数是对话框标题栏上的文字,这两个参数我们都用TEXT宏将他们封装了起来,在第二章Unicode中,我们会详细介绍为什么要这么做和TEXT宏具体的 内容;第四个参数表示MessageBox的类型,用来指定MessageBox对话框中出现的按钮,定义在WINUSER.H中,通常有这么一些:

    Code: Select all
    #define MB_OK                       0x00000000L
    #define MB_OKCANCEL                 0x00000001L
    #define MB_ABORTRETRYIGNORE         0x00000002L
    #define MB_YESNOCANCEL              0x00000003L
    #define MB_YESNO                    0x00000004L
    #define MB_RETRYCANCEL              0x00000005L


    如果MessageBox中显示了多个按钮的话,我们可以将上面的常数和下面的常数做|运算,从而指定一个Default Button:

    Code: Select all
    #define MB_DEFBUTTON1               0x00000000L
    #define MB_DEFBUTTON2               0x00000100L
    #define MB_DEFBUTTON3               0x00000200L
    #define MB_DEFBUTTON4               0x00000300L


    我们还可以在这个参数中指定MessageBox对话框中出现的图标:

    Code: Select all
    #define MB_ICONHAND                 0x00000010L
    #define MB_ICONQUESTION             0x00000020L
    #define MB_ICONEXCLAMATION          0x00000030L
    #define MB_ICONASTERISK             0x00000040L

    #define MB_ICONWARNING              MB_ICONEXCLAMATION
    #define MB_ICONERROR                MB_ICONHAND
    #define MB_ICONINFORMATION          MB_ICONASTERISK
    #define MB_ICONSTOP                 MB_ICONHAND


    将这些常量互相 | 起来,就可以达到组合使用他们的目的。

    至于MessageBox函数的返回值,在本程序中,MessageBox返回数值1,但更严格地说它返回IDOK,IDOK在 WINUSER.H中定义,等于1。根据在消息框中显示的其它按钮,MessageBox函数还可返回IDYES、IDNO、IDCANCEL、 IDABORT、 IDRETRY或IDIGNORE。

    程序解释完了,最后在编译的时候,在Project Properties中,定义两个预编译条件变量(Preprocessor):UNICODE, _UNICODE,这两个东西打开了Unicode的支持,至于是如何实现的,第二章Unicode会详细讲述。 :idea: :idea: 8) :idea:
  • 相关阅读:
    BZOJ 3669 & luogu 2387 魔法森林
    caioj 2064 & POJ 1741 & CH 0x40数据结构进阶(0x45 点分治)例题1:树
    caioj 2063& CH 0x40数据结构进阶(0x44 分块)例题4:小Z的袜子
    BZOJ 2154: Crash的数字表格
    追查坏牛奶(最大流)
    [JLOI2014]松鼠的新家
    [HAOI2015]树上操作
    [NOI2015]软件包管理器(树链刨分)
    [JSOI2008]球形空间产生器(高斯消元)
    [ZJOI2008]树的统计(树链刨分)
  • 原文地址:https://www.cnblogs.com/super119/p/2011325.html
Copyright © 2011-2022 走看看