VC6 使用基础
◆ 一、 VC6 + XPSP2 SDK 使用方法:
当我们在 VC6 中写这样的代码:
CString buffer1, buffer2;
buffer1.Format("_WIN32_WINNT=%x", _WIN32_WINNT);
buffer2.Format("WINVER=%x", WINVER);
MessageBox(buffer1, buffer2, MB_OK);
SetWindowLong(this->GetSafeHwnd(), GWL_EXSTYLE, GetWindowLong(this->GetSafeHwnd(), GWL_EXSTYLE) ^ WS_EX_LAYERED);
SetLayeredWindowAttributes(this->GetSafeHwnd(), 0, 127, LWA_ALPHA);
编译不能通过,这是为什么呢?
VC6 是 98 年出来的,对 Win2k 系统上才有的 API 无法直接调用。虽然我们可以动态调用 DLL 的方式来使用它的 API,但是这样很不方便。升级 SDK 可以解决以上问题,目前所知,仅有两个版本支持 VC6,一个是 Server2003 SDK,另一个就是 XPSP2 SDK ,可以查阅我前面写的 Microsoft Platform SDK 的文章,里面有它们的下载地址。
我在 XP 系统上使用 VC,所以这里下载 XPSP2 SDK 。SDK 安装完成后,在“开始菜单\程序\Microsoft Platform SDK for Windows XP SP2\Visual Studio Registration\” 里可以找到 Register PSDK Directories with Visual Studio 项,它能将 SDK 中的头文件和库文件目录配置到 VC6 的头文件和库文件搜索目录项中。
但是,这样做完后还不能使 VC 直接调用 Win2k API。这是因为目前在 SDK 里,头文件中使用 _WIN32_WINNT 来标识可使用的 API 函数集。它的取值不同,可使用的 API 函数范围也不同。
我们在 Platform SDK for Windows XP SP2 帮助中的 Index 标签页中输入 _WIN32_WINNT 可以看到一篇文章:Using the Windows Headers ;你也可以这样打开它:切换到 Contents 标签页: Development Guides -> Windows API -> Window API Reference -> Using the Windows Headers 。
这篇文章告诉我们有两个关键的宏定义,它们的取值所表达的意思就是系统版本号。头文件中就是使用该值来包含对应系统版本的 API 函数头的。
比如我们要使用 SetLayeredWindowAttributes() ,该 API 被声明在 WinUser.h 文件中,打开该文件,我们会发现在它后面有 /* _WIN32_WINNT >= 0x0500 */ 注释,即如果我们定义 _WIN32_WINNT >= 0x0500,就可以使用该函数。
而 0x0500 正是指的 Win2k,所以该函数在 Win2k 及以上版本中才存在,这就是版本控制。
为了保证 VC6 和 SDK 的兼容性,我们取的 API 函数集应该限制在 Win2k 系统里,即要这样定义:
#define WINVER 0x0500
#define _WIN32_WINNT 0x0500
哦,想必大家已经看出来了,是的,_WIN32_WINNT 定义没有写在 Windows.h 中,就是要让用户自己指定所使用的 API 函数集范围。但是如果没有定义 WINVER,则
在 Windows.h 中它会这么做 #define WINVER 0x0501
而在 WinUser.h 中它会这么做 #define WINVER 0x0500 /* version 5.0 */
故,我们最好先定义一下它们,使 API 和常量定义的使用范围更明确些。
最好的方案是在程序引用 Windows.h 之前定义它们,但是对于 MFC 程序,我们很难找到定义处,因为类封装了它。
怎么办呢?我在这里提供两个可选方法:
▲方法一:在编译预处理中指定
新建工程,点主菜单,Project -> Settings 打开 Project Settings 对话框。
或者按 ALT + F7 直接打开该对话框。
找到 C/C++ 标签页, 在 Category: 下拉菜单中选择 General,可看到底下 Preprocessor definitions: 编辑框,在里面填入 _WIN32_WINNT=0x0500
每个预处理标识符都是用逗号分隔的。
当你这么填入后点确定,它会在下面的 Project Options: 框里加上
/D WIN32_WINNT=0x0500 选项。
它相当于下面这条语句:
#define _WIN32_WINNT 0x0500
其实我们应该定义两个,
#define WINVER 0x0500
#define _WIN32_WINNT 0x0500
只不过我们在这里指定 WINVER 会发生重复,编译器会报错。查看 Windows.h 头文件,发现有 WINVER 定义。
所以编译器是先处理文件,当找不到相应常量时才会使用在编译器中指定的。虽然这里我们不加上 /D WINVER=0x0500,在该 XPSP2 SDK 中会自动在 Windows.h 中定义 #define WINVER 0x0501 ,程序依然可以使用 Win2k API,但是如果不小心使用了 XP 的 API,可能会造成不兼容的问题,比如程序可以编译但不能连接,或者编译连接正常,但运行会出错等,这些问题就不太好查了。
所以,我建议,两个都要先定义。怎么才能做到呢?请看下面的方法:
▲方法二:修改 Windows.h 文件法
我想你也注意到了,既然 _WIN32_WINNT 是没有定义的符号,我们就在 Windows.h 中将它加上好了。如果你的源程序不需要拿到其它环境里去编译,完全可以这么做。如果你确定要这么干,这里我有个更好的做法,不改变原 Windows.h, 而是复制一份到另一个目录里,然后修改这个副本,在文件开头添加
#define WINVER 0x0500
#define _WIN32_WINNT 0x0500
然后我们再到 VC 集成环境中,选 Tools -> Options,打开 Options 对话框,找到 Directories 标签页,在 Show directories for: 下拉列表中选择 include files,在里面添加副本所在目录,比如 c:\win2k.inc, 并将其移到最上面,这样无论编译什么,就算是 MFC 工程, 一样可以使用 Win2k API 。
◆ 二、VC 中新建的工程第一次应该使用 Rebuild All 。
在VC中,新建立的工程第一次编译,应该使用主菜单中的
Build -> Rebuild All
这是因为 VC 有时候不重新编译一些公共文件,造成编译连接错误。本来 VC 是为了加速编译速度,不对公共文件重新编译,但有时新建了工程,它也不重新编译,还用先前那个,这就会造成编译连接错误。为了不必要的麻烦,在一开始将所有的文件全部 Rebuild All 一次。
注意,在菜单 Build 中, Rebuild All 的图标带三个小箭头,而 Build 旁边没有图标,但是在 Build MiniBar 工具条上的 Build 是带二个小箭头的图标,注意分清楚。
以前我使用 VC 时,就误解了 Build MiniBar 上的图标和 Rebuild All 的图标,就是因为在主菜单 Build 中没有标出 Build 的二箭头图标,害得我好几次出了问题不知所云。
如果不清楚,最好直接使用主菜单。
◆ 三、在 VC 中,让调试器带上符号调试
在主菜单中选 Tools -> Options,在 Debug 标签页中,将 Disassembly window 中的 Symbols 勾上。
为了在 VC 调试器中用符号代替变量地址,我们还需要把代码用一个大括号括起来,并且使用的变量都要是在这个大括号里面定义的,才会出现带符号调试。
如:
void main()
{
{
int a, b, c;
a = b = c = 1;
a = a + b + c;
cout << "a= " << a << endl;
}
}