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
;