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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "winnls.h"
29 #include "shlwapi.h"
30 #include "wine/debug.h"
31 #include "msi.h"
32 #include "msiquery.h"
33 #include "msipriv.h"
34 #include "wincrypt.h"
35 #include "winver.h"
36 #include "winuser.h"
37 #include "sddl.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
40
41 /*
42 * These apis are defined in MSI 3.0
43 */
44
45 struct media_info
46 {
47 struct list entry;
48 LPWSTR path;
49 WCHAR szIndex[10];
50 DWORD index;
51 };
52
OpenSourceKey(LPCWSTR szProduct,HKEY * key,DWORD dwOptions,MSIINSTALLCONTEXT context,BOOL create)53 static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, DWORD dwOptions,
54 MSIINSTALLCONTEXT context, BOOL create)
55 {
56 HKEY rootkey = 0;
57 UINT rc = ERROR_FUNCTION_FAILED;
58
59 if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
60 {
61 if (dwOptions & MSICODE_PATCH)
62 rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
63 else
64 rc = MSIREG_OpenProductKey(szProduct, NULL, context,
65 &rootkey, create);
66 }
67 else if (context == MSIINSTALLCONTEXT_USERMANAGED)
68 {
69 if (dwOptions & MSICODE_PATCH)
70 rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
71 else
72 rc = MSIREG_OpenProductKey(szProduct, NULL, context,
73 &rootkey, create);
74 }
75 else if (context == MSIINSTALLCONTEXT_MACHINE)
76 {
77 if (dwOptions & MSICODE_PATCH)
78 rc = MSIREG_OpenPatchesKey(szProduct, &rootkey, create);
79 else
80 rc = MSIREG_OpenProductKey(szProduct, NULL, context,
81 &rootkey, create);
82 }
83
84 if (rc != ERROR_SUCCESS)
85 {
86 if (dwOptions & MSICODE_PATCH)
87 return ERROR_UNKNOWN_PATCH;
88 else
89 return ERROR_UNKNOWN_PRODUCT;
90 }
91
92 if (create)
93 rc = RegCreateKeyW(rootkey, L"SourceList", key);
94 else
95 {
96 rc = RegOpenKeyW(rootkey, L"SourceList", key);
97 if (rc != ERROR_SUCCESS)
98 rc = ERROR_BAD_CONFIGURATION;
99 }
100 RegCloseKey(rootkey);
101
102 return rc;
103 }
104
OpenMediaSubkey(HKEY rootkey,HKEY * key,BOOL create)105 static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create)
106 {
107 UINT rc;
108
109 if (create)
110 rc = RegCreateKeyW(rootkey, L"Media", key);
111 else
112 rc = RegOpenKeyW(rootkey, L"Media", key);
113
114 return rc;
115 }
116
OpenNetworkSubkey(HKEY rootkey,HKEY * key,BOOL create)117 static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create)
118 {
119 UINT rc;
120
121 if (create)
122 rc = RegCreateKeyW(rootkey, L"Net", key);
123 else
124 rc = RegOpenKeyW(rootkey, L"Net", key);
125
126 return rc;
127 }
128
OpenURLSubkey(HKEY rootkey,HKEY * key,BOOL create)129 static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create)
130 {
131 UINT rc;
132
133 if (create)
134 rc = RegCreateKeyW(rootkey, L"URL", key);
135 else
136 rc = RegOpenKeyW(rootkey, L"URL", key);
137
138 return rc;
139 }
140
141 /******************************************************************
142 * MsiSourceListEnumMediaDisksA (MSI.@)
143 */
MsiSourceListEnumMediaDisksA(const char * szProductCodeOrPatchCode,const char * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,DWORD dwIndex,DWORD * pdwDiskId,char * szVolumeLabel,DWORD * pcchVolumeLabel,char * szDiskPrompt,DWORD * pcchDiskPrompt)144 UINT WINAPI MsiSourceListEnumMediaDisksA( const char *szProductCodeOrPatchCode, const char *szUserSid,
145 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex,
146 DWORD *pdwDiskId, char *szVolumeLabel, DWORD *pcchVolumeLabel,
147 char *szDiskPrompt, DWORD *pcchDiskPrompt )
148 {
149 WCHAR *product = NULL, *usersid = NULL, *volume = NULL, *prompt = NULL;
150 UINT r = ERROR_INVALID_PARAMETER;
151
152 TRACE( "%s, %s, %d, %#lx, %lu, %p, %p, %p, %p, %p\n", debugstr_a(szProductCodeOrPatchCode),
153 debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, pdwDiskId, szVolumeLabel, pcchVolumeLabel,
154 szDiskPrompt, pcchDiskPrompt );
155
156 if (szDiskPrompt && !pcchDiskPrompt)
157 return ERROR_INVALID_PARAMETER;
158
159 if (szProductCodeOrPatchCode) product = strdupAtoW(szProductCodeOrPatchCode);
160 if (szUserSid) usersid = strdupAtoW(szUserSid);
161
162 /* FIXME: add tests for an invalid format */
163
164 if (pcchVolumeLabel)
165 volume = malloc(*pcchVolumeLabel * sizeof(WCHAR));
166
167 if (pcchDiskPrompt)
168 prompt = malloc(*pcchDiskPrompt * sizeof(WCHAR));
169
170 if (volume) *volume = '\0';
171 if (prompt) *prompt = '\0';
172 r = MsiSourceListEnumMediaDisksW(product, usersid, dwContext, dwOptions,
173 dwIndex, pdwDiskId, volume, pcchVolumeLabel,
174 prompt, pcchDiskPrompt);
175 if (r != ERROR_SUCCESS)
176 goto done;
177
178 if (szVolumeLabel && pcchVolumeLabel)
179 WideCharToMultiByte(CP_ACP, 0, volume, -1, szVolumeLabel,
180 *pcchVolumeLabel + 1, NULL, NULL);
181
182 if (szDiskPrompt)
183 WideCharToMultiByte(CP_ACP, 0, prompt, -1, szDiskPrompt,
184 *pcchDiskPrompt + 1, NULL, NULL);
185
186 done:
187 free(product);
188 free(usersid);
189 free(volume);
190 free(prompt);
191
192 return r;
193 }
194
195 /******************************************************************
196 * MsiSourceListEnumMediaDisksW (MSI.@)
197 */
MsiSourceListEnumMediaDisksW(const WCHAR * szProductCodeOrPatchCode,const WCHAR * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,DWORD dwIndex,DWORD * pdwDiskId,WCHAR * szVolumeLabel,DWORD * pcchVolumeLabel,WCHAR * szDiskPrompt,DWORD * pcchDiskPrompt)198 UINT WINAPI MsiSourceListEnumMediaDisksW( const WCHAR *szProductCodeOrPatchCode, const WCHAR *szUserSid,
199 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex,
200 DWORD *pdwDiskId, WCHAR *szVolumeLabel, DWORD *pcchVolumeLabel,
201 WCHAR *szDiskPrompt, DWORD *pcchDiskPrompt )
202 {
203 WCHAR squashed_pc[SQUASHED_GUID_SIZE], convert[11];
204 WCHAR *value = NULL, *data = NULL, *ptr, *ptr2;
205 HKEY source, media;
206 DWORD valuesz, datasz = 0, type, numvals, size;
207 LONG res;
208 UINT r;
209 static DWORD index = 0;
210
211 TRACE( "%s, %s, %d, %#lx, %lu, %p, %p, %p, %p\n", debugstr_w(szProductCodeOrPatchCode),
212 debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szVolumeLabel, pcchVolumeLabel,
213 szDiskPrompt, pcchDiskPrompt );
214
215 if (!szProductCodeOrPatchCode || !squash_guid( szProductCodeOrPatchCode, squashed_pc ))
216 return ERROR_INVALID_PARAMETER;
217
218 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
219 return ERROR_INVALID_PARAMETER;
220
221 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
222 return ERROR_INVALID_PARAMETER;
223
224 if (szDiskPrompt && !pcchDiskPrompt)
225 return ERROR_INVALID_PARAMETER;
226
227 if (dwIndex == 0)
228 index = 0;
229
230 if (dwIndex != index)
231 return ERROR_INVALID_PARAMETER;
232
233 r = OpenSourceKey(szProductCodeOrPatchCode, &source, dwOptions, dwContext, FALSE);
234 if (r != ERROR_SUCCESS)
235 return r;
236
237 r = OpenMediaSubkey(source, &media, FALSE);
238 if (r != ERROR_SUCCESS)
239 {
240 RegCloseKey(source);
241 return ERROR_NO_MORE_ITEMS;
242 }
243
244 res = RegQueryInfoKeyW(media, NULL, NULL, NULL, NULL, NULL,
245 NULL, &numvals, &valuesz, &datasz, NULL, NULL);
246 if (res != ERROR_SUCCESS)
247 {
248 r = ERROR_BAD_CONFIGURATION;
249 goto done;
250 }
251
252 value = malloc(++valuesz * sizeof(WCHAR));
253 data = malloc(++datasz * sizeof(WCHAR));
254 if (!value || !data)
255 {
256 r = ERROR_OUTOFMEMORY;
257 goto done;
258 }
259
260 r = RegEnumValueW(media, dwIndex, value, &valuesz,
261 NULL, &type, (LPBYTE)data, &datasz);
262 if (r != ERROR_SUCCESS)
263 goto done;
264
265 if (pdwDiskId)
266 *pdwDiskId = wcstol(value, NULL, 10);
267
268 ptr2 = data;
269 ptr = wcschr(data, ';');
270 if (!ptr)
271 ptr = data;
272 else
273 *ptr = '\0';
274
275 if (pcchVolumeLabel)
276 {
277 if (type == REG_DWORD)
278 {
279 swprintf(convert, ARRAY_SIZE(convert), L"#%d", *data);
280 size = lstrlenW(convert);
281 ptr2 = convert;
282 }
283 else
284 size = lstrlenW(data);
285
286 if (size >= *pcchVolumeLabel)
287 r = ERROR_MORE_DATA;
288 else if (szVolumeLabel)
289 lstrcpyW(szVolumeLabel, ptr2);
290
291 *pcchVolumeLabel = size;
292 }
293
294 if (pcchDiskPrompt)
295 {
296 if (!*ptr)
297 ptr++;
298
299 if (type == REG_DWORD)
300 {
301 swprintf(convert, ARRAY_SIZE(convert), L"#%d", *ptr);
302 size = lstrlenW(convert);
303 ptr = convert;
304 }
305 else
306 size = lstrlenW(ptr);
307
308 if (size >= *pcchDiskPrompt)
309 r = ERROR_MORE_DATA;
310 else if (szDiskPrompt)
311 lstrcpyW(szDiskPrompt, ptr);
312
313 *pcchDiskPrompt = size;
314 }
315
316 index++;
317
318 done:
319 free(value);
320 free(data);
321 RegCloseKey(source);
322
323 return r;
324 }
325
326 /******************************************************************
327 * MsiSourceListEnumSourcesA (MSI.@)
328 */
MsiSourceListEnumSourcesA(const char * szProductCodeOrPatch,const char * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,DWORD dwIndex,char * szSource,DWORD * pcchSource)329 UINT WINAPI MsiSourceListEnumSourcesA( const char *szProductCodeOrPatch, const char *szUserSid,
330 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex, char *szSource,
331 DWORD *pcchSource )
332 {
333 WCHAR *product = NULL, *usersid = NULL, *source = NULL;
334 DWORD len = 0;
335 UINT r = ERROR_INVALID_PARAMETER;
336 static DWORD index = 0;
337
338 TRACE( "%s, %s, %d, %#lx, %lu, %p, %p)\n", debugstr_a(szProductCodeOrPatch), debugstr_a(szUserSid), dwContext,
339 dwOptions, dwIndex, szSource, pcchSource );
340
341 if (dwIndex == 0)
342 index = 0;
343
344 if (szSource && !pcchSource)
345 goto done;
346
347 if (dwIndex != index)
348 goto done;
349
350 if (szProductCodeOrPatch) product = strdupAtoW(szProductCodeOrPatch);
351 if (szUserSid) usersid = strdupAtoW(szUserSid);
352
353 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
354 dwIndex, NULL, &len);
355 if (r != ERROR_SUCCESS)
356 goto done;
357
358 source = malloc(++len * sizeof(WCHAR));
359 if (!source)
360 {
361 r = ERROR_OUTOFMEMORY;
362 goto done;
363 }
364
365 *source = '\0';
366 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
367 dwIndex, source, &len);
368 if (r != ERROR_SUCCESS)
369 goto done;
370
371 len = WideCharToMultiByte(CP_ACP, 0, source, -1, NULL, 0, NULL, NULL);
372 if (pcchSource && *pcchSource >= len)
373 WideCharToMultiByte(CP_ACP, 0, source, -1, szSource, len, NULL, NULL);
374 else if (szSource)
375 r = ERROR_MORE_DATA;
376
377 if (pcchSource)
378 *pcchSource = len - 1;
379
380 done:
381 free(product);
382 free(usersid);
383 free(source);
384
385 if (r == ERROR_SUCCESS)
386 {
387 if (szSource || !pcchSource) index++;
388 }
389 else if (dwIndex > index)
390 index = 0;
391
392 return r;
393 }
394
395 /******************************************************************
396 * MsiSourceListEnumSourcesW (MSI.@)
397 */
MsiSourceListEnumSourcesW(const WCHAR * szProductCodeOrPatch,const WCHAR * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,DWORD dwIndex,WCHAR * szSource,DWORD * pcchSource)398 UINT WINAPI MsiSourceListEnumSourcesW( const WCHAR *szProductCodeOrPatch, const WCHAR *szUserSid,
399 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwIndex, WCHAR *szSource,
400 DWORD *pcchSource )
401 {
402 WCHAR squashed_pc[SQUASHED_GUID_SIZE], name[32];
403 HKEY source = NULL, subkey = NULL;
404 LONG res;
405 UINT r = ERROR_INVALID_PARAMETER;
406 static DWORD index = 0;
407
408 TRACE( "%s, %s, %d, %#lx, %lu, %p, %p\n", debugstr_w(szProductCodeOrPatch), debugstr_w(szUserSid), dwContext,
409 dwOptions, dwIndex, szSource, pcchSource );
410
411 if (dwIndex == 0)
412 index = 0;
413
414 if (!szProductCodeOrPatch || !squash_guid( szProductCodeOrPatch, squashed_pc ))
415 goto done;
416
417 if (szSource && !pcchSource)
418 goto done;
419
420 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
421 goto done;
422
423 if ((dwOptions & MSISOURCETYPE_NETWORK) && (dwOptions & MSISOURCETYPE_URL))
424 goto done;
425
426 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
427 goto done;
428
429 if (dwIndex != index)
430 goto done;
431
432 r = OpenSourceKey( szProductCodeOrPatch, &source, dwOptions, dwContext, FALSE );
433 if (r != ERROR_SUCCESS)
434 goto done;
435
436 if (dwOptions & MSISOURCETYPE_NETWORK)
437 r = OpenNetworkSubkey(source, &subkey, FALSE);
438 else if (dwOptions & MSISOURCETYPE_URL)
439 r = OpenURLSubkey(source, &subkey, FALSE);
440
441 if (r != ERROR_SUCCESS)
442 {
443 r = ERROR_NO_MORE_ITEMS;
444 goto done;
445 }
446
447 swprintf(name, ARRAY_SIZE(name), L"%d", dwIndex + 1);
448
449 res = RegQueryValueExW(subkey, name, 0, 0, (LPBYTE)szSource, pcchSource);
450 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
451 r = ERROR_NO_MORE_ITEMS;
452
453 done:
454 RegCloseKey(subkey);
455 RegCloseKey(source);
456
457 if (r == ERROR_SUCCESS)
458 {
459 if (szSource || !pcchSource) index++;
460 }
461 else if (dwIndex > index)
462 index = 0;
463
464 return r;
465 }
466
467 /******************************************************************
468 * MsiSourceListGetInfoA (MSI.@)
469 */
MsiSourceListGetInfoA(LPCSTR szProduct,LPCSTR szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,LPCSTR szProperty,LPSTR szValue,LPDWORD pcchValue)470 UINT WINAPI MsiSourceListGetInfoA( LPCSTR szProduct, LPCSTR szUserSid,
471 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
472 LPCSTR szProperty, LPSTR szValue,
473 LPDWORD pcchValue)
474 {
475 UINT ret;
476 LPWSTR product = NULL;
477 LPWSTR usersid = NULL;
478 LPWSTR property = NULL;
479 LPWSTR value = NULL;
480 DWORD len = 0;
481
482 if (szValue && !pcchValue)
483 return ERROR_INVALID_PARAMETER;
484
485 if (szProduct) product = strdupAtoW(szProduct);
486 if (szUserSid) usersid = strdupAtoW(szUserSid);
487 if (szProperty) property = strdupAtoW(szProperty);
488
489 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
490 property, NULL, &len);
491 if (ret != ERROR_SUCCESS)
492 goto done;
493
494 value = malloc(++len * sizeof(WCHAR));
495 if (!value)
496 return ERROR_OUTOFMEMORY;
497
498 *value = '\0';
499 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
500 property, value, &len);
501 if (ret != ERROR_SUCCESS)
502 goto done;
503
504 len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
505 if (*pcchValue >= len)
506 WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
507 else if (szValue)
508 ret = ERROR_MORE_DATA;
509
510 *pcchValue = len - 1;
511
512 done:
513 free(product);
514 free(usersid);
515 free(property);
516 free(value);
517 return ret;
518 }
519
520 /******************************************************************
521 * MsiSourceListGetInfoW (MSI.@)
522 */
MsiSourceListGetInfoW(LPCWSTR szProduct,LPCWSTR szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,LPCWSTR szProperty,LPWSTR szValue,LPDWORD pcchValue)523 UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
524 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
525 LPCWSTR szProperty, LPWSTR szValue,
526 LPDWORD pcchValue)
527 {
528 WCHAR *source, *ptr, squashed_pc[SQUASHED_GUID_SIZE];
529 HKEY sourcekey, media;
530 DWORD size;
531 UINT rc;
532
533 TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty));
534
535 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
536 return ERROR_INVALID_PARAMETER;
537
538 if (szValue && !pcchValue)
539 return ERROR_INVALID_PARAMETER;
540
541 if (dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
542 dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
543 dwContext != MSIINSTALLCONTEXT_MACHINE)
544 return ERROR_INVALID_PARAMETER;
545
546 if (!szProperty)
547 return ERROR_INVALID_PARAMETER;
548
549 if (szUserSid)
550 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
551
552 rc = OpenSourceKey(szProduct, &sourcekey, dwOptions, dwContext, FALSE);
553 if (rc != ERROR_SUCCESS)
554 return rc;
555
556 if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
557 !wcscmp( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
558 {
559 rc = OpenMediaSubkey(sourcekey, &media, FALSE);
560 if (rc != ERROR_SUCCESS)
561 {
562 RegCloseKey(sourcekey);
563 return ERROR_SUCCESS;
564 }
565
566 if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
567 szProperty = L"MediaPackage";
568
569 RegQueryValueExW(media, szProperty, 0, 0, (LPBYTE)szValue, pcchValue);
570 RegCloseKey(media);
571 }
572 else if (!wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) ||
573 !wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
574 {
575 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
576 0, 0, NULL, &size);
577 if (rc != ERROR_SUCCESS)
578 {
579 static WCHAR szEmpty[] = L"";
580 rc = ERROR_SUCCESS;
581 source = NULL;
582 ptr = szEmpty;
583 goto output_out;
584 }
585
586 source = malloc(size);
587 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
588 0, 0, (LPBYTE)source, &size);
589
590 if (!*source)
591 {
592 free(source);
593 RegCloseKey(sourcekey);
594 return ERROR_SUCCESS;
595 }
596
597 if (!wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW ))
598 {
599 if (*source != 'n' && *source != 'u' && *source != 'm')
600 {
601 free(source);
602 RegCloseKey(sourcekey);
603 return ERROR_SUCCESS;
604 }
605
606 ptr = source;
607 source[1] = '\0';
608 }
609 else
610 {
611 ptr = wcsrchr(source, ';');
612 if (!ptr)
613 ptr = source;
614 else
615 ptr++;
616 }
617 output_out:
618 if (szValue)
619 {
620 if (lstrlenW(ptr) < *pcchValue)
621 lstrcpyW(szValue, ptr);
622 else
623 rc = ERROR_MORE_DATA;
624 }
625
626 *pcchValue = lstrlenW(ptr);
627 free(source);
628 }
629 else if (!wcscmp( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
630 {
631 *pcchValue = *pcchValue * sizeof(WCHAR);
632 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0,
633 (LPBYTE)szValue, pcchValue);
634 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
635 {
636 *pcchValue = 0;
637 rc = ERROR_SUCCESS;
638 }
639 else
640 {
641 if (*pcchValue)
642 *pcchValue = (*pcchValue - 1) / sizeof(WCHAR);
643 if (szValue)
644 szValue[*pcchValue] = '\0';
645 }
646 }
647 else
648 {
649 FIXME("Unknown property %s\n",debugstr_w(szProperty));
650 rc = ERROR_UNKNOWN_PROPERTY;
651 }
652
653 RegCloseKey(sourcekey);
654 return rc;
655 }
656
657 /******************************************************************
658 * MsiSourceListSetInfoA (MSI.@)
659 */
MsiSourceListSetInfoA(LPCSTR szProduct,LPCSTR szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,LPCSTR szProperty,LPCSTR szValue)660 UINT WINAPI MsiSourceListSetInfoA(LPCSTR szProduct, LPCSTR szUserSid,
661 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
662 LPCSTR szProperty, LPCSTR szValue)
663 {
664 UINT ret;
665 LPWSTR product = NULL;
666 LPWSTR usersid = NULL;
667 LPWSTR property = NULL;
668 LPWSTR value = NULL;
669
670 if (szProduct) product = strdupAtoW(szProduct);
671 if (szUserSid) usersid = strdupAtoW(szUserSid);
672 if (szProperty) property = strdupAtoW(szProperty);
673 if (szValue) value = strdupAtoW(szValue);
674
675 ret = MsiSourceListSetInfoW(product, usersid, dwContext, dwOptions,
676 property, value);
677
678 free(product);
679 free(usersid);
680 free(property);
681 free(value);
682
683 return ret;
684 }
685
msi_set_last_used_source(LPCWSTR product,LPCWSTR usersid,MSIINSTALLCONTEXT context,DWORD options,LPCWSTR value)686 UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid,
687 MSIINSTALLCONTEXT context, DWORD options,
688 LPCWSTR value)
689 {
690 HKEY source;
691 LPWSTR buffer;
692 WCHAR typechar;
693 DWORD size;
694 UINT r;
695 int index = 1;
696
697 if (options & MSISOURCETYPE_NETWORK)
698 typechar = 'n';
699 else if (options & MSISOURCETYPE_URL)
700 typechar = 'u';
701 else if (options & MSISOURCETYPE_MEDIA)
702 typechar = 'm';
703 else
704 return ERROR_INVALID_PARAMETER;
705
706 if (!(options & MSISOURCETYPE_MEDIA))
707 {
708 r = MsiSourceListAddSourceExW(product, usersid, context,
709 options, value, 0);
710 if (r != ERROR_SUCCESS)
711 return r;
712
713 index = 0;
714 while ((r = MsiSourceListEnumSourcesW(product, usersid, context, options,
715 index, NULL, NULL)) == ERROR_SUCCESS)
716 index++;
717
718 if (r != ERROR_NO_MORE_ITEMS)
719 return r;
720 }
721
722 size = lstrlenW(L"%c;%d;%s") + lstrlenW(value) + 7;
723 buffer = malloc(size * sizeof(WCHAR));
724 if (!buffer)
725 return ERROR_OUTOFMEMORY;
726
727 r = OpenSourceKey(product, &source, MSICODE_PRODUCT, context, FALSE);
728 if (r != ERROR_SUCCESS)
729 {
730 free(buffer);
731 return r;
732 }
733
734 swprintf(buffer, size, L"%c;%d;%s", typechar, index, value);
735
736 size = (lstrlenW(buffer) + 1) * sizeof(WCHAR);
737 r = RegSetValueExW(source, INSTALLPROPERTY_LASTUSEDSOURCEW, 0,
738 REG_SZ, (LPBYTE)buffer, size);
739 free(buffer);
740
741 RegCloseKey(source);
742 return r;
743 }
744
745 /******************************************************************
746 * MsiSourceListSetInfoW (MSI.@)
747 */
MsiSourceListSetInfoW(const WCHAR * szProduct,const WCHAR * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,const WCHAR * szProperty,const WCHAR * szValue)748 UINT WINAPI MsiSourceListSetInfoW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext,
749 DWORD dwOptions, const WCHAR *szProperty, const WCHAR *szValue )
750 {
751 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
752 HKEY sourcekey, media;
753 LPCWSTR property;
754 UINT rc;
755
756 TRACE( "%s, %s, %d, %#lx, %s, %s\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions,
757 debugstr_w(szProperty), debugstr_w(szValue) );
758
759 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
760 return ERROR_INVALID_PARAMETER;
761
762 if (!szProperty)
763 return ERROR_INVALID_PARAMETER;
764
765 if (!szValue)
766 return ERROR_UNKNOWN_PROPERTY;
767
768 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
769 return ERROR_INVALID_PARAMETER;
770
771 if (dwOptions & MSICODE_PATCH)
772 {
773 FIXME("Unhandled options MSICODE_PATCH\n");
774 return ERROR_UNKNOWN_PATCH;
775 }
776
777 property = szProperty;
778 if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ))
779 property = L"MediaPackage";
780
781 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
782 if (rc != ERROR_SUCCESS)
783 return rc;
784
785 if (wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) &&
786 dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))
787 {
788 RegCloseKey(sourcekey);
789 return ERROR_INVALID_PARAMETER;
790 }
791
792 if (!wcscmp( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) ||
793 !wcscmp( szProperty, INSTALLPROPERTY_DISKPROMPTW ))
794 {
795 rc = OpenMediaSubkey(sourcekey, &media, TRUE);
796 if (rc == ERROR_SUCCESS)
797 {
798 rc = msi_reg_set_val_str(media, property, szValue);
799 RegCloseKey(media);
800 }
801 }
802 else if (!wcscmp( szProperty, INSTALLPROPERTY_PACKAGENAMEW ))
803 {
804 DWORD size = (lstrlenW(szValue) + 1) * sizeof(WCHAR);
805 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0,
806 REG_SZ, (const BYTE *)szValue, size);
807 if (rc != ERROR_SUCCESS)
808 rc = ERROR_UNKNOWN_PROPERTY;
809 }
810 else if (!wcscmp( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ))
811 {
812 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
813 rc = ERROR_INVALID_PARAMETER;
814 else
815 rc = msi_set_last_used_source(szProduct, szUserSid, dwContext,
816 dwOptions, szValue);
817 }
818 else
819 rc = ERROR_UNKNOWN_PROPERTY;
820
821 RegCloseKey(sourcekey);
822 return rc;
823 }
824
825 /******************************************************************
826 * MsiSourceListAddSourceW (MSI.@)
827 */
MsiSourceListAddSourceW(LPCWSTR szProduct,LPCWSTR szUserName,DWORD dwReserved,LPCWSTR szSource)828 UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
829 DWORD dwReserved, LPCWSTR szSource)
830 {
831 WCHAR *sidstr = NULL, squashed_pc[SQUASHED_GUID_SIZE];
832 INT ret;
833 DWORD sidsize = 0, domsize = 0, context;
834 HKEY hkey = 0;
835 UINT r;
836
837 TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
838
839 if (!szSource || !*szSource)
840 return ERROR_INVALID_PARAMETER;
841
842 if (dwReserved != 0)
843 return ERROR_INVALID_PARAMETER;
844
845 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
846 return ERROR_INVALID_PARAMETER;
847
848 if (!szUserName || !*szUserName)
849 context = MSIINSTALLCONTEXT_MACHINE;
850 else
851 {
852 if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, &domsize, NULL))
853 {
854 PSID psid = malloc(sidsize);
855
856 if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL))
857 ConvertSidToStringSidW(psid, &sidstr);
858
859 free(psid);
860 }
861
862 r = MSIREG_OpenProductKey(szProduct, NULL,
863 MSIINSTALLCONTEXT_USERMANAGED, &hkey, FALSE);
864 if (r == ERROR_SUCCESS)
865 context = MSIINSTALLCONTEXT_USERMANAGED;
866 else
867 {
868 r = MSIREG_OpenProductKey(szProduct, NULL,
869 MSIINSTALLCONTEXT_USERUNMANAGED,
870 &hkey, FALSE);
871 if (r != ERROR_SUCCESS)
872 return ERROR_UNKNOWN_PRODUCT;
873
874 context = MSIINSTALLCONTEXT_USERUNMANAGED;
875 }
876
877 RegCloseKey(hkey);
878 }
879
880 ret = MsiSourceListAddSourceExW(szProduct, sidstr,
881 context, MSISOURCETYPE_NETWORK, szSource, 0);
882
883 if (sidstr)
884 LocalFree(sidstr);
885
886 return ret;
887 }
888
889 /******************************************************************
890 * MsiSourceListAddSourceA (MSI.@)
891 */
MsiSourceListAddSourceA(LPCSTR szProduct,LPCSTR szUserName,DWORD dwReserved,LPCSTR szSource)892 UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName,
893 DWORD dwReserved, LPCSTR szSource)
894 {
895 INT ret;
896 LPWSTR szwproduct;
897 LPWSTR szwusername;
898 LPWSTR szwsource;
899
900 szwproduct = strdupAtoW( szProduct );
901 szwusername = strdupAtoW( szUserName );
902 szwsource = strdupAtoW( szSource );
903
904 ret = MsiSourceListAddSourceW(szwproduct, szwusername, dwReserved, szwsource);
905
906 free(szwproduct);
907 free(szwusername);
908 free(szwsource);
909
910 return ret;
911 }
912
913 /******************************************************************
914 * MsiSourceListAddSourceExA (MSI.@)
915 */
MsiSourceListAddSourceExA(LPCSTR szProduct,LPCSTR szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,LPCSTR szSource,DWORD dwIndex)916 UINT WINAPI MsiSourceListAddSourceExA(LPCSTR szProduct, LPCSTR szUserSid,
917 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCSTR szSource, DWORD dwIndex)
918 {
919 UINT ret;
920 LPWSTR product, usersid, source;
921
922 product = strdupAtoW(szProduct);
923 usersid = strdupAtoW(szUserSid);
924 source = strdupAtoW(szSource);
925
926 ret = MsiSourceListAddSourceExW(product, usersid, dwContext,
927 dwOptions, source, dwIndex);
928
929 free(product);
930 free(usersid);
931 free(source);
932
933 return ret;
934 }
935
free_source_list(struct list * sourcelist)936 static void free_source_list(struct list *sourcelist)
937 {
938 while (!list_empty(sourcelist))
939 {
940 struct media_info *info = LIST_ENTRY(list_head(sourcelist), struct media_info, entry);
941 list_remove(&info->entry);
942 free(info->path);
943 free(info);
944 }
945 }
946
add_source_to_list(struct list * sourcelist,struct media_info * info,DWORD * index)947 static void add_source_to_list(struct list *sourcelist, struct media_info *info, DWORD *index)
948 {
949 struct media_info *iter;
950 BOOL found = FALSE;
951
952 if (index) *index = 0;
953
954 if (list_empty(sourcelist))
955 {
956 list_add_head(sourcelist, &info->entry);
957 return;
958 }
959
960 LIST_FOR_EACH_ENTRY(iter, sourcelist, struct media_info, entry)
961 {
962 if (!found && info->index < iter->index)
963 {
964 found = TRUE;
965 list_add_before(&iter->entry, &info->entry);
966 }
967
968 /* update the rest of the list */
969 if (found)
970 swprintf(iter->szIndex, ARRAY_SIZE(iter->szIndex), L"%d", ++iter->index);
971 else if (index)
972 (*index)++;
973 }
974
975 if (!found)
976 list_add_after(&iter->entry, &info->entry);
977 }
978
fill_source_list(struct list * sourcelist,HKEY sourcekey,DWORD * count)979 static UINT fill_source_list(struct list *sourcelist, HKEY sourcekey, DWORD *count)
980 {
981 UINT r = ERROR_SUCCESS;
982 DWORD index = 0;
983 WCHAR name[10];
984 DWORD size, val_size;
985 struct media_info *entry;
986
987 *count = 0;
988
989 while (r == ERROR_SUCCESS)
990 {
991 size = ARRAY_SIZE(name);
992 r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, NULL, &val_size);
993 if (r != ERROR_SUCCESS)
994 return r;
995
996 entry = malloc(sizeof(*entry));
997 if (!entry)
998 goto error;
999
1000 entry->path = malloc(val_size);
1001 if (!entry->path)
1002 {
1003 free(entry);
1004 goto error;
1005 }
1006
1007 lstrcpyW(entry->szIndex, name);
1008 entry->index = wcstol(name, NULL, 10);
1009
1010 size++;
1011 r = RegEnumValueW(sourcekey, index, name, &size, NULL,
1012 NULL, (LPBYTE)entry->path, &val_size);
1013 if (r != ERROR_SUCCESS)
1014 {
1015 free(entry->path);
1016 free(entry);
1017 goto error;
1018 }
1019
1020 index = ++(*count);
1021 add_source_to_list(sourcelist, entry, NULL);
1022 }
1023
1024 error:
1025 *count = -1;
1026 free_source_list(sourcelist);
1027 return ERROR_OUTOFMEMORY;
1028 }
1029
1030 /******************************************************************
1031 * MsiSourceListAddSourceExW (MSI.@)
1032 */
MsiSourceListAddSourceExW(const WCHAR * szProduct,const WCHAR * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,const WCHAR * szSource,DWORD dwIndex)1033 UINT WINAPI MsiSourceListAddSourceExW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext,
1034 DWORD dwOptions, const WCHAR *szSource, DWORD dwIndex )
1035 {
1036 HKEY sourcekey, typekey;
1037 UINT rc;
1038 struct list sourcelist;
1039 struct media_info *info;
1040 WCHAR *source, squashed_pc[SQUASHED_GUID_SIZE], name[10];
1041 LPCWSTR postfix;
1042 DWORD size, count, index;
1043
1044 TRACE( "%s, %s, %d, %#lx, %s, %lu\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions,
1045 debugstr_w(szSource), dwIndex );
1046
1047 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1048 return ERROR_INVALID_PARAMETER;
1049
1050 if (!szSource || !*szSource)
1051 return ERROR_INVALID_PARAMETER;
1052
1053 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
1054 return ERROR_INVALID_PARAMETER;
1055
1056 if (dwOptions & MSICODE_PATCH)
1057 {
1058 FIXME("Unhandled options MSICODE_PATCH\n");
1059 return ERROR_FUNCTION_FAILED;
1060 }
1061
1062 if (szUserSid && (dwContext & MSIINSTALLCONTEXT_MACHINE))
1063 return ERROR_INVALID_PARAMETER;
1064
1065 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1066 if (rc != ERROR_SUCCESS)
1067 return rc;
1068
1069 if (dwOptions & MSISOURCETYPE_NETWORK)
1070 rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
1071 else if (dwOptions & MSISOURCETYPE_URL)
1072 rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
1073 else if (dwOptions & MSISOURCETYPE_MEDIA)
1074 rc = OpenMediaSubkey(sourcekey, &typekey, TRUE);
1075 else
1076 {
1077 ERR( "unknown media type: %#lx\n", dwOptions );
1078 RegCloseKey(sourcekey);
1079 return ERROR_FUNCTION_FAILED;
1080 }
1081 if (rc != ERROR_SUCCESS)
1082 {
1083 ERR("can't open subkey %u\n", rc);
1084 RegCloseKey(sourcekey);
1085 return rc;
1086 }
1087
1088 postfix = (dwOptions & MSISOURCETYPE_NETWORK) ? L"\\" : L"/";
1089 if (szSource[lstrlenW(szSource) - 1] == *postfix)
1090 source = wcsdup(szSource);
1091 else
1092 {
1093 size = lstrlenW(szSource) + 2;
1094 source = malloc(size * sizeof(WCHAR));
1095 lstrcpyW(source, szSource);
1096 lstrcatW(source, postfix);
1097 }
1098
1099 list_init(&sourcelist);
1100 rc = fill_source_list(&sourcelist, typekey, &count);
1101 if (rc != ERROR_NO_MORE_ITEMS)
1102 goto done;
1103
1104 size = (lstrlenW(source) + 1) * sizeof(WCHAR);
1105
1106 if (count == 0)
1107 {
1108 rc = RegSetValueExW(typekey, L"1", 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1109 goto done;
1110 }
1111 else if (dwIndex > count || dwIndex == 0)
1112 {
1113 swprintf(name, ARRAY_SIZE(name), L"%d", count + 1);
1114 rc = RegSetValueExW(typekey, name, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
1115 goto done;
1116 }
1117 else
1118 {
1119 swprintf(name, ARRAY_SIZE(name), L"%d", dwIndex);
1120 info = malloc(sizeof(*info));
1121 if (!info)
1122 {
1123 rc = ERROR_OUTOFMEMORY;
1124 goto done;
1125 }
1126
1127 info->path = wcsdup(source);
1128 lstrcpyW(info->szIndex, name);
1129 info->index = dwIndex;
1130 add_source_to_list(&sourcelist, info, &index);
1131
1132 LIST_FOR_EACH_ENTRY(info, &sourcelist, struct media_info, entry)
1133 {
1134 if (info->index < index)
1135 continue;
1136
1137 size = (lstrlenW(info->path) + 1) * sizeof(WCHAR);
1138 rc = RegSetValueExW(typekey, info->szIndex, 0,
1139 REG_EXPAND_SZ, (LPBYTE)info->path, size);
1140 if (rc != ERROR_SUCCESS)
1141 goto done;
1142 }
1143 }
1144
1145 done:
1146 free_source_list(&sourcelist);
1147 free(source);
1148 RegCloseKey(typekey);
1149 RegCloseKey(sourcekey);
1150 return rc;
1151 }
1152
1153 /******************************************************************
1154 * MsiSourceListAddMediaDiskA (MSI.@)
1155 */
MsiSourceListAddMediaDiskA(LPCSTR szProduct,LPCSTR szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,DWORD dwDiskId,LPCSTR szVolumeLabel,LPCSTR szDiskPrompt)1156 UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR szProduct, LPCSTR szUserSid,
1157 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
1158 LPCSTR szVolumeLabel, LPCSTR szDiskPrompt)
1159 {
1160 UINT r;
1161 LPWSTR product = NULL;
1162 LPWSTR usersid = NULL;
1163 LPWSTR volume = NULL;
1164 LPWSTR prompt = NULL;
1165
1166 if (szProduct) product = strdupAtoW(szProduct);
1167 if (szUserSid) usersid = strdupAtoW(szUserSid);
1168 if (szVolumeLabel) volume = strdupAtoW(szVolumeLabel);
1169 if (szDiskPrompt) prompt = strdupAtoW(szDiskPrompt);
1170
1171 r = MsiSourceListAddMediaDiskW(product, usersid, dwContext, dwOptions,
1172 dwDiskId, volume, prompt);
1173
1174 free(product);
1175 free(usersid);
1176 free(volume);
1177 free(prompt);
1178
1179 return r;
1180 }
1181
1182 /******************************************************************
1183 * MsiSourceListAddMediaDiskW (MSI.@)
1184 */
MsiSourceListAddMediaDiskW(const WCHAR * szProduct,const WCHAR * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,DWORD dwDiskId,const WCHAR * szVolumeLabel,const WCHAR * szDiskPrompt)1185 UINT WINAPI MsiSourceListAddMediaDiskW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext,
1186 DWORD dwOptions, DWORD dwDiskId, const WCHAR *szVolumeLabel,
1187 const WCHAR *szDiskPrompt )
1188 {
1189 HKEY sourcekey, mediakey;
1190 UINT rc;
1191 WCHAR *buffer, squashed_pc[SQUASHED_GUID_SIZE], szIndex[10];
1192 DWORD size;
1193
1194 TRACE( "%s, %s, %d, %#lx, %lu, %s, %s\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions,
1195 dwDiskId, debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt) );
1196
1197 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
1198 return ERROR_INVALID_PARAMETER;
1199
1200 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH)
1201 return ERROR_INVALID_PARAMETER;
1202
1203 if ((szVolumeLabel && !*szVolumeLabel) || (szDiskPrompt && !*szDiskPrompt))
1204 return ERROR_INVALID_PARAMETER;
1205
1206 if ((dwContext & MSIINSTALLCONTEXT_MACHINE) && szUserSid)
1207 return ERROR_INVALID_PARAMETER;
1208
1209 if (dwOptions & MSICODE_PATCH)
1210 {
1211 FIXME("Unhandled options MSICODE_PATCH\n");
1212 return ERROR_FUNCTION_FAILED;
1213 }
1214
1215 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
1216 if (rc != ERROR_SUCCESS)
1217 return rc;
1218
1219 OpenMediaSubkey(sourcekey, &mediakey, TRUE);
1220
1221 swprintf(szIndex, ARRAY_SIZE(szIndex), L"%d", dwDiskId);
1222
1223 size = 2;
1224 if (szVolumeLabel) size += lstrlenW(szVolumeLabel);
1225 if (szDiskPrompt) size += lstrlenW(szDiskPrompt);
1226
1227 size *= sizeof(WCHAR);
1228 buffer = malloc(size);
1229 *buffer = '\0';
1230
1231 if (szVolumeLabel) lstrcpyW(buffer, szVolumeLabel);
1232 lstrcatW(buffer, L";");
1233 if (szDiskPrompt) lstrcatW(buffer, szDiskPrompt);
1234
1235 RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
1236 free(buffer);
1237
1238 RegCloseKey(sourcekey);
1239 RegCloseKey(mediakey);
1240
1241 return ERROR_SUCCESS;
1242 }
1243
1244 /******************************************************************
1245 * MsiSourceListClearAllA (MSI.@)
1246 */
MsiSourceListClearAllA(const char * szProduct,const char * szUserName,DWORD dwReserved)1247 UINT WINAPI MsiSourceListClearAllA( const char *szProduct, const char *szUserName, DWORD dwReserved )
1248 {
1249 FIXME( "%s, %s, %#lx\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved );
1250 return ERROR_SUCCESS;
1251 }
1252
1253 /******************************************************************
1254 * MsiSourceListClearAllW (MSI.@)
1255 */
MsiSourceListClearAllW(const WCHAR * szProduct,const WCHAR * szUserName,DWORD dwReserved)1256 UINT WINAPI MsiSourceListClearAllW( const WCHAR *szProduct, const WCHAR *szUserName, DWORD dwReserved )
1257 {
1258 FIXME( "%s, %s, %#lx\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved );
1259 return ERROR_SUCCESS;
1260 }
1261
1262 /******************************************************************
1263 * MsiSourceListClearAllExA (MSI.@)
1264 */
MsiSourceListClearAllExA(const char * szProduct,const char * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions)1265 UINT WINAPI MsiSourceListClearAllExA( const char *szProduct, const char *szUserSid, MSIINSTALLCONTEXT dwContext,
1266 DWORD dwOptions )
1267 {
1268 FIXME( "%s, %s, %d, %#lx\n", debugstr_a(szProduct), debugstr_a(szUserSid), dwContext, dwOptions );
1269 return ERROR_SUCCESS;
1270 }
1271
1272 /******************************************************************
1273 * MsiSourceListClearAllExW (MSI.@)
1274 */
MsiSourceListClearAllExW(const WCHAR * szProduct,const WCHAR * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions)1275 UINT WINAPI MsiSourceListClearAllExW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext,
1276 DWORD dwOptions )
1277 {
1278 FIXME( "%s, %s, %d, %#lx\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions );
1279 return ERROR_SUCCESS;
1280 }
1281
1282 /******************************************************************
1283 * MsiSourceListClearSourceA (MSI.@)
1284 */
MsiSourceListClearSourceA(const char * szProductCodeOrPatchCode,const char * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,const char * szSource)1285 UINT WINAPI MsiSourceListClearSourceA( const char *szProductCodeOrPatchCode, const char *szUserSid,
1286 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, const char *szSource )
1287 {
1288 FIXME( "%s, %s, %d, %#lx, %s\n", debugstr_a(szProductCodeOrPatchCode), debugstr_a(szUserSid), dwContext,
1289 dwOptions, debugstr_a(szSource) );
1290 return ERROR_SUCCESS;
1291 }
1292
1293 /******************************************************************
1294 * MsiSourceListClearSourceW (MSI.@)
1295 */
MsiSourceListClearSourceW(const WCHAR * szProductCodeOrPatchCode,const WCHAR * szUserSid,MSIINSTALLCONTEXT dwContext,DWORD dwOptions,LPCWSTR szSource)1296 UINT WINAPI MsiSourceListClearSourceW( const WCHAR *szProductCodeOrPatchCode, const WCHAR *szUserSid,
1297 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource )
1298 {
1299 FIXME( "%s, %s, %d, %#lx, %s\n", debugstr_w(szProductCodeOrPatchCode), debugstr_w(szUserSid), dwContext,
1300 dwOptions, debugstr_w(szSource) );
1301 return ERROR_SUCCESS;
1302 }
1303
1304 /******************************************************************
1305 * MsiSourceListForceResolutionA (MSI.@)
1306 */
MsiSourceListForceResolutionA(const char * product,const char * user,DWORD reserved)1307 UINT WINAPI MsiSourceListForceResolutionA( const char *product, const char *user, DWORD reserved )
1308 {
1309 FIXME( "%s, %s, %#lx\n", debugstr_a(product), debugstr_a(user), reserved );
1310 return ERROR_SUCCESS;
1311 }
1312
1313 /******************************************************************
1314 * MsiSourceListForceResolutionW (MSI.@)
1315 */
MsiSourceListForceResolutionW(const WCHAR * product,const WCHAR * user,DWORD reserved)1316 UINT WINAPI MsiSourceListForceResolutionW( const WCHAR *product, const WCHAR *user, DWORD reserved )
1317 {
1318 FIXME( "%s, %s, %#lx\n", debugstr_w(product), debugstr_w(user), reserved );
1319 return ERROR_SUCCESS;
1320 }
1321