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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 rc
= RegEnumValueW(key
, index
, szIndex
, &size
, NULL
, NULL
, NULL
, &val_size
);
130 if (rc
!= ERROR_NO_MORE_ITEMS
)
132 val
= msi_alloc(val_size
);
133 RegEnumValueW(key
, index
, szIndex
, &size
, NULL
, NULL
, (LPBYTE
)val
,
135 if (lstrcmpiW(szSource
,val
)==0)
138 strcpyW(ss
->szIndex
,szIndex
);
142 strcpyW(ss
->szIndex
,szIndex
);
151 /******************************************************************
152 * MsiSourceListGetInfoW (MSI.@)
154 UINT WINAPI
MsiSourceListGetInfoW( LPCWSTR szProduct
, LPCWSTR szUserSid
,
155 MSIINSTALLCONTEXT dwContext
, DWORD dwOptions
,
156 LPCWSTR szProperty
, LPWSTR szValue
,
162 TRACE("%s %s\n", debugstr_w(szProduct
), debugstr_w(szProperty
));
164 if (!szProduct
|| lstrlenW(szProduct
) > 39)
165 return ERROR_INVALID_PARAMETER
;
167 if (szValue
&& !pcchValue
)
168 return ERROR_INVALID_PARAMETER
;
170 if (dwOptions
== MSICODE_PATCH
)
172 FIXME("Unhandled options MSICODE_PATCH\n");
173 return ERROR_FUNCTION_FAILED
;
177 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid
));
179 if (dwContext
== MSIINSTALLCONTEXT_USERUNMANAGED
)
180 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
182 if (dwContext
== MSIINSTALLCONTEXT_MACHINE
)
183 rc
= OpenSourceKey(szProduct
, &sourcekey
, FALSE
, FALSE
);
185 rc
= OpenSourceKey(szProduct
, &sourcekey
, TRUE
, FALSE
);
187 if (rc
!= ERROR_SUCCESS
)
188 return ERROR_UNKNOWN_PRODUCT
;
190 if (strcmpW(szProperty
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
) == 0)
193 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
194 if (rc
== ERROR_SUCCESS
)
195 rc
= RegQueryValueExW(key
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
,
196 0, 0, (LPBYTE
)szValue
, pcchValue
);
197 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_MORE_DATA
)
198 rc
= ERROR_UNKNOWN_PROPERTY
;
201 else if (strcmpW(szProperty
, INSTALLPROPERTY_DISKPROMPTW
) ==0)
204 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
205 if (rc
== ERROR_SUCCESS
)
206 rc
= RegQueryValueExW(key
, INSTALLPROPERTY_DISKPROMPTW
, 0, 0,
207 (LPBYTE
)szValue
, pcchValue
);
208 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_MORE_DATA
)
209 rc
= ERROR_UNKNOWN_PROPERTY
;
212 else if (strcmpW(szProperty
, INSTALLPROPERTY_LASTUSEDSOURCEW
)==0)
217 RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
, 0, 0,
220 rc
= ERROR_UNKNOWN_PROPERTY
;
224 buffer
= msi_alloc(size
);
225 rc
= RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
,
226 0, 0, (LPBYTE
)buffer
,&size
);
227 ptr
= strchrW(buffer
,';');
228 if (ptr
) ptr
= strchrW(ptr
+1,';');
230 rc
= ERROR_UNKNOWN_PROPERTY
;
234 lstrcpynW(szValue
, ptr
, *pcchValue
);
235 if (lstrlenW(ptr
) > *pcchValue
)
237 *pcchValue
= lstrlenW(ptr
)+1;
238 rc
= ERROR_MORE_DATA
;
246 else if (strcmpW(INSTALLPROPERTY_LASTUSEDTYPEW
, szProperty
)==0)
251 RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
, 0, 0,
254 rc
= ERROR_UNKNOWN_PROPERTY
;
257 buffer
= msi_alloc(size
);
258 rc
= RegQueryValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
,
259 0, 0, (LPBYTE
)buffer
,&size
);
262 rc
= ERROR_MORE_DATA
;
267 szValue
[0] = buffer
[0];
273 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW
, szProperty
)==0)
275 rc
= RegQueryValueExW(sourcekey
, INSTALLPROPERTY_PACKAGENAMEW
, 0, 0,
276 (LPBYTE
)szValue
, pcchValue
);
277 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_MORE_DATA
)
278 rc
= ERROR_UNKNOWN_PROPERTY
;
282 FIXME("Unknown property %s\n",debugstr_w(szProperty
));
283 rc
= ERROR_UNKNOWN_PROPERTY
;
286 RegCloseKey(sourcekey
);
290 /******************************************************************
291 * MsiSourceListSetInfoW (MSI.@)
293 UINT WINAPI
MsiSourceListSetInfoW( LPCWSTR szProduct
, LPCWSTR szUserSid
,
294 MSIINSTALLCONTEXT dwContext
, DWORD dwOptions
,
295 LPCWSTR szProperty
, LPCWSTR szValue
)
300 TRACE("%s %s %x %lx %s %s\n", debugstr_w(szProduct
), debugstr_w(szUserSid
),
301 dwContext
, dwOptions
, debugstr_w(szProperty
), debugstr_w(szValue
));
303 if (!szProduct
|| lstrlenW(szProduct
) > 39)
304 return ERROR_INVALID_PARAMETER
;
306 if (dwOptions
& MSICODE_PATCH
)
308 FIXME("Unhandled options MSICODE_PATCH\n");
309 return ERROR_FUNCTION_FAILED
;
313 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid
));
315 if (dwContext
== MSIINSTALLCONTEXT_USERUNMANAGED
)
316 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
318 if (dwContext
== MSIINSTALLCONTEXT_MACHINE
)
319 rc
= OpenSourceKey(szProduct
, &sourcekey
, FALSE
, TRUE
);
321 rc
= OpenSourceKey(szProduct
, &sourcekey
, TRUE
, TRUE
);
323 if (rc
!= ERROR_SUCCESS
)
324 return ERROR_UNKNOWN_PRODUCT
;
327 if (strcmpW(szProperty
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
) == 0)
330 DWORD size
= lstrlenW(szValue
)*sizeof(WCHAR
);
331 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
332 if (rc
== ERROR_SUCCESS
)
333 rc
= RegSetValueExW(key
, INSTALLPROPERTY_MEDIAPACKAGEPATHW
, 0,
334 REG_SZ
, (LPBYTE
)szValue
, size
);
335 if (rc
!= ERROR_SUCCESS
)
336 rc
= ERROR_UNKNOWN_PROPERTY
;
339 else if (strcmpW(szProperty
, INSTALLPROPERTY_DISKPROMPTW
) == 0)
342 DWORD size
= lstrlenW(szValue
)*sizeof(WCHAR
);
343 rc
= OpenMediaSubkey(sourcekey
, &key
, FALSE
);
344 if (rc
== ERROR_SUCCESS
)
345 rc
= RegSetValueExW(key
, INSTALLPROPERTY_DISKPROMPTW
, 0,
346 REG_SZ
, (LPBYTE
)szValue
, size
);
347 if (rc
!= ERROR_SUCCESS
)
348 rc
= ERROR_UNKNOWN_PROPERTY
;
351 else if (strcmpW(szProperty
, INSTALLPROPERTY_LASTUSEDSOURCEW
)==0)
353 LPWSTR buffer
= NULL
;
355 WCHAR typechar
= 'n';
356 static const WCHAR LastUsedSource_Fmt
[] = {'%','c',';','%','i',';','%','s',0};
358 /* make sure the source is registered */
359 MsiSourceListAddSourceExW(szProduct
, szUserSid
, dwContext
,
360 dwOptions
, szValue
, 0);
362 if (dwOptions
& MSISOURCETYPE_NETWORK
)
364 else if (dwOptions
& MSISOURCETYPE_URL
)
366 else if (dwOptions
& MSISOURCETYPE_MEDIA
)
369 ERR("Unknown source type! 0x%lx\n",dwOptions
);
371 size
= (lstrlenW(szValue
)+5)*sizeof(WCHAR
);
372 buffer
= msi_alloc(size
);
373 sprintfW(buffer
, LastUsedSource_Fmt
, typechar
, 1, szValue
);
374 rc
= RegSetValueExW(sourcekey
, INSTALLPROPERTY_LASTUSEDSOURCEW
, 0,
375 REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
376 if (rc
!= ERROR_SUCCESS
)
377 rc
= ERROR_UNKNOWN_PROPERTY
;
380 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW
, szProperty
)==0)
382 DWORD size
= lstrlenW(szValue
)*sizeof(WCHAR
);
383 rc
= RegSetValueExW(sourcekey
, INSTALLPROPERTY_PACKAGENAMEW
, 0,
384 REG_SZ
, (LPBYTE
)szValue
, size
);
385 if (rc
!= ERROR_SUCCESS
)
386 rc
= ERROR_UNKNOWN_PROPERTY
;
390 FIXME("Unknown property %s\n",debugstr_w(szProperty
));
391 rc
= ERROR_UNKNOWN_PROPERTY
;
394 RegCloseKey(sourcekey
);
399 /******************************************************************
400 * MsiSourceListAddSourceExW (MSI.@)
402 UINT WINAPI
MsiSourceListAddSourceExW( LPCWSTR szProduct
, LPCWSTR szUserSid
,
403 MSIINSTALLCONTEXT dwContext
, DWORD dwOptions
, LPCWSTR szSource
,
409 media_info source_struct
;
411 TRACE("%s, %s, %x, %lx, %s, %li\n", debugstr_w(szProduct
),
412 debugstr_w(szUserSid
), dwContext
, dwOptions
, debugstr_w(szSource
),
416 return ERROR_INVALID_PARAMETER
;
419 return ERROR_INVALID_PARAMETER
;
421 if (dwOptions
& MSICODE_PATCH
)
423 FIXME("Unhandled options MSICODE_PATCH\n");
424 return ERROR_FUNCTION_FAILED
;
428 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid
));
430 if (dwContext
== MSIINSTALLCONTEXT_USERUNMANAGED
)
431 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
433 if (dwContext
== MSIINSTALLCONTEXT_MACHINE
)
434 rc
= OpenSourceKey(szProduct
, &sourcekey
, FALSE
, TRUE
);
436 rc
= OpenSourceKey(szProduct
, &sourcekey
, TRUE
, TRUE
);
438 if (rc
!= ERROR_SUCCESS
)
439 return ERROR_UNKNOWN_PRODUCT
;
441 if (dwOptions
& MSISOURCETYPE_NETWORK
)
442 rc
= OpenNetworkSubkey(sourcekey
, &typekey
, TRUE
);
443 else if (dwOptions
& MSISOURCETYPE_URL
)
444 rc
= OpenURLSubkey(sourcekey
, &typekey
, TRUE
);
447 ERR("unknown media type: %08lx\n", dwOptions
);
448 RegCloseKey(sourcekey
);
449 return ERROR_FUNCTION_FAILED
;
452 source_struct
.szIndex
[0] = 0;
453 if (find_given_source(typekey
, szSource
, &source_struct
)==ERROR_SUCCESS
)
455 DWORD current_index
= atoiW(source_struct
.szIndex
);
456 /* found the source */
457 if (dwIndex
> 0 && current_index
!= dwIndex
)
458 FIXME("Need to reorder the sources!\n");
462 DWORD current_index
= 0;
463 static const WCHAR fmt
[] = {'%','i',0};
464 DWORD size
= lstrlenW(szSource
)*sizeof(WCHAR
);
466 if (source_struct
.szIndex
[0])
467 current_index
= atoiW(source_struct
.szIndex
);
469 if (dwIndex
> 0 && dwIndex
< current_index
)
470 FIXME("Need to reorder the sources!\n");
473 sprintfW(source_struct
.szIndex
,fmt
,current_index
);
474 rc
= RegSetValueExW(typekey
, source_struct
.szIndex
, 0, REG_EXPAND_SZ
,
475 (LPBYTE
)szSource
, size
);
478 RegCloseKey(typekey
);
479 RegCloseKey(sourcekey
);
483 /******************************************************************
484 * MsiSourceListAddMediaDisk(MSI.@)
486 UINT WINAPI
MsiSourceListAddMediaDiskW(LPCWSTR szProduct
, LPCWSTR szUserSid
,
487 MSIINSTALLCONTEXT dwContext
, DWORD dwOptions
, DWORD dwDiskId
,
488 LPCWSTR szVolumeLabel
, LPCWSTR szDiskPrompt
)
494 static const WCHAR fmt
[] = {'%','i',0};
495 static const WCHAR disk_fmt
[] = {'%','s',';','%','s',0};
496 static const WCHAR empty
[1] = {0};
501 TRACE("%s %s %x %lx %li %s %s\n", debugstr_w(szProduct
),
502 debugstr_w(szUserSid
), dwContext
, dwOptions
, dwDiskId
,
503 debugstr_w(szVolumeLabel
), debugstr_w(szDiskPrompt
));
505 if (!szProduct
|| lstrlenW(szProduct
) > 39)
506 return ERROR_INVALID_PARAMETER
;
508 if (dwOptions
& MSICODE_PATCH
)
510 FIXME("Unhandled options MSICODE_PATCH\n");
511 return ERROR_FUNCTION_FAILED
;
515 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid
));
517 if (dwContext
== MSIINSTALLCONTEXT_USERUNMANAGED
)
518 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
520 if (dwContext
== MSIINSTALLCONTEXT_MACHINE
)
521 rc
= OpenSourceKey(szProduct
, &sourcekey
, FALSE
, TRUE
);
523 rc
= OpenSourceKey(szProduct
, &sourcekey
, TRUE
, TRUE
);
525 if (rc
!= ERROR_SUCCESS
)
526 return ERROR_UNKNOWN_PRODUCT
;
528 OpenMediaSubkey(sourcekey
,&mediakey
,TRUE
);
530 sprintfW(szIndex
,fmt
,dwDiskId
);
535 size
+=lstrlenW(szVolumeLabel
);
542 size
+=lstrlenW(szDiskPrompt
);
548 size
*=sizeof(WCHAR
);
550 buffer
= msi_alloc(size
);
551 sprintfW(buffer
,disk_fmt
,pt1
,pt2
);
553 RegSetValueExW(mediakey
, szIndex
, 0, REG_SZ
, (LPBYTE
)buffer
, size
);
556 RegCloseKey(sourcekey
);
557 RegCloseKey(mediakey
);
559 return ERROR_SUCCESS
;