reshuffling of dlls
[reactos.git] / reactos / dll / msi / source.c
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
4 * Copyright 2005 Aric Stewart 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "shlwapi.h"
31 #include "wine/debug.h"
32 #include "msi.h"
33 #include "msiquery.h"
34 #include "msipriv.h"
35 #include "wincrypt.h"
36 #include "winver.h"
37 #include "winuser.h"
38 #include "wine/unicode.h"
39 #include "action.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42
43 /*
44 * These apis are defined in MSI 3.0
45 */
46
47 typedef struct tagMediaInfo
48 {
49 LPWSTR path;
50 WCHAR szIndex[10];
51 WCHAR type;
52 } media_info;
53
54 static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, BOOL user, BOOL create)
55 {
56 HKEY rootkey = 0;
57 UINT rc;
58 static const WCHAR szSourceList[] = {'S','o','u','r','c','e','L','i','s','t',0};
59
60 if (user)
61 rc = MSIREG_OpenUserProductsKey(szProduct, &rootkey, create);
62 else
63 rc = MSIREG_OpenProductsKey(szProduct, &rootkey, create);
64
65 if (rc)
66 return rc;
67
68 if (create)
69 rc = RegCreateKeyW(rootkey, szSourceList, key);
70 else
71 rc = RegOpenKeyW(rootkey,szSourceList, key);
72
73 return rc;
74 }
75
76 static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create)
77 {
78 UINT rc;
79 static const WCHAR media[] = {'M','e','d','i','a',0};
80
81 if (create)
82 rc = RegCreateKeyW(rootkey, media, key);
83 else
84 rc = RegOpenKeyW(rootkey,media, key);
85
86 return rc;
87 }
88
89 static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create)
90 {
91 UINT rc;
92 static const WCHAR net[] = {'N','e','t',0};
93
94 if (create)
95 rc = RegCreateKeyW(rootkey, net, key);
96 else
97 rc = RegOpenKeyW(rootkey, net, key);
98
99 return rc;
100 }
101
102 static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create)
103 {
104 UINT rc;
105 static const WCHAR URL[] = {'U','R','L',0};
106
107 if (create)
108 rc = RegCreateKeyW(rootkey, URL, key);
109 else
110 rc = RegOpenKeyW(rootkey, URL, key);
111
112 return rc;
113 }
114
115
116 static UINT find_given_source(HKEY key, LPCWSTR szSource, media_info *ss)
117 {
118 DWORD index = 0;
119 WCHAR szIndex[10];
120 DWORD size;
121 DWORD val_size;
122 LPWSTR val;
123 UINT rc = ERROR_SUCCESS;
124
125 while (rc == ERROR_SUCCESS)
126 {
127 val = NULL;
128 val_size = 0;
129 rc = RegEnumValueW(key, index, szIndex, &size, NULL, NULL, NULL, &val_size);
130 if (rc != ERROR_NO_MORE_ITEMS)
131 {
132 val = msi_alloc(val_size);
133 RegEnumValueW(key, index, szIndex, &size, NULL, NULL, (LPBYTE)val,
134 &val_size);
135 if (lstrcmpiW(szSource,val)==0)
136 {
137 ss->path = val;
138 strcpyW(ss->szIndex,szIndex);
139 break;
140 }
141 else
142 strcpyW(ss->szIndex,szIndex);
143
144 msi_free(val);
145 index ++;
146 }
147 }
148 return rc;
149 }
150
151 /******************************************************************
152 * MsiSourceListGetInfoW (MSI.@)
153 */
154 UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
155 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
156 LPCWSTR szProperty, LPWSTR szValue,
157 LPDWORD pcchValue)
158 {
159 HKEY sourcekey;
160 UINT rc;
161
162 TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty));
163
164 if (!szProduct || lstrlenW(szProduct) > 39)
165 return ERROR_INVALID_PARAMETER;
166
167 if (szValue && !pcchValue)
168 return ERROR_INVALID_PARAMETER;
169
170 if (dwOptions == MSICODE_PATCH)
171 {
172 FIXME("Unhandled options MSICODE_PATCH\n");
173 return ERROR_FUNCTION_FAILED;
174 }
175
176 if (szUserSid)
177 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
178
179 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
180 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
181
182 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
183 rc = OpenSourceKey(szProduct, &sourcekey, FALSE, FALSE);
184 else
185 rc = OpenSourceKey(szProduct, &sourcekey, TRUE, FALSE);
186
187 if (rc != ERROR_SUCCESS)
188 return ERROR_UNKNOWN_PRODUCT;
189
190 if (strcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) == 0)
191 {
192 HKEY key;
193 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
194 if (rc == ERROR_SUCCESS)
195 rc = RegQueryValueExW(key, INSTALLPROPERTY_MEDIAPACKAGEPATHW,
196 0, 0, (LPBYTE)szValue, pcchValue);
197 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
198 rc = ERROR_UNKNOWN_PROPERTY;
199 RegCloseKey(key);
200 }
201 else if (strcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW) ==0)
202 {
203 HKEY key;
204 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
205 if (rc == ERROR_SUCCESS)
206 rc = RegQueryValueExW(key, INSTALLPROPERTY_DISKPROMPTW, 0, 0,
207 (LPBYTE)szValue, pcchValue);
208 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
209 rc = ERROR_UNKNOWN_PROPERTY;
210 RegCloseKey(key);
211 }
212 else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0)
213 {
214 LPWSTR buffer;
215 DWORD size = 0;
216
217 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0,
218 NULL, &size);
219 if (size == 0)
220 rc = ERROR_UNKNOWN_PROPERTY;
221 else
222 {
223 LPWSTR ptr;
224 buffer = msi_alloc(size);
225 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
226 0, 0, (LPBYTE)buffer,&size);
227 ptr = strchrW(buffer,';');
228 if (ptr) ptr = strchrW(ptr+1,';');
229 if (!ptr)
230 rc = ERROR_UNKNOWN_PROPERTY;
231 else
232 {
233 ptr ++;
234 lstrcpynW(szValue, ptr, *pcchValue);
235 if (lstrlenW(ptr) > *pcchValue)
236 {
237 *pcchValue = lstrlenW(ptr)+1;
238 rc = ERROR_MORE_DATA;
239 }
240 else
241 rc = ERROR_SUCCESS;
242 }
243 msi_free(buffer);
244 }
245 }
246 else if (strcmpW(INSTALLPROPERTY_LASTUSEDTYPEW, szProperty)==0)
247 {
248 LPWSTR buffer;
249 DWORD size = 0;
250
251 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0,
252 NULL, &size);
253 if (size == 0)
254 rc = ERROR_UNKNOWN_PROPERTY;
255 else
256 {
257 buffer = msi_alloc(size);
258 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
259 0, 0, (LPBYTE)buffer,&size);
260 if (*pcchValue < 1)
261 {
262 rc = ERROR_MORE_DATA;
263 *pcchValue = 1;
264 }
265 else
266 {
267 szValue[0] = buffer[0];
268 rc = ERROR_SUCCESS;
269 }
270 msi_free(buffer);
271 }
272 }
273 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
274 {
275 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0,
276 (LPBYTE)szValue, pcchValue);
277 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
278 rc = ERROR_UNKNOWN_PROPERTY;
279 }
280 else
281 {
282 FIXME("Unknown property %s\n",debugstr_w(szProperty));
283 rc = ERROR_UNKNOWN_PROPERTY;
284 }
285
286 RegCloseKey(sourcekey);
287 return rc;
288 }
289
290 /******************************************************************
291 * MsiSourceListSetInfoW (MSI.@)
292 */
293 UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
294 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
295 LPCWSTR szProperty, LPCWSTR szValue)
296 {
297 HKEY sourcekey;
298 UINT rc;
299
300 TRACE("%s %s %x %lx %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid),
301 dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue));
302
303 if (!szProduct || lstrlenW(szProduct) > 39)
304 return ERROR_INVALID_PARAMETER;
305
306 if (dwOptions & MSICODE_PATCH)
307 {
308 FIXME("Unhandled options MSICODE_PATCH\n");
309 return ERROR_FUNCTION_FAILED;
310 }
311
312 if (szUserSid)
313 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
314
315 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
316 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
317
318 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
319 rc = OpenSourceKey(szProduct, &sourcekey, FALSE, TRUE);
320 else
321 rc = OpenSourceKey(szProduct, &sourcekey, TRUE, TRUE);
322
323 if (rc != ERROR_SUCCESS)
324 return ERROR_UNKNOWN_PRODUCT;
325
326
327 if (strcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) == 0)
328 {
329 HKEY key;
330 DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
331 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
332 if (rc == ERROR_SUCCESS)
333 rc = RegSetValueExW(key, INSTALLPROPERTY_MEDIAPACKAGEPATHW, 0,
334 REG_SZ, (LPBYTE)szValue, size);
335 if (rc != ERROR_SUCCESS)
336 rc = ERROR_UNKNOWN_PROPERTY;
337 RegCloseKey(key);
338 }
339 else if (strcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW) == 0)
340 {
341 HKEY key;
342 DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
343 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
344 if (rc == ERROR_SUCCESS)
345 rc = RegSetValueExW(key, INSTALLPROPERTY_DISKPROMPTW, 0,
346 REG_SZ, (LPBYTE)szValue, size);
347 if (rc != ERROR_SUCCESS)
348 rc = ERROR_UNKNOWN_PROPERTY;
349 RegCloseKey(key);
350 }
351 else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0)
352 {
353 LPWSTR buffer = NULL;
354 DWORD size;
355 WCHAR typechar = 'n';
356 static const WCHAR LastUsedSource_Fmt[] = {'%','c',';','%','i',';','%','s',0};
357
358 /* make sure the source is registered */
359 MsiSourceListAddSourceExW(szProduct, szUserSid, dwContext,
360 dwOptions, szValue, 0);
361
362 if (dwOptions & MSISOURCETYPE_NETWORK)
363 typechar = 'n';
364 else if (dwOptions & MSISOURCETYPE_URL)
365 typechar = 'u';
366 else if (dwOptions & MSISOURCETYPE_MEDIA)
367 typechar = 'm';
368 else
369 ERR("Unknown source type! 0x%lx\n",dwOptions);
370
371 size = (lstrlenW(szValue)+5)*sizeof(WCHAR);
372 buffer = msi_alloc(size);
373 sprintfW(buffer, LastUsedSource_Fmt, typechar, 1, szValue);
374 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0,
375 REG_EXPAND_SZ, (LPBYTE)buffer, size);
376 if (rc != ERROR_SUCCESS)
377 rc = ERROR_UNKNOWN_PROPERTY;
378 msi_free( buffer );
379 }
380 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
381 {
382 DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
383 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0,
384 REG_SZ, (LPBYTE)szValue, size);
385 if (rc != ERROR_SUCCESS)
386 rc = ERROR_UNKNOWN_PROPERTY;
387 }
388 else
389 {
390 FIXME("Unknown property %s\n",debugstr_w(szProperty));
391 rc = ERROR_UNKNOWN_PROPERTY;
392 }
393
394 RegCloseKey(sourcekey);
395 return rc;
396
397 }
398
399 /******************************************************************
400 * MsiSourceListAddSourceExW (MSI.@)
401 */
402 UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
403 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource,
404 DWORD dwIndex)
405 {
406 HKEY sourcekey;
407 HKEY typekey;
408 UINT rc;
409 media_info source_struct;
410
411 TRACE("%s, %s, %x, %lx, %s, %li\n", debugstr_w(szProduct),
412 debugstr_w(szUserSid), dwContext, dwOptions, debugstr_w(szSource),
413 dwIndex);
414
415 if (!szProduct)
416 return ERROR_INVALID_PARAMETER;
417
418 if (!szSource)
419 return ERROR_INVALID_PARAMETER;
420
421 if (dwOptions & MSICODE_PATCH)
422 {
423 FIXME("Unhandled options MSICODE_PATCH\n");
424 return ERROR_FUNCTION_FAILED;
425 }
426
427 if (szUserSid)
428 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
429
430 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
431 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
432
433 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
434 rc = OpenSourceKey(szProduct, &sourcekey, FALSE, TRUE);
435 else
436 rc = OpenSourceKey(szProduct, &sourcekey, TRUE, TRUE);
437
438 if (rc != ERROR_SUCCESS)
439 return ERROR_UNKNOWN_PRODUCT;
440
441 if (dwOptions & MSISOURCETYPE_NETWORK)
442 rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
443 else if (dwOptions & MSISOURCETYPE_URL)
444 rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
445 else
446 {
447 ERR("unknown media type: %08lx\n", dwOptions);
448 RegCloseKey(sourcekey);
449 return ERROR_FUNCTION_FAILED;
450 }
451
452 source_struct.szIndex[0] = 0;
453 if (find_given_source(typekey, szSource, &source_struct)==ERROR_SUCCESS)
454 {
455 DWORD current_index = atoiW(source_struct.szIndex);
456 /* found the source */
457 if (dwIndex > 0 && current_index != dwIndex)
458 FIXME("Need to reorder the sources!\n");
459 }
460 else
461 {
462 DWORD current_index = 0;
463 static const WCHAR fmt[] = {'%','i',0};
464 DWORD size = lstrlenW(szSource)*sizeof(WCHAR);
465
466 if (source_struct.szIndex[0])
467 current_index = atoiW(source_struct.szIndex);
468 /* new source */
469 if (dwIndex > 0 && dwIndex < current_index)
470 FIXME("Need to reorder the sources!\n");
471
472 current_index ++;
473 sprintfW(source_struct.szIndex,fmt,current_index);
474 rc = RegSetValueExW(typekey, source_struct.szIndex, 0, REG_EXPAND_SZ,
475 (LPBYTE)szSource, size);
476 }
477
478 RegCloseKey(typekey);
479 RegCloseKey(sourcekey);
480 return rc;
481 }
482
483 /******************************************************************
484 * MsiSourceListAddMediaDisk(MSI.@)
485 */
486 UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid,
487 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
488 LPCWSTR szVolumeLabel, LPCWSTR szDiskPrompt)
489 {
490 HKEY sourcekey;
491 HKEY mediakey;
492 UINT rc;
493 WCHAR szIndex[10];
494 static const WCHAR fmt[] = {'%','i',0};
495 static const WCHAR disk_fmt[] = {'%','s',';','%','s',0};
496 static const WCHAR empty[1] = {0};
497 LPCWSTR pt1,pt2;
498 LPWSTR buffer;
499 DWORD size;
500
501 TRACE("%s %s %x %lx %li %s %s\n", debugstr_w(szProduct),
502 debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId,
503 debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt));
504
505 if (!szProduct || lstrlenW(szProduct) > 39)
506 return ERROR_INVALID_PARAMETER;
507
508 if (dwOptions & MSICODE_PATCH)
509 {
510 FIXME("Unhandled options MSICODE_PATCH\n");
511 return ERROR_FUNCTION_FAILED;
512 }
513
514 if (szUserSid)
515 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
516
517 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
518 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
519
520 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
521 rc = OpenSourceKey(szProduct, &sourcekey, FALSE, TRUE);
522 else
523 rc = OpenSourceKey(szProduct, &sourcekey, TRUE, TRUE);
524
525 if (rc != ERROR_SUCCESS)
526 return ERROR_UNKNOWN_PRODUCT;
527
528 OpenMediaSubkey(sourcekey,&mediakey,TRUE);
529
530 sprintfW(szIndex,fmt,dwDiskId);
531
532 size = 2;
533 if (szVolumeLabel)
534 {
535 size +=lstrlenW(szVolumeLabel);
536 pt1 = szVolumeLabel;
537 }
538 else
539 pt1 = empty;
540 if (szDiskPrompt)
541 {
542 size +=lstrlenW(szDiskPrompt);
543 pt2 = szDiskPrompt;
544 }
545 else
546 pt2 = empty;
547
548 size *=sizeof(WCHAR);
549
550 buffer = msi_alloc(size);
551 sprintfW(buffer,disk_fmt,pt1,pt2);
552
553 RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
554 msi_free( buffer );
555
556 RegCloseKey(sourcekey);
557 RegCloseKey(mediakey);
558
559 return ERROR_SUCCESS;
560 }