diff options
Diffstat (limited to 'libmsi/handle.c')
-rw-r--r-- | libmsi/handle.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/libmsi/handle.c b/libmsi/handle.c new file mode 100644 index 0000000..80c6873 --- /dev/null +++ b/libmsi/handle.c @@ -0,0 +1,346 @@ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002-2004 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "shlwapi.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "msipriv.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +static CRITICAL_SECTION MSI_handle_cs; +static CRITICAL_SECTION_DEBUG MSI_handle_cs_debug = +{ + 0, 0, &MSI_handle_cs, + { &MSI_handle_cs_debug.ProcessLocksList, + &MSI_handle_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": MSI_handle_cs") } +}; +static CRITICAL_SECTION MSI_handle_cs = { &MSI_handle_cs_debug, -1, 0, 0, 0, 0 }; + +static CRITICAL_SECTION MSI_object_cs; +static CRITICAL_SECTION_DEBUG MSI_object_cs_debug = +{ + 0, 0, &MSI_object_cs, + { &MSI_object_cs_debug.ProcessLocksList, + &MSI_object_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": MSI_object_cs") } +}; +static CRITICAL_SECTION MSI_object_cs = { &MSI_object_cs_debug, -1, 0, 0, 0, 0 }; + +typedef struct msi_handle_info_t +{ + BOOL remote; + union { + MSIOBJECTHDR *obj; + IUnknown *unk; + } u; + DWORD dwThreadId; +} msi_handle_info; + +static msi_handle_info *msihandletable = NULL; +static unsigned int msihandletable_size = 0; + +void msi_free_handle_table(void) +{ + msi_free( msihandletable ); + msihandletable = NULL; + msihandletable_size = 0; + DeleteCriticalSection(&MSI_handle_cs); + DeleteCriticalSection(&MSI_object_cs); +} + +static MSIHANDLE alloc_handle_table_entry(void) +{ + UINT i; + + /* find a slot */ + for(i=0; i<msihandletable_size; i++) + if( !msihandletable[i].u.obj && !msihandletable[i].u.unk ) + break; + if( i==msihandletable_size ) + { + msi_handle_info *p; + int newsize; + if (msihandletable_size == 0) + { + newsize = 256; + p = msi_alloc_zero(newsize*sizeof(msi_handle_info)); + } + else + { + newsize = msihandletable_size * 2; + p = msi_realloc_zero(msihandletable, + newsize*sizeof(msi_handle_info)); + } + if (!p) + return 0; + msihandletable = p; + msihandletable_size = newsize; + } + return i + 1; +} + +MSIHANDLE alloc_msihandle( MSIOBJECTHDR *obj ) +{ + msi_handle_info *entry; + MSIHANDLE ret; + + EnterCriticalSection( &MSI_handle_cs ); + + ret = alloc_handle_table_entry(); + if (ret) + { + entry = &msihandletable[ ret - 1 ]; + msiobj_addref( obj ); + entry->u.obj = obj; + entry->dwThreadId = GetCurrentThreadId(); + entry->remote = FALSE; + } + + LeaveCriticalSection( &MSI_handle_cs ); + + TRACE("%p -> %d\n", obj, ret ); + + return ret; +} + +MSIHANDLE alloc_msi_remote_handle( IUnknown *unk ) +{ + msi_handle_info *entry; + MSIHANDLE ret; + + EnterCriticalSection( &MSI_handle_cs ); + + ret = alloc_handle_table_entry(); + if (ret) + { + entry = &msihandletable[ ret - 1 ]; + IUnknown_AddRef( unk ); + entry->u.unk = unk; + entry->dwThreadId = GetCurrentThreadId(); + entry->remote = TRUE; + } + + LeaveCriticalSection( &MSI_handle_cs ); + + TRACE("%p -> %d\n", unk, ret); + + return ret; +} + +void *msihandle2msiinfo(MSIHANDLE handle, UINT type) +{ + MSIOBJECTHDR *ret = NULL; + + EnterCriticalSection( &MSI_handle_cs ); + handle--; + if( handle >= msihandletable_size ) + goto out; + if( msihandletable[handle].remote) + goto out; + if( !msihandletable[handle].u.obj ) + goto out; + if( msihandletable[handle].u.obj->magic != MSIHANDLE_MAGIC ) + goto out; + if( type && (msihandletable[handle].u.obj->type != type) ) + goto out; + ret = msihandletable[handle].u.obj; + msiobj_addref( ret ); + +out: + LeaveCriticalSection( &MSI_handle_cs ); + + return ret; +} + +IUnknown *msi_get_remote( MSIHANDLE handle ) +{ + IUnknown *unk = NULL; + + EnterCriticalSection( &MSI_handle_cs ); + handle--; + if( handle>=msihandletable_size ) + goto out; + if( !msihandletable[handle].remote) + goto out; + unk = msihandletable[handle].u.unk; + if( unk ) + IUnknown_AddRef( unk ); + +out: + LeaveCriticalSection( &MSI_handle_cs ); + + return unk; +} + +void *alloc_msiobject(UINT type, UINT size, msihandledestructor destroy ) +{ + MSIOBJECTHDR *info; + + info = msi_alloc_zero( size ); + if( info ) + { + info->magic = MSIHANDLE_MAGIC; + info->type = type; + info->refcount = 1; + info->destructor = destroy; + } + + return info; +} + +void msiobj_addref( MSIOBJECTHDR *info ) +{ + if( !info ) + return; + + if( info->magic != MSIHANDLE_MAGIC ) + { + ERR("Invalid handle!\n"); + return; + } + + InterlockedIncrement(&info->refcount); +} + +void msiobj_lock( MSIOBJECTHDR *info ) +{ + EnterCriticalSection( &MSI_object_cs ); +} + +void msiobj_unlock( MSIOBJECTHDR *info ) +{ + LeaveCriticalSection( &MSI_object_cs ); +} + +int msiobj_release( MSIOBJECTHDR *info ) +{ + int ret; + + if( !info ) + return -1; + + if( info->magic != MSIHANDLE_MAGIC ) + { + ERR("Invalid handle!\n"); + return -1; + } + + ret = InterlockedDecrement( &info->refcount ); + if( ret==0 ) + { + if( info->destructor ) + info->destructor( info ); + msi_free( info ); + TRACE("object %p destroyed\n", info); + } + + return ret; +} + +/*********************************************************** + * MsiCloseHandle [MSI.@] + */ +UINT WINAPI MsiCloseHandle(MSIHANDLE handle) +{ + MSIOBJECTHDR *info = NULL; + UINT ret = ERROR_INVALID_HANDLE; + + TRACE("%x\n",handle); + + if (!handle) + return ERROR_SUCCESS; + + EnterCriticalSection( &MSI_handle_cs ); + + handle--; + if (handle >= msihandletable_size) + goto out; + + if (msihandletable[handle].remote) + { + IUnknown_Release( msihandletable[handle].u.unk ); + } + else + { + info = msihandletable[handle].u.obj; + if( !info ) + goto out; + + if( info->magic != MSIHANDLE_MAGIC ) + { + ERR("Invalid handle!\n"); + goto out; + } + } + + msihandletable[handle].u.obj = NULL; + msihandletable[handle].remote = 0; + msihandletable[handle].dwThreadId = 0; + + ret = ERROR_SUCCESS; + + TRACE("handle %x destroyed\n", handle+1); +out: + LeaveCriticalSection( &MSI_handle_cs ); + if( info ) + msiobj_release( info ); + + return ret; +} + +/*********************************************************** + * MsiCloseAllHandles [MSI.@] + * + * Closes all handles owned by the current thread + * + * RETURNS: + * The number of handles closed + */ +UINT WINAPI MsiCloseAllHandles(void) +{ + UINT i, n=0; + + TRACE("\n"); + + EnterCriticalSection( &MSI_handle_cs ); + for(i=0; i<msihandletable_size; i++) + { + if(msihandletable[i].dwThreadId == GetCurrentThreadId()) + { + LeaveCriticalSection( &MSI_handle_cs ); + MsiCloseHandle( i+1 ); + EnterCriticalSection( &MSI_handle_cs ); + n++; + } + } + LeaveCriticalSection( &MSI_handle_cs ); + + return n; +} |