Ответ
MsiViewClose()
не требуется для закрытия ручки.Это необходимо, только если вы хотите снова запустить MsiViewExecute()
в том же представлении, что может быть полезно для передачи различных параметров в параметризованный запрос SQL.Это указано в комментариях к документации :
Функция MsiViewClose должна быть вызвана до повторного вызова функции MsiViewExecute в представлении, если только все строки набора результатов не имеютбыло получено с помощью функции 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*
может быть удобным, оно также опасно, поскольку позволяет случайно перезаписать существующий дескриптор, не закрывая его вначале.
Вот альтернатива PMSIHANDLE
на основеC ++ 11s std::unique_ptr
:
// 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
.
Преимущества:
- Меньше способов сделать что-то неправильно.
- Очистить владение и Подвижность .
- Каждый, кто привык к
std::unique_ptr
, сразу поймет семантику UniqueMsiHandle
.