1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2002-2004 Mike McCormack for CodeWeavers 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #define COBJMACROS 22 23 #include <stdarg.h> 24 25 #include "windef.h" 26 #include "winbase.h" 27 #include "winreg.h" 28 #include "shlwapi.h" 29 #include "wine/debug.h" 30 #include "msi.h" 31 #include "msiquery.h" 32 #include "msipriv.h" 33 34 WINE_DEFAULT_DEBUG_CHANNEL(msi); 35 36 static CRITICAL_SECTION MSI_handle_cs; 37 static CRITICAL_SECTION_DEBUG MSI_handle_cs_debug = 38 { 39 0, 0, &MSI_handle_cs, 40 { &MSI_handle_cs_debug.ProcessLocksList, 41 &MSI_handle_cs_debug.ProcessLocksList }, 42 0, 0, { (DWORD_PTR)(__FILE__ ": MSI_handle_cs") } 43 }; 44 static CRITICAL_SECTION MSI_handle_cs = { &MSI_handle_cs_debug, -1, 0, 0, 0, 0 }; 45 46 static CRITICAL_SECTION MSI_object_cs; 47 static CRITICAL_SECTION_DEBUG MSI_object_cs_debug = 48 { 49 0, 0, &MSI_object_cs, 50 { &MSI_object_cs_debug.ProcessLocksList, 51 &MSI_object_cs_debug.ProcessLocksList }, 52 0, 0, { (DWORD_PTR)(__FILE__ ": MSI_object_cs") } 53 }; 54 static CRITICAL_SECTION MSI_object_cs = { &MSI_object_cs_debug, -1, 0, 0, 0, 0 }; 55 56 typedef struct msi_handle_info_t 57 { 58 BOOL remote; 59 union { 60 MSIOBJECTHDR *obj; 61 IUnknown *unk; 62 } u; 63 DWORD dwThreadId; 64 } msi_handle_info; 65 66 static msi_handle_info *msihandletable = NULL; 67 static unsigned int msihandletable_size = 0; 68 69 void msi_free_handle_table(void) 70 { 71 msi_free( msihandletable ); 72 msihandletable = NULL; 73 msihandletable_size = 0; 74 DeleteCriticalSection(&MSI_handle_cs); 75 DeleteCriticalSection(&MSI_object_cs); 76 } 77 78 static MSIHANDLE alloc_handle_table_entry(void) 79 { 80 UINT i; 81 82 /* find a slot */ 83 for(i=0; i<msihandletable_size; i++) 84 if( !msihandletable[i].u.obj && !msihandletable[i].u.unk ) 85 break; 86 if( i==msihandletable_size ) 87 { 88 msi_handle_info *p; 89 int newsize; 90 if (msihandletable_size == 0) 91 { 92 newsize = 256; 93 p = msi_alloc_zero(newsize*sizeof(msi_handle_info)); 94 } 95 else 96 { 97 newsize = msihandletable_size * 2; 98 p = msi_realloc_zero(msihandletable, 99 newsize*sizeof(msi_handle_info)); 100 } 101 if (!p) 102 return 0; 103 msihandletable = p; 104 msihandletable_size = newsize; 105 } 106 return i + 1; 107 } 108 109 MSIHANDLE alloc_msihandle( MSIOBJECTHDR *obj ) 110 { 111 msi_handle_info *entry; 112 MSIHANDLE ret; 113 114 EnterCriticalSection( &MSI_handle_cs ); 115 116 ret = alloc_handle_table_entry(); 117 if (ret) 118 { 119 entry = &msihandletable[ ret - 1 ]; 120 msiobj_addref( obj ); 121 entry->u.obj = obj; 122 entry->dwThreadId = GetCurrentThreadId(); 123 entry->remote = FALSE; 124 } 125 126 LeaveCriticalSection( &MSI_handle_cs ); 127 128 TRACE("%p -> %d\n", obj, ret ); 129 130 return ret; 131 } 132 133 MSIHANDLE alloc_msi_remote_handle( IUnknown *unk ) 134 { 135 msi_handle_info *entry; 136 MSIHANDLE ret; 137 138 EnterCriticalSection( &MSI_handle_cs ); 139 140 ret = alloc_handle_table_entry(); 141 if (ret) 142 { 143 entry = &msihandletable[ ret - 1 ]; 144 IUnknown_AddRef( unk ); 145 entry->u.unk = unk; 146 entry->dwThreadId = GetCurrentThreadId(); 147 entry->remote = TRUE; 148 } 149 150 LeaveCriticalSection( &MSI_handle_cs ); 151 152 TRACE("%p -> %d\n", unk, ret); 153 154 return ret; 155 } 156 157 void *msihandle2msiinfo(MSIHANDLE handle, UINT type) 158 { 159 MSIOBJECTHDR *ret = NULL; 160 161 EnterCriticalSection( &MSI_handle_cs ); 162 handle--; 163 if( handle >= msihandletable_size ) 164 goto out; 165 if( msihandletable[handle].remote) 166 goto out; 167 if( !msihandletable[handle].u.obj ) 168 goto out; 169 if( msihandletable[handle].u.obj->magic != MSIHANDLE_MAGIC ) 170 goto out; 171 if( type && (msihandletable[handle].u.obj->type != type) ) 172 goto out; 173 ret = msihandletable[handle].u.obj; 174 msiobj_addref( ret ); 175 176 out: 177 LeaveCriticalSection( &MSI_handle_cs ); 178 179 return ret; 180 } 181 182 IUnknown *msi_get_remote( MSIHANDLE handle ) 183 { 184 IUnknown *unk = NULL; 185 186 EnterCriticalSection( &MSI_handle_cs ); 187 handle--; 188 if( handle>=msihandletable_size ) 189 goto out; 190 if( !msihandletable[handle].remote) 191 goto out; 192 unk = msihandletable[handle].u.unk; 193 if( unk ) 194 IUnknown_AddRef( unk ); 195 196 out: 197 LeaveCriticalSection( &MSI_handle_cs ); 198 199 return unk; 200 } 201 202 void *alloc_msiobject(UINT type, UINT size, msihandledestructor destroy ) 203 { 204 MSIOBJECTHDR *info; 205 206 info = msi_alloc_zero( size ); 207 if( info ) 208 { 209 info->magic = MSIHANDLE_MAGIC; 210 info->type = type; 211 info->refcount = 1; 212 info->destructor = destroy; 213 } 214 215 return info; 216 } 217 218 void msiobj_addref( MSIOBJECTHDR *info ) 219 { 220 if( !info ) 221 return; 222 223 if( info->magic != MSIHANDLE_MAGIC ) 224 { 225 ERR("Invalid handle!\n"); 226 return; 227 } 228 229 InterlockedIncrement(&info->refcount); 230 } 231 232 void msiobj_lock( MSIOBJECTHDR *info ) 233 { 234 EnterCriticalSection( &MSI_object_cs ); 235 } 236 237 void msiobj_unlock( MSIOBJECTHDR *info ) 238 { 239 LeaveCriticalSection( &MSI_object_cs ); 240 } 241 242 int msiobj_release( MSIOBJECTHDR *info ) 243 { 244 int ret; 245 246 if( !info ) 247 return -1; 248 249 if( info->magic != MSIHANDLE_MAGIC ) 250 { 251 ERR("Invalid handle!\n"); 252 return -1; 253 } 254 255 ret = InterlockedDecrement( &info->refcount ); 256 if( ret==0 ) 257 { 258 if( info->destructor ) 259 info->destructor( info ); 260 msi_free( info ); 261 TRACE("object %p destroyed\n", info); 262 } 263 264 return ret; 265 } 266 267 /*********************************************************** 268 * MsiCloseHandle [MSI.@] 269 */ 270 UINT WINAPI MsiCloseHandle(MSIHANDLE handle) 271 { 272 MSIOBJECTHDR *info = NULL; 273 UINT ret = ERROR_INVALID_HANDLE; 274 275 TRACE("%x\n",handle); 276 277 if (!handle) 278 return ERROR_SUCCESS; 279 280 EnterCriticalSection( &MSI_handle_cs ); 281 282 handle--; 283 if (handle >= msihandletable_size) 284 goto out; 285 286 if (msihandletable[handle].remote) 287 { 288 IUnknown_Release( msihandletable[handle].u.unk ); 289 } 290 else 291 { 292 info = msihandletable[handle].u.obj; 293 if( !info ) 294 goto out; 295 296 if( info->magic != MSIHANDLE_MAGIC ) 297 { 298 ERR("Invalid handle!\n"); 299 goto out; 300 } 301 } 302 303 msihandletable[handle].u.obj = NULL; 304 msihandletable[handle].remote = 0; 305 msihandletable[handle].dwThreadId = 0; 306 307 ret = ERROR_SUCCESS; 308 309 TRACE("handle %x destroyed\n", handle+1); 310 out: 311 LeaveCriticalSection( &MSI_handle_cs ); 312 if( info ) 313 msiobj_release( info ); 314 315 return ret; 316 } 317 318 /*********************************************************** 319 * MsiCloseAllHandles [MSI.@] 320 * 321 * Closes all handles owned by the current thread 322 * 323 * RETURNS: 324 * The number of handles closed 325 */ 326 UINT WINAPI MsiCloseAllHandles(void) 327 { 328 UINT i, n=0; 329 330 TRACE("\n"); 331 332 EnterCriticalSection( &MSI_handle_cs ); 333 for(i=0; i<msihandletable_size; i++) 334 { 335 if(msihandletable[i].dwThreadId == GetCurrentThreadId()) 336 { 337 LeaveCriticalSection( &MSI_handle_cs ); 338 MsiCloseHandle( i+1 ); 339 EnterCriticalSection( &MSI_handle_cs ); 340 n++; 341 } 342 } 343 LeaveCriticalSection( &MSI_handle_cs ); 344 345 return n; 346 } 347