1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2005 Aric Stewart for CodeWeavers 5 * 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. 10 * 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. 15 * 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 19 */ 20 21 #include <stdarg.h> 22 23 #define COBJMACROS 24 25 #include "windef.h" 26 #include "winbase.h" 27 #include "winreg.h" 28 #include "winnls.h" 29 #include "shlwapi.h" 30 #include "wine/debug.h" 31 #include "msi.h" 32 #include "msiquery.h" 33 #include "msipriv.h" 34 #include "wincrypt.h" 35 #include "winver.h" 36 #include "winuser.h" 37 #include "wine/unicode.h" 38 #include "sddl.h" 39 40 WINE_DEFAULT_DEBUG_CHANNEL(msi); 41 42 /* 43 * These apis are defined in MSI 3.0 44 */ 45 46 typedef struct tagMediaInfo 47 { 48 struct list entry; 49 LPWSTR path; 50 WCHAR szIndex[10]; 51 DWORD index; 52 } media_info; 53 54 static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, DWORD dwOptions, 55 MSIINSTALLCONTEXT context, BOOL create) 56 { 57 HKEY rootkey = 0; 58 UINT rc = ERROR_FUNCTION_FAILED; 59 60 if (context == MSIINSTALLCONTEXT_USERUNMANAGED) 61 { 62 if (dwOptions & MSICODE_PATCH) 63 rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create); 64 else 65 rc = MSIREG_OpenProductKey(szProduct, NULL, context, 66 &rootkey, create); 67 } 68 else if (context == MSIINSTALLCONTEXT_USERMANAGED) 69 { 70 if (dwOptions & MSICODE_PATCH) 71 rc = MSIREG_OpenUserPatchesKey(szProduct, &rootkey, create); 72 else 73 rc = MSIREG_OpenProductKey(szProduct, NULL, context, 74 &rootkey, create); 75 } 76 else if (context == MSIINSTALLCONTEXT_MACHINE) 77 { 78 if (dwOptions & MSICODE_PATCH) 79 rc = MSIREG_OpenPatchesKey(szProduct, &rootkey, create); 80 else 81 rc = MSIREG_OpenProductKey(szProduct, NULL, context, 82 &rootkey, create); 83 } 84 85 if (rc != ERROR_SUCCESS) 86 { 87 if (dwOptions & MSICODE_PATCH) 88 return ERROR_UNKNOWN_PATCH; 89 else 90 return ERROR_UNKNOWN_PRODUCT; 91 } 92 93 if (create) 94 rc = RegCreateKeyW(rootkey, szSourceList, key); 95 else 96 { 97 rc = RegOpenKeyW(rootkey,szSourceList, key); 98 if (rc != ERROR_SUCCESS) 99 rc = ERROR_BAD_CONFIGURATION; 100 } 101 102 return rc; 103 } 104 105 static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create) 106 { 107 UINT rc; 108 static const WCHAR media[] = {'M','e','d','i','a',0}; 109 110 if (create) 111 rc = RegCreateKeyW(rootkey, media, key); 112 else 113 rc = RegOpenKeyW(rootkey,media, key); 114 115 return rc; 116 } 117 118 static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create) 119 { 120 UINT rc; 121 static const WCHAR net[] = {'N','e','t',0}; 122 123 if (create) 124 rc = RegCreateKeyW(rootkey, net, key); 125 else 126 rc = RegOpenKeyW(rootkey, net, key); 127 128 return rc; 129 } 130 131 static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create) 132 { 133 UINT rc; 134 static const WCHAR URL[] = {'U','R','L',0}; 135 136 if (create) 137 rc = RegCreateKeyW(rootkey, URL, key); 138 else 139 rc = RegOpenKeyW(rootkey, URL, key); 140 141 return rc; 142 } 143 144 /****************************************************************** 145 * MsiSourceListEnumMediaDisksA (MSI.@) 146 */ 147 UINT WINAPI MsiSourceListEnumMediaDisksA(LPCSTR szProductCodeOrPatchCode, 148 LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext, 149 DWORD dwOptions, DWORD dwIndex, LPDWORD pdwDiskId, 150 LPSTR szVolumeLabel, LPDWORD pcchVolumeLabel, 151 LPSTR szDiskPrompt, LPDWORD pcchDiskPrompt) 152 { 153 LPWSTR product = NULL; 154 LPWSTR usersid = NULL; 155 LPWSTR volume = NULL; 156 LPWSTR prompt = NULL; 157 UINT r = ERROR_INVALID_PARAMETER; 158 159 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n", debugstr_a(szProductCodeOrPatchCode), 160 debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, pdwDiskId, 161 szVolumeLabel, pcchVolumeLabel, szDiskPrompt, pcchDiskPrompt); 162 163 if (szDiskPrompt && !pcchDiskPrompt) 164 return ERROR_INVALID_PARAMETER; 165 166 if (szProductCodeOrPatchCode) product = strdupAtoW(szProductCodeOrPatchCode); 167 if (szUserSid) usersid = strdupAtoW(szUserSid); 168 169 /* FIXME: add tests for an invalid format */ 170 171 if (pcchVolumeLabel) 172 volume = msi_alloc(*pcchVolumeLabel * sizeof(WCHAR)); 173 174 if (pcchDiskPrompt) 175 prompt = msi_alloc(*pcchDiskPrompt * sizeof(WCHAR)); 176 177 if (volume) *volume = '\0'; 178 if (prompt) *prompt = '\0'; 179 r = MsiSourceListEnumMediaDisksW(product, usersid, dwContext, dwOptions, 180 dwIndex, pdwDiskId, volume, pcchVolumeLabel, 181 prompt, pcchDiskPrompt); 182 if (r != ERROR_SUCCESS) 183 goto done; 184 185 if (szVolumeLabel && pcchVolumeLabel) 186 WideCharToMultiByte(CP_ACP, 0, volume, -1, szVolumeLabel, 187 *pcchVolumeLabel + 1, NULL, NULL); 188 189 if (szDiskPrompt) 190 WideCharToMultiByte(CP_ACP, 0, prompt, -1, szDiskPrompt, 191 *pcchDiskPrompt + 1, NULL, NULL); 192 193 done: 194 msi_free(product); 195 msi_free(usersid); 196 msi_free(volume); 197 msi_free(prompt); 198 199 return r; 200 } 201 202 /****************************************************************** 203 * MsiSourceListEnumMediaDisksW (MSI.@) 204 */ 205 UINT WINAPI MsiSourceListEnumMediaDisksW(LPCWSTR szProductCodeOrPatchCode, 206 LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, 207 DWORD dwOptions, DWORD dwIndex, LPDWORD pdwDiskId, 208 LPWSTR szVolumeLabel, LPDWORD pcchVolumeLabel, 209 LPWSTR szDiskPrompt, LPDWORD pcchDiskPrompt) 210 { 211 static const WCHAR fmt[] = {'#','%','d',0}; 212 WCHAR squashed_pc[SQUASHED_GUID_SIZE], convert[11]; 213 WCHAR *value = NULL, *data = NULL, *ptr, *ptr2; 214 HKEY source, media; 215 DWORD valuesz, datasz = 0, type, numvals, size; 216 LONG res; 217 UINT r; 218 static DWORD index = 0; 219 220 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p)\n", debugstr_w(szProductCodeOrPatchCode), 221 debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szVolumeLabel, 222 pcchVolumeLabel, szDiskPrompt, pcchDiskPrompt); 223 224 if (!szProductCodeOrPatchCode || !squash_guid( szProductCodeOrPatchCode, squashed_pc )) 225 return ERROR_INVALID_PARAMETER; 226 227 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid) 228 return ERROR_INVALID_PARAMETER; 229 230 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH) 231 return ERROR_INVALID_PARAMETER; 232 233 if (szDiskPrompt && !pcchDiskPrompt) 234 return ERROR_INVALID_PARAMETER; 235 236 if (dwIndex == 0) 237 index = 0; 238 239 if (dwIndex != index) 240 return ERROR_INVALID_PARAMETER; 241 242 r = OpenSourceKey(szProductCodeOrPatchCode, &source, dwOptions, dwContext, FALSE); 243 if (r != ERROR_SUCCESS) 244 return r; 245 246 r = OpenMediaSubkey(source, &media, FALSE); 247 if (r != ERROR_SUCCESS) 248 { 249 RegCloseKey(source); 250 return ERROR_NO_MORE_ITEMS; 251 } 252 253 res = RegQueryInfoKeyW(media, NULL, NULL, NULL, NULL, NULL, 254 NULL, &numvals, &valuesz, &datasz, NULL, NULL); 255 if (res != ERROR_SUCCESS) 256 { 257 r = ERROR_BAD_CONFIGURATION; 258 goto done; 259 } 260 261 value = msi_alloc(++valuesz * sizeof(WCHAR)); 262 data = msi_alloc(++datasz * sizeof(WCHAR)); 263 if (!value || !data) 264 { 265 r = ERROR_OUTOFMEMORY; 266 goto done; 267 } 268 269 r = RegEnumValueW(media, dwIndex, value, &valuesz, 270 NULL, &type, (LPBYTE)data, &datasz); 271 if (r != ERROR_SUCCESS) 272 goto done; 273 274 if (pdwDiskId) 275 *pdwDiskId = atolW(value); 276 277 ptr2 = data; 278 ptr = strchrW(data, ';'); 279 if (!ptr) 280 ptr = data; 281 else 282 *ptr = '\0'; 283 284 if (pcchVolumeLabel) 285 { 286 if (type == REG_DWORD) 287 { 288 sprintfW(convert, fmt, *data); 289 size = lstrlenW(convert); 290 ptr2 = convert; 291 } 292 else 293 size = lstrlenW(data); 294 295 if (size >= *pcchVolumeLabel) 296 r = ERROR_MORE_DATA; 297 else if (szVolumeLabel) 298 lstrcpyW(szVolumeLabel, ptr2); 299 300 *pcchVolumeLabel = size; 301 } 302 303 if (pcchDiskPrompt) 304 { 305 if (!*ptr) 306 ptr++; 307 308 if (type == REG_DWORD) 309 { 310 sprintfW(convert, fmt, *ptr); 311 size = lstrlenW(convert); 312 ptr = convert; 313 } 314 else 315 size = lstrlenW(ptr); 316 317 if (size >= *pcchDiskPrompt) 318 r = ERROR_MORE_DATA; 319 else if (szDiskPrompt) 320 lstrcpyW(szDiskPrompt, ptr); 321 322 *pcchDiskPrompt = size; 323 } 324 325 index++; 326 327 done: 328 msi_free(value); 329 msi_free(data); 330 RegCloseKey(source); 331 332 return r; 333 } 334 335 /****************************************************************** 336 * MsiSourceListEnumSourcesA (MSI.@) 337 */ 338 UINT WINAPI MsiSourceListEnumSourcesA(LPCSTR szProductCodeOrPatch, LPCSTR szUserSid, 339 MSIINSTALLCONTEXT dwContext, 340 DWORD dwOptions, DWORD dwIndex, 341 LPSTR szSource, LPDWORD pcchSource) 342 { 343 LPWSTR product = NULL; 344 LPWSTR usersid = NULL; 345 LPWSTR source = NULL; 346 DWORD len = 0; 347 UINT r = ERROR_INVALID_PARAMETER; 348 static DWORD index = 0; 349 350 TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_a(szProductCodeOrPatch), 351 debugstr_a(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource); 352 353 if (dwIndex == 0) 354 index = 0; 355 356 if (szSource && !pcchSource) 357 goto done; 358 359 if (dwIndex != index) 360 goto done; 361 362 if (szProductCodeOrPatch) product = strdupAtoW(szProductCodeOrPatch); 363 if (szUserSid) usersid = strdupAtoW(szUserSid); 364 365 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions, 366 dwIndex, NULL, &len); 367 if (r != ERROR_SUCCESS) 368 goto done; 369 370 source = msi_alloc(++len * sizeof(WCHAR)); 371 if (!source) 372 { 373 r = ERROR_OUTOFMEMORY; 374 goto done; 375 } 376 377 *source = '\0'; 378 r = MsiSourceListEnumSourcesW(product, usersid, dwContext, dwOptions, 379 dwIndex, source, &len); 380 if (r != ERROR_SUCCESS) 381 goto done; 382 383 len = WideCharToMultiByte(CP_ACP, 0, source, -1, NULL, 0, NULL, NULL); 384 if (pcchSource && *pcchSource >= len) 385 WideCharToMultiByte(CP_ACP, 0, source, -1, szSource, len, NULL, NULL); 386 else if (szSource) 387 r = ERROR_MORE_DATA; 388 389 if (pcchSource) 390 *pcchSource = len - 1; 391 392 done: 393 msi_free(product); 394 msi_free(usersid); 395 msi_free(source); 396 397 if (r == ERROR_SUCCESS) 398 { 399 if (szSource || !pcchSource) index++; 400 } 401 else if (dwIndex > index) 402 index = 0; 403 404 return r; 405 } 406 407 /****************************************************************** 408 * MsiSourceListEnumSourcesW (MSI.@) 409 */ 410 UINT WINAPI MsiSourceListEnumSourcesW(LPCWSTR szProductCodeOrPatch, LPCWSTR szUserSid, 411 MSIINSTALLCONTEXT dwContext, 412 DWORD dwOptions, DWORD dwIndex, 413 LPWSTR szSource, LPDWORD pcchSource) 414 { 415 static const WCHAR format[] = {'%','d',0}; 416 WCHAR squashed_pc[SQUASHED_GUID_SIZE], name[32]; 417 HKEY source = NULL, subkey = NULL; 418 LONG res; 419 UINT r = ERROR_INVALID_PARAMETER; 420 static DWORD index = 0; 421 422 TRACE("(%s, %s, %d, %d, %d, %p, %p)\n", debugstr_w(szProductCodeOrPatch), 423 debugstr_w(szUserSid), dwContext, dwOptions, dwIndex, szSource, pcchSource); 424 425 if (dwIndex == 0) 426 index = 0; 427 428 if (!szProductCodeOrPatch || !squash_guid( szProductCodeOrPatch, squashed_pc )) 429 goto done; 430 431 if (szSource && !pcchSource) 432 goto done; 433 434 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))) 435 goto done; 436 437 if ((dwOptions & MSISOURCETYPE_NETWORK) && (dwOptions & MSISOURCETYPE_URL)) 438 goto done; 439 440 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid) 441 goto done; 442 443 if (dwIndex != index) 444 goto done; 445 446 r = OpenSourceKey( szProductCodeOrPatch, &source, dwOptions, dwContext, FALSE ); 447 if (r != ERROR_SUCCESS) 448 goto done; 449 450 if (dwOptions & MSISOURCETYPE_NETWORK) 451 r = OpenNetworkSubkey(source, &subkey, FALSE); 452 else if (dwOptions & MSISOURCETYPE_URL) 453 r = OpenURLSubkey(source, &subkey, FALSE); 454 455 if (r != ERROR_SUCCESS) 456 { 457 r = ERROR_NO_MORE_ITEMS; 458 goto done; 459 } 460 461 sprintfW(name, format, dwIndex + 1); 462 463 res = RegQueryValueExW(subkey, name, 0, 0, (LPBYTE)szSource, pcchSource); 464 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) 465 r = ERROR_NO_MORE_ITEMS; 466 467 done: 468 RegCloseKey(subkey); 469 RegCloseKey(source); 470 471 if (r == ERROR_SUCCESS) 472 { 473 if (szSource || !pcchSource) index++; 474 } 475 else if (dwIndex > index) 476 index = 0; 477 478 return r; 479 } 480 481 /****************************************************************** 482 * MsiSourceListGetInfoA (MSI.@) 483 */ 484 UINT WINAPI MsiSourceListGetInfoA( LPCSTR szProduct, LPCSTR szUserSid, 485 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, 486 LPCSTR szProperty, LPSTR szValue, 487 LPDWORD pcchValue) 488 { 489 UINT ret; 490 LPWSTR product = NULL; 491 LPWSTR usersid = NULL; 492 LPWSTR property = NULL; 493 LPWSTR value = NULL; 494 DWORD len = 0; 495 496 if (szValue && !pcchValue) 497 return ERROR_INVALID_PARAMETER; 498 499 if (szProduct) product = strdupAtoW(szProduct); 500 if (szUserSid) usersid = strdupAtoW(szUserSid); 501 if (szProperty) property = strdupAtoW(szProperty); 502 503 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions, 504 property, NULL, &len); 505 if (ret != ERROR_SUCCESS) 506 goto done; 507 508 value = msi_alloc(++len * sizeof(WCHAR)); 509 if (!value) 510 return ERROR_OUTOFMEMORY; 511 512 *value = '\0'; 513 ret = MsiSourceListGetInfoW(product, usersid, dwContext, dwOptions, 514 property, value, &len); 515 if (ret != ERROR_SUCCESS) 516 goto done; 517 518 len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL); 519 if (*pcchValue >= len) 520 WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL); 521 else if (szValue) 522 ret = ERROR_MORE_DATA; 523 524 *pcchValue = len - 1; 525 526 done: 527 msi_free(product); 528 msi_free(usersid); 529 msi_free(property); 530 msi_free(value); 531 return ret; 532 } 533 534 /****************************************************************** 535 * MsiSourceListGetInfoW (MSI.@) 536 */ 537 UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid, 538 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, 539 LPCWSTR szProperty, LPWSTR szValue, 540 LPDWORD pcchValue) 541 { 542 static const WCHAR mediapack[] = {'M','e','d','i','a','P','a','c','k','a','g','e',0}; 543 WCHAR *source, *ptr, squashed_pc[SQUASHED_GUID_SIZE]; 544 HKEY sourcekey, media; 545 DWORD size; 546 UINT rc; 547 548 TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty)); 549 550 if (!szProduct || !squash_guid( szProduct, squashed_pc )) 551 return ERROR_INVALID_PARAMETER; 552 553 if (szValue && !pcchValue) 554 return ERROR_INVALID_PARAMETER; 555 556 if (dwContext != MSIINSTALLCONTEXT_USERMANAGED && 557 dwContext != MSIINSTALLCONTEXT_USERUNMANAGED && 558 dwContext != MSIINSTALLCONTEXT_MACHINE) 559 return ERROR_INVALID_PARAMETER; 560 561 if (!szProperty) 562 return ERROR_INVALID_PARAMETER; 563 564 if (szUserSid) 565 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid)); 566 567 rc = OpenSourceKey(szProduct, &sourcekey, dwOptions, dwContext, FALSE); 568 if (rc != ERROR_SUCCESS) 569 return rc; 570 571 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) || 572 !strcmpW( szProperty, INSTALLPROPERTY_DISKPROMPTW )) 573 { 574 rc = OpenMediaSubkey(sourcekey, &media, FALSE); 575 if (rc != ERROR_SUCCESS) 576 { 577 RegCloseKey(sourcekey); 578 return ERROR_SUCCESS; 579 } 580 581 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW )) 582 szProperty = mediapack; 583 584 RegQueryValueExW(media, szProperty, 0, 0, (LPBYTE)szValue, pcchValue); 585 RegCloseKey(media); 586 } 587 else if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) || 588 !strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW )) 589 { 590 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 591 0, 0, NULL, &size); 592 if (rc != ERROR_SUCCESS) 593 { 594 RegCloseKey(sourcekey); 595 return ERROR_SUCCESS; 596 } 597 598 source = msi_alloc(size); 599 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 600 0, 0, (LPBYTE)source, &size); 601 602 if (!*source) 603 { 604 msi_free(source); 605 RegCloseKey(sourcekey); 606 return ERROR_SUCCESS; 607 } 608 609 if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDTYPEW )) 610 { 611 if (*source != 'n' && *source != 'u' && *source != 'm') 612 { 613 msi_free(source); 614 RegCloseKey(sourcekey); 615 return ERROR_SUCCESS; 616 } 617 618 ptr = source; 619 source[1] = '\0'; 620 } 621 else 622 { 623 ptr = strrchrW(source, ';'); 624 if (!ptr) 625 ptr = source; 626 else 627 ptr++; 628 } 629 630 if (szValue) 631 { 632 if (strlenW(ptr) < *pcchValue) 633 lstrcpyW(szValue, ptr); 634 else 635 rc = ERROR_MORE_DATA; 636 } 637 638 *pcchValue = lstrlenW(ptr); 639 msi_free(source); 640 } 641 else if (!strcmpW( szProperty, INSTALLPROPERTY_PACKAGENAMEW )) 642 { 643 *pcchValue = *pcchValue * sizeof(WCHAR); 644 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0, 645 (LPBYTE)szValue, pcchValue); 646 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA) 647 { 648 *pcchValue = 0; 649 rc = ERROR_SUCCESS; 650 } 651 else 652 { 653 if (*pcchValue) 654 *pcchValue = (*pcchValue - 1) / sizeof(WCHAR); 655 if (szValue) 656 szValue[*pcchValue] = '\0'; 657 } 658 } 659 else 660 { 661 FIXME("Unknown property %s\n",debugstr_w(szProperty)); 662 rc = ERROR_UNKNOWN_PROPERTY; 663 } 664 665 RegCloseKey(sourcekey); 666 return rc; 667 } 668 669 /****************************************************************** 670 * MsiSourceListSetInfoA (MSI.@) 671 */ 672 UINT WINAPI MsiSourceListSetInfoA(LPCSTR szProduct, LPCSTR szUserSid, 673 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, 674 LPCSTR szProperty, LPCSTR szValue) 675 { 676 UINT ret; 677 LPWSTR product = NULL; 678 LPWSTR usersid = NULL; 679 LPWSTR property = NULL; 680 LPWSTR value = NULL; 681 682 if (szProduct) product = strdupAtoW(szProduct); 683 if (szUserSid) usersid = strdupAtoW(szUserSid); 684 if (szProperty) property = strdupAtoW(szProperty); 685 if (szValue) value = strdupAtoW(szValue); 686 687 ret = MsiSourceListSetInfoW(product, usersid, dwContext, dwOptions, 688 property, value); 689 690 msi_free(product); 691 msi_free(usersid); 692 msi_free(property); 693 msi_free(value); 694 695 return ret; 696 } 697 698 UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid, 699 MSIINSTALLCONTEXT context, DWORD options, 700 LPCWSTR value) 701 { 702 HKEY source; 703 LPWSTR buffer; 704 WCHAR typechar; 705 DWORD size; 706 UINT r; 707 int index = 1; 708 709 static const WCHAR format[] = {'%','c',';','%','i',';','%','s',0}; 710 711 if (options & MSISOURCETYPE_NETWORK) 712 typechar = 'n'; 713 else if (options & MSISOURCETYPE_URL) 714 typechar = 'u'; 715 else if (options & MSISOURCETYPE_MEDIA) 716 typechar = 'm'; 717 else 718 return ERROR_INVALID_PARAMETER; 719 720 if (!(options & MSISOURCETYPE_MEDIA)) 721 { 722 r = MsiSourceListAddSourceExW(product, usersid, context, 723 options, value, 0); 724 if (r != ERROR_SUCCESS) 725 return r; 726 727 index = 0; 728 while ((r = MsiSourceListEnumSourcesW(product, usersid, context, options, 729 index, NULL, NULL)) == ERROR_SUCCESS) 730 index++; 731 732 if (r != ERROR_NO_MORE_ITEMS) 733 return r; 734 } 735 736 size = (lstrlenW(format) + lstrlenW(value) + 7) * sizeof(WCHAR); 737 buffer = msi_alloc(size); 738 if (!buffer) 739 return ERROR_OUTOFMEMORY; 740 741 r = OpenSourceKey(product, &source, MSICODE_PRODUCT, context, FALSE); 742 if (r != ERROR_SUCCESS) 743 { 744 msi_free(buffer); 745 return r; 746 } 747 748 sprintfW(buffer, format, typechar, index, value); 749 750 size = (lstrlenW(buffer) + 1) * sizeof(WCHAR); 751 r = RegSetValueExW(source, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 752 REG_SZ, (LPBYTE)buffer, size); 753 msi_free(buffer); 754 755 RegCloseKey(source); 756 return r; 757 } 758 759 /****************************************************************** 760 * MsiSourceListSetInfoW (MSI.@) 761 */ 762 UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid, 763 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, 764 LPCWSTR szProperty, LPCWSTR szValue) 765 { 766 static const WCHAR media_package[] = {'M','e','d','i','a','P','a','c','k','a','g','e',0}; 767 WCHAR squashed_pc[SQUASHED_GUID_SIZE]; 768 HKEY sourcekey, media; 769 LPCWSTR property; 770 UINT rc; 771 772 TRACE("%s %s %x %x %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid), 773 dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue)); 774 775 if (!szProduct || !squash_guid( szProduct, squashed_pc )) 776 return ERROR_INVALID_PARAMETER; 777 778 if (!szProperty) 779 return ERROR_INVALID_PARAMETER; 780 781 if (!szValue) 782 return ERROR_UNKNOWN_PROPERTY; 783 784 if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid) 785 return ERROR_INVALID_PARAMETER; 786 787 if (dwOptions & MSICODE_PATCH) 788 { 789 FIXME("Unhandled options MSICODE_PATCH\n"); 790 return ERROR_UNKNOWN_PATCH; 791 } 792 793 property = szProperty; 794 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW )) 795 property = media_package; 796 797 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE); 798 if (rc != ERROR_SUCCESS) 799 return rc; 800 801 if (strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW ) && 802 dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL)) 803 { 804 RegCloseKey(sourcekey); 805 return ERROR_INVALID_PARAMETER; 806 } 807 808 if (!strcmpW( szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW ) || 809 !strcmpW( szProperty, INSTALLPROPERTY_DISKPROMPTW )) 810 { 811 rc = OpenMediaSubkey(sourcekey, &media, TRUE); 812 if (rc == ERROR_SUCCESS) 813 { 814 rc = msi_reg_set_val_str(media, property, szValue); 815 RegCloseKey(media); 816 } 817 } 818 else if (!strcmpW( szProperty, INSTALLPROPERTY_PACKAGENAMEW )) 819 { 820 DWORD size = (lstrlenW(szValue) + 1) * sizeof(WCHAR); 821 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 822 REG_SZ, (const BYTE *)szValue, size); 823 if (rc != ERROR_SUCCESS) 824 rc = ERROR_UNKNOWN_PROPERTY; 825 } 826 else if (!strcmpW( szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW )) 827 { 828 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))) 829 rc = ERROR_INVALID_PARAMETER; 830 else 831 rc = msi_set_last_used_source(szProduct, szUserSid, dwContext, 832 dwOptions, szValue); 833 } 834 else 835 rc = ERROR_UNKNOWN_PROPERTY; 836 837 RegCloseKey(sourcekey); 838 return rc; 839 } 840 841 /****************************************************************** 842 * MsiSourceListAddSourceW (MSI.@) 843 */ 844 UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName, 845 DWORD dwReserved, LPCWSTR szSource) 846 { 847 WCHAR *sidstr = NULL, squashed_pc[SQUASHED_GUID_SIZE]; 848 INT ret; 849 DWORD sidsize = 0, domsize = 0, context; 850 HKEY hkey = 0; 851 UINT r; 852 853 TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource)); 854 855 if (!szSource || !*szSource) 856 return ERROR_INVALID_PARAMETER; 857 858 if (dwReserved != 0) 859 return ERROR_INVALID_PARAMETER; 860 861 if (!szProduct || !squash_guid( szProduct, squashed_pc )) 862 return ERROR_INVALID_PARAMETER; 863 864 if (!szUserName || !*szUserName) 865 context = MSIINSTALLCONTEXT_MACHINE; 866 else 867 { 868 if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, &domsize, NULL)) 869 { 870 PSID psid = msi_alloc(sidsize); 871 872 if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL)) 873 ConvertSidToStringSidW(psid, &sidstr); 874 875 msi_free(psid); 876 } 877 878 r = MSIREG_OpenProductKey(szProduct, NULL, 879 MSIINSTALLCONTEXT_USERMANAGED, &hkey, FALSE); 880 if (r == ERROR_SUCCESS) 881 context = MSIINSTALLCONTEXT_USERMANAGED; 882 else 883 { 884 r = MSIREG_OpenProductKey(szProduct, NULL, 885 MSIINSTALLCONTEXT_USERUNMANAGED, 886 &hkey, FALSE); 887 if (r != ERROR_SUCCESS) 888 return ERROR_UNKNOWN_PRODUCT; 889 890 context = MSIINSTALLCONTEXT_USERUNMANAGED; 891 } 892 893 RegCloseKey(hkey); 894 } 895 896 ret = MsiSourceListAddSourceExW(szProduct, sidstr, 897 context, MSISOURCETYPE_NETWORK, szSource, 0); 898 899 if (sidstr) 900 LocalFree(sidstr); 901 902 return ret; 903 } 904 905 /****************************************************************** 906 * MsiSourceListAddSourceA (MSI.@) 907 */ 908 UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName, 909 DWORD dwReserved, LPCSTR szSource) 910 { 911 INT ret; 912 LPWSTR szwproduct; 913 LPWSTR szwusername; 914 LPWSTR szwsource; 915 916 szwproduct = strdupAtoW( szProduct ); 917 szwusername = strdupAtoW( szUserName ); 918 szwsource = strdupAtoW( szSource ); 919 920 ret = MsiSourceListAddSourceW(szwproduct, szwusername, dwReserved, szwsource); 921 922 msi_free(szwproduct); 923 msi_free(szwusername); 924 msi_free(szwsource); 925 926 return ret; 927 } 928 929 /****************************************************************** 930 * MsiSourceListAddSourceExA (MSI.@) 931 */ 932 UINT WINAPI MsiSourceListAddSourceExA(LPCSTR szProduct, LPCSTR szUserSid, 933 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCSTR szSource, DWORD dwIndex) 934 { 935 UINT ret; 936 LPWSTR product, usersid, source; 937 938 product = strdupAtoW(szProduct); 939 usersid = strdupAtoW(szUserSid); 940 source = strdupAtoW(szSource); 941 942 ret = MsiSourceListAddSourceExW(product, usersid, dwContext, 943 dwOptions, source, dwIndex); 944 945 msi_free(product); 946 msi_free(usersid); 947 msi_free(source); 948 949 return ret; 950 } 951 952 static void free_source_list(struct list *sourcelist) 953 { 954 while (!list_empty(sourcelist)) 955 { 956 media_info *info = LIST_ENTRY(list_head(sourcelist), media_info, entry); 957 list_remove(&info->entry); 958 msi_free(info->path); 959 msi_free(info); 960 } 961 } 962 963 static void add_source_to_list(struct list *sourcelist, media_info *info, 964 DWORD *index) 965 { 966 media_info *iter; 967 BOOL found = FALSE; 968 static const WCHAR fmt[] = {'%','i',0}; 969 970 if (index) *index = 0; 971 972 if (list_empty(sourcelist)) 973 { 974 list_add_head(sourcelist, &info->entry); 975 return; 976 } 977 978 LIST_FOR_EACH_ENTRY(iter, sourcelist, media_info, entry) 979 { 980 if (!found && info->index < iter->index) 981 { 982 found = TRUE; 983 list_add_before(&iter->entry, &info->entry); 984 } 985 986 /* update the rest of the list */ 987 if (found) 988 sprintfW(iter->szIndex, fmt, ++iter->index); 989 else if (index) 990 (*index)++; 991 } 992 993 if (!found) 994 list_add_after(&iter->entry, &info->entry); 995 } 996 997 static UINT fill_source_list(struct list *sourcelist, HKEY sourcekey, DWORD *count) 998 { 999 UINT r = ERROR_SUCCESS; 1000 DWORD index = 0; 1001 WCHAR name[10]; 1002 DWORD size, val_size; 1003 media_info *entry; 1004 1005 *count = 0; 1006 1007 while (r == ERROR_SUCCESS) 1008 { 1009 size = sizeof(name) / sizeof(name[0]); 1010 r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, NULL, &val_size); 1011 if (r != ERROR_SUCCESS) 1012 return r; 1013 1014 entry = msi_alloc(sizeof(media_info)); 1015 if (!entry) 1016 goto error; 1017 1018 entry->path = msi_alloc(val_size); 1019 if (!entry->path) 1020 { 1021 msi_free(entry); 1022 goto error; 1023 } 1024 1025 lstrcpyW(entry->szIndex, name); 1026 entry->index = atoiW(name); 1027 1028 size++; 1029 r = RegEnumValueW(sourcekey, index, name, &size, NULL, 1030 NULL, (LPBYTE)entry->path, &val_size); 1031 if (r != ERROR_SUCCESS) 1032 { 1033 msi_free(entry->path); 1034 msi_free(entry); 1035 goto error; 1036 } 1037 1038 index = ++(*count); 1039 add_source_to_list(sourcelist, entry, NULL); 1040 } 1041 1042 error: 1043 *count = -1; 1044 free_source_list(sourcelist); 1045 return ERROR_OUTOFMEMORY; 1046 } 1047 1048 /****************************************************************** 1049 * MsiSourceListAddSourceExW (MSI.@) 1050 */ 1051 UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid, 1052 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource, 1053 DWORD dwIndex) 1054 { 1055 static const WCHAR fmt[] = {'%','i',0}; 1056 HKEY sourcekey, typekey; 1057 UINT rc; 1058 struct list sourcelist; 1059 media_info *info; 1060 WCHAR *source, squashed_pc[SQUASHED_GUID_SIZE], name[10]; 1061 LPCWSTR postfix; 1062 DWORD size, count, index; 1063 1064 TRACE("%s %s %x %x %s %i\n", debugstr_w(szProduct), debugstr_w(szUserSid), 1065 dwContext, dwOptions, debugstr_w(szSource), dwIndex); 1066 1067 if (!szProduct || !squash_guid( szProduct, squashed_pc )) 1068 return ERROR_INVALID_PARAMETER; 1069 1070 if (!szSource || !*szSource) 1071 return ERROR_INVALID_PARAMETER; 1072 1073 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))) 1074 return ERROR_INVALID_PARAMETER; 1075 1076 if (dwOptions & MSICODE_PATCH) 1077 { 1078 FIXME("Unhandled options MSICODE_PATCH\n"); 1079 return ERROR_FUNCTION_FAILED; 1080 } 1081 1082 if (szUserSid && (dwContext & MSIINSTALLCONTEXT_MACHINE)) 1083 return ERROR_INVALID_PARAMETER; 1084 1085 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE); 1086 if (rc != ERROR_SUCCESS) 1087 return rc; 1088 1089 if (dwOptions & MSISOURCETYPE_NETWORK) 1090 rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE); 1091 else if (dwOptions & MSISOURCETYPE_URL) 1092 rc = OpenURLSubkey(sourcekey, &typekey, TRUE); 1093 else if (dwOptions & MSISOURCETYPE_MEDIA) 1094 rc = OpenMediaSubkey(sourcekey, &typekey, TRUE); 1095 else 1096 { 1097 ERR("unknown media type: %08x\n", dwOptions); 1098 RegCloseKey(sourcekey); 1099 return ERROR_FUNCTION_FAILED; 1100 } 1101 if (rc != ERROR_SUCCESS) 1102 { 1103 ERR("can't open subkey %u\n", rc); 1104 RegCloseKey(sourcekey); 1105 return rc; 1106 } 1107 1108 postfix = (dwOptions & MSISOURCETYPE_NETWORK) ? szBackSlash : szForwardSlash; 1109 if (szSource[lstrlenW(szSource) - 1] == *postfix) 1110 source = strdupW(szSource); 1111 else 1112 { 1113 size = lstrlenW(szSource) + 2; 1114 source = msi_alloc(size * sizeof(WCHAR)); 1115 lstrcpyW(source, szSource); 1116 lstrcatW(source, postfix); 1117 } 1118 1119 list_init(&sourcelist); 1120 rc = fill_source_list(&sourcelist, typekey, &count); 1121 if (rc != ERROR_NO_MORE_ITEMS) 1122 goto done; 1123 1124 size = (lstrlenW(source) + 1) * sizeof(WCHAR); 1125 1126 if (count == 0) 1127 { 1128 rc = RegSetValueExW(typekey, szOne, 0, REG_EXPAND_SZ, (LPBYTE)source, size); 1129 goto done; 1130 } 1131 else if (dwIndex > count || dwIndex == 0) 1132 { 1133 sprintfW(name, fmt, count + 1); 1134 rc = RegSetValueExW(typekey, name, 0, REG_EXPAND_SZ, (LPBYTE)source, size); 1135 goto done; 1136 } 1137 else 1138 { 1139 sprintfW(name, fmt, dwIndex); 1140 info = msi_alloc(sizeof(media_info)); 1141 if (!info) 1142 { 1143 rc = ERROR_OUTOFMEMORY; 1144 goto done; 1145 } 1146 1147 info->path = strdupW(source); 1148 lstrcpyW(info->szIndex, name); 1149 info->index = dwIndex; 1150 add_source_to_list(&sourcelist, info, &index); 1151 1152 LIST_FOR_EACH_ENTRY(info, &sourcelist, media_info, entry) 1153 { 1154 if (info->index < index) 1155 continue; 1156 1157 size = (lstrlenW(info->path) + 1) * sizeof(WCHAR); 1158 rc = RegSetValueExW(typekey, info->szIndex, 0, 1159 REG_EXPAND_SZ, (LPBYTE)info->path, size); 1160 if (rc != ERROR_SUCCESS) 1161 goto done; 1162 } 1163 } 1164 1165 done: 1166 free_source_list(&sourcelist); 1167 msi_free(source); 1168 RegCloseKey(typekey); 1169 RegCloseKey(sourcekey); 1170 return rc; 1171 } 1172 1173 /****************************************************************** 1174 * MsiSourceListAddMediaDiskA (MSI.@) 1175 */ 1176 UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR szProduct, LPCSTR szUserSid, 1177 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId, 1178 LPCSTR szVolumeLabel, LPCSTR szDiskPrompt) 1179 { 1180 UINT r; 1181 LPWSTR product = NULL; 1182 LPWSTR usersid = NULL; 1183 LPWSTR volume = NULL; 1184 LPWSTR prompt = NULL; 1185 1186 if (szProduct) product = strdupAtoW(szProduct); 1187 if (szUserSid) usersid = strdupAtoW(szUserSid); 1188 if (szVolumeLabel) volume = strdupAtoW(szVolumeLabel); 1189 if (szDiskPrompt) prompt = strdupAtoW(szDiskPrompt); 1190 1191 r = MsiSourceListAddMediaDiskW(product, usersid, dwContext, dwOptions, 1192 dwDiskId, volume, prompt); 1193 1194 msi_free(product); 1195 msi_free(usersid); 1196 msi_free(volume); 1197 msi_free(prompt); 1198 1199 return r; 1200 } 1201 1202 /****************************************************************** 1203 * MsiSourceListAddMediaDiskW (MSI.@) 1204 */ 1205 UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid, 1206 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId, 1207 LPCWSTR szVolumeLabel, LPCWSTR szDiskPrompt) 1208 { 1209 static const WCHAR fmt[] = {'%','i',0}; 1210 HKEY sourcekey, mediakey; 1211 UINT rc; 1212 WCHAR *buffer, squashed_pc[SQUASHED_GUID_SIZE], szIndex[10]; 1213 DWORD size; 1214 1215 TRACE("%s %s %x %x %i %s %s\n", debugstr_w(szProduct), 1216 debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId, 1217 debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt)); 1218 1219 if (!szProduct || !squash_guid( szProduct, squashed_pc )) 1220 return ERROR_INVALID_PARAMETER; 1221 1222 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH) 1223 return ERROR_INVALID_PARAMETER; 1224 1225 if ((szVolumeLabel && !*szVolumeLabel) || (szDiskPrompt && !*szDiskPrompt)) 1226 return ERROR_INVALID_PARAMETER; 1227 1228 if ((dwContext & MSIINSTALLCONTEXT_MACHINE) && szUserSid) 1229 return ERROR_INVALID_PARAMETER; 1230 1231 if (dwOptions & MSICODE_PATCH) 1232 { 1233 FIXME("Unhandled options MSICODE_PATCH\n"); 1234 return ERROR_FUNCTION_FAILED; 1235 } 1236 1237 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE); 1238 if (rc != ERROR_SUCCESS) 1239 return rc; 1240 1241 OpenMediaSubkey(sourcekey, &mediakey, TRUE); 1242 1243 sprintfW(szIndex, fmt, dwDiskId); 1244 1245 size = 2; 1246 if (szVolumeLabel) size += lstrlenW(szVolumeLabel); 1247 if (szDiskPrompt) size += lstrlenW(szDiskPrompt); 1248 1249 size *= sizeof(WCHAR); 1250 buffer = msi_alloc(size); 1251 *buffer = '\0'; 1252 1253 if (szVolumeLabel) lstrcpyW(buffer, szVolumeLabel); 1254 lstrcatW(buffer, szSemiColon); 1255 if (szDiskPrompt) lstrcatW(buffer, szDiskPrompt); 1256 1257 RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size); 1258 msi_free(buffer); 1259 1260 RegCloseKey(sourcekey); 1261 RegCloseKey(mediakey); 1262 1263 return ERROR_SUCCESS; 1264 } 1265 1266 /****************************************************************** 1267 * MsiSourceListClearAllA (MSI.@) 1268 */ 1269 UINT WINAPI MsiSourceListClearAllA( LPCSTR szProduct, LPCSTR szUserName, DWORD dwReserved ) 1270 { 1271 FIXME("(%s %s %d)\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved); 1272 return ERROR_SUCCESS; 1273 } 1274 1275 /****************************************************************** 1276 * MsiSourceListClearAllW (MSI.@) 1277 */ 1278 UINT WINAPI MsiSourceListClearAllW( LPCWSTR szProduct, LPCWSTR szUserName, DWORD dwReserved ) 1279 { 1280 FIXME("(%s %s %d)\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved); 1281 return ERROR_SUCCESS; 1282 } 1283 1284 /****************************************************************** 1285 * MsiSourceListClearAllExA (MSI.@) 1286 */ 1287 UINT WINAPI MsiSourceListClearAllExA( LPCSTR szProduct, LPCSTR szUserSid, 1288 MSIINSTALLCONTEXT dwContext, DWORD dwOptions ) 1289 { 1290 FIXME("(%s %s %d %08x)\n", debugstr_a(szProduct), debugstr_a(szUserSid), 1291 dwContext, dwOptions); 1292 return ERROR_SUCCESS; 1293 } 1294 1295 /****************************************************************** 1296 * MsiSourceListClearAllExW (MSI.@) 1297 */ 1298 UINT WINAPI MsiSourceListClearAllExW( LPCWSTR szProduct, LPCWSTR szUserSid, 1299 MSIINSTALLCONTEXT dwContext, DWORD dwOptions ) 1300 { 1301 FIXME("(%s %s %d %08x)\n", debugstr_w(szProduct), debugstr_w(szUserSid), 1302 dwContext, dwOptions); 1303 return ERROR_SUCCESS; 1304 } 1305 1306 /****************************************************************** 1307 * MsiSourceListClearSourceA (MSI.@) 1308 */ 1309 UINT WINAPI MsiSourceListClearSourceA(LPCSTR szProductCodeOrPatchCode, LPCSTR szUserSid, 1310 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, 1311 LPCSTR szSource) 1312 { 1313 FIXME("(%s %s %x %x %s)\n", debugstr_a(szProductCodeOrPatchCode), debugstr_a(szUserSid), 1314 dwContext, dwOptions, debugstr_a(szSource)); 1315 return ERROR_SUCCESS; 1316 } 1317 1318 /****************************************************************** 1319 * MsiSourceListClearSourceW (MSI.@) 1320 */ 1321 UINT WINAPI MsiSourceListClearSourceW(LPCWSTR szProductCodeOrPatchCode, LPCWSTR szUserSid, 1322 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, 1323 LPCWSTR szSource) 1324 { 1325 FIXME("(%s %s %x %x %s)\n", debugstr_w(szProductCodeOrPatchCode), debugstr_w(szUserSid), 1326 dwContext, dwOptions, debugstr_w(szSource)); 1327 return ERROR_SUCCESS; 1328 } 1329