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