xref: /reactos/dll/win32/msi/handle.c (revision b707be90)
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