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