标题: [转载]探讨改进的系统信息API 新内核API 调试API 安全API和UI API [打印本页] 作者: x86 时间: 2006-2-26 20:33 标题: [转载]探讨改进的系统信息API 新内核API 调试API 安全API和UI API
[转载]探讨改进的系统信息API 新内核API 调试API 安全API和UI API
文章作者:Matt Pietrek
摘要 关于 Windows Server 2003,我们有许多话要说。首先,它是第一个内置了 .NET 框架支持的操作系统,也是 Microsoft 推出的第一个 64 位操作系统。 但我们要讨论的不只这些! 这个操作系统版本中还有许多新特性和 API。 例如,Windows Server 2003 采用了“热添加内存”和许多其他巧妙的新功能。 系统中还包括新 API,用于处理线程、目录和文件,以及新特性,如用于管理内存和系统信息的低碎片堆。 此外,还有向量化异常处理和新 UI API。
操作系统内核领域的专家 Matt Pietrek 将讨论他认为最有趣和最有用的新内容,这样,在深入 Windows Server 2003 之前,您将有一个很好的开端。
返回页首
就年纪而言,我可能还不具备谈论这个话题的资格,但我的确记得过去的好时光 — 开发人员热切等待发布新 Windows 版本的那些日子。 新版本中会包含哪些新的特别吸引人的特性呢?这些好的特性又会有哪些用途呢? 随着 Microsoft .NET 框架的出现,在某些圈子里,开始流行这样一种言论 — Windows 没有什么变化、不值得讨论。 有些人似乎认为,用哪个 Windows 版本作为运行平台都没有关系。
您可能已经猜到了,我可不属于这类人。 虽然我像任何其他人一样,是 Microsoft .NET 的忠实爱好者,但我仍然充满热情地扫描头文件,比较来自每个新 Windows 版本的系统 DLL 的导出。 我希望知道,Microsoft Windows 团队中的风云人物最近都在忙些什么。
Microsoft 推出的最新、最酷的操作系统就是 Windows Server? 2003,在我撰写本文时,它还处于发行候选版阶段。 在本文中,我将讨论 Windows Server 2003 中为应用程序级的程序员提供了哪些新的特别吸引人的特性。 不过,在深入探讨新 API 之前,了解一些背景信息会有助于您加深理解。
我们首先要确定这个“新”字的含义。 Windows Server 2003 是为了取代 Windows 2000 Server 系列(Server、Advanced Server 和 Datacenter Server)而推出的。 因此,原来出现在 Windows XP 里的操作系统特性中有许多在技术上可以属于本文中所说的“新”特性类别。
实际上,大多数新 API(相对于 Windows 2000 而言)首先出现在 Windows XP 中,而不是 Windows Server 2003 中。出现这种情况是有充分理由的。 一开始,Windows 2000 的下一个版本的代号为 Whistler,它的测试版包括了工作站和服务器两个版本。 2001 年,Microsoft 决定服务器版本需要酝酿更长时间,因此发布了作为消费者版本和工作站版本的 Windows XP。 Microsoft 原本打算很快就发布服务器版本。 正如您已经知道的那样,发布延迟了一年半。 延迟的部分时间是由“Microsoft 可信赖计算计划”导致。根据该计划,Microsoft 的开发人员停止了新的开发,以寻找代码中的安全问题。
问题的关键在于,到某个日期时,Whistler 的工作站版本和服务器版本基本上都具有完整的特性,并使用了同样的代码库。 Windows XP 和 Windows Server 2003 之间的发布时间差主要用于使操作系统尽可能稳定。 因此,Windows Server 2003 的新特性和 API 中有许多也可以在 Windows XP 中找到 — 这根本不足为奇。
Platform SDK 头文件中使用的版本号可以证明该操作系统的公共接口(也就是 API)在 Windows XP 之后的改变非常小。 为了启用 Windows XP(及更高版本)API,需要将 _WIN32_WINNT 定义为 0x0501(也就是说,在内部,Windows XP 被认为是 Windows 5.01)。 对于 Windows Server 2003,_WIN32_WINNT 所需的 #define 值只变成 0x0502。 您稍后将看到示例程序中使用的 _WIN32_WINNT #defines。
Windows Server 2003 可以保留开发过程中名称更改的最大次数的记录。 起初,它的代号是 Whistler,后来改为 "Windows 2002 Server"。 接着,.NET 计划渗透了 Microsoft 的所有产品,该操作系统被重新命名为 "Windows .NET Server"。 在经历了另一次延迟之后,它的名称改为 "Windows .NET Server 2003"。 最后,深谋远虑的 Microsoft 高层取得了胜利,操作系统更名为 "Windows Server 2003"。 如果我漏掉了其中的一次更名,也不足为奇。
不过,从更名的过程中,我们可以看出一个重点: Windows Server 2003 是第一个将 .NET 框架作为操作系统组成部分的操作系统。 为了实现向后兼容性,该系统同时包括了最新的 .NET 框架 1.1 以及原来的 1.0 版本的 .NET 框架。 由于 MSDNMagazine 和其他地方对 .NET 进行了大量介绍,因此我在本文中不打算将 .NET 框架作为新 API。
除了作为内置 .NET 框架支持的第一个操作系统,Windows Server 2003 还是第一个 Microsoft 64 位服务器操作系统,因而与众不同。 Windows XP Professional 虽然有 64 位版本,但到目前为止,对基于 Itanium 的 64 位工作站的需求还不是很大。 现在,Microsoft 终于推出了 64 位服务器操作系统,拥有大型数据库的公司可能会开始转移到 64 位 Windows。 64 位版本的 SQL Server? 预计将与 64 位版本的 Windows Server 2003 一起提供。
Windows Server 2003 最初将提供六种配置。 对于 Intel x86 CPU,低端是用于基本 Web 服务的 Web 版服务器。 再高一级是作为部门级服务器的标准版。 从它再往上一级是面向大中型企业的企业版。 最后,针对运行在多达 32 个处理器上的大规模数据库系统提供数据中心版。 其余两种配置是企业版和数据中心版的 64 位 Itanium 版本。
比较有趣的是,64 位版本的 Windows Server 2003 不包括 .NET 框架。 显然,64 位版本的 .NET 还没有准备就绪,因此将在以后的版本中提供。
Windows Server 2003 中有许多新特性,我不会在此详述,但仍然值得一提,因为这些特性太棒了。 例如,Internet 信息服务 (IIS) 现在提供的版本是 6.0。 它在结构上有了较大改动,并且由于对内核模式侦听器下了更多的工夫,性能也获得很大的提高。 如果需要,您还可以在三种 IIS 5.0 保护级别下运行它。
Windows Server 2003 中其他异乎寻常的新特性包括(但不只限于这些特性):卷影复制、热添加内存和非统一内存访问 (NUMA) 支持。
卷影复制服务提供了一种进行完整备份的方式,即使是备份时打开的文件也可以备份。 虽然我不喜欢谈论备份,但我认为使用驱动程序透明地实现此功能是很不错的。 Mark Russinovich 和 David Solomon 在 2001 年 12 月刊上发表的文章 Windows XP:Kernel Improvements Create a More Robust, Powerful, and Scalable OS 涵盖了卷影复制服务及许多其他新特性。
热添加内存是完全异乎寻常的特性之一,它会使您想知道那些稀奇古怪的硬件设计人员接下来会有什么奇思妙想。 这种特性能够在系统运行时向系统添加 RAM。 当您插入 RAM 后,操作系统自动进行检测,并开始使用 RAM。不过,为了实现此目的,您需要运行一个在设计上支持这种特性的系统。 在 Microsoft 文档中,您会发现来自硬件维修权威的警告:不要在任何旧系统打开时向其中盲目添加 RAM — 这样做会导致发生意外。
NUMA 是一种在企业级多处理器系统中使用的高端技术。 它的中心内容是,将内存和处理器组成单元。 处理器在访问其单元内的内存时,速度会比访问另一个单元中的内存时更快。 Windows 中的 NUMA 支持导致计划程序试图使相关的进程运行在同一个单元中。
在进入 Windows Server 2003 新 API 的核心之前,我需要在这里做一项声明。下面只是我个人的主观看法,并不全面。 我阅读了数百个头文件和 beta 文档页,精选了我认为最有趣的内容。 我不得不做出许多关于包括哪些内容和放弃哪些内容的艰难选择。 通常,对我来说,要选择一个包括在这里的特性,它必须是用户模式的 API,而不是完全深奥的 API 或与某个特定程序相关的 API。 我看到了许多设备驱动程序级的新功能,但它们不在本文的范围内。
新KERNEL API
现在,我们即将开始内核级功能的讨论。 您可能会认为内核级功能指的是 KERNEL32(稍后将充分探讨这方面的内容)。 真正的系统编程发烧友知道,NTDLL 是用户模式内核的真正核心。 我已经对 Windows Server 2003 版本的 NTDLL.DLL 的导出与 Windows 2000 版本的 NTDLL.DLL 的导出做了比较。 您可能已经预料到,许多 API 被添加进去,有几个 API 消失了。 重要的是,它们都是未公开的 API,对吗? 不要这么快就得出结论!
当我在不同版本的 Platform SDK 之间比较所有那些 .H 文件时,我偶然发现一个 2002 年 10 月版的非常有趣的文件。 该文件名为 WINTERNL.H。这肯定是一个我们要紧紧抓住的文件。 它也可能在未来的 Platform SDK 中消失。 在 WINTERNL.H 的开头,是一个包括三个段落的警告,警告的内容是,所有数据结构和 API 随时可能更改,仅限 Windows 核心组件使用。 (我们以前好像见过那些警告吧,不是吗?)
不管怎样,WINTERNL.H 中包括什么特别吸引人的东西呢? 不幸的是,并不像您希望的那么多。 但还是有一些众所周知的、但仍未公开的数据结构的线索引人入胜。 例如,您将看到定义的进程环境块 (PEB) 和线程环境块 (TEB)。 不过,大多数字段是作为保留字段列出的。 同样,该文件中还包括调用 NtQueryInformationProcess 和 NtQueryInformationThread 时所必需的结构和原型。 不过,目前有各种图书和 Web 站点提供了关于这些 API 和结构的许多信息,比 WINTERNL.H 要详细得多。 必须承认,该文件对 Windows Server 2003 来说没有什么新东西。不过,该文件首次出现在随 Windows Server 2003 提供的 SDK 中。
为什么我要对这件事情如此小题大做呢? 它的重要意义在于,Microsoft 最终承认,许多有趣的东西没有公开。 WINTERNL.H 中还有其他几个值得注意的 API: NtCreateFile、NtOpenFile、NtClose 和 NtWaitForSingleObject。 这些 API 是公共 KERNEL32 API 的用户模式实现的核心。 同样,RtlUnwind 是结构化异常处理 (SEH) 中使用的关键 API,我于 1997 年 1 月在 Microsoft Systems Journal 上发表的文章 "A Crash Course on the Depths of Win32 Structured Exception Handling " 描述了这一内容。 RtlUnwind 发生变化的可能性极小。 如果它发生了变化,那么,很大一部分现有的应用程序会无法运行。
进程、线程和纤程,天哪!
现在我们开始讨论 KERNEL32。我的第一组 API,如图 1 所示,与进程和线程相关。出现一个异常时,它们都检索有关进程或线程的某段信息。 GetThreadId 获取线程句柄,返回相关的线程 ID。GetProcessId 也是这样。 很难相信这些函数 10 年前还没有出现在 Win32 API 中! IsWow64Process 会告知调用进程是否为运行在 64 位 Windows 下的 32 位进程。
GetProcessHandleCount 返回指定的进程已经打开的句柄数。 该计数与我们在性能监视器数据或任务管理器中看到的是同一个值。 RestoreLastError 有些不可思议。 它的代码与 SetLastError 完全一样。 我还不清楚为什么将它作为一个单独的 API。
为了示范这些新 API 中的一部分,请查看图 2中的 ProcessesAndThreads 程序。 该代码是不言自明的,因此在这里我将不再对其深究。 要编译该程序(及其他示例程序),您至少需要 2002 年 10 月的 Platform SDK,其编译器和链接器的目录搜索顺序的最前面是 Include 目录和 Lib 目录。 如果您运行的是 Windows XP,可以在编译程序时使它只使用 API 的 Windows XP 子集。 只要对开头附近的 #define W2K3SERVER 行取消注释,然后重新编译就可以了。
除了线程处理支持,Windows Server 2003 还添加了一些新纤程 API, 如图 3中的所示。 这里要提到一条重要消息,新增了纤程本地存储 (FLS)。 这些 API 同样用于其对应的线程本地存储 (TLS)。 通过 FlsAlloc 函数来分配一个槽。 要设置或检索值,可使用 FlsGetValue 和 FlsSetValue 函数。 用完槽后,调用 FlsFree。
我顺便研究了 FLS 函数的实现。 线程环境块中偏移量为 0xFB4 处是一个指向数据结构的指针。 此结构中有八个字节是一组 128 个槽。 这些槽在概念上与 TLS 槽相同。 当线程在纤程之间切换时,偏移量为 0xFB4 处的指针也随之更新。
ConvertFiberToThread API 撤消了 ConvertThreadToFiber 的效果。 调用它之后,无法再对线程调用其他纤程函数。 图 3 中列出的其余两个 API 只是现有 API 的“扩展”版本。 CreateFiberEx 就像 CreateFiber,但它能够指定堆栈保留大小。 不过,ConvertThreadToFiberEx 非常有趣。 在原来的纤程实现中,并不在各纤程切换之间保存和还原浮点寄存器、MMX 寄存器和 SSE 寄存器来改进性能。 而新 API 允许您指定,这些寄存器也需要保存和还原。
调试 API
在调试方面,也有几个新 API。 最令人兴奋的要算是 DebugSetProcessKillOnExit。 直到现在,如果您在调试另一个进程,您没有办法停止调试。 您不能从正在调试的进程中分离。 当您调试另一个进程时,您的线程之一是调试线程,处理所有调试通知消息。 正常情况下,如果此线程终止,则被调试的进程也会终止。 DebugSetProcessKillOnExit API 改变了这种行为。 通过传递 FALSE,您可以告诉系统停止要求调试线程处理被调试进程的消息。
与该 API 有几分相似的是 DebugActiveProcessStop,它可以通知系统使指定的进程从正在调试它的进程中分离。 它只能被名为 DebugActiveProcess 或 CreateProcess 的线程调用。 由于可以认为调试器线程能同时调试多个进程,DebugActiveProcessStop 需要指示从哪个进程分离的参数。
DebugBreakProcess 就像 DebugBreak 一样,不同的是,它适用于指定的进程,而不是当前线程。 该 API 的工作方式是,在目标进程中创建一个线程,这种做法很像 CreateRemoteThread。 新创建的线程调用一个断点指令,该指令导致普通的 SEH 机制来接管工作。 对于开发人员,这通常意味着实时调试对话框会出现。
最后一个新调试 API 是 CheckRemoteDebuggerPresent。 它类似于 IsDebuggerPresent API,因为它可以告诉您某个进程是否在调试器进程的控制下运行。 IsDebuggerPresent 可以告知您的进程是否正在被调试;而 CheckRemoteDebuggerPresent 则允许查询有关您拥有其句柄的任何进程的信息。
并行执行
在 .NET 框架中,已经有不少并行安装和执行功能了。 不过,这些同样的功能也内置在 Windows Server 2003 和 Windows XP 中。 这些功能的关键之处是,新激活上下文 (ActCtx) API,如图 11
所示。
激活上下文是一组系统管理的数据结构,它们包含用于使应用程序基于清单文件使用特定 DLL 版本或 COM 对象实例的信息。 清单文件使用 XML 格式(这不足为奇!),看上去很像 .NET 清单。 关于激活上下文的使用,完全可以再写一篇文章专门进行讨论,因此我将在 SDK 文档中安排。 不过,值得注意的是,为进行并行执行,启用了某些系统 DLL,其相应的 .H 文件现在正使用激活上下文 API。 举个最好的例子,我们来研究一下 COMMCTRL.H 的最近版本。目前存在着无数其名称类似 IsolationAwareImageList_Add 这样的内联函数。这些内联函数显示了激活上下文 API 的作用。 您还会看到一些使用 C++ 宏的高明技巧,这些技巧使现有的代码无需任何改动就可以编译。
还剩下最后一个不适合归入任何其他类别的 Kernel32 API。 GetModuleHandleEx 本应该在几年前就包括在 Win32 API 中。 它所增加的关键功能是,当给定了模块内的地址时,可以查找 HMODULE。 如果您曾经编写过调试代码或诊断代码,可能遇到过这样的情况:您知道代码地址,但需要确定它来自哪个 DLL。 我们也可以使用 VirtualQuery 这种比较笨拙的方式来实现此目的,但 GetModuleHandleEx 更加简洁。
与其前身 API (GetModuleHandle) 不同,GetModuleHandleEx 影响模块的引用计数,除非您显式指定它不要这样做。 根据指定的标志,它可以递增引用计数、使之保持不变或在进程的生存期 内一直将此 DLL 定位在内存中。 GET_MODULE_HANDLE_EX_FLAG_PIN 标志解决了我萦绕于心的一个担忧。 假设您调用了 GetModuleHandle 来检索 模块句柄。 在一个多线程程序中,有可能发生这样的情况:另一个线程会在同一个地址卸载 DLL 并加载另一个 DLL。 上述这种情况可能发生在第一个线程 获得 HMODULE、但还没有开始使用它的时候。 通过在内存中定位模块,您可以确保您获得的 HMODULE 在稍后被使用时是有效的。
用户接口方面的新内容
在用户接口方面,USER32 的最大新内容就是原始输入 API。 在键盘和鼠标作为接收来自用户输入的唯一方式外,这些 API 提供了另外一种方式。 使用原始输入 API,游戏杆、麦克风或触摸屏等设备,与键盘和鼠标具有同样的作用。
在标准 Windows 输入模型中,键盘和鼠标驱动程序创建低级扫描码和移动事件。 系统接受这些低级事件,将它们转换成更高级的消息,例如,WM_CHAR 或 WM_APPCOMMAND。 虽然这种方式使输入捕获变得非常简单,但对于其他输入设备不是非常适用。
用于原始输入的新 API 如图 12 所示。 在默认情况下,应用程序不接受原始输入。 取而代之的是,您必须进行注册,通过 RegisterRawInputDevices API 接受输入,该 API 接受您感兴趣的所有设备。
当设备发生输入时,系统就向程序的消息队列发出一个 WM_INPUT 消息。 程序在无缓冲模式(一次读取一个消息)下或缓冲模式(一次读取多个消息)下读取该输入。 正如您预料的那样,有一些 API 可以枚举所有原始输入设备,查询有关它们的信息。
在 USER32 中还有其他几个我认为很有趣的新 API。(请参见图 12)。 PrintWindow API 将指定的 HWND 的内容复制到指定的设备上下文 (DC)。 IsGUIThread 返回(也可以设置)一个值,该值可确定调用线程是否为 GUI 线程,这意味着该线程已调入 Win32K.SYS,有更大的内核模式堆栈。 BroadcastSystemMessageEx 类似 BroadcastSystemMessage,不同的是,它返回有关已拒绝请求的窗口的更多信息。
虽然文本服务框架 (TSF) 是作为早期操作系统的可重新发布版提供的,但它是第一次随 Windows Server 2003 和 Windows XP 一起出现。 文本服务框架是一个可扩展的系统,它可以用一种独立于输入/输出设备的方式读取和写入文本。 TSF 最擅长的访问方式是,允许应用程序从诸如笔或麦克风这样的设备接受文本输入。
每个不同类型的文本输入/输出设备都是一个“文本服务”。 文本服务和应用程序之间是 TSF 管理器。 如果用数据库来比喻,每个文本服务就像一个 ODBC 驱动程序,TSF 管理器则扮演着 ODBC 管理器的角色。 TSF 由几个 API 和许许多多接口组成。 如果要讨论这个话题,即使不需要一本书,也得占用文章的所有篇幅 — 因此我不打算在这里进一步说明。
近年来,Microsoft 以一种更图形化的表达方式,使 GDI 变得友好,面向对象。 当然,诸如 MFC 这样的应用程序框架已经朝着这个方向努力好几年了,但新的 GDI+ API 是核心操作系统的一部分,您无需再引入应用程序框架的所有那些概念。 大体上来说,GDI+ 功能可以分为以下四类: 二维矢量图形(直线和曲线)、图像处理(位图)、版式(文本显示)和矩阵变换。
虽然 GDI+ API 从技术上来说就像任何其他 Win32 API 一样,但您不可能直接调用它们(至少是从 C++ 代码)。 而 Platform SDK 则有一组定义了大约 40 个 C++ 类的头文件(例如,头文件名为 GDIPlus.H)。 这些类中比较典型的有 Bitmap、Font 和 Region。 这些类的方法通常是调用 GDIPlus.DLL 中的基础 API 的内联函数。
下面是 GDIPlus 类在 C++ 代码中的典型使用示例: VOID OnPaint(HDC hdc) { Graphics graphics(hdc); Pen pen(Color(255, 0, 0, 255)); graphics.DrawLine(&pen, 0, 0, 200, 100); } 注意,代码中没有 BeginPaint/EndPaint 这样麻烦的过程。 一切都是面向对象的。 Graphics 对象是相当于设备上下文句柄 (HDC) 的 GDI+。 Pen 对象为您负责基础 GDI 笔的创建和析构。
了解 GDI+ 的最佳方法是,浏览 GDIPlus.H 以及它引用的文件。 要使用 GDI+,您需要在源文件中加入 #include GDIPlus.H,然后将 GDIPlus.lib 文件添加到链接器行。 要注意的是,GDIPlus.DLL 是并行启用的。 因此,您不会在 \windows\system32 目录中找到它。 相反,您会在 \windows\winsxs\ 下的各子目录中看到它的各种版本。
新公开的接口
Microsoft 最近公开了 Windows 2000 或更早期的操作系统中就已出现的几百个 API 和 COM 接口。 您可以访问 Settlement Program Interfaces 找到这些 API。 虽然它们在技术上不是新内容,但现在有了公开的文档,因此您可以放心地在 Windows XP 和更高版本的操作系统中调用它们。 坦率地说,当我看到这些 API 时,我认为除了几个以外,确实没有什么新鲜的东西。 当您以挑剔的眼光研究这些 API 之后,您会发现,它们大多数都是在完善现有的 API 集合而已。 此外,该列表中的一些 API 已经公开过了,但这次增加了新的细节。
到目前为止,最大的 API 子集要算是 SHELL32 库。 里面大约包括了 110 个 API,但从名称来看,许多 API 的使用非常有限。 比如说,有人用过 CDefFolderMenu_Create2 吗? 不过,令人高兴的是,超过 20 个的新 COM 接口公开了,包括 IMenuBand、IShellItem 和 IShellTaskScheduler。
新公开的 API 还有一些与密码有关的新函数。 WININET.DLL 有五个新 API,大多数都与代理支持有关。 DirectShow 功能增加了 12 个左右的新 API。 最后,其中有些 API,如 NtQuerySystemTime 和 RtlUnwind,在前面提到的 WINTERNL.H 文件中介绍过了。
Windows 错误报告
一个新 DLL 只有两个导出的 API? 这就是 Windows 错误报告 API 涉及的内容。 近几年来,您可能已经注意到,Microsoft 已经做了大量工作,尽量减少应用程序错误带给普通用户的困扰。 例如,从 Windows XP 开始,当程序遇到一个未处理的异常时,会弹出一个对话框,询问您是否希望将报告发送给 Microsoft。 利用新的错误报告 API,应用程序可以在这点上更好地与系统集成。
第一个 API 是 ReportFault,在利用 try 块捕获自己的异常应用程序中使用该 API。 该 API 将应用程序绑定到系统的错误报告机制。 ReportFault 采用 EXCEPTION_POINTERS 结构作为参数。 调用 ReportFault 后导致的系统操作与没有捕获异常的情况下发生的系统操作是一样的。 ReportFault 的返回值是一个指示系统做了什么的代码。 例如,返回代码 frrvLaunchDebugger 指示,启动了调试器来连接程序。
第二个 API 是 AddERExcludedApplication,该 API 阻止系统报告有关指定的可执行文件的错误。 例如,如果调用该 API 时传递字符串 foo.exe,则调用 foo.exe 的任何程序如果出现未处理的异常,都不会报告。 AddERExcludedApplication 的参数应该只是一个简单的 EXE 名称,没有任何路径信息。
ADVAPI32
由于 Microsoft 非常重视安全问题,那么新增了一组被称为凭据 API 的接口也就不足为奇了。 这些 API 获取和管理诸如用户名和密码这样的信息。 它们可以请求 Windows XP 帐户信息,以代替登录时建立的凭据来使用。 这种请求通常发生在登录凭据没有应用程序所需的权限的情况下。
图 13显示了凭据 API,它们来自新 WINCRED.H 文件。 为了说明某个基本功能,我编写了 Credential 程序,该程序枚举所有当前凭据并显示每个凭据的基本信息(请参见图 14
)。 请试着在您的系统上运行该程序。 您可能会对看到的结果感到惊讶。
ADVAPI32 中的另一组新安全 API 是 safer API。 这些 API 旨在使启动其他程序的程序可以很容易地查询安全策略,以便在启动可执行文件之前获得批准。 此功能不仅限于可执行文件,因为还可以验证其他种类的活动内容,如脚本。 这些 API 对于处理电子邮件附件尤其有用。 图 15
显示了 safer API,它们是在 WinSafer.H 中定义的。现在的情况是,在有关如何使用函数的实际示例中,缺少这些 API 的内容。
ADVAPI32 还新增了几个事件跟踪 API(请参见图 15
)。 事件跟踪是在 Windows 2000 中引入的。正如您预想的那样,TraceMessage 将事件发送到指定的跟踪会话。 TraceMessageVA 在本质上是相同的 API,不同的是,它接受数量可变的参数。 EnumerateTraceGUIDs 返回有关系统的事件跟踪提供程序的信息,而您从名称就可以看出 FlushTrace 的功能。
OLE 已经过时
过去,OLE32 和 OLEAUT32 DLL 一直是新 API 和接口的温床。 自从 Windows 2000 推出以来,由于将重心放在 .NET 框架上,它的速度大大降低了。 CoRegisterInitializeSpy 是一个似乎很有趣的新 API。 您提供类型 IInitializeSpy 的接口实现,其方法在注册 spy 的线程上的 CoInitialize(Ex) 和 CoUninitialize 之前和之后调用。
CoGetContextToken API 返回当前上下文的 IObjContext。 令我们感兴趣的原因主要是,该值存储在 TEB 中的 ReservedForOle 字段中,它最后记录在 WINTERNL.H 中。
CoFreeUnusedLibrariesEx 函数类似其前身函数,它增加的功能是,立即释放未使用的库,而不是在默认情况下等待 10 分钟。 最后,新的 CoInvalidateRemoteMachineBindings API 通知 OLE 服务控制管理器刷新所指定计算机的任何缓存远程过程调用的绑定句柄。 除了这几个 API,OLE 中没有什么其他新内容了,OLEAUT32 也是一样。
群集
群集 API 有少量值得一提的新函数。 群集就是使用一个以上的物理资源向外界表示一个逻辑资源、从而使资源(例如,应用程序、硬盘和文件共享)保持高度可用的能力。 新的群集 API 中大多数是我所说的 "EnumCount" 子集。 简单地说,群集对象可分为五种类型: Group、Network、Node、Resource 和 Resource Type。 这些对象可以通过基于句柄的 API 来枚举。 这里提到的新 API(例如,ClusterNodeGetEnumCount)返回枚举句柄表示的对象的数量。
其余两个新 API 是 EvictClusterNodeEx 和 SetClusterServiceAccountPassword。 EvictClusterNodeEx 类似其前身函数,但增加了超时功能。 SetClusterServiceAccountPassword 可更改所有在线节点上的群集服务用户帐户的密码。
实时客户端 API
实时客户端 (RTC) API 有一个很大气的名称,但并没有真实地反映出它的功能。 虽然 RTC API 包括相当多的功能,但我发现很容易将它主要视为即时消息 (IM) API。 有关文档已经大致描述了它的作用,然而我一定要在这里转述一下:
利用 RTC 客户端 API,您能构建可发出 PC 到 PC 的呼叫、PC 到电话的呼叫或电话到电话的呼叫,或在 Internet 上创建 IM 会话的应用程序。 语音呼叫和视频呼叫都可以在 PC 到 PC 的呼叫上建立。 它还支持联系人列表上的“存在”信息。 另外,可以添加应用程序共享和白板,以增强任何会话类型的通信能力。
那么,RTC API 究竟是什么样子呢? 它是基于 COM 的,所以不用感到惊讶。 用于与 RTC API 协同工作的根接口是 IRTCClient,您可以使用 CoCreateInstance 获得该接口。 从该接口可以创建(或提供)其他接口,例如,IRTCSession、IRTCParticipant、IRTCBuddy 和 IRTCProfile 等等。 加在一起,共有二十四个以上的 RTC 接口。 如果您有具体的倾向,可以使用 RTC 接口创建自己的自定义即时消息客户端。
小结
就上述内容来看,很明显,Windows Server 2003 相比 Windows 2000 有了很大的改进。我一向将工作重点放在用户模式的编程 API,但在后台还有性能和可靠性方面的重大变动和新增内容。 就我个人来说,我非常兴奋地看到,向量化异常处理、并行执行以及对调试符号更好的支持等功能,都在朝着 Windows 的方向发展。
我们都知道: Windows XP 是 Microsoft 推出的最新客户端操作系统。 由于 Windows Server 2003 在各方面都涵盖了 Windows XP,您至少可以考虑使用 Windows XP 提供的新 API。 就个人来说,我在自己的一些机器上运行 Windows XP,在其他机器上运行 Windows Server 2003,在日常工作方面,我看不出它们有什么区别。 我希望您着眼于未来,自己努力探索 Windows Server 2003 中的奥秘。
Matt Pietrek 是一位软件架构师兼作家。 他在 Compuware/NuMega 实验室担任 BoundsChecker 和 Distributed Analyzer 产品的首席 架构师。 他已经出版了三本有关 Windows 系统编程的书,并且是 MSDN Magazine 的特约编辑。 您可以访问他的个人 Web 站点 (http://www.wheaty.net),了解有关以前文章和专栏的常见问题解答和其他信息