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 handle_cs; 39 static CRITICAL_SECTION_DEBUG handle_cs_debug = 40 { 41 0, 0, &handle_cs, 42 { &handle_cs_debug.ProcessLocksList, 43 &handle_cs_debug.ProcessLocksList }, 44 0, 0, { (DWORD_PTR)(__FILE__ ": handle_cs") } 45 }; 46 static CRITICAL_SECTION handle_cs = { &handle_cs_debug, -1, 0, 0, 0, 0 }; 47 48 static CRITICAL_SECTION object_cs; 49 static CRITICAL_SECTION_DEBUG object_cs_debug = 50 { 51 0, 0, &object_cs, 52 { &object_cs_debug.ProcessLocksList, 53 &object_cs_debug.ProcessLocksList }, 54 0, 0, { (DWORD_PTR)(__FILE__ ": object_cs") } 55 }; 56 static CRITICAL_SECTION object_cs = { &object_cs_debug, -1, 0, 0, 0, 0 }; 57 58 struct handle_info 59 { 60 BOOL remote; 61 union { 62 MSIOBJECTHDR *obj; 63 MSIHANDLE rem; 64 } u; 65 DWORD dwThreadId; 66 }; 67 68 static struct handle_info *handle_table = NULL; 69 static unsigned int handle_table_size = 0; 70 71 void msi_free_handle_table(void) 72 { 73 free( handle_table ); 74 handle_table = NULL; 75 handle_table_size = 0; 76 DeleteCriticalSection(&handle_cs); 77 DeleteCriticalSection(&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 < handle_table_size; i++) 86 if (!handle_table[i].u.obj && !handle_table[i].u.rem) 87 break; 88 if (i == handle_table_size) 89 { 90 struct handle_info *p; 91 int newsize; 92 if (!handle_table_size) 93 { 94 newsize = 256; 95 p = calloc(newsize, sizeof(*p)); 96 } 97 else 98 { 99 newsize = handle_table_size * 2; 100 p = realloc(handle_table, newsize * sizeof(*p)); 101 if (p) memset(p + handle_table_size, 0, (newsize - handle_table_size) * sizeof(*p)); 102 } 103 if (!p) 104 return 0; 105 handle_table = p; 106 handle_table_size = newsize; 107 } 108 return i + 1; 109 } 110 111 MSIHANDLE alloc_msihandle( MSIOBJECTHDR *obj ) 112 { 113 struct handle_info *entry; 114 MSIHANDLE ret; 115 116 EnterCriticalSection( &handle_cs ); 117 118 ret = alloc_handle_table_entry(); 119 if (ret) 120 { 121 entry = &handle_table[ ret - 1 ]; 122 msiobj_addref( obj ); 123 entry->u.obj = obj; 124 entry->dwThreadId = GetCurrentThreadId(); 125 entry->remote = FALSE; 126 } 127 128 LeaveCriticalSection( &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 struct handle_info *entry; 138 MSIHANDLE ret; 139 140 EnterCriticalSection( &handle_cs ); 141 142 ret = alloc_handle_table_entry(); 143 if (ret) 144 { 145 entry = &handle_table[ ret - 1 ]; 146 entry->u.rem = remote; 147 entry->dwThreadId = GetCurrentThreadId(); 148 entry->remote = TRUE; 149 } 150 151 LeaveCriticalSection( &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( &handle_cs ); 163 handle--; 164 if (handle >= handle_table_size) 165 goto out; 166 if (handle_table[handle].remote) 167 goto out; 168 if (!handle_table[handle].u.obj) 169 goto out; 170 if (handle_table[handle].u.obj->magic != MSIHANDLE_MAGIC) 171 goto out; 172 if (type && (handle_table[handle].u.obj->type != type)) 173 goto out; 174 ret = handle_table[handle].u.obj; 175 msiobj_addref( ret ); 176 177 out: 178 LeaveCriticalSection( &handle_cs ); 179 180 return ret; 181 } 182 183 MSIHANDLE msi_get_remote( MSIHANDLE handle ) 184 { 185 MSIHANDLE ret = 0; 186 187 EnterCriticalSection( &handle_cs ); 188 handle--; 189 if (handle >= handle_table_size) 190 goto out; 191 if (!handle_table[handle].remote) 192 goto out; 193 ret = handle_table[handle].u.rem; 194 195 out: 196 LeaveCriticalSection( &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 = calloc( 1, 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( &object_cs ); 234 } 235 236 void msiobj_unlock( MSIOBJECTHDR *info ) 237 { 238 LeaveCriticalSection( &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 TRACE("object %p destroyed\n", info); 260 free( 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( &handle_cs ); 280 281 handle--; 282 if (handle >= handle_table_size) 283 goto out; 284 285 if (handle_table[handle].remote) 286 { 287 remote_CloseHandle( handle_table[handle].u.rem ); 288 } 289 else 290 { 291 info = handle_table[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 handle_table[handle].u.obj = NULL; 303 handle_table[handle].remote = 0; 304 handle_table[handle].dwThreadId = 0; 305 306 ret = ERROR_SUCCESS; 307 308 TRACE( "handle %lu destroyed\n", handle + 1 ); 309 out: 310 LeaveCriticalSection( &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( &handle_cs ); 332 for (i = 0; i < handle_table_size; i++) 333 { 334 if (handle_table[i].dwThreadId == GetCurrentThreadId()) 335 { 336 LeaveCriticalSection( &handle_cs ); 337 MsiCloseHandle( i + 1 ); 338 EnterCriticalSection( &handle_cs ); 339 n++; 340 } 341 } 342 LeaveCriticalSection( &handle_cs ); 343 344 return n; 345 } 346 347 UINT __cdecl s_remote_CloseHandle(MSIHANDLE handle) 348 { 349 return MsiCloseHandle(handle); 350 } 351