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"
42 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
45 * These apis are defined in MSI 3.0
48 typedef struct tagMediaInfo
55 static UINT
OpenSourceKey(LPCWSTR szProduct
, HKEY
* key
, BOOL user
, BOOL create
)
59 static const WCHAR szSourceList
[] = {'S','o','u','r','c','e','L','i','s','t',0};
62 rc
= MSIREG_OpenUserProductsKey(szProduct
, &rootkey
, create
);
64 rc
= MSIREG_OpenProductsKey(szProduct
, &rootkey
, create
);
70 rc
= RegCreateKeyW(rootkey
, szSourceList
, key
);
72 rc
= RegOpenKeyW(rootkey
,szSourceList
, key
);
77 static UINT
OpenMediaSubkey(HKEY rootkey
, HKEY
*key
, BOOL create
)
80 static const WCHAR media
[] = {'M','e','d','i','a',0};
83 rc
= RegCreateKeyW(rootkey
, media
, key
);
85 rc
= RegOpenKeyW(rootkey
,media
, key
);
90 static UINT
OpenNetworkSubkey(HKEY rootkey
, HKEY
*key
, BOOL create
)
93 static const WCHAR net
[] = {'N','e','t',0};
96 rc
= RegCreateKeyW(rootkey
, net
, key
);
98 rc
= RegOpenKeyW(rootkey
, net
, key
);
103 static UINT
OpenURLSubkey(HKEY rootkey
, HKEY
*key
, BOOL create
)
106 static const WCHAR URL
[] = {'U','R','L',0};
109 rc
= RegCreateKeyW(rootkey
, URL
, key
);
111 rc
= RegOpenKeyW(rootkey
, URL
, key
);
117 static UINT
find_given_source(HKEY key
, LPCWSTR szSource
, media_info
*ss
)
124 UINT rc
= ERROR_SUCCESS
;
126 while (rc
== ERROR_SUCCESS
)
130 size
= sizeof(szIndex
)/sizeof(szIndex
[0]);
131 rc
= RegEnumValueW(key
, index
, szIndex
, &size
, NULL
, NULL
, NULL
, &val_size
);
132 if (rc
!= ERROR_NO_MORE_ITEMS
)
134 val
= msi_alloc(val_size
);
135 RegEnumValueW(key
, index
, szIndex
, &size
, NULL
, NULL
, (LPBYTE
)val
,
137 if (lstrcmpiW(szSource
,val
)==0)
140 strcpyW(ss
->szIndex
,szIndex
);
144 strcpyW(ss
->szIndex
,szIndex
);
153 /******************************************************************
154 * MsiSourceListGetInfoW (MSI.@)
156 UINT WINAPI
MsiSourceListGetInfoW( LPCWSTR szProduct
, LPCWSTR szUserSid
,
157 MSIINSTALLCONTEXT dwContext
, DWORD dwOptions
,
158 LPCWSTR szProperty
, LPWSTR szValue
,
164 TRACE("%s %s\n", debugstr_w(szProduct
), debugstr_w(szProperty
));
166 if (!szProduct
|| lstrlenW(szProduct
) > 39)
167 return ERROR_INVALID_PARAMETER
;
169 if (szValue
&& !pcchValue
)
170 return ERROR_INVALID_PARAMETER
;
172 if (dwOptions
== MSICODE_PATCH
)
174 FIXME("Unhandled options MSICODE_PATCH\n");
175 return ERROR_FUNCTION_FAILED
;
179 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid
));
181 if (dwContext
== MSIINSTALLCONTEXT_USERUNMANAGED
)
182 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
184 if (dwContext
== MSIINSTALLCONTEXT_MACHINE
)
185 rc
= OpenSourceKey(szProduct
, &sourcekey
, FALSE
, FALSE
);
187 rc
= OpenSourceKey(szProduct
, &sourcekey
, TRUE
, FALSE
);
189 if (rc
!= ERROR_SUCCESS
)
190 return ERROR_UNKNOWN_PRODUCT
;
192 if (strcmpW(szProperty
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
) == 0)
195 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
196 if (rc
== ERROR_SUCCESS
)
197 rc
= RegQueryValueExW(key
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
,
198 0, 0, (LPBYTE
)szValue
, pcchValue
);
199 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_MORE_DATA
)
200 rc
= ERROR_UNKNOWN_PROPERTY
;
203 else if (strcmpW(szProperty
, INSTALLPROPERTY_DISKPROMPTW
) ==0)
206 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
207 if (rc
== ERROR_SUCCESS
)
208 rc
= RegQueryValueExW(key
, INSTALLPROPERTY_DISKPROMPTW
, 0, 0,
209 (LPBYTE
)szValue
, pcchValue
);
210 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_MORE_DATA
)
211 rc
= ERROR_UNKNOWN_PROPERTY
;
214 else if (strcmpW(szProperty
, INSTALLPROPERTY_LASTUSEDSOURCEW
)==0)
219 RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
, 0, 0,
222 rc
= ERROR_UNKNOWN_PROPERTY
;
226 buffer
= msi_alloc(size
);
227 rc
= RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
,
228 0, 0, (LPBYTE
)buffer
,&size
);
229 ptr
= strchrW(buffer
,';');
230 if (ptr
) ptr
= strchrW(ptr
+1,';');
232 rc
= ERROR_UNKNOWN_PROPERTY
;
236 lstrcpynW(szValue
, ptr
, *pcchValue
);
237 if (lstrlenW(ptr
) > *pcchValue
)
239 *pcchValue
= lstrlenW(ptr
)+1;
240 rc
= ERROR_MORE_DATA
;
248 else if (strcmpW(INSTALLPROPERTY_LASTUSEDTYPEW
, szProperty
)==0)
253 RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
, 0, 0,
256 rc
= ERROR_UNKNOWN_PROPERTY
;
259 buffer
= msi_alloc(size
);
260 rc
= RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
,
261 0, 0, (LPBYTE
)buffer
,&size
);
264 rc
= ERROR_MORE_DATA
;
269 szValue
[0] = buffer
[0];
275 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW
, szProperty
)==0)
277 rc
= RegQueryValueExW(sourcekey
, INSTALLPROPERTY_PACKAGENAMEW
, 0, 0,
278 (LPBYTE
)szValue
, pcchValue
);
279 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_MORE_DATA
)
280 rc
= ERROR_UNKNOWN_PROPERTY
;
284 FIXME("Unknown property %s\n",debugstr_w(szProperty
));
285 rc
= ERROR_UNKNOWN_PROPERTY
;
288 RegCloseKey(sourcekey
);
292 /******************************************************************
293 * MsiSourceListSetInfoW (MSI.@)
295 UINT WINAPI
MsiSourceListSetInfoW( LPCWSTR szProduct
, LPCWSTR szUserSid
,
296 MSIINSTALLCONTEXT dwContext
, DWORD dwOptions
,
297 LPCWSTR szProperty
, LPCWSTR szValue
)
302 TRACE("%s %s %x %lx %s %s\n", debugstr_w(szProduct
), debugstr_w(szUserSid
),
303 dwContext
, dwOptions
, debugstr_w(szProperty
), debugstr_w(szValue
));
305 if (!szProduct
|| lstrlenW(szProduct
) > 39)
306 return ERROR_INVALID_PARAMETER
;
308 if (dwOptions
& MSICODE_PATCH
)
310 FIXME("Unhandled options MSICODE_PATCH\n");
311 return ERROR_FUNCTION_FAILED
;
315 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid
));
317 if (dwContext
== MSIINSTALLCONTEXT_USERUNMANAGED
)
318 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
320 if (dwContext
== MSIINSTALLCONTEXT_MACHINE
)
321 rc
= OpenSourceKey(szProduct
, &sourcekey
, FALSE
, TRUE
);
323 rc
= OpenSourceKey(szProduct
, &sourcekey
, TRUE
, TRUE
);
325 if (rc
!= ERROR_SUCCESS
)
326 return ERROR_UNKNOWN_PRODUCT
;
329 if (strcmpW(szProperty
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
) == 0)
332 DWORD size
= lstrlenW(szValue
)*sizeof(WCHAR
);
333 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
334 if (rc
== ERROR_SUCCESS
)
335 rc
= RegSetValueExW(key
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
, 0,
336 REG_SZ
, (LPBYTE
)szValue
, size
);
337 if (rc
!= ERROR_SUCCESS
)
338 rc
= ERROR_UNKNOWN_PROPERTY
;
341 else if (strcmpW(szProperty
, INSTALLPROPERTY_DISKPROMPTW
) == 0)
344 DWORD size
= lstrlenW(szValue
)*sizeof(WCHAR
);
345 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
346 if (rc
== ERROR_SUCCESS
)
347 rc
= RegSetValueExW(key
, INSTALLPROPERTY_DISKPROMPTW
, 0,
348 REG_SZ
, (LPBYTE
)szValue
, size
);
349 if (rc
!= ERROR_SUCCESS
)
350 rc
= ERROR_UNKNOWN_PROPERTY
;
353 else if (strcmpW(szProperty
, INSTALLPROPERTY_LASTUSEDSOURCEW
)==0)
355 LPWSTR buffer
= NULL
;
357 WCHAR typechar
= 'n';
358 static const WCHAR LastUsedSource_Fmt
[] = {'%','c',';','%','i',';','%','s',0};
360 /* make sure the source is registered */
361 MsiSourceListAddSourceExW(szProduct
, szUserSid
, dwContext
,
362 dwOptions
, szValue
, 0);
364 if (dwOptions
& MSISOURCETYPE_NETWORK
)
366 else if (dwOptions
& MSISOURCETYPE_URL
)
368 else if (dwOptions
& MSISOURCETYPE_MEDIA
)
371 ERR("Unknown source type! 0x%lx\n",dwOptions
);
373 size
= (lstrlenW(szValue
)+5)*sizeof(WCHAR
);
374 buffer
= msi_alloc(size
);
375 sprintfW(buffer
, LastUsedSource_Fmt
, typechar
, 1, szValue
);
376 rc
= RegSetValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
, 0,
377 REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
378 if (rc
!= ERROR_SUCCESS
)
379 rc
= ERROR_UNKNOWN_PROPERTY
;
382 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW
, szProperty
)==0)
384 DWORD size
= lstrlenW(szValue
)*sizeof(WCHAR
);
385 rc
= RegSetValueExW(sourcekey
, INSTALLPROPERTY_PACKAGENAMEW
, 0,
386 REG_SZ
, (LPBYTE
)szValue
, size
);
387 if (rc
!= ERROR_SUCCESS
)
388 rc
= ERROR_UNKNOWN_PROPERTY
;
392 FIXME("Unknown property %s\n",debugstr_w(szProperty
));
393 rc
= ERROR_UNKNOWN_PROPERTY
;
396 RegCloseKey(sourcekey
);
401 /******************************************************************
402 * MsiSourceListAddSourceW (MSI.@)
404 UINT WINAPI
MsiSourceListAddSourceW( LPCWSTR szProduct
, LPCWSTR szUserName
,
405 DWORD dwReserved
, LPCWSTR szSource
)
408 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
, NULL
, NULL
))
415 PSID psid
= msi_alloc(sidsize
);
417 if (LookupAccountNameW(NULL
, szUserName
, psid
, &sidsize
, NULL
, NULL
, 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, %lx, %s, %li\n", debugstr_w(szProduct
),
469 debugstr_w(szUserSid
), dwContext
, dwOptions
, debugstr_w(szSource
),
473 return ERROR_INVALID_PARAMETER
;
476 return ERROR_INVALID_PARAMETER
;
478 if (dwOptions
& MSICODE_PATCH
)
480 FIXME("Unhandled options MSICODE_PATCH\n");
481 return ERROR_FUNCTION_FAILED
;
485 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid
));
487 if (dwContext
== MSIINSTALLCONTEXT_USERUNMANAGED
)
488 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
490 if (dwContext
== MSIINSTALLCONTEXT_MACHINE
)
491 rc
= OpenSourceKey(szProduct
, &sourcekey
, FALSE
, TRUE
);
493 rc
= OpenSourceKey(szProduct
, &sourcekey
, TRUE
, TRUE
);
495 if (rc
!= ERROR_SUCCESS
)
496 return ERROR_UNKNOWN_PRODUCT
;
498 if (dwOptions
& MSISOURCETYPE_NETWORK
)
499 rc
= OpenNetworkSubkey(sourcekey
, &typekey
, TRUE
);
500 else if (dwOptions
& MSISOURCETYPE_URL
)
501 rc
= OpenURLSubkey(sourcekey
, &typekey
, TRUE
);
502 else if (dwOptions
& MSISOURCETYPE_MEDIA
)
503 rc
= OpenMediaSubkey(sourcekey
, &typekey
, TRUE
);
506 ERR("unknown media type: %08lx\n", dwOptions
);
507 RegCloseKey(sourcekey
);
508 return ERROR_FUNCTION_FAILED
;
511 source_struct
.szIndex
[0] = 0;
512 if (find_given_source(typekey
, szSource
, &source_struct
)==ERROR_SUCCESS
)
514 DWORD current_index
= atoiW(source_struct
.szIndex
);
515 /* found the source */
516 if (dwIndex
> 0 && current_index
!= dwIndex
)
517 FIXME("Need to reorder the sources!\n");
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 (LPBYTE
)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 %lx %li %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
;