summaryrefslogtreecommitdiffstats
path: root/libmsi/handle.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmsi/handle.c')
-rw-r--r--libmsi/handle.c346
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;
+}