atl80: Added AtlComModuleRegisterServer implementation (based on AtlModuleRegisterSer...
[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     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 }