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 * MsiSourceListGetInfoW (MSI.@)
155 UINT WINAPI
MsiSourceListGetInfoW( LPCWSTR szProduct
, LPCWSTR szUserSid
,
156 MSIINSTALLCONTEXT dwContext
, DWORD dwOptions
,
157 LPCWSTR szProperty
, LPWSTR szValue
,
163 TRACE("%s %s\n", debugstr_w(szProduct
), debugstr_w(szProperty
));
165 if (!szProduct
|| lstrlenW(szProduct
) > 39)
166 return ERROR_INVALID_PARAMETER
;
168 if (szValue
&& !pcchValue
)
169 return ERROR_INVALID_PARAMETER
;
171 if (dwOptions
== MSICODE_PATCH
)
173 FIXME("Unhandled options MSICODE_PATCH\n");
174 return ERROR_FUNCTION_FAILED
;
178 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid
));
180 if (dwContext
== MSIINSTALLCONTEXT_USERUNMANAGED
)
181 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
183 if (dwContext
== MSIINSTALLCONTEXT_MACHINE
)
184 rc
= OpenSourceKey(szProduct
, &sourcekey
, FALSE
, FALSE
);
186 rc
= OpenSourceKey(szProduct
, &sourcekey
, TRUE
, FALSE
);
188 if (rc
!= ERROR_SUCCESS
)
189 return ERROR_UNKNOWN_PRODUCT
;
191 if (strcmpW(szProperty
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
) == 0)
194 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
195 if (rc
== ERROR_SUCCESS
)
196 rc
= RegQueryValueExW(key
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
,
197 0, 0, (LPBYTE
)szValue
, pcchValue
);
198 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_MORE_DATA
)
199 rc
= ERROR_UNKNOWN_PROPERTY
;
202 else if (strcmpW(szProperty
, INSTALLPROPERTY_DISKPROMPTW
) ==0)
205 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
206 if (rc
== ERROR_SUCCESS
)
207 rc
= RegQueryValueExW(key
, INSTALLPROPERTY_DISKPROMPTW
, 0, 0,
208 (LPBYTE
)szValue
, pcchValue
);
209 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_MORE_DATA
)
210 rc
= ERROR_UNKNOWN_PROPERTY
;
213 else if (strcmpW(szProperty
, INSTALLPROPERTY_LASTUSEDSOURCEW
)==0)
218 RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
, 0, 0,
221 rc
= ERROR_UNKNOWN_PROPERTY
;
225 buffer
= msi_alloc(size
);
226 rc
= RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
,
227 0, 0, (LPBYTE
)buffer
,&size
);
228 ptr
= strchrW(buffer
,';');
229 if (ptr
) ptr
= strchrW(ptr
+1,';');
231 rc
= ERROR_UNKNOWN_PROPERTY
;
235 lstrcpynW(szValue
, ptr
, *pcchValue
);
236 if (lstrlenW(ptr
) > *pcchValue
)
238 *pcchValue
= lstrlenW(ptr
)+1;
239 rc
= ERROR_MORE_DATA
;
247 else if (strcmpW(INSTALLPROPERTY_LASTUSEDTYPEW
, szProperty
)==0)
252 RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
, 0, 0,
255 rc
= ERROR_UNKNOWN_PROPERTY
;
258 buffer
= msi_alloc(size
);
259 rc
= RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
,
260 0, 0, (LPBYTE
)buffer
,&size
);
263 rc
= ERROR_MORE_DATA
;
268 szValue
[0] = buffer
[0];
274 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW
, szProperty
)==0)
276 rc
= RegQueryValueExW(sourcekey
, INSTALLPROPERTY_PACKAGENAMEW
, 0, 0,
277 (LPBYTE
)szValue
, pcchValue
);
278 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_MORE_DATA
)
279 rc
= ERROR_UNKNOWN_PROPERTY
;
283 FIXME("Unknown property %s\n",debugstr_w(szProperty
));
284 rc
= ERROR_UNKNOWN_PROPERTY
;
287 RegCloseKey(sourcekey
);
291 /******************************************************************
292 * MsiSourceListSetInfoW (MSI.@)
294 UINT WINAPI
MsiSourceListSetInfoW( LPCWSTR szProduct
, LPCWSTR szUserSid
,
295 MSIINSTALLCONTEXT dwContext
, DWORD dwOptions
,
296 LPCWSTR szProperty
, LPCWSTR szValue
)
301 TRACE("%s %s %x %x %s %s\n", debugstr_w(szProduct
), debugstr_w(szUserSid
),
302 dwContext
, dwOptions
, debugstr_w(szProperty
), debugstr_w(szValue
));
304 if (!szProduct
|| lstrlenW(szProduct
) > 39)
305 return ERROR_INVALID_PARAMETER
;
307 if (dwOptions
& MSICODE_PATCH
)
309 FIXME("Unhandled options MSICODE_PATCH\n");
310 return ERROR_FUNCTION_FAILED
;
314 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid
));
316 if (dwContext
== MSIINSTALLCONTEXT_USERUNMANAGED
)
317 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
319 if (dwContext
== MSIINSTALLCONTEXT_MACHINE
)
320 rc
= OpenSourceKey(szProduct
, &sourcekey
, FALSE
, TRUE
);
322 rc
= OpenSourceKey(szProduct
, &sourcekey
, TRUE
, TRUE
);
324 if (rc
!= ERROR_SUCCESS
)
325 return ERROR_UNKNOWN_PRODUCT
;
328 if (strcmpW(szProperty
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
) == 0)
331 DWORD size
= lstrlenW(szValue
)*sizeof(WCHAR
);
332 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
333 if (rc
== ERROR_SUCCESS
)
334 rc
= RegSetValueExW(key
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
, 0,
335 REG_SZ
, (const BYTE
*)szValue
, size
);
336 if (rc
!= ERROR_SUCCESS
)
337 rc
= ERROR_UNKNOWN_PROPERTY
;
340 else if (strcmpW(szProperty
, INSTALLPROPERTY_DISKPROMPTW
) == 0)
343 DWORD size
= lstrlenW(szValue
)*sizeof(WCHAR
);
344 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
345 if (rc
== ERROR_SUCCESS
)
346 rc
= RegSetValueExW(key
, INSTALLPROPERTY_DISKPROMPTW
, 0,
347 REG_SZ
, (const BYTE
*)szValue
, size
);
348 if (rc
!= ERROR_SUCCESS
)
349 rc
= ERROR_UNKNOWN_PROPERTY
;
352 else if (strcmpW(szProperty
, INSTALLPROPERTY_LASTUSEDSOURCEW
)==0)
354 LPWSTR buffer
= NULL
;
356 WCHAR typechar
= 'n';
357 static const WCHAR LastUsedSource_Fmt
[] = {'%','c',';','%','i',';','%','s',0};
359 /* make sure the source is registered */
360 MsiSourceListAddSourceExW(szProduct
, szUserSid
, dwContext
,
361 dwOptions
, szValue
, 0);
363 if (dwOptions
& MSISOURCETYPE_NETWORK
)
365 else if (dwOptions
& MSISOURCETYPE_URL
)
367 else if (dwOptions
& MSISOURCETYPE_MEDIA
)
370 ERR("Unknown source type! %x\n", dwOptions
);
372 size
= (lstrlenW(szValue
)+5)*sizeof(WCHAR
);
373 buffer
= msi_alloc(size
);
374 sprintfW(buffer
, LastUsedSource_Fmt
, typechar
, 1, szValue
);
375 rc
= RegSetValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
, 0,
376 REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
377 if (rc
!= ERROR_SUCCESS
)
378 rc
= ERROR_UNKNOWN_PROPERTY
;
381 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW
, szProperty
)==0)
383 DWORD size
= lstrlenW(szValue
)*sizeof(WCHAR
);
384 rc
= RegSetValueExW(sourcekey
, INSTALLPROPERTY_PACKAGENAMEW
, 0,
385 REG_SZ
, (const BYTE
*)szValue
, size
);
386 if (rc
!= ERROR_SUCCESS
)
387 rc
= ERROR_UNKNOWN_PROPERTY
;
391 FIXME("Unknown property %s\n",debugstr_w(szProperty
));
392 rc
= ERROR_UNKNOWN_PROPERTY
;
395 RegCloseKey(sourcekey
);
400 /******************************************************************
401 * MsiSourceListAddSourceW (MSI.@)
403 UINT WINAPI
MsiSourceListAddSourceW( LPCWSTR szProduct
, LPCWSTR szUserName
,
404 DWORD dwReserved
, LPCWSTR szSource
)
407 LPWSTR sidstr
= NULL
;
411 TRACE("%s %s %s\n", debugstr_w(szProduct
), debugstr_w(szUserName
), debugstr_w(szSource
));
413 if (LookupAccountNameW(NULL
, szUserName
, NULL
, &sidsize
, NULL
, &domsize
, NULL
))
415 PSID psid
= msi_alloc(sidsize
);
417 if (LookupAccountNameW(NULL
, szUserName
, psid
, &sidsize
, NULL
, &domsize
, NULL
))
418 ConvertSidToStringSidW(psid
, &sidstr
);
423 ret
= MsiSourceListAddSourceExW(szProduct
, sidstr
,
424 MSIINSTALLCONTEXT_USERMANAGED
, MSISOURCETYPE_NETWORK
, szSource
, 0);
432 /******************************************************************
433 * MsiSourceListAddSourceA (MSI.@)
435 UINT WINAPI
MsiSourceListAddSourceA( LPCSTR szProduct
, LPCSTR szUserName
,
436 DWORD dwReserved
, LPCSTR szSource
)
443 szwproduct
= strdupAtoW( szProduct
);
444 szwusername
= strdupAtoW( szUserName
);
445 szwsource
= strdupAtoW( szSource
);
447 ret
= MsiSourceListAddSourceW(szwproduct
, szwusername
, 0, szwsource
);
449 msi_free(szwproduct
);
450 msi_free(szwusername
);
456 /******************************************************************
457 * MsiSourceListAddSourceExW (MSI.@)
459 UINT WINAPI
MsiSourceListAddSourceExW( LPCWSTR szProduct
, LPCWSTR szUserSid
,
460 MSIINSTALLCONTEXT dwContext
, DWORD dwOptions
, LPCWSTR szSource
,
466 media_info source_struct
;
468 TRACE("%s %s %x %x %s %i\n", debugstr_w(szProduct
), debugstr_w(szUserSid
),
469 dwContext
, dwOptions
, debugstr_w(szSource
), dwIndex
);
472 return ERROR_INVALID_PARAMETER
;
475 return ERROR_INVALID_PARAMETER
;
477 if (dwOptions
& MSICODE_PATCH
)
479 FIXME("Unhandled options MSICODE_PATCH\n");
480 return ERROR_FUNCTION_FAILED
;
484 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid
));
486 if (dwContext
== MSIINSTALLCONTEXT_USERUNMANAGED
)
487 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
489 if (dwContext
== MSIINSTALLCONTEXT_MACHINE
)
490 rc
= OpenSourceKey(szProduct
, &sourcekey
, FALSE
, TRUE
);
492 rc
= OpenSourceKey(szProduct
, &sourcekey
, TRUE
, TRUE
);
494 if (rc
!= ERROR_SUCCESS
)
495 return ERROR_UNKNOWN_PRODUCT
;
497 if (dwOptions
& MSISOURCETYPE_NETWORK
)
498 rc
= OpenNetworkSubkey(sourcekey
, &typekey
, TRUE
);
499 else if (dwOptions
& MSISOURCETYPE_URL
)
500 rc
= OpenURLSubkey(sourcekey
, &typekey
, TRUE
);
501 else if (dwOptions
& MSISOURCETYPE_MEDIA
)
502 rc
= OpenMediaSubkey(sourcekey
, &typekey
, TRUE
);
505 ERR("unknown media type: %08x\n", dwOptions
);
506 RegCloseKey(sourcekey
);
507 return ERROR_FUNCTION_FAILED
;
510 source_struct
.szIndex
[0] = 0;
511 if (find_given_source(typekey
, szSource
, &source_struct
)==ERROR_SUCCESS
)
513 DWORD current_index
= atoiW(source_struct
.szIndex
);
514 /* found the source */
515 if (dwIndex
> 0 && current_index
!= dwIndex
)
516 FIXME("Need to reorder the sources!\n");
517 msi_free( source_struct
.path
);
521 DWORD current_index
= 0;
522 static const WCHAR fmt
[] = {'%','i',0};
523 DWORD size
= lstrlenW(szSource
)*sizeof(WCHAR
);
525 if (source_struct
.szIndex
[0])
526 current_index
= atoiW(source_struct
.szIndex
);
528 if (dwIndex
> 0 && dwIndex
< current_index
)
529 FIXME("Need to reorder the sources!\n");
532 sprintfW(source_struct
.szIndex
,fmt
,current_index
);
533 rc
= RegSetValueExW(typekey
, source_struct
.szIndex
, 0, REG_EXPAND_SZ
,
534 (const BYTE
*)szSource
, size
);
537 RegCloseKey(typekey
);
538 RegCloseKey(sourcekey
);
542 /******************************************************************
543 * MsiSourceListAddMediaDisk(MSI.@)
545 UINT WINAPI
MsiSourceListAddMediaDiskW(LPCWSTR szProduct
, LPCWSTR szUserSid
,
546 MSIINSTALLCONTEXT dwContext
, DWORD dwOptions
, DWORD dwDiskId
,
547 LPCWSTR szVolumeLabel
, LPCWSTR szDiskPrompt
)
553 static const WCHAR fmt
[] = {'%','i',0};
554 static const WCHAR disk_fmt
[] = {'%','s',';','%','s',0};
555 static const WCHAR empty
[1] = {0};
560 TRACE("%s %s %x %x %i %s %s\n", debugstr_w(szProduct
),
561 debugstr_w(szUserSid
), dwContext
, dwOptions
, dwDiskId
,
562 debugstr_w(szVolumeLabel
), debugstr_w(szDiskPrompt
));
564 if (!szProduct
|| lstrlenW(szProduct
) > 39)
565 return ERROR_INVALID_PARAMETER
;
567 if (dwOptions
& MSICODE_PATCH
)
569 FIXME("Unhandled options MSICODE_PATCH\n");
570 return ERROR_FUNCTION_FAILED
;
574 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid
));
576 if (dwContext
== MSIINSTALLCONTEXT_USERUNMANAGED
)
577 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
579 if (dwContext
== MSIINSTALLCONTEXT_MACHINE
)
580 rc
= OpenSourceKey(szProduct
, &sourcekey
, FALSE
, TRUE
);
582 rc
= OpenSourceKey(szProduct
, &sourcekey
, TRUE
, TRUE
);
584 if (rc
!= ERROR_SUCCESS
)
585 return ERROR_UNKNOWN_PRODUCT
;
587 OpenMediaSubkey(sourcekey
,&mediakey
,TRUE
);
589 sprintfW(szIndex
,fmt
,dwDiskId
);
594 size
+=lstrlenW(szVolumeLabel
);
601 size
+=lstrlenW(szDiskPrompt
);
607 size
*=sizeof(WCHAR
);
609 buffer
= msi_alloc(size
);
610 sprintfW(buffer
,disk_fmt
,pt1
,pt2
);
612 RegSetValueExW(mediakey
, szIndex
, 0, REG_SZ
, (LPBYTE
)buffer
, size
);
615 RegCloseKey(sourcekey
);
616 RegCloseKey(mediakey
);
618 return ERROR_SUCCESS
;
621 /******************************************************************
622 * MsiSourceListAddSourceExA (MSI.@)
624 UINT WINAPI
MsiSourceListClearAllA( LPCSTR szProduct
, LPCSTR szUserName
, DWORD dwReserved
)
626 FIXME("(%s %s %d)\n", debugstr_a(szProduct
), debugstr_a(szUserName
), dwReserved
);
627 return ERROR_SUCCESS
;
630 /******************************************************************
631 * MsiSourceListAddSourceExW (MSI.@)
633 UINT WINAPI
MsiSourceListClearAllW( LPCWSTR szProduct
, LPCWSTR szUserName
, DWORD dwReserved
)
635 FIXME("(%s %s %d)\n", debugstr_w(szProduct
), debugstr_w(szUserName
), dwReserved
);
636 return ERROR_SUCCESS
;