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
24 #define NONAMELESSUNION
31 #include "wine/debug.h"
38 #include "wine/unicode.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
44 * These apis are defined in MSI 3.0
47 typedef struct tagMediaInfo
54 static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, DWORD dwOptions, BOOL user, BOOL create)
58 static const WCHAR szSourceList[] = {'S','o','u','r','c','e','L','i','s','t',0};
62 if (dwOptions == MSICODE_PATCH)
63 rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create);
65 rc = MSIREG_OpenUserProductsKey(szProduct, &rootkey, create);
69 if (dwOptions == MSICODE_PATCH)
70 rc = MSIREG_OpenPatchesKey(szProduct, &rootkey, create);
72 rc = MSIREG_OpenProductsKey(szProduct, &rootkey, create);
77 if (dwOptions == MSICODE_PATCH)
78 return ERROR_UNKNOWN_PATCH;
80 return ERROR_UNKNOWN_PRODUCT;
84 rc = RegCreateKeyW(rootkey, szSourceList, key);
87 rc = RegOpenKeyW(rootkey,szSourceList, key);
88 if (rc != ERROR_SUCCESS)
89 rc = ERROR_BAD_CONFIGURATION;
95 static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create)
98 static const WCHAR media[] = {'M','e','d','i','a',0};
101 rc = RegCreateKeyW(rootkey, media, key);
103 rc = RegOpenKeyW(rootkey,media, key);
108 static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create)
111 static const WCHAR net[] = {'N','e','t',0};
114 rc = RegCreateKeyW(rootkey, net, key);
116 rc = RegOpenKeyW(rootkey, net, key);
121 static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create)
124 static const WCHAR URL[] = {'U','R','L',0};
127 rc = RegCreateKeyW(rootkey, URL, key);
129 rc = RegOpenKeyW(rootkey, URL, key);
135 static UINT find_given_source(HKEY key, LPCWSTR szSource, media_info *ss)
142 UINT rc = ERROR_SUCCESS;
144 while (rc == ERROR_SUCCESS)
148 size = sizeof(szIndex)/sizeof(szIndex[0]);
149 rc = RegEnumValueW(key, index, szIndex, &size, NULL, NULL, NULL, &val_size);
150 if (rc != ERROR_NO_MORE_ITEMS)
152 val = msi_alloc(val_size);
153 RegEnumValueW(key, index, szIndex, &size, NULL, NULL, (LPBYTE)val,
155 if (lstrcmpiW(szSource,val)==0)
158 strcpyW(ss->szIndex,szIndex);
162 strcpyW(ss->szIndex,szIndex);
171 /******************************************************************
172 * MsiSourceListGetInfoA (MSI.@)
174 UINT WINAPI MsiSourceListGetInfoA( LPCSTR szProduct, LPCSTR szUserSid,
175 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
176 LPCSTR szProperty, LPSTR szValue,
180 LPWSTR product = NULL;
181 LPWSTR usersid = NULL;
182 LPWSTR property = NULL;
186 if (szValue && !pcchValue)
187 return ERROR_INVALID_PARAMETER;
189 if (szProduct) product = strdupAtoW(szProduct);
190 if (szUserSid) usersid = strdupAtoW(szUserSid);
191 if (szProperty) property = strdupAtoW(szProperty);
193 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
194 property, NULL, &len);
195 if (ret != ERROR_SUCCESS)
198 value = msi_alloc(++len * sizeof(WCHAR));
200 return ERROR_OUTOFMEMORY;
203 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions,
204 property, value, &len);
205 if (ret != ERROR_SUCCESS)
208 len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
209 if (*pcchValue >= len)
210 WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
212 ret = ERROR_MORE_DATA;
214 *pcchValue = len - 1;
224 /******************************************************************
225 * MsiSourceListGetInfoW (MSI.@)
227 UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
228 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
229 LPCWSTR szProperty, LPWSTR szValue,
235 TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty));
237 if (!szProduct || !*szProduct)
238 return ERROR_INVALID_PARAMETER;
240 if (lstrlenW(szProduct) != GUID_SIZE - 1 ||
241 (szProduct[0] != '{' && szProduct[GUID_SIZE - 2] != '}'))
242 return ERROR_INVALID_PARAMETER;
244 if (szValue && !pcchValue)
245 return ERROR_INVALID_PARAMETER;
247 if (dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
248 dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
249 dwContext != MSIINSTALLCONTEXT_MACHINE)
250 return ERROR_INVALID_PARAMETER;
253 return ERROR_INVALID_PARAMETER;
256 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
258 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
259 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
261 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
262 rc = OpenSourceKey(szProduct, &sourcekey, dwOptions, FALSE, FALSE);
264 rc = OpenSourceKey(szProduct, &sourcekey, dwOptions, TRUE, FALSE);
266 if (rc != ERROR_SUCCESS)
269 if (strcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) == 0)
272 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
273 if (rc == ERROR_SUCCESS)
274 rc = RegQueryValueExW(key, INSTALLPROPERTY_MEDIAPACKAGEPATHW,
275 0, 0, (LPBYTE)szValue, pcchValue);
276 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
277 rc = ERROR_UNKNOWN_PROPERTY;
280 else if (strcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW) ==0)
283 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
284 if (rc == ERROR_SUCCESS)
285 rc = RegQueryValueExW(key, INSTALLPROPERTY_DISKPROMPTW, 0, 0,
286 (LPBYTE)szValue, pcchValue);
287 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
288 rc = ERROR_UNKNOWN_PROPERTY;
291 else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0)
296 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0,
299 rc = ERROR_UNKNOWN_PROPERTY;
303 buffer = msi_alloc(size);
304 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
305 0, 0, (LPBYTE)buffer,&size);
306 ptr = strchrW(buffer,';');
307 if (ptr) ptr = strchrW(ptr+1,';');
309 rc = ERROR_UNKNOWN_PROPERTY;
313 lstrcpynW(szValue, ptr, *pcchValue);
314 if (lstrlenW(ptr) > *pcchValue)
316 *pcchValue = lstrlenW(ptr)+1;
317 rc = ERROR_MORE_DATA;
325 else if (strcmpW(INSTALLPROPERTY_LASTUSEDTYPEW, szProperty)==0)
330 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0,
333 rc = ERROR_UNKNOWN_PROPERTY;
336 buffer = msi_alloc(size);
337 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
338 0, 0, (LPBYTE)buffer,&size);
341 rc = ERROR_MORE_DATA;
346 szValue[0] = buffer[0];
352 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
354 *pcchValue = *pcchValue * sizeof(WCHAR);
355 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0,
356 (LPBYTE)szValue, pcchValue);
357 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
365 *pcchValue = (*pcchValue - 1) / sizeof(WCHAR);
367 szValue[*pcchValue] = '\0';
372 FIXME("Unknown property %s\n",debugstr_w(szProperty));
373 rc = ERROR_UNKNOWN_PROPERTY;
376 RegCloseKey(sourcekey);
380 /******************************************************************
381 * MsiSourceListSetInfoW (MSI.@)
383 UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
384 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
385 LPCWSTR szProperty, LPCWSTR szValue)
390 TRACE("%s %s %x %x %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid),
391 dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue));
393 if (!szProduct || lstrlenW(szProduct) > 39)
394 return ERROR_INVALID_PARAMETER;
396 if (dwOptions & MSICODE_PATCH)
398 FIXME("Unhandled options MSICODE_PATCH\n");
399 return ERROR_FUNCTION_FAILED;
403 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
405 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
406 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
408 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
409 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, FALSE, TRUE);
411 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, TRUE, TRUE);
413 if (rc != ERROR_SUCCESS)
414 return ERROR_UNKNOWN_PRODUCT;
417 if (strcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) == 0)
420 DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
421 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
422 if (rc == ERROR_SUCCESS)
423 rc = RegSetValueExW(key, INSTALLPROPERTY_MEDIAPACKAGEPATHW, 0,
424 REG_SZ, (const BYTE *)szValue, size);
425 if (rc != ERROR_SUCCESS)
426 rc = ERROR_UNKNOWN_PROPERTY;
429 else if (strcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW) == 0)
432 DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
433 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
434 if (rc == ERROR_SUCCESS)
435 rc = RegSetValueExW(key, INSTALLPROPERTY_DISKPROMPTW, 0,
436 REG_SZ, (const BYTE *)szValue, size);
437 if (rc != ERROR_SUCCESS)
438 rc = ERROR_UNKNOWN_PROPERTY;
441 else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0)
443 LPWSTR buffer = NULL;
445 WCHAR typechar = 'n';
446 static const WCHAR LastUsedSource_Fmt[] = {'%','c',';','%','i',';','%','s',0};
448 /* make sure the source is registered */
449 MsiSourceListAddSourceExW(szProduct, szUserSid, dwContext,
450 dwOptions, szValue, 0);
452 if (dwOptions & MSISOURCETYPE_NETWORK)
454 else if (dwOptions & MSISOURCETYPE_URL)
456 else if (dwOptions & MSISOURCETYPE_MEDIA)
459 ERR("Unknown source type! %x\n", dwOptions);
461 size = (lstrlenW(szValue)+5)*sizeof(WCHAR);
462 buffer = msi_alloc(size);
463 sprintfW(buffer, LastUsedSource_Fmt, typechar, 1, szValue);
464 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0,
465 REG_EXPAND_SZ, (LPBYTE)buffer, size);
466 if (rc != ERROR_SUCCESS)
467 rc = ERROR_UNKNOWN_PROPERTY;
470 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
472 DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
473 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0,
474 REG_SZ, (const BYTE *)szValue, size);
475 if (rc != ERROR_SUCCESS)
476 rc = ERROR_UNKNOWN_PROPERTY;
480 FIXME("Unknown property %s\n",debugstr_w(szProperty));
481 rc = ERROR_UNKNOWN_PROPERTY;
484 RegCloseKey(sourcekey);
489 /******************************************************************
490 * MsiSourceListAddSourceW (MSI.@)
492 UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
493 DWORD dwReserved, LPCWSTR szSource)
496 LPWSTR sidstr = NULL;
500 TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
502 if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, &domsize, NULL))
504 PSID psid = msi_alloc(sidsize);
506 if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL))
507 ConvertSidToStringSidW(psid, &sidstr);
512 ret = MsiSourceListAddSourceExW(szProduct, sidstr,
513 MSIINSTALLCONTEXT_USERMANAGED, MSISOURCETYPE_NETWORK, szSource, 0);
521 /******************************************************************
522 * MsiSourceListAddSourceA (MSI.@)
524 UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName,
525 DWORD dwReserved, LPCSTR szSource)
532 szwproduct = strdupAtoW( szProduct );
533 szwusername = strdupAtoW( szUserName );
534 szwsource = strdupAtoW( szSource );
536 ret = MsiSourceListAddSourceW(szwproduct, szwusername, 0, szwsource);
538 msi_free(szwproduct);
539 msi_free(szwusername);
545 /******************************************************************
546 * MsiSourceListAddSourceExW (MSI.@)
548 UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
549 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource,
555 media_info source_struct;
557 TRACE("%s %s %x %x %s %i\n", debugstr_w(szProduct), debugstr_w(szUserSid),
558 dwContext, dwOptions, debugstr_w(szSource), dwIndex);
561 return ERROR_INVALID_PARAMETER;
564 return ERROR_INVALID_PARAMETER;
566 if (dwOptions & MSICODE_PATCH)
568 FIXME("Unhandled options MSICODE_PATCH\n");
569 return ERROR_FUNCTION_FAILED;
573 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
575 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
576 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
578 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
579 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, FALSE, TRUE);
581 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, TRUE, TRUE);
583 if (rc != ERROR_SUCCESS)
584 return ERROR_UNKNOWN_PRODUCT;
586 if (dwOptions & MSISOURCETYPE_NETWORK)
587 rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
588 else if (dwOptions & MSISOURCETYPE_URL)
589 rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
590 else if (dwOptions & MSISOURCETYPE_MEDIA)
591 rc = OpenMediaSubkey(sourcekey, &typekey, TRUE);
594 ERR("unknown media type: %08x\n", dwOptions);
595 RegCloseKey(sourcekey);
596 return ERROR_FUNCTION_FAILED;
599 source_struct.szIndex[0] = 0;
600 if (find_given_source(typekey, szSource, &source_struct)==ERROR_SUCCESS)
602 DWORD current_index = atoiW(source_struct.szIndex);
603 /* found the source */
604 if (dwIndex > 0 && current_index != dwIndex)
605 FIXME("Need to reorder the sources!\n");
606 msi_free( source_struct.path );
610 DWORD current_index = 0;
611 static const WCHAR fmt[] = {'%','i',0};
612 DWORD size = lstrlenW(szSource)*sizeof(WCHAR);
614 if (source_struct.szIndex[0])
615 current_index = atoiW(source_struct.szIndex);
617 if (dwIndex > 0 && dwIndex < current_index)
618 FIXME("Need to reorder the sources!\n");
621 sprintfW(source_struct.szIndex,fmt,current_index);
622 rc = RegSetValueExW(typekey, source_struct.szIndex, 0, REG_EXPAND_SZ,
623 (const BYTE *)szSource, size);
626 RegCloseKey(typekey);
627 RegCloseKey(sourcekey);
631 /******************************************************************
632 * MsiSourceListAddMediaDisk(MSI.@)
634 UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid,
635 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
636 LPCWSTR szVolumeLabel, LPCWSTR szDiskPrompt)
642 static const WCHAR fmt[] = {'%','i',0};
643 static const WCHAR disk_fmt[] = {'%','s',';','%','s',0};
644 static const WCHAR empty[1] = {0};
649 TRACE("%s %s %x %x %i %s %s\n", debugstr_w(szProduct),
650 debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId,
651 debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt));
653 if (!szProduct || lstrlenW(szProduct) > 39)
654 return ERROR_INVALID_PARAMETER;
656 if (dwOptions & MSICODE_PATCH)
658 FIXME("Unhandled options MSICODE_PATCH\n");
659 return ERROR_FUNCTION_FAILED;
663 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
665 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
666 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
668 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
669 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, FALSE, TRUE);
671 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, TRUE, TRUE);
673 if (rc != ERROR_SUCCESS)
674 return ERROR_UNKNOWN_PRODUCT;
676 OpenMediaSubkey(sourcekey,&mediakey,TRUE);
678 sprintfW(szIndex,fmt,dwDiskId);
683 size +=lstrlenW(szVolumeLabel);
690 size +=lstrlenW(szDiskPrompt);
696 size *=sizeof(WCHAR);
698 buffer = msi_alloc(size);
699 sprintfW(buffer,disk_fmt,pt1,pt2);
701 RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
704 RegCloseKey(sourcekey);
705 RegCloseKey(mediakey);
707 return ERROR_SUCCESS;
710 /******************************************************************
711 * MsiSourceListAddSourceExA (MSI.@)
713 UINT WINAPI MsiSourceListClearAllA( LPCSTR szProduct, LPCSTR szUserName, DWORD dwReserved )
715 FIXME("(%s %s %d)\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved);
716 return ERROR_SUCCESS;
719 /******************************************************************
720 * MsiSourceListAddSourceExW (MSI.@)
722 UINT WINAPI MsiSourceListClearAllW( LPCWSTR szProduct, LPCWSTR szUserName, DWORD dwReserved )
724 FIXME("(%s %s %d)\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved);
725 return ERROR_SUCCESS;