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