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 33 #include "msipriv.h" 34 #include "winemsi_s.h" 35 36 WINE_DEFAULT_DEBUG_CHANNEL(msi); 37 38 static CRITICAL_SECTION MSI_handle_cs; 39 static CRITICAL_SECTION_DEBUG MSI_handle_cs_debug = 40 { 41 0, 0, &MSI_handle_cs, 42 { &MSI_handle_cs_debug.ProcessLocksList, 43 &MSI_handle_cs_debug.ProcessLocksList }, 44 0, 0, { (DWORD_PTR)(__FILE__ ": MSI_handle_cs") } 45 }; 46 static CRITICAL_SECTION MSI_handle_cs = { &MSI_handle_cs_debug, -1, 0, 0, 0, 0 }; 47 48 static CRITICAL_SECTION MSI_object_cs; 49 static CRITICAL_SECTION_DEBUG MSI_object_cs_debug = 50 { 51 0, 0, &MSI_object_cs, 52 { &MSI_object_cs_debug.ProcessLocksList, 53 &MSI_object_cs_debug.ProcessLocksList }, 54 0, 0, { (DWORD_PTR)(__FILE__ ": MSI_object_cs") } 55 }; 56 static CRITICAL_SECTION MSI_object_cs = { &MSI_object_cs_debug, -1, 0, 0, 0, 0 }; 57 58 typedef struct msi_handle_info_t 59 { 60 BOOL remote; 61 union { 62 MSIOBJECTHDR *obj; 63 MSIHANDLE rem; 64 } u; 65 DWORD dwThreadId; 66 } msi_handle_info; 67 68 static msi_handle_info *msihandletable = NULL; 69 static unsigned int msihandletable_size = 0; 70 71 void msi_free_handle_table(void) 72 { 73 msi_free( msihandletable ); 74 msihandletable = NULL; 75 msihandletable_size = 0; 76 DeleteCriticalSection(&MSI_handle_cs); 77 DeleteCriticalSection(&MSI_object_cs); 78 } 79 80 static MSIHANDLE alloc_handle_table_entry(void) 81 { 82 UINT i; 83 84 /* find a slot */ 85 for(i=0; i<msihandletable_size; i++) 86 if( !msihandletable[i].u.obj && !msihandletable[i].u.rem ) 87 break; 88 if( i==msihandletable_size ) 89 { 90 msi_handle_info *p; 91 int newsize; 92 if (msihandletable_size == 0) 93 { 94 newsize = 256; 95 p = msi_alloc_zero(newsize * sizeof(*p)); 96 } 97 else 98 { 99 newsize = msihandletable_size * 2; 100 p = msi_realloc(msihandletable, newsize * sizeof(*p)); 101 if (p) memset(p + msihandletable_size, 0, (newsize - msihandletable_size) * sizeof(*p)); 102 } 103 if (!p) 104 return 0; 105 msihandletable = p; 106 msihandletable_size = newsize; 107 } 108 return i + 1; 109 } 110 111 MSIHANDLE alloc_msihandle( MSIOBJECTHDR *obj ) 112 { 113 msi_handle_info *entry; 114 MSIHANDLE ret; 115 116 EnterCriticalSection( &MSI_handle_cs ); 117 118 ret = alloc_handle_table_entry(); 119 if (ret) 120 { 121 entry = &msihandletable[ ret - 1 ]; 122 msiobj_addref( obj ); 123 entry->u.obj = obj; 124 entry->dwThreadId = GetCurrentThreadId(); 125 entry->remote = FALSE; 126 } 127 128 LeaveCriticalSection( &MSI_handle_cs ); 129 130 TRACE( "%p -> %lu\n", obj, ret ); 131 132 return ret; 133 } 134 135 MSIHANDLE alloc_msi_remote_handle(MSIHANDLE remote) 136 { 137 msi_handle_info *entry; 138 MSIHANDLE ret; 139 140 EnterCriticalSection( &MSI_handle_cs ); 141 142 ret = alloc_handle_table_entry(); 143 if (ret) 144 { 145 entry = &msihandletable[ ret - 1 ]; 146 entry->u.rem = remote; 147 entry->dwThreadId = GetCurrentThreadId(); 148 entry->remote = TRUE; 149 } 150 151 LeaveCriticalSection( &MSI_handle_cs ); 152 153 TRACE( "%lu -> %lu\n", remote, ret ); 154 155 return ret; 156 } 157 158 void *msihandle2msiinfo(MSIHANDLE handle, UINT type) 159 { 160 MSIOBJECTHDR *ret = NULL; 161 162 EnterCriticalSection( &MSI_handle_cs ); 163 handle--; 164 if( handle >= msihandletable_size ) 165 goto out; 166 if( msihandletable[handle].remote) 167 goto out; 168 if( !msihandletable[handle].u.obj ) 169 goto out; 170 if( msihandletable[handle].u.obj->magic != MSIHANDLE_MAGIC ) 171 goto out; 172 if( type && (msihandletable[handle].u.obj->type != type) ) 173 goto out; 174 ret = msihandletable[handle].u.obj; 175 msiobj_addref( ret ); 176 177 out: 178 LeaveCriticalSection( &MSI_handle_cs ); 179 180 return ret; 181 } 182 183 MSIHANDLE msi_get_remote( MSIHANDLE handle ) 184 { 185 MSIHANDLE ret = 0; 186 187 EnterCriticalSection( &MSI_handle_cs ); 188 handle--; 189 if( handle>=msihandletable_size ) 190 goto out; 191 if( !msihandletable[handle].remote) 192 goto out; 193 ret = msihandletable[handle].u.rem; 194 195 out: 196 LeaveCriticalSection( &MSI_handle_cs ); 197 198 return ret; 199 } 200 201 void *alloc_msiobject(UINT type, UINT size, msihandledestructor destroy ) 202 { 203 MSIOBJECTHDR *info; 204 205 info = msi_alloc_zero( size ); 206 if( info ) 207 { 208 info->magic = MSIHANDLE_MAGIC; 209 info->type = type; 210 info->refcount = 1; 211 info->destructor = destroy; 212 } 213 214 return info; 215 } 216 217 void msiobj_addref( MSIOBJECTHDR *info ) 218 { 219 if( !info ) 220 return; 221 222 if( info->magic != MSIHANDLE_MAGIC ) 223 { 224 ERR("Invalid handle!\n"); 225 return; 226 } 227 228 InterlockedIncrement(&info->refcount); 229 } 230 231 void msiobj_lock( MSIOBJECTHDR *info ) 232 { 233 EnterCriticalSection( &MSI_object_cs ); 234 } 235 236 void msiobj_unlock( MSIOBJECTHDR *info ) 237 { 238 LeaveCriticalSection( &MSI_object_cs ); 239 } 240 241 int msiobj_release( MSIOBJECTHDR *info ) 242 { 243 int ret; 244 245 if( !info ) 246 return -1; 247 248 if( info->magic != MSIHANDLE_MAGIC ) 249 { 250 ERR("Invalid handle!\n"); 251 return -1; 252 } 253 254 ret = InterlockedDecrement( &info->refcount ); 255 if( ret==0 ) 256 { 257 if( info->destructor ) 258 info->destructor( info ); 259 msi_free( info ); 260 TRACE("object %p destroyed\n", info); 261 } 262 263 return ret; 264 } 265 266 /*********************************************************** 267 * MsiCloseHandle [MSI.@] 268 */ 269 UINT WINAPI MsiCloseHandle(MSIHANDLE handle) 270 { 271 MSIOBJECTHDR *info = NULL; 272 UINT ret = ERROR_INVALID_HANDLE; 273 274 TRACE( "%lu\n", handle ); 275 276 if (!handle) 277 return ERROR_SUCCESS; 278 279 EnterCriticalSection( &MSI_handle_cs ); 280 281 handle--; 282 if (handle >= msihandletable_size) 283 goto out; 284 285 if (msihandletable[handle].remote) 286 { 287 remote_CloseHandle( msihandletable[handle].u.rem ); 288 } 289 else 290 { 291 info = msihandletable[handle].u.obj; 292 if( !info ) 293 goto out; 294 295 if( info->magic != MSIHANDLE_MAGIC ) 296 { 297 ERR("Invalid handle!\n"); 298 goto out; 299 } 300 } 301 302 msihandletable[handle].u.obj = NULL; 303 msihandletable[handle].remote = 0; 304 msihandletable[handle].dwThreadId = 0; 305 306 ret = ERROR_SUCCESS; 307 308 TRACE( "handle %lu destroyed\n", handle + 1 ); 309 out: 310 LeaveCriticalSection( &MSI_handle_cs ); 311 if( info ) 312 msiobj_release( info ); 313 314 return ret; 315 } 316 317 /*********************************************************** 318 * MsiCloseAllHandles [MSI.@] 319 * 320 * Closes all handles owned by the current thread 321 * 322 * RETURNS: 323 * The number of handles closed 324 */ 325 UINT WINAPI MsiCloseAllHandles(void) 326 { 327 UINT i, n=0; 328 329 TRACE("\n"); 330 331 EnterCriticalSection( &MSI_handle_cs ); 332 for(i=0; i<msihandletable_size; i++) 333 { 334 if(msihandletable[i].dwThreadId == GetCurrentThreadId()) 335 { 336 LeaveCriticalSection( &MSI_handle_cs ); 337 MsiCloseHandle( i+1 ); 338 EnterCriticalSection( &MSI_handle_cs ); 339 n++; 340 } 341 } 342 LeaveCriticalSection( &MSI_handle_cs ); 343 344 return n; 345 } 346 347 UINT __cdecl s_remote_CloseHandle(MSIHANDLE handle) 348 { 349 return MsiCloseHandle(handle); 350 } 351