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
, BOOL user
, BOOL create
)
58 static const WCHAR szSourceList
[] = {'S','o','u','r','c','e','L','i','s','t',0};
61 rc
= MSIREG_OpenUserProductsKey(szProduct
, &rootkey
, create
);
63 rc
= MSIREG_OpenProductsKey(szProduct
, &rootkey
, create
);
69 rc
= RegCreateKeyW(rootkey
, szSourceList
, key
);
71 rc
= RegOpenKeyW(rootkey
,szSourceList
, key
);
76 static UINT
OpenMediaSubkey(HKEY rootkey
, HKEY
*key
, BOOL create
)
79 static const WCHAR media
[] = {'M','e','d','i','a',0};
82 rc
= RegCreateKeyW(rootkey
, media
, key
);
84 rc
= RegOpenKeyW(rootkey
,media
, key
);
89 static UINT
OpenNetworkSubkey(HKEY rootkey
, HKEY
*key
, BOOL create
)
92 static const WCHAR net
[] = {'N','e','t',0};
95 rc
= RegCreateKeyW(rootkey
, net
, key
);
97 rc
= RegOpenKeyW(rootkey
, net
, key
);
102 static UINT
OpenURLSubkey(HKEY rootkey
, HKEY
*key
, BOOL create
)
105 static const WCHAR URL
[] = {'U','R','L',0};
108 rc
= RegCreateKeyW(rootkey
, URL
, key
);
110 rc
= RegOpenKeyW(rootkey
, URL
, key
);
116 static UINT
find_given_source(HKEY key
, LPCWSTR szSource
, media_info
*ss
)
123 UINT rc
= ERROR_SUCCESS
;
125 while (rc
== ERROR_SUCCESS
)
129 size
= sizeof(szIndex
)/sizeof(szIndex
[0]);
130 rc
= RegEnumValueW(key
, index
, szIndex
, &size
, NULL
, NULL
, NULL
, &val_size
);
131 if (rc
!= ERROR_NO_MORE_ITEMS
)
133 val
= msi_alloc(val_size
);
134 RegEnumValueW(key
, index
, szIndex
, &size
, NULL
, NULL
, (LPBYTE
)val
,
136 if (lstrcmpiW(szSource
,val
)==0)
139 strcpyW(ss
->szIndex
,szIndex
);
143 strcpyW(ss
->szIndex
,szIndex
);
152 /******************************************************************
153 * MsiSourceListGetInfoA (MSI.@)
155 UINT WINAPI
MsiSourceListGetInfoA( LPCSTR szProduct
, LPCSTR szUserSid
,
156 MSIINSTALLCONTEXT dwContext
, DWORD dwOptions
,
157 LPCSTR szProperty
, LPSTR szValue
,
161 LPWSTR product
= NULL
;
162 LPWSTR usersid
= NULL
;
163 LPWSTR property
= NULL
;
167 if (szValue
&& !pcchValue
)
168 return ERROR_INVALID_PARAMETER
;
170 if (szProduct
) product
= strdupAtoW(szProduct
);
171 if (szUserSid
) usersid
= strdupAtoW(szUserSid
);
172 if (szProperty
) property
= strdupAtoW(szProperty
);
174 ret
= MsiSourceListGetInfoW(product
, usersid
, dwContext
, dwOptions
,
175 property
, NULL
, &len
);
176 if (ret
!= ERROR_SUCCESS
)
179 value
= msi_alloc(++len
* sizeof(WCHAR
));
181 return ERROR_OUTOFMEMORY
;
183 ret
= MsiSourceListGetInfoW(product
, usersid
, dwContext
, dwOptions
,
184 property
, value
, &len
);
185 if (ret
!= ERROR_SUCCESS
)
188 len
= WideCharToMultiByte(CP_ACP
, 0, value
, -1, NULL
, 0, NULL
, NULL
);
189 if (*pcchValue
>= len
)
190 WideCharToMultiByte(CP_ACP
, 0, value
, -1, szValue
, len
, NULL
, NULL
);
192 ret
= ERROR_MORE_DATA
;
194 *pcchValue
= len
- 1;
204 /******************************************************************
205 * MsiSourceListGetInfoW (MSI.@)
207 UINT WINAPI
MsiSourceListGetInfoW( LPCWSTR szProduct
, LPCWSTR szUserSid
,
208 MSIINSTALLCONTEXT dwContext
, DWORD dwOptions
,
209 LPCWSTR szProperty
, LPWSTR szValue
,
215 TRACE("%s %s\n", debugstr_w(szProduct
), debugstr_w(szProperty
));
217 if (!szProduct
|| lstrlenW(szProduct
) > 39)
218 return ERROR_INVALID_PARAMETER
;
220 if (szValue
&& !pcchValue
)
221 return ERROR_INVALID_PARAMETER
;
223 if (dwOptions
== MSICODE_PATCH
)
225 FIXME("Unhandled options MSICODE_PATCH\n");
226 return ERROR_FUNCTION_FAILED
;
230 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid
));
232 if (dwContext
== MSIINSTALLCONTEXT_USERUNMANAGED
)
233 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
235 if (dwContext
== MSIINSTALLCONTEXT_MACHINE
)
236 rc
= OpenSourceKey(szProduct
, &sourcekey
, FALSE
, FALSE
);
238 rc
= OpenSourceKey(szProduct
, &sourcekey
, TRUE
, FALSE
);
240 if (rc
!= ERROR_SUCCESS
)
241 return ERROR_UNKNOWN_PRODUCT
;
243 if (strcmpW(szProperty
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
) == 0)
246 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
247 if (rc
== ERROR_SUCCESS
)
248 rc
= RegQueryValueExW(key
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
,
249 0, 0, (LPBYTE
)szValue
, pcchValue
);
250 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_MORE_DATA
)
251 rc
= ERROR_UNKNOWN_PROPERTY
;
254 else if (strcmpW(szProperty
, INSTALLPROPERTY_DISKPROMPTW
) ==0)
257 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
258 if (rc
== ERROR_SUCCESS
)
259 rc
= RegQueryValueExW(key
, INSTALLPROPERTY_DISKPROMPTW
, 0, 0,
260 (LPBYTE
)szValue
, pcchValue
);
261 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_MORE_DATA
)
262 rc
= ERROR_UNKNOWN_PROPERTY
;
265 else if (strcmpW(szProperty
, INSTALLPROPERTY_LASTUSEDSOURCEW
)==0)
270 RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
, 0, 0,
273 rc
= ERROR_UNKNOWN_PROPERTY
;
277 buffer
= msi_alloc(size
);
278 rc
= RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
,
279 0, 0, (LPBYTE
)buffer
,&size
);
280 ptr
= strchrW(buffer
,';');
281 if (ptr
) ptr
= strchrW(ptr
+1,';');
283 rc
= ERROR_UNKNOWN_PROPERTY
;
287 lstrcpynW(szValue
, ptr
, *pcchValue
);
288 if (lstrlenW(ptr
) > *pcchValue
)
290 *pcchValue
= lstrlenW(ptr
)+1;
291 rc
= ERROR_MORE_DATA
;
299 else if (strcmpW(INSTALLPROPERTY_LASTUSEDTYPEW
, szProperty
)==0)
304 RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
, 0, 0,
307 rc
= ERROR_UNKNOWN_PROPERTY
;
310 buffer
= msi_alloc(size
);
311 rc
= RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
,
312 0, 0, (LPBYTE
)buffer
,&size
);
315 rc
= ERROR_MORE_DATA
;
320 szValue
[0] = buffer
[0];
326 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW
, szProperty
)==0)
328 rc
= RegQueryValueExW(sourcekey
, INSTALLPROPERTY_PACKAGENAMEW
, 0, 0,
329 (LPBYTE
)szValue
, pcchValue
);
330 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_MORE_DATA
)
331 rc
= ERROR_UNKNOWN_PROPERTY
;
335 FIXME("Unknown property %s\n",debugstr_w(szProperty
));
336 rc
= ERROR_UNKNOWN_PROPERTY
;
339 RegCloseKey(sourcekey
);
343 /******************************************************************
344 * MsiSourceListSetInfoW (MSI.@)
346 UINT WINAPI
MsiSourceListSetInfoW( LPCWSTR szProduct
, LPCWSTR szUserSid
,
347 MSIINSTALLCONTEXT dwContext
, DWORD dwOptions
,
348 LPCWSTR szProperty
, LPCWSTR szValue
)
353 TRACE("%s %s %x %x %s %s\n", debugstr_w(szProduct
), debugstr_w(szUserSid
),
354 dwContext
, dwOptions
, debugstr_w(szProperty
), debugstr_w(szValue
));
356 if (!szProduct
|| lstrlenW(szProduct
) > 39)
357 return ERROR_INVALID_PARAMETER
;
359 if (dwOptions
& MSICODE_PATCH
)
361 FIXME("Unhandled options MSICODE_PATCH\n");
362 return ERROR_FUNCTION_FAILED
;
366 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid
));
368 if (dwContext
== MSIINSTALLCONTEXT_USERUNMANAGED
)
369 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
371 if (dwContext
== MSIINSTALLCONTEXT_MACHINE
)
372 rc
= OpenSourceKey(szProduct
, &sourcekey
, FALSE
, TRUE
);
374 rc
= OpenSourceKey(szProduct
, &sourcekey
, TRUE
, TRUE
);
376 if (rc
!= ERROR_SUCCESS
)
377 return ERROR_UNKNOWN_PRODUCT
;
380 if (strcmpW(szProperty
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
) == 0)
383 DWORD size
= lstrlenW(szValue
)*sizeof(WCHAR
);
384 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
385 if (rc
== ERROR_SUCCESS
)
386 rc
= RegSetValueExW(key
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
, 0,
387 REG_SZ
, (const BYTE
*)szValue
, size
);
388 if (rc
!= ERROR_SUCCESS
)
389 rc
= ERROR_UNKNOWN_PROPERTY
;
392 else if (strcmpW(szProperty
, INSTALLPROPERTY_DISKPROMPTW
) == 0)
395 DWORD size
= lstrlenW(szValue
)*sizeof(WCHAR
);
396 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
397 if (rc
== ERROR_SUCCESS
)
398 rc
= RegSetValueExW(key
, INSTALLPROPERTY_DISKPROMPTW
, 0,
399 REG_SZ
, (const BYTE
*)szValue
, size
);
400 if (rc
!= ERROR_SUCCESS
)
401 rc
= ERROR_UNKNOWN_PROPERTY
;
404 else if (strcmpW(szProperty
, INSTALLPROPERTY_LASTUSEDSOURCEW
)==0)
406 LPWSTR buffer
= NULL
;
408 WCHAR typechar
= 'n';
409 static const WCHAR LastUsedSource_Fmt
[] = {'%','c',';','%','i',';','%','s',0};
411 /* make sure the source is registered */
412 MsiSourceListAddSourceExW(szProduct
, szUserSid
, dwContext
,
413 dwOptions
, szValue
, 0);
415 if (dwOptions
& MSISOURCETYPE_NETWORK
)
417 else if (dwOptions
& MSISOURCETYPE_URL
)
419 else if (dwOptions
& MSISOURCETYPE_MEDIA
)
422 ERR("Unknown source type! %x\n", dwOptions
);
424 size
= (lstrlenW(szValue
)+5)*sizeof(WCHAR
);
425 buffer
= msi_alloc(size
);
426 sprintfW(buffer
, LastUsedSource_Fmt
, typechar
, 1, szValue
);
427 rc
= RegSetValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
, 0,
428 REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
429 if (rc
!= ERROR_SUCCESS
)
430 rc
= ERROR_UNKNOWN_PROPERTY
;
433 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW
, szProperty
)==0)
435 DWORD size
= lstrlenW(szValue
)*sizeof(WCHAR
);
436 rc
= RegSetValueExW(sourcekey
, INSTALLPROPERTY_PACKAGENAMEW
, 0,
437 REG_SZ
, (const BYTE
*)szValue
, size
);
438 if (rc
!= ERROR_SUCCESS
)
439 rc
= ERROR_UNKNOWN_PROPERTY
;
443 FIXME("Unknown property %s\n",debugstr_w(szProperty
));
444 rc
= ERROR_UNKNOWN_PROPERTY
;
447 RegCloseKey(sourcekey
);
452 /******************************************************************
453 * MsiSourceListAddSourceW (MSI.@)
455 UINT WINAPI
MsiSourceListAddSourceW( LPCWSTR szProduct
, LPCWSTR szUserName
,
456 DWORD dwReserved
, LPCWSTR szSource
)
459 LPWSTR sidstr
= NULL
;
463 TRACE("%s %s %s\n", debugstr_w(szProduct
), debugstr_w(szUserName
), debugstr_w(szSource
));
465 if (LookupAccountNameW(NULL
, szUserName
, NULL
, &sidsize
, NULL
, &domsize
, NULL
))
467 PSID psid
= msi_alloc(sidsize
);
469 if (LookupAccountNameW(NULL
, szUserName
, psid
, &sidsize
, NULL
, &domsize
, NULL
))
470 ConvertSidToStringSidW(psid
, &sidstr
);
475 ret
= MsiSourceListAddSourceExW(szProduct
, sidstr
,
476 MSIINSTALLCONTEXT_USERMANAGED
, MSISOURCETYPE_NETWORK
, szSource
, 0);
484 /******************************************************************
485 * MsiSourceListAddSourceA (MSI.@)
487 UINT WINAPI
MsiSourceListAddSourceA( LPCSTR szProduct
, LPCSTR szUserName
,
488 DWORD dwReserved
, LPCSTR szSource
)
495 szwproduct
= strdupAtoW( szProduct
);
496 szwusername
= strdupAtoW( szUserName
);
497 szwsource
= strdupAtoW( szSource
);
499 ret
= MsiSourceListAddSourceW(szwproduct
, szwusername
, 0, szwsource
);
501 msi_free(szwproduct
);
502 msi_free(szwusername
);
508 /******************************************************************
509 * MsiSourceListAddSourceExW (MSI.@)
511 UINT WINAPI
MsiSourceListAddSourceExW( LPCWSTR szProduct
, LPCWSTR szUserSid
,
512 MSIINSTALLCONTEXT dwContext
, DWORD dwOptions
, LPCWSTR szSource
,
518 media_info source_struct
;
520 TRACE("%s %s %x %x %s %i\n", debugstr_w(szProduct
), debugstr_w(szUserSid
),
521 dwContext
, dwOptions
, debugstr_w(szSource
), dwIndex
);
524 return ERROR_INVALID_PARAMETER
;
527 return ERROR_INVALID_PARAMETER
;
529 if (dwOptions
& MSICODE_PATCH
)
531 FIXME("Unhandled options MSICODE_PATCH\n");
532 return ERROR_FUNCTION_FAILED
;
536 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid
));
538 if (dwContext
== MSIINSTALLCONTEXT_USERUNMANAGED
)
539 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
541 if (dwContext
== MSIINSTALLCONTEXT_MACHINE
)
542 rc
= OpenSourceKey(szProduct
, &sourcekey
, FALSE
, TRUE
);
544 rc
= OpenSourceKey(szProduct
, &sourcekey
, TRUE
, TRUE
);
546 if (rc
!= ERROR_SUCCESS
)
547 return ERROR_UNKNOWN_PRODUCT
;
549 if (dwOptions
& MSISOURCETYPE_NETWORK
)
550 rc
= OpenNetworkSubkey(sourcekey
, &typekey
, TRUE
);
551 else if (dwOptions
& MSISOURCETYPE_URL
)
552 rc
= OpenURLSubkey(sourcekey
, &typekey
, TRUE
);
553 else if (dwOptions
& MSISOURCETYPE_MEDIA
)
554 rc
= OpenMediaSubkey(sourcekey
, &typekey
, TRUE
);
557 ERR("unknown media type: %08x\n", dwOptions
);
558 RegCloseKey(sourcekey
);
559 return ERROR_FUNCTION_FAILED
;
562 source_struct
.szIndex
[0] = 0;
563 if (find_given_source(typekey
, szSource
, &source_struct
)==ERROR_SUCCESS
)
565 DWORD current_index
= atoiW(source_struct
.szIndex
);
566 /* found the source */
567 if (dwIndex
> 0 && current_index
!= dwIndex
)
568 FIXME("Need to reorder the sources!\n");
569 msi_free( source_struct
.path
);
573 DWORD current_index
= 0;
574 static const WCHAR fmt
[] = {'%','i',0};
575 DWORD size
= lstrlenW(szSource
)*sizeof(WCHAR
);
577 if (source_struct
.szIndex
[0])
578 current_index
= atoiW(source_struct
.szIndex
);
580 if (dwIndex
> 0 && dwIndex
< current_index
)
581 FIXME("Need to reorder the sources!\n");
584 sprintfW(source_struct
.szIndex
,fmt
,current_index
);
585 rc
= RegSetValueExW(typekey
, source_struct
.szIndex
, 0, REG_EXPAND_SZ
,
586 (const BYTE
*)szSource
, size
);
589 RegCloseKey(typekey
);
590 RegCloseKey(sourcekey
);
594 /******************************************************************
595 * MsiSourceListAddMediaDisk(MSI.@)
597 UINT WINAPI
MsiSourceListAddMediaDiskW(LPCWSTR szProduct
, LPCWSTR szUserSid
,
598 MSIINSTALLCONTEXT dwContext
, DWORD dwOptions
, DWORD dwDiskId
,
599 LPCWSTR szVolumeLabel
, LPCWSTR szDiskPrompt
)
605 static const WCHAR fmt
[] = {'%','i',0};
606 static const WCHAR disk_fmt
[] = {'%','s',';','%','s',0};
607 static const WCHAR empty
[1] = {0};
612 TRACE("%s %s %x %x %i %s %s\n", debugstr_w(szProduct
),
613 debugstr_w(szUserSid
), dwContext
, dwOptions
, dwDiskId
,
614 debugstr_w(szVolumeLabel
), debugstr_w(szDiskPrompt
));
616 if (!szProduct
|| lstrlenW(szProduct
) > 39)
617 return ERROR_INVALID_PARAMETER
;
619 if (dwOptions
& MSICODE_PATCH
)
621 FIXME("Unhandled options MSICODE_PATCH\n");
622 return ERROR_FUNCTION_FAILED
;
626 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid
));
628 if (dwContext
== MSIINSTALLCONTEXT_USERUNMANAGED
)
629 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
631 if (dwContext
== MSIINSTALLCONTEXT_MACHINE
)
632 rc
= OpenSourceKey(szProduct
, &sourcekey
, FALSE
, TRUE
);
634 rc
= OpenSourceKey(szProduct
, &sourcekey
, TRUE
, TRUE
);
636 if (rc
!= ERROR_SUCCESS
)
637 return ERROR_UNKNOWN_PRODUCT
;
639 OpenMediaSubkey(sourcekey
,&mediakey
,TRUE
);
641 sprintfW(szIndex
,fmt
,dwDiskId
);
646 size
+=lstrlenW(szVolumeLabel
);
653 size
+=lstrlenW(szDiskPrompt
);
659 size
*=sizeof(WCHAR
);
661 buffer
= msi_alloc(size
);
662 sprintfW(buffer
,disk_fmt
,pt1
,pt2
);
664 RegSetValueExW(mediakey
, szIndex
, 0, REG_SZ
, (LPBYTE
)buffer
, size
);
667 RegCloseKey(sourcekey
);
668 RegCloseKey(mediakey
);
670 return ERROR_SUCCESS
;
673 /******************************************************************
674 * MsiSourceListAddSourceExA (MSI.@)
676 UINT WINAPI
MsiSourceListClearAllA( LPCSTR szProduct
, LPCSTR szUserName
, DWORD dwReserved
)
678 FIXME("(%s %s %d)\n", debugstr_a(szProduct
), debugstr_a(szUserName
), dwReserved
);
679 return ERROR_SUCCESS
;
682 /******************************************************************
683 * MsiSourceListAddSourceExW (MSI.@)
685 UINT WINAPI
MsiSourceListClearAllW( LPCWSTR szProduct
, LPCWSTR szUserName
, DWORD dwReserved
)
687 FIXME("(%s %s %d)\n", debugstr_w(szProduct
), debugstr_w(szUserName
), dwReserved
);
688 return ERROR_SUCCESS
;