本港台开奖现场直播 j2开奖直播报码现场
当前位置: 新闻频道 > IT新闻 >

码报:使用新式 C++ 访问 Windows 注册表

时间:2017-07-11 15:22来源:本港台直播 作者:本港台直播 点击:
Windows OS 公开了一系列 C 接口 API,以方便开发者访问注册表。其中一些 API 的级别相当低,需要程序员注意许多细节。自 Windows Vista 起,这一大家庭又新增了一种更高级别的 API:RegG

Windows OS 公开了一系列 C 接口 API,以方便开发者访问注册表。其中一些 API 的级别相当低,需要程序员注意许多细节。自 Windows Vista 起,这一大家庭又新增了一种更高级别的 API:RegGetValue 函数 (bit.ly/2jXtfpJ)。在引入此 API 之前,若要读取注册表中的值,必须先调用 RegOpenKeyEx 来打开包含值的相应注册表项。然后,必须调用 RegQueryValueEx API,同时处理许多复杂的细节。例如,如果使用 RegQueryValueEx 读取字符串值,则不能保证返回的字符串以 NUL 正确结尾,这可能会导致代中出现一系列危险的安全 bug。为了防止这种情况发生,务必要检查返回的字符串是否以 NUL 结尾;如果不是,需要手动添加。此外,还务必要使用 RegCloseKey 正确关闭已打开的注册表项。

当然,打开注册表项可能会失败。因此,为了处理此问题,还必须添加代。RegGetValue API 简化了这一工作流,因为它会自动打开并在使用后关闭所需的注册表项,同时还会先在字符串末尾正确添加 NUL,然后再将字符串返回给调用方。虽然进行了这样的简化,但 RegGetValue 函数仍是低级别 C 接口函数;此外,该函数实际上可以处理多种不同类型的注册表值(包括 DWORD、字符串和二进制数据),因此接口编程起来十分复杂。

万幸的是,可以使用新式 C++ 在此 RegGetValue Win32 API 基础之上正确生成更高级别的抽象,提供一个用于读取注册表中不同类型值的简便接口。

使用异常表示错误

RegGetValue API 是 C 接口 API,因此会使用返回代码向调用方指明错误条件。特别是,此函数返回 LONG 类型的值: 如果成功,返回 ERROR_SUCCESS(即值为零);如果出错,返回其他值。例如,如果调用方提供的输出缓冲区不够大,导致 API 无法写入数据,此函数返回 ERROR_MORE_DATA。为了在此 C API 基础之上生成更高级别的 C++ 接口,可以定义用于表示错误的 C++ 异常类。此类可以派生自标准的 std::runtime_error 类,能够在其中嵌入 RegGetValue 返回的 LONG 错误代码:

classRegistryError : publicstd::runtime_error{ public: ... private: LONG m_errorCode;};

此外,还可以在异常对象中嵌入其他信息;例如,HKEY 和子项的名称。这就是基本实现代码。

可以添加构造函数,使用失败的 RegGetValue 调用生成的错误消息和返回代码创建此异常类的实例:

RegistryError( constchar* message, LONG errorCode) : std::runtime_error{message} , m_errorCode{errorCode}{}

可以向使用只读取值函数 (getter) 的客户端公开错误代码:

LONG ErrorCode() constnoexcept{ returnm_errorCode;}

至此,你已生成此异常类,可以继续将 RegGetValue C API 包装在更高级别的 C++ 接口中,此接口不仅更易于使用,还能减少出错。

读取注册表中的 DWORD 值

让我们从下面的简单操作入手:使用 RegGetValue API 读取注册表中的 DWORD 值。此示例中的使用模式相当简单。但首先,让我们看看可以在 C++ 中定义什么类型的接口来管理这种情况。

下面是 RegGetValue API 原型:

LONG WINAPI RegGetValue( _In_ HKEY hkey, _In_opt_ LPCTSTR lpSubKey, _In_opt_ LPCTSTR lpValue, _In_opt_ DWORD dwFlags, _Out_opt_ LPDWORD pdwType, _Out_opt_ PVOID pvData, _Inout_opt_ LPDWORD pcbData);

如你所见,此 C 接口函数需要使用高度泛型数据,如 void* 输出缓冲区 (pvData) 和输入/输出缓冲区大小参数 (pcbData)。此外,还有标识注册表项及其下特定值名称的 C 样式字符串(lpSubKey 和 lpValue)。可以略微调整一下此 C 函数原型,使其更易于 C++ 调用方使用。

首先,由于要指明抛出 C++ 异常的错误条件,C++ 包装器可以直接以返回值的形式返回从注册表中读取的 DWORD 值。这样一来,便自动无需使用原始 void* 输出缓冲区参数 (pvData) 和相关大小参数 (pcbData)。

此外,由于要使用 C++,最好使用 std::wstring 类(而不是 C 样式的原始指针)表示 Unicode (UTF-16) 字符串。所以,可以定义更为简单的 C++ 函数,从而读取注册表中的 DWORD 值:

DWORD RegGetDword( HKEY hKey, conststd::wstring& subKey, conststd::wstring& value)

如你所见,其中没有 PVOID 和 LPDWORD 参数;输入字符串通过常量引用传递到 std::wstring 对象,从注册表中读取的值则以 DWORD 的形式由此 C++ 函数返回。这绝对是一个更简单的更高级别接口。

(责任编辑:本港台直播)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
栏目列表
推荐内容