msi: Implement MsiSourceListEnumSources.
[wine.git] / dlls / msi / source.c
blob53a2821c662f41d0f0e9d587b44c306bf0517f8f
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2005 Aric Stewart for CodeWeavers
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.
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.
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
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
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 "sddl.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
44 * These apis are defined in MSI 3.0
47 typedef struct tagMediaInfo
49 struct list entry;
50 LPWSTR path;
51 WCHAR szIndex[10];
52 DWORD index;
53 } media_info;
55 static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, DWORD dwOptions,
56 MSIINSTALLCONTEXT context, BOOL create)
58 HKEY rootkey = 0;
59 UINT rc = ERROR_FUNCTION_FAILED;
60 static const WCHAR szSourceList[] = {'S','o','u','r','c','e','L','i','s','t',0};
62 if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
64 if (dwOptions & MSICODE_PATCH)
65 rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
66 else
67 rc = MSIREG_OpenUserProductsKey(szProduct, &rootkey, create);
69 else if (context == MSIINSTALLCONTEXT_USERMANAGED)
71 if (dwOptions & MSICODE_PATCH)
72 rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
73 else
74 rc = MSIREG_OpenLocalManagedProductKey(szProduct, &rootkey, create);
76 else if (context == MSIINSTALLCONTEXT_MACHINE)
78 if (dwOptions & MSICODE_PATCH)
79 rc = MSIREG_OpenPatchesKey(szProduct, &rootkey, create);
80 else
81 rc = MSIREG_OpenLocalClassesProductKey(szProduct, &rootkey, create);
84 if (rc != ERROR_SUCCESS)
86 if (dwOptions & MSICODE_PATCH)
87 return ERROR_UNKNOWN_PATCH;
88 else
89 return ERROR_UNKNOWN_PRODUCT;
92 if (create)
93 rc = RegCreateKeyW(rootkey, szSourceList, key);
94 else
96 rc = RegOpenKeyW(rootkey,szSourceList, key);
97 if (rc != ERROR_SUCCESS)
98 rc = ERROR_BAD_CONFIGURATION;
101 return rc;
104 static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create)
106 UINT rc;
107 static const WCHAR media[] = {'M','e','d','i','a',0};
109 if (create)
110 rc = RegCreateKeyW(rootkey, media, key);
111 else
112 rc = RegOpenKeyW(rootkey,media, key);
114 return rc;
117 static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create)
119 UINT rc;
120 static const WCHAR net[] = {'N','e','t',0};
122 if (create)
123 rc = RegCreateKeyW(rootkey, net, key);
124 else
125 rc = RegOpenKeyW(rootkey, net, key);
127 return rc;
130 static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create)
132 UINT rc;
133 static const WCHAR URL[] = {'U','R','L',0};
135 if (create)
136 rc = RegCreateKeyW(rootkey, URL, key);
137 else
138 rc = RegOpenKeyW(rootkey, URL, key);
140 return rc;
143 /******************************************************************
144 * MsiSourceListEnumSourcesA (MSI.@)
146 UINT WINAPI MsiSourceListEnumSourcesA(LPCSTR szProductCodeOrPatch, LPCSTR szUserSid,
147 MSIINSTALLCONTEXT dwContext,
148 DWORD dwOptions, DWORD dwIndex,
149 LPSTR szSource, LPDWORD pcchSource)
151 LPWSTR product = NULL;
152 LPWSTR usersid = NULL;
153 LPWSTR source = NULL;
154 DWORD len = 0;
155 UINT r = ERROR_INVALID_PARAMETER;
156 static int index = 0;
158 TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_a(szProductCodeOrPatch),
159 debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource);
161 if (dwIndex == 0)
162 index = 0;
164 if (szSource && !pcchSource)
165 goto done;
167 if (dwIndex != index)
168 goto done;
170 if (szProductCodeOrPatch) product = strdupAtoW(szProductCodeOrPatch);
171 if (szUserSid) usersid = strdupAtoW(szUserSid);
173 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
174 dwIndex, NULL, &len);
175 if (r != ERROR_SUCCESS)
176 goto done;
178 source = msi_alloc(++len * sizeof(WCHAR));
179 if (!source)
181 r = ERROR_OUTOFMEMORY;
182 goto done;
185 *source = '\0';
186 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions,
187 dwIndex, source, &len);
188 if (r != ERROR_SUCCESS)
189 goto done;
191 len = WideCharToMultiByte(CP_ACP, 0, source, -1, NULL, 0, NULL, NULL);
192 if (*pcchSource >= len)
193 WideCharToMultiByte(CP_ACP, 0, source, -1, szSource, len, NULL, NULL);
194 else if (szSource)
195 r = ERROR_MORE_DATA;
197 *pcchSource = len - 1;
199 done:
200 msi_free(product);
201 msi_free(usersid);
202 msi_free(source);
204 if (r == ERROR_SUCCESS)
206 if (szSource) index++;
208 else if (dwIndex > index)
209 index = 0;
211 return r;
214 /******************************************************************
215 * MsiSourceListEnumSourcesW (MSI.@)
217 UINT WINAPI MsiSourceListEnumSourcesW(LPCWSTR szProductCodeOrPatch, LPCWSTR szUserSid,
218 MSIINSTALLCONTEXT dwContext,
219 DWORD dwOptions, DWORD dwIndex,
220 LPWSTR szSource, LPDWORD pcchSource)
222 WCHAR squished_pc[GUID_SIZE];
223 WCHAR name[32];
224 HKEY source = NULL;
225 HKEY subkey = NULL;
226 LONG res;
227 UINT r = ERROR_INVALID_PARAMETER;
228 static int index = 0;
230 static const WCHAR format[] = {'%','d',0};
232 TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_w(szProductCodeOrPatch),
233 debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource);
235 if (dwIndex == 0)
236 index = 0;
238 if (!szProductCodeOrPatch || !squash_guid(szProductCodeOrPatch, squished_pc))
239 goto done;
241 if (szSource && !pcchSource)
242 goto done;
244 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
245 goto done;
247 if ((dwOptions & MSISOURCETYPE_NETWORK) && (dwOptions & MSISOURCETYPE_URL))
248 goto done;
250 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
251 goto done;
253 if (dwIndex != index)
254 goto done;
256 r = OpenSourceKey(szProductCodeOrPatch, &source,
257 dwOptions, dwContext, FALSE);
258 if (r != ERROR_SUCCESS)
259 goto done;
261 if (dwOptions & MSISOURCETYPE_NETWORK)
262 r = OpenNetworkSubkey(source, &subkey, FALSE);
263 else if (dwOptions & MSISOURCETYPE_URL)
264 r = OpenURLSubkey(source, &subkey, FALSE);
266 if (r != ERROR_SUCCESS)
268 r = ERROR_NO_MORE_ITEMS;
269 goto done;
272 sprintfW(name, format, dwIndex + 1);
274 res = RegQueryValueExW(subkey, name, 0, 0, (LPBYTE)szSource, pcchSource);
275 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
276 r = ERROR_NO_MORE_ITEMS;
278 done:
279 RegCloseKey(subkey);
280 RegCloseKey(source);
282 if (r == ERROR_SUCCESS)
284 if (szSource) index++;
286 else if (dwIndex > index)
287 index = 0;
289 return r;
292 /******************************************************************
293 * MsiSourceListGetInfoA (MSI.@)
295 UINT WINAPI MsiSourceListGetInfoA( LPCSTR szProduct, LPCSTR szUserSid,
296 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
297 LPCSTR szProperty, LPSTR szValue,
298 LPDWORD pcchValue)
300 UINT ret;
301 LPWSTR product = NULL;
302 LPWSTR usersid = NULL;
303 LPWSTR property = NULL;
304 LPWSTR value = NULL;
305 DWORD len = 0;
307 if (szValue && !pcchValue)
308 return ERROR_INVALID_PARAMETER;
310 if (szProduct) product = strdupAtoW(szProduct);
311 if (szUserSid) usersid = strdupAtoW(szUserSid);
312 if (szProperty) property = strdupAtoW(szProperty);
314 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
315 property, NULL, &len);
316 if (ret != ERROR_SUCCESS)
317 goto done;
319 value = msi_alloc(++len * sizeof(WCHAR));
320 if (!value)
321 return ERROR_OUTOFMEMORY;
323 *value = '\0';
324 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
325 property, value, &len);
326 if (ret != ERROR_SUCCESS)
327 goto done;
329 len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
330 if (*pcchValue >= len)
331 WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
332 else if (szValue)
333 ret = ERROR_MORE_DATA;
335 *pcchValue = len - 1;
337 done:
338 msi_free(product);
339 msi_free(usersid);
340 msi_free(property);
341 msi_free(value);
342 return ret;
345 /******************************************************************
346 * MsiSourceListGetInfoW (MSI.@)
348 UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
349 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
350 LPCWSTR szProperty, LPWSTR szValue,
351 LPDWORD pcchValue)
353 HKEY sourcekey;
354 UINT rc;
356 TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty));
358 if (!szProduct || !*szProduct)
359 return ERROR_INVALID_PARAMETER;
361 if (lstrlenW(szProduct) != GUID_SIZE - 1 ||
362 (szProduct[0] != '{' && szProduct[GUID_SIZE - 2] != '}'))
363 return ERROR_INVALID_PARAMETER;
365 if (szValue && !pcchValue)
366 return ERROR_INVALID_PARAMETER;
368 if (dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
369 dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
370 dwContext != MSIINSTALLCONTEXT_MACHINE)
371 return ERROR_INVALID_PARAMETER;
373 if (!szProperty)
374 return ERROR_INVALID_PARAMETER;
376 if (szUserSid)
377 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
379 if (dwContext != MSIINSTALLCONTEXT_USERUNMANAGED)
380 FIXME("Unhandled context %d\n", dwContext);
382 rc = OpenSourceKey(szProduct, &sourcekey, dwOptions, dwContext, FALSE);
383 if (rc != ERROR_SUCCESS)
384 return rc;
386 if (strcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) == 0)
388 HKEY key;
389 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
390 if (rc == ERROR_SUCCESS)
391 rc = RegQueryValueExW(key, INSTALLPROPERTY_MEDIAPACKAGEPATHW,
392 0, 0, (LPBYTE)szValue, pcchValue);
393 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
394 rc = ERROR_UNKNOWN_PROPERTY;
395 RegCloseKey(key);
397 else if (strcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW) ==0)
399 HKEY key;
400 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
401 if (rc == ERROR_SUCCESS)
402 rc = RegQueryValueExW(key, INSTALLPROPERTY_DISKPROMPTW, 0, 0,
403 (LPBYTE)szValue, pcchValue);
404 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
405 rc = ERROR_UNKNOWN_PROPERTY;
406 RegCloseKey(key);
408 else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0)
410 LPWSTR buffer;
411 DWORD size = 0;
413 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0,
414 NULL, &size);
415 if (size == 0)
416 rc = ERROR_UNKNOWN_PROPERTY;
417 else
419 LPWSTR ptr;
420 buffer = msi_alloc(size);
421 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
422 0, 0, (LPBYTE)buffer,&size);
423 ptr = strchrW(buffer,';');
424 if (ptr) ptr = strchrW(ptr+1,';');
425 if (!ptr)
426 rc = ERROR_UNKNOWN_PROPERTY;
427 else
429 ptr ++;
430 lstrcpynW(szValue, ptr, *pcchValue);
431 if (lstrlenW(ptr) > *pcchValue)
433 *pcchValue = lstrlenW(ptr)+1;
434 rc = ERROR_MORE_DATA;
436 else
437 rc = ERROR_SUCCESS;
439 msi_free(buffer);
442 else if (strcmpW(INSTALLPROPERTY_LASTUSEDTYPEW, szProperty)==0)
444 LPWSTR buffer;
445 DWORD size = 0;
447 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0,
448 NULL, &size);
449 if (size == 0)
450 rc = ERROR_UNKNOWN_PROPERTY;
451 else
453 buffer = msi_alloc(size);
454 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
455 0, 0, (LPBYTE)buffer,&size);
456 if (*pcchValue < 1)
458 rc = ERROR_MORE_DATA;
459 *pcchValue = 1;
461 else
463 szValue[0] = buffer[0];
464 rc = ERROR_SUCCESS;
466 msi_free(buffer);
469 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
471 *pcchValue = *pcchValue * sizeof(WCHAR);
472 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0,
473 (LPBYTE)szValue, pcchValue);
474 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
476 *pcchValue = 0;
477 rc = ERROR_SUCCESS;
479 else
481 if (*pcchValue)
482 *pcchValue = (*pcchValue - 1) / sizeof(WCHAR);
483 if (szValue)
484 szValue[*pcchValue] = '\0';
487 else
489 FIXME("Unknown property %s\n",debugstr_w(szProperty));
490 rc = ERROR_UNKNOWN_PROPERTY;
493 RegCloseKey(sourcekey);
494 return rc;
497 /******************************************************************
498 * MsiSourceListSetInfoA (MSI.@)
500 UINT WINAPI MsiSourceListSetInfoA(LPCSTR szProduct, LPCSTR szUserSid,
501 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
502 LPCSTR szProperty, LPCSTR szValue)
504 UINT ret;
505 LPWSTR product = NULL;
506 LPWSTR usersid = NULL;
507 LPWSTR property = NULL;
508 LPWSTR value = NULL;
510 if (szProduct) product = strdupAtoW(szProduct);
511 if (szUserSid) usersid = strdupAtoW(szUserSid);
512 if (szProperty) property = strdupAtoW(szProperty);
513 if (szValue) value = strdupAtoW(szValue);
515 ret = MsiSourceListSetInfoW(product, usersid, dwContext, dwOptions,
516 property, value);
518 msi_free(product);
519 msi_free(usersid);
520 msi_free(property);
521 msi_free(value);
523 return ret;
526 /******************************************************************
527 * MsiSourceListSetInfoW (MSI.@)
529 UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
530 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
531 LPCWSTR szProperty, LPCWSTR szValue)
533 WCHAR squished_pc[GUID_SIZE];
534 HKEY sourcekey, media;
535 LPCWSTR property;
536 UINT rc;
538 static const WCHAR media_package[] = {
539 'M','e','d','i','a','P','a','c','k','a','g','e',0
542 TRACE("%s %s %x %x %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid),
543 dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue));
545 if (!szProduct || !squash_guid(szProduct, squished_pc))
546 return ERROR_INVALID_PARAMETER;
548 if (!szProperty)
549 return ERROR_INVALID_PARAMETER;
551 if (!szValue)
552 return ERROR_UNKNOWN_PROPERTY;
554 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
555 return ERROR_INVALID_PARAMETER;
557 if (dwOptions & MSICODE_PATCH)
559 FIXME("Unhandled options MSICODE_PATCH\n");
560 return ERROR_UNKNOWN_PATCH;
563 property = szProperty;
564 if (!lstrcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW))
565 property = media_package;
567 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
568 if (rc != ERROR_SUCCESS)
569 return rc;
571 if (lstrcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW) &&
572 dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))
574 RegCloseKey(sourcekey);
575 return ERROR_INVALID_PARAMETER;
578 if (!lstrcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) ||
579 !lstrcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW))
581 rc = OpenMediaSubkey(sourcekey, &media, TRUE);
582 if (rc == ERROR_SUCCESS)
584 rc = msi_reg_set_val_str(media, property, szValue);
585 RegCloseKey(media);
588 else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0)
590 LPWSTR buffer = NULL;
591 DWORD size;
592 WCHAR typechar = 'n';
593 static const WCHAR LastUsedSource_Fmt[] = {'%','c',';','%','i',';','%','s',0};
595 /* make sure the source is registered */
596 MsiSourceListAddSourceExW(szProduct, szUserSid, dwContext,
597 dwOptions, szValue, 0);
599 if (dwOptions & MSISOURCETYPE_NETWORK)
600 typechar = 'n';
601 else if (dwOptions & MSISOURCETYPE_URL)
602 typechar = 'u';
603 else if (dwOptions & MSISOURCETYPE_MEDIA)
604 typechar = 'm';
605 else
606 ERR("Unknown source type! %x\n", dwOptions);
608 size = (lstrlenW(szValue)+5)*sizeof(WCHAR);
609 buffer = msi_alloc(size);
610 sprintfW(buffer, LastUsedSource_Fmt, typechar, 1, szValue);
611 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0,
612 REG_EXPAND_SZ, (LPBYTE)buffer, size);
613 if (rc != ERROR_SUCCESS)
614 rc = ERROR_UNKNOWN_PROPERTY;
615 msi_free( buffer );
617 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
619 DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
620 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0,
621 REG_SZ, (const BYTE *)szValue, size);
622 if (rc != ERROR_SUCCESS)
623 rc = ERROR_UNKNOWN_PROPERTY;
625 else
626 rc = ERROR_UNKNOWN_PROPERTY;
628 RegCloseKey(sourcekey);
629 return rc;
633 /******************************************************************
634 * MsiSourceListAddSourceW (MSI.@)
636 UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
637 DWORD dwReserved, LPCWSTR szSource)
639 INT ret;
640 LPWSTR sidstr = NULL;
641 DWORD sidsize = 0;
642 DWORD domsize = 0;
644 TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
646 if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, &domsize, NULL))
648 PSID psid = msi_alloc(sidsize);
650 if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL))
651 ConvertSidToStringSidW(psid, &sidstr);
653 msi_free(psid);
656 ret = MsiSourceListAddSourceExW(szProduct, sidstr,
657 MSIINSTALLCONTEXT_USERMANAGED, MSISOURCETYPE_NETWORK, szSource, 0);
659 if (sidstr)
660 LocalFree(sidstr);
662 return ret;
665 /******************************************************************
666 * MsiSourceListAddSourceA (MSI.@)
668 UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName,
669 DWORD dwReserved, LPCSTR szSource)
671 INT ret;
672 LPWSTR szwproduct;
673 LPWSTR szwusername;
674 LPWSTR szwsource;
676 szwproduct = strdupAtoW( szProduct );
677 szwusername = strdupAtoW( szUserName );
678 szwsource = strdupAtoW( szSource );
680 ret = MsiSourceListAddSourceW(szwproduct, szwusername, 0, szwsource);
682 msi_free(szwproduct);
683 msi_free(szwusername);
684 msi_free(szwsource);
686 return ret;
689 /******************************************************************
690 * MsiSourceListAddSourceExA (MSI.@)
692 UINT WINAPI MsiSourceListAddSourceExA(LPCSTR szProduct, LPCSTR szUserSid,
693 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCSTR szSource, DWORD dwIndex)
695 UINT ret;
696 LPWSTR product, usersid, source;
698 product = strdupAtoW(szProduct);
699 usersid = strdupAtoW(szUserSid);
700 source = strdupAtoW(szSource);
702 ret = MsiSourceListAddSourceExW(product, usersid, dwContext,
703 dwOptions, source, dwIndex);
705 msi_free(product);
706 msi_free(usersid);
707 msi_free(source);
709 return ret;
712 static void free_source_list(struct list *sourcelist)
714 while (!list_empty(sourcelist))
716 media_info *info = LIST_ENTRY(list_head(sourcelist), media_info, entry);
717 list_remove(&info->entry);
718 msi_free(info->path);
719 msi_free(info);
723 static void add_source_to_list(struct list *sourcelist, media_info *info)
725 media_info *iter;
726 BOOL found = FALSE;
727 static const WCHAR fmt[] = {'%','i',0};
729 if (list_empty(sourcelist))
731 list_add_head(sourcelist, &info->entry);
732 return;
735 LIST_FOR_EACH_ENTRY(iter, sourcelist, media_info, entry)
737 if (!found && info->index < iter->index)
739 found = TRUE;
740 list_add_before(&iter->entry, &info->entry);
743 /* update the rest of the list */
744 if (found)
745 sprintfW(iter->szIndex, fmt, ++iter->index);
748 if (!found)
749 list_add_after(&iter->entry, &info->entry);
752 static UINT fill_source_list(struct list *sourcelist, HKEY sourcekey, DWORD *count)
754 UINT r = ERROR_SUCCESS;
755 DWORD index = 0;
756 WCHAR name[10];
757 DWORD size, val_size;
758 media_info *entry;
760 *count = 0;
762 while (r == ERROR_SUCCESS)
764 size = sizeof(name) / sizeof(name[0]);
765 r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, NULL, &val_size);
766 if (r != ERROR_SUCCESS)
767 return r;
769 entry = msi_alloc(sizeof(media_info));
770 if (!entry)
771 goto error;
773 entry->path = msi_alloc(val_size);
774 if (!entry->path)
776 msi_free(entry);
777 goto error;
780 lstrcpyW(entry->szIndex, name);
781 entry->index = atoiW(name);
783 size++;
784 r = RegEnumValueW(sourcekey, index, name, &size, NULL,
785 NULL, (LPBYTE)entry->path, &val_size);
786 if (r != ERROR_SUCCESS)
788 msi_free(entry->path);
789 msi_free(entry);
790 goto error;
793 index = ++(*count);
794 add_source_to_list(sourcelist, entry);
797 error:
798 *count = -1;
799 free_source_list(sourcelist);
800 return ERROR_OUTOFMEMORY;
803 /******************************************************************
804 * MsiSourceListAddSourceExW (MSI.@)
806 UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
807 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource,
808 DWORD dwIndex)
810 HKEY sourcekey;
811 HKEY typekey;
812 UINT rc;
813 struct list sourcelist;
814 media_info *info;
815 WCHAR squished_pc[GUID_SIZE];
816 WCHAR name[10];
817 LPWSTR source;
818 LPCWSTR postfix;
819 DWORD size, count;
821 static const WCHAR fmt[] = {'%','i',0};
822 static const WCHAR one[] = {'1',0};
823 static const WCHAR backslash[] = {'\\',0};
824 static const WCHAR forwardslash[] = {'/',0};
826 TRACE("%s %s %x %x %s %i\n", debugstr_w(szProduct), debugstr_w(szUserSid),
827 dwContext, dwOptions, debugstr_w(szSource), dwIndex);
829 if (!szProduct || !squash_guid(szProduct, squished_pc))
830 return ERROR_INVALID_PARAMETER;
832 if (!szSource || !*szSource)
833 return ERROR_INVALID_PARAMETER;
835 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)))
836 return ERROR_INVALID_PARAMETER;
838 if (dwOptions & MSICODE_PATCH)
840 FIXME("Unhandled options MSICODE_PATCH\n");
841 return ERROR_FUNCTION_FAILED;
844 if (szUserSid && (dwContext & MSIINSTALLCONTEXT_MACHINE))
845 return ERROR_INVALID_PARAMETER;
847 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE);
848 if (rc != ERROR_SUCCESS)
849 return rc;
851 if (dwOptions & MSISOURCETYPE_NETWORK)
852 rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
853 else if (dwOptions & MSISOURCETYPE_URL)
854 rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
855 else if (dwOptions & MSISOURCETYPE_MEDIA)
856 rc = OpenMediaSubkey(sourcekey, &typekey, TRUE);
857 else
859 ERR("unknown media type: %08x\n", dwOptions);
860 RegCloseKey(sourcekey);
861 return ERROR_FUNCTION_FAILED;
864 postfix = (dwOptions & MSISOURCETYPE_NETWORK) ? backslash : forwardslash;
865 if (szSource[lstrlenW(szSource) - 1] == *postfix)
866 source = strdupW(szSource);
867 else
869 size = lstrlenW(szSource) + 2;
870 source = msi_alloc(size * sizeof(WCHAR));
871 lstrcpyW(source, szSource);
872 lstrcatW(source, postfix);
875 list_init(&sourcelist);
876 rc = fill_source_list(&sourcelist, typekey, &count);
877 if (rc != ERROR_NO_MORE_ITEMS)
878 return rc;
880 size = (lstrlenW(source) + 1) * sizeof(WCHAR);
882 if (count == 0)
884 rc = RegSetValueExW(typekey, one, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
885 goto done;
887 else if (dwIndex > count)
889 sprintfW(name, fmt, count + 1);
890 rc = RegSetValueExW(typekey, name, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
891 goto done;
893 else
895 /* add to the end of the list */
896 if (dwIndex == 0)
897 dwIndex = count + 1;
899 sprintfW(name, fmt, dwIndex);
900 info = msi_alloc(sizeof(media_info));
901 if (!info)
903 rc = ERROR_OUTOFMEMORY;
904 goto done;
907 info->path = strdupW(source);
908 lstrcpyW(info->szIndex, name);
909 info->index = dwIndex;
910 add_source_to_list(&sourcelist, info);
912 LIST_FOR_EACH_ENTRY(info, &sourcelist, media_info, entry)
914 size = (lstrlenW(info->path) + 1) * sizeof(WCHAR);
915 rc = RegSetValueExW(typekey, info->szIndex, 0,
916 REG_EXPAND_SZ, (LPBYTE)info->path, size);
917 if (rc != ERROR_SUCCESS)
918 goto done;
922 done:
923 free_source_list(&sourcelist);
924 msi_free(source);
925 RegCloseKey(typekey);
926 RegCloseKey(sourcekey);
927 return rc;
930 /******************************************************************
931 * MsiSourceListAddMediaDisk(MSI.@)
933 UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid,
934 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
935 LPCWSTR szVolumeLabel, LPCWSTR szDiskPrompt)
937 HKEY sourcekey;
938 HKEY mediakey;
939 UINT rc;
940 WCHAR szIndex[10];
941 static const WCHAR fmt[] = {'%','i',0};
942 static const WCHAR disk_fmt[] = {'%','s',';','%','s',0};
943 static const WCHAR empty[1] = {0};
944 LPCWSTR pt1,pt2;
945 LPWSTR buffer;
946 DWORD size;
948 TRACE("%s %s %x %x %i %s %s\n", debugstr_w(szProduct),
949 debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId,
950 debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt));
952 if (!szProduct || lstrlenW(szProduct) > 39)
953 return ERROR_INVALID_PARAMETER;
955 if (dwOptions & MSICODE_PATCH)
957 FIXME("Unhandled options MSICODE_PATCH\n");
958 return ERROR_FUNCTION_FAILED;
961 if (szUserSid)
962 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
964 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
965 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
967 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, TRUE);
968 if (rc != ERROR_SUCCESS)
969 return ERROR_UNKNOWN_PRODUCT;
971 OpenMediaSubkey(sourcekey,&mediakey,TRUE);
973 sprintfW(szIndex,fmt,dwDiskId);
975 size = 2;
976 if (szVolumeLabel)
978 size +=lstrlenW(szVolumeLabel);
979 pt1 = szVolumeLabel;
981 else
982 pt1 = empty;
983 if (szDiskPrompt)
985 size +=lstrlenW(szDiskPrompt);
986 pt2 = szDiskPrompt;
988 else
989 pt2 = empty;
991 size *=sizeof(WCHAR);
993 buffer = msi_alloc(size);
994 sprintfW(buffer,disk_fmt,pt1,pt2);
996 RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
997 msi_free( buffer );
999 RegCloseKey(sourcekey);
1000 RegCloseKey(mediakey);
1002 return ERROR_SUCCESS;
1005 /******************************************************************
1006 * MsiSourceListClearAllA (MSI.@)
1008 UINT WINAPI MsiSourceListClearAllA( LPCSTR szProduct, LPCSTR szUserName, DWORD dwReserved )
1010 FIXME("(%s %s %d)\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved);
1011 return ERROR_SUCCESS;
1014 /******************************************************************
1015 * MsiSourceListClearAllW (MSI.@)
1017 UINT WINAPI MsiSourceListClearAllW( LPCWSTR szProduct, LPCWSTR szUserName, DWORD dwReserved )
1019 FIXME("(%s %s %d)\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved);
1020 return ERROR_SUCCESS;