You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
637 lines
11 KiB
637 lines
11 KiB
////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 2000-2001 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
// All rights reserved.
|
|
//
|
|
// Module Name:
|
|
//
|
|
// MSIDataLock.cpp
|
|
//
|
|
// Abstract:
|
|
//
|
|
// definitions of lock for msi handles
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "precomp.h"
|
|
#include "MSIDataLock.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// extern variables
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
extern CRITICAL_SECTION g_msi_prov_cs;
|
|
|
|
MSIHANDLE MSIDataLockBase::m_hProduct = NULL;
|
|
MSIHANDLE MSIDataLockBase::m_hDatabase = NULL;
|
|
HANDLE MSIDataLockBase::m_hOwn = NULL;
|
|
LPWSTR MSIDataLockBase::m_wszProduct = NULL;
|
|
DWORD MSIDataLockBase::m_ThreadID = 0L;
|
|
LONG MSIDataLockBase::m_lRefProduct = 0L;
|
|
LONG MSIDataLockBase::m_lRefDatabase = 0L;
|
|
BOOL MSIDataLockBase::m_bProductOwn = FALSE;
|
|
BOOL MSIDataLockBase::m_bDatabaseOwn = FALSE;
|
|
LONG MSIDataLockBase::m_lRef = 0L;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// IMPLEMENTATION
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
MSIDataLockBase::MSIDataLockBase ()
|
|
{
|
|
Initialize ();
|
|
}
|
|
|
|
MSIDataLockBase::~MSIDataLockBase ()
|
|
{
|
|
Uninitialize ();
|
|
}
|
|
|
|
BOOL MSIDataLockBase::Initialize ()
|
|
{
|
|
BOOL bResult = TRUE;
|
|
|
|
::EnterCriticalSection ( &g_msi_prov_cs );
|
|
|
|
if ( ! m_hOwn && ( m_hOwn = ::CreateEvent ( NULL, TRUE, TRUE, NULL ) ) == NULL )
|
|
{
|
|
bResult = FALSE;
|
|
}
|
|
|
|
if ( bResult )
|
|
{
|
|
m_lRef++;
|
|
}
|
|
|
|
::LeaveCriticalSection ( &g_msi_prov_cs );
|
|
|
|
return bResult;
|
|
}
|
|
|
|
void MSIDataLockBase::Uninitialize ()
|
|
{
|
|
::EnterCriticalSection ( &g_msi_prov_cs );
|
|
|
|
if ( m_lRef && ( --m_lRef == 0 ) )
|
|
{
|
|
if ( m_hOwn )
|
|
{
|
|
::CloseHandle ( m_hOwn );
|
|
m_hOwn = NULL;
|
|
}
|
|
}
|
|
|
|
::LeaveCriticalSection ( &g_msi_prov_cs );
|
|
|
|
return;
|
|
}
|
|
|
|
BOOL MSIDataLockBase::Lock ( void )
|
|
{
|
|
BOOL bResult = FALSE;
|
|
BOOL bWork = TRUE;
|
|
BOOL bSect = TRUE;
|
|
|
|
while ( bWork )
|
|
{
|
|
::EnterCriticalSection ( &g_msi_prov_cs );
|
|
|
|
// we have obtained critsec now
|
|
bSect = TRUE;
|
|
|
|
// are handles already allocated ?
|
|
if ( m_hProduct != NULL || m_hDatabase != NULL )
|
|
{
|
|
if ( ::GetCurrentThreadId () != m_ThreadID )
|
|
{
|
|
DWORD dwWaitResult = 0L;
|
|
|
|
// we have left crit sec
|
|
::LeaveCriticalSection ( &g_msi_prov_cs );
|
|
bSect = FALSE;
|
|
|
|
// wait till resource gets free again
|
|
dwWaitResult = ::WaitForSingleObject ( m_hOwn, INFINITE );
|
|
|
|
if ( dwWaitResult == WAIT_OBJECT_0 )
|
|
{
|
|
bWork = TRUE;
|
|
bResult = FALSE;
|
|
}
|
|
else
|
|
{
|
|
bWork = FALSE;
|
|
bResult = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bWork = FALSE;
|
|
bResult = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_ThreadID = ::GetCurrentThreadId ( );
|
|
|
|
bWork = FALSE;
|
|
bResult = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( bSect && ! bResult )
|
|
{
|
|
::LeaveCriticalSection ( &g_msi_prov_cs );
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
void MSIDataLockBase::Unlock ( void )
|
|
{
|
|
try
|
|
{
|
|
if ( !m_bProductOwn && !m_bDatabaseOwn )
|
|
{
|
|
m_ThreadID = 0;
|
|
::SetEvent ( m_hOwn );
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
::LeaveCriticalSection ( &g_msi_prov_cs );
|
|
throw ;
|
|
}
|
|
|
|
::LeaveCriticalSection ( &g_msi_prov_cs );
|
|
}
|
|
|
|
HRESULT MSIDataLock::OpenProductAlloc ( LPCWSTR wszProduct )
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
try
|
|
{
|
|
if ( ( m_wszProduct = new WCHAR [ lstrlenW ( wszProduct ) + 1 ] ) == NULL )
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception::E_ALLOCATION_ERROR );
|
|
}
|
|
|
|
lstrcpyW ( m_wszProduct, wszProduct );
|
|
}
|
|
catch ( ... )
|
|
{
|
|
if ( m_wszProduct )
|
|
{
|
|
delete [] m_wszProduct;
|
|
m_wszProduct = NULL;
|
|
}
|
|
|
|
throw;
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT MSIDataLock::OpenProductInternal ( LPCWSTR wszProduct )
|
|
{
|
|
HRESULT hRes = E_FAIL;
|
|
UINT uiStatus = ERROR_SUCCESS;
|
|
|
|
BOOL bAlloc = FALSE;
|
|
|
|
try
|
|
{
|
|
if ( ( uiStatus = g_fpMsiOpenProductW ( wszProduct, &m_hProduct ) ) != ERROR_SUCCESS )
|
|
{
|
|
if ( uiStatus == static_cast < UINT > ( E_OUTOFMEMORY ) )
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception::E_ALLOCATION_ERROR );
|
|
}
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
if ( m_hProduct )
|
|
{
|
|
g_fpMsiCloseHandle ( m_hProduct );
|
|
m_hProduct = NULL;
|
|
}
|
|
|
|
throw;
|
|
}
|
|
|
|
if ( uiStatus != ERROR_SUCCESS )
|
|
{
|
|
//and if that didn't work, yet another way
|
|
WCHAR * wcBuf = NULL;
|
|
DWORD dwBufsize = BUFF_SIZE;
|
|
|
|
if ( ( wcBuf = new WCHAR [ BUFF_SIZE ] ) == NULL )
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception::E_ALLOCATION_ERROR );
|
|
}
|
|
|
|
try
|
|
{
|
|
if ( ( uiStatus = g_fpMsiGetProductInfoW ( wszProduct, INSTALLPROPERTY_LOCALPACKAGE, wcBuf, &dwBufsize ) ) == ERROR_SUCCESS )
|
|
{
|
|
if ( dwBufsize > 0 )
|
|
{
|
|
uiStatus = g_fpMsiOpenPackageW ( wcBuf, &m_hProduct );
|
|
}
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
delete [] wcBuf;
|
|
throw ;
|
|
}
|
|
|
|
delete [] wcBuf;
|
|
|
|
if ( uiStatus == ERROR_SUCCESS && m_hProduct )
|
|
{
|
|
bAlloc = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( m_hProduct )
|
|
{
|
|
bAlloc = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( bAlloc )
|
|
{
|
|
try
|
|
{
|
|
hRes = OpenProductAlloc ( wszProduct );
|
|
}
|
|
catch ( ... )
|
|
{
|
|
if ( m_hProduct )
|
|
{
|
|
g_fpMsiCloseHandle ( m_hProduct );
|
|
m_hProduct = NULL;
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT MSIDataLock::OpenProduct ( LPCWSTR wszProduct )
|
|
{
|
|
HRESULT hRes = E_FAIL;
|
|
|
|
if ( ! wszProduct )
|
|
{
|
|
hRes = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
if ( Lock ( ) )
|
|
{
|
|
try
|
|
{
|
|
if ( ! m_hProduct && ! m_wszProduct )
|
|
{
|
|
hRes = OpenProductInternal ( wszProduct );
|
|
|
|
if FAILED ( hRes )
|
|
{
|
|
if ( m_wszProduct )
|
|
{
|
|
delete [] m_wszProduct;
|
|
m_wszProduct = NULL;
|
|
}
|
|
|
|
if ( m_hProduct )
|
|
{
|
|
g_fpMsiCloseHandle ( m_hProduct );
|
|
m_hProduct = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( m_hProduct && m_wszProduct && lstrcmpW ( wszProduct, m_wszProduct ) == 0 )
|
|
{
|
|
hRes = S_OK;
|
|
}
|
|
}
|
|
|
|
if SUCCEEDED ( hRes )
|
|
{
|
|
if ( m_lRefProduct == 0 )
|
|
{
|
|
m_bProductOwn = TRUE;
|
|
::ResetEvent ( m_hOwn );
|
|
}
|
|
|
|
m_lRefProduct++;
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
Unlock ( );
|
|
throw;
|
|
}
|
|
|
|
Unlock ( );
|
|
}
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT MSIDataLock::OpenDatabase ( )
|
|
{
|
|
HRESULT hRes = E_FAIL;
|
|
|
|
if ( Lock ( ) )
|
|
{
|
|
try
|
|
{
|
|
if ( m_hProduct )
|
|
{
|
|
if ( ! m_hDatabase )
|
|
{
|
|
m_hDatabase = g_fpMsiGetActiveDatabase ( m_hProduct );
|
|
|
|
if ( m_hDatabase != NULL )
|
|
{
|
|
hRes = S_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MSIHANDLE hDatabase = NULL;
|
|
hDatabase = g_fpMsiGetActiveDatabase ( m_hProduct );
|
|
|
|
if ( hDatabase != NULL )
|
|
{
|
|
if ( hDatabase == m_hDatabase )
|
|
{
|
|
g_fpMsiCloseHandle ( hDatabase );
|
|
hDatabase = NULL;
|
|
|
|
hRes = S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
if SUCCEEDED ( hRes )
|
|
{
|
|
if ( m_lRefDatabase == 0 )
|
|
{
|
|
m_bDatabaseOwn = TRUE;
|
|
::ResetEvent ( m_hOwn );
|
|
}
|
|
|
|
m_lRefDatabase++;
|
|
}
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
Unlock ( );
|
|
throw;
|
|
}
|
|
|
|
Unlock ( );
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT MSIDataLock::OpenDatabase ( LPCWSTR wszProduct )
|
|
{
|
|
HRESULT hRes = E_FAIL;
|
|
|
|
if ( Lock ( ) )
|
|
{
|
|
try
|
|
{
|
|
if SUCCEEDED ( hRes = OpenProduct ( wszProduct ) )
|
|
{
|
|
hRes = OpenDatabase ();
|
|
|
|
if FAILED ( hRes )
|
|
{
|
|
// we have to close product
|
|
CloseProduct ();
|
|
}
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
Unlock ( );
|
|
throw;
|
|
}
|
|
|
|
Unlock ( );
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT MSIDataLock::CloseProduct ()
|
|
{
|
|
HRESULT hRes = S_FALSE;
|
|
|
|
if ( Lock ( ) )
|
|
{
|
|
try
|
|
{
|
|
if ( m_hProduct && m_lRefProduct && ( --m_lRefProduct == 0 ) )
|
|
{
|
|
delete [] m_wszProduct;
|
|
m_wszProduct = NULL;
|
|
|
|
g_fpMsiCloseHandle ( m_hProduct );
|
|
m_hProduct = NULL;
|
|
m_bProductOwn = FALSE;
|
|
hRes = S_OK;
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
Unlock ( );
|
|
throw;
|
|
}
|
|
|
|
Unlock ( );
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT MSIDataLock::CloseDatabase ( )
|
|
{
|
|
HRESULT hRes = E_FAIL;
|
|
|
|
if ( Lock ( ) )
|
|
{
|
|
try
|
|
{
|
|
if ( m_hDatabase && m_lRefDatabase && ( --m_lRefDatabase == 0 ) )
|
|
{
|
|
g_fpMsiCloseHandle ( m_hDatabase );
|
|
m_hDatabase = NULL;
|
|
m_bDatabaseOwn = FALSE;
|
|
hRes = S_OK;
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
Unlock ( );
|
|
throw;
|
|
}
|
|
|
|
Unlock ( );
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT MSIDataLock::Query ( MSIHANDLE* pView, LPCWSTR wszQuery, LPCWSTR wszTable )
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
UINT uiStatus= ERROR_SUCCESS;
|
|
|
|
if ( ! pView )
|
|
{
|
|
hRes = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
( * pView ) = NULL;
|
|
|
|
if ( ! wszQuery )
|
|
{
|
|
hRes = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
if ( Lock ( ) )
|
|
{
|
|
if ( m_hDatabase )
|
|
{
|
|
try
|
|
{
|
|
if ( wszTable )
|
|
{
|
|
if ( g_fpMsiDatabaseIsTablePersistentW ( m_hDatabase, wszTable ) != MSICONDITION_TRUE )
|
|
{
|
|
hRes = E_FAIL;
|
|
}
|
|
}
|
|
|
|
if SUCCEEDED ( hRes )
|
|
{
|
|
if ( ( uiStatus = g_fpMsiDatabaseOpenViewW ( m_hDatabase, wszQuery, pView ) ) == ERROR_SUCCESS )
|
|
{
|
|
if ( g_fpMsiViewExecute ( *pView, 0 ) != ERROR_SUCCESS )
|
|
{
|
|
if ( *pView )
|
|
{
|
|
g_fpMsiCloseHandle ( *pView );
|
|
( * pView ) = NULL;
|
|
}
|
|
|
|
hRes = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( uiStatus == static_cast < UINT > ( E_OUTOFMEMORY ) )
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception::E_ALLOCATION_ERROR );
|
|
}
|
|
|
|
// what is the failure here ?
|
|
hRes = HRESULT_FROM_WIN32 ( uiStatus );
|
|
}
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
Unlock ( );
|
|
throw;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
}
|
|
|
|
Unlock ( );
|
|
}
|
|
}
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
bool MSIDataLock::GetView ( MSIHANDLE *phView,
|
|
WCHAR *wcPackage,
|
|
WCHAR *wcQuery,
|
|
WCHAR *wcTable,
|
|
BOOL bCloseProduct,
|
|
BOOL bCloseDatabase
|
|
)
|
|
{
|
|
bool bResult = false;
|
|
|
|
if ( wcPackage )
|
|
{
|
|
if ( Lock () )
|
|
{
|
|
try
|
|
{
|
|
if SUCCEEDED ( OpenDatabase ( wcPackage ) )
|
|
{
|
|
if ( phView && wcQuery )
|
|
{
|
|
if SUCCEEDED ( Query ( phView, wcQuery, wcTable ) )
|
|
{
|
|
bResult = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bResult = true;
|
|
}
|
|
|
|
if ( bCloseDatabase )
|
|
{
|
|
CloseDatabase ();
|
|
}
|
|
}
|
|
|
|
if ( bCloseProduct )
|
|
{
|
|
CloseProduct ();
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
CloseProduct ();
|
|
CloseDatabase ();
|
|
|
|
Unlock ();
|
|
|
|
throw;
|
|
}
|
|
|
|
Unlock ();
|
|
}
|
|
}
|
|
|
|
return bResult;
|
|
}
|