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