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;