我使用MsiDatabaseOpenView
打开MSI数据库视图,然后调用MsiViewExecute
。那么,即使我确实致电MsiViewClose
,也需要打电话给MsiCloseHandle
吗? MsiCloseHandle
不会调用MsiViewClose
(或做一些事情来在内部关闭所有必需的句柄)吗?
我问这个的实际原因:
建议使用类PMSIHANDLE
而不是手动关闭句柄(析构函数将调用MsiCloseHandle
-在VS中可见的源代码)。因此,当我使用MsiDatabaseOpenView
打开视图并将句柄包裹在PMSIHANDLE
中时,我不必调用MsiCloseHandle
,但是必须(?)调用MsiViewClose
!?>
答案 0 :(得分:3)
MsiViewClose()
不需要关闭手柄。仅当您要在同一视图上再次运行MsiViewExecute()
时才需要,这对于将不同的参数传递给参数化的SQL查询很有用。 documentation的备注中对此进行了说明:
必须在MsiViewExecute之前调用MsiViewClose函数 除非结果的所有行都在视图上再次调用该函数 MsiViewFetch函数已获得该设置。
在最常见的用例中,您只需要对给定视图进行一次MsiViewExecute()
调用,则无需调用MsiViewClose()
:
PMSIHANDLE pView;
UINT res = MsiDatabaseOpenViewW( hDatabase, L"SELECT * FROM `File`", &pView );
if( res == ERROR_SUCCESS )
{
res = MsiViewExecute( pView, nullptr );
}
// Destructor of PMSIHANDLE calls MsiCloseHandle()
从现代C ++的角度来看,PMSIHANDLE
的设计似乎很糟糕。首先,它无法防止意外复制句柄,否则会导致在同一句柄上两次调用MsiViewClose()
。同样,虽然隐式转换为MSIHANDLE*
很方便,但也很危险,因为它有可能不经先关闭就意外覆盖现有句柄。
以下是基于C ++ 11 std::unique_ptr
的PMSIHANDLE
的替代方法:
// A deleter for MSIHANDLE.
struct MsiHandleDeleter
{
// This alias enables us to actually store values of type MSIHANDLE in the unique_ptr
// (by default it would be MSIHANDLE*).
using pointer = MSIHANDLE;
void operator()( MSIHANDLE h ) const { if( h ) ::MsiCloseHandle( h ); }
};
// A RAII wrapper for MSI handle. The destructor automatically closes the handle, if not 0.
using UniqueMsiHandle = std::unique_ptr< MSIHANDLE, MsiHandleDeleter >;
用法示例:
UniqueMsiHandle record{ ::MsiCreateRecord( 1 ) };
::MsiRecordSetInteger( record.get(), 1, 42 );
// Destructor takes care of calling MsiCloseHandle(), just like PMSIHANDLE.
与PMSIHANDLE
相比,将其与具有MSIHANDLE*
输出参数的函数一起使用比较麻烦,但是可以通过创建与UnqiueMsiHandle
一起使用的包装函数或类来轻松地对其进行补救。 / p>
优势:
std::unique_ptr
的人都会立即理解UniqueMsiHandle
的语义。