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 struct media_info 46 { 47 struct list entry; 48 LPWSTR path; 49 WCHAR szIndex[10]; 50 DWORD index; 51 }; 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 = malloc(*pcchVolumeLabel * sizeof(WCHAR)); 166 167 if (pcchDiskPrompt) 168 prompt = malloc(*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 free(product); 188 free(usersid); 189 free(volume); 190 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 = malloc(++valuesz * sizeof(WCHAR)); 253 data = malloc(++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 free(value); 320 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 = malloc(++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 free(product); 382 free(usersid); 383 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 = malloc(++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 free(product); 514 free(usersid); 515 free(property); 516 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 = malloc(size); 587 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 588 0, 0, (LPBYTE)source, &size); 589 590 if (!*source) 591 { 592 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 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 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 free(product); 679 free(usersid); 680 free(property); 681 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 = malloc(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 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 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 = malloc(sidsize); 855 856 if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL)) 857 ConvertSidToStringSidW(psid, &sidstr); 858 859 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 free(szwproduct); 907 free(szwusername); 908 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 free(product); 930 free(usersid); 931 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 struct media_info *info = LIST_ENTRY(list_head(sourcelist), struct media_info, entry); 941 list_remove(&info->entry); 942 free(info->path); 943 free(info); 944 } 945 } 946 947 static void add_source_to_list(struct list *sourcelist, struct media_info *info, DWORD *index) 948 { 949 struct media_info *iter; 950 BOOL found = FALSE; 951 952 if (index) *index = 0; 953 954 if (list_empty(sourcelist)) 955 { 956 list_add_head(sourcelist, &info->entry); 957 return; 958 } 959 960 LIST_FOR_EACH_ENTRY(iter, sourcelist, struct media_info, entry) 961 { 962 if (!found && info->index < iter->index) 963 { 964 found = TRUE; 965 list_add_before(&iter->entry, &info->entry); 966 } 967 968 /* update the rest of the list */ 969 if (found) 970 swprintf(iter->szIndex, ARRAY_SIZE(iter->szIndex), L"%d", ++iter->index); 971 else if (index) 972 (*index)++; 973 } 974 975 if (!found) 976 list_add_after(&iter->entry, &info->entry); 977 } 978 979 static UINT fill_source_list(struct list *sourcelist, HKEY sourcekey, DWORD *count) 980 { 981 UINT r = ERROR_SUCCESS; 982 DWORD index = 0; 983 WCHAR name[10]; 984 DWORD size, val_size; 985 struct media_info *entry; 986 987 *count = 0; 988 989 while (r == ERROR_SUCCESS) 990 { 991 size = ARRAY_SIZE(name); 992 r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, NULL, &val_size); 993 if (r != ERROR_SUCCESS) 994 return r; 995 996 entry = malloc(sizeof(*entry)); 997 if (!entry) 998 goto error; 999 1000 entry->path = malloc(val_size); 1001 if (!entry->path) 1002 { 1003 free(entry); 1004 goto error; 1005 } 1006 1007 lstrcpyW(entry->szIndex, name); 1008 entry->index = wcstol(name, NULL, 10); 1009 1010 size++; 1011 r = RegEnumValueW(sourcekey, index, name, &size, NULL, 1012 NULL, (LPBYTE)entry->path, &val_size); 1013 if (r != ERROR_SUCCESS) 1014 { 1015 free(entry->path); 1016 free(entry); 1017 goto error; 1018 } 1019 1020 index = ++(*count); 1021 add_source_to_list(sourcelist, entry, NULL); 1022 } 1023 1024 error: 1025 *count = -1; 1026 free_source_list(sourcelist); 1027 return ERROR_OUTOFMEMORY; 1028 } 1029 1030 /****************************************************************** 1031 * MsiSourceListAddSourceExW (MSI.@) 1032 */ 1033 UINT WINAPI MsiSourceListAddSourceExW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext, 1034 DWORD dwOptions, const WCHAR *szSource, DWORD dwIndex ) 1035 { 1036 HKEY sourcekey, typekey; 1037 UINT rc; 1038 struct list sourcelist; 1039 struct media_info *info; 1040 WCHAR *source, squashed_pc[SQUASHED_GUID_SIZE], name[10]; 1041 LPCWSTR postfix; 1042 DWORD size, count, index; 1043 1044 TRACE( "%s, %s, %d, %#lx, %s, %lu\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions, 1045 debugstr_w(szSource), dwIndex ); 1046 1047 if (!szProduct || !squash_guid( szProduct, squashed_pc )) 1048 return ERROR_INVALID_PARAMETER; 1049 1050 if (!szSource || !*szSource) 1051 return ERROR_INVALID_PARAMETER; 1052 1053 if (!(dwOptions & (MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL))) 1054 return ERROR_INVALID_PARAMETER; 1055 1056 if (dwOptions & MSICODE_PATCH) 1057 { 1058 FIXME("Unhandled options MSICODE_PATCH\n"); 1059 return ERROR_FUNCTION_FAILED; 1060 } 1061 1062 if (szUserSid && (dwContext & MSIINSTALLCONTEXT_MACHINE)) 1063 return ERROR_INVALID_PARAMETER; 1064 1065 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE); 1066 if (rc != ERROR_SUCCESS) 1067 return rc; 1068 1069 if (dwOptions & MSISOURCETYPE_NETWORK) 1070 rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE); 1071 else if (dwOptions & MSISOURCETYPE_URL) 1072 rc = OpenURLSubkey(sourcekey, &typekey, TRUE); 1073 else if (dwOptions & MSISOURCETYPE_MEDIA) 1074 rc = OpenMediaSubkey(sourcekey, &typekey, TRUE); 1075 else 1076 { 1077 ERR( "unknown media type: %#lx\n", dwOptions ); 1078 RegCloseKey(sourcekey); 1079 return ERROR_FUNCTION_FAILED; 1080 } 1081 if (rc != ERROR_SUCCESS) 1082 { 1083 ERR("can't open subkey %u\n", rc); 1084 RegCloseKey(sourcekey); 1085 return rc; 1086 } 1087 1088 postfix = (dwOptions & MSISOURCETYPE_NETWORK) ? L"\\" : L"/"; 1089 if (szSource[lstrlenW(szSource) - 1] == *postfix) 1090 source = wcsdup(szSource); 1091 else 1092 { 1093 size = lstrlenW(szSource) + 2; 1094 source = malloc(size * sizeof(WCHAR)); 1095 lstrcpyW(source, szSource); 1096 lstrcatW(source, postfix); 1097 } 1098 1099 list_init(&sourcelist); 1100 rc = fill_source_list(&sourcelist, typekey, &count); 1101 if (rc != ERROR_NO_MORE_ITEMS) 1102 goto done; 1103 1104 size = (lstrlenW(source) + 1) * sizeof(WCHAR); 1105 1106 if (count == 0) 1107 { 1108 rc = RegSetValueExW(typekey, L"1", 0, REG_EXPAND_SZ, (LPBYTE)source, size); 1109 goto done; 1110 } 1111 else if (dwIndex > count || dwIndex == 0) 1112 { 1113 swprintf(name, ARRAY_SIZE(name), L"%d", count + 1); 1114 rc = RegSetValueExW(typekey, name, 0, REG_EXPAND_SZ, (LPBYTE)source, size); 1115 goto done; 1116 } 1117 else 1118 { 1119 swprintf(name, ARRAY_SIZE(name), L"%d", dwIndex); 1120 info = malloc(sizeof(*info)); 1121 if (!info) 1122 { 1123 rc = ERROR_OUTOFMEMORY; 1124 goto done; 1125 } 1126 1127 info->path = wcsdup(source); 1128 lstrcpyW(info->szIndex, name); 1129 info->index = dwIndex; 1130 add_source_to_list(&sourcelist, info, &index); 1131 1132 LIST_FOR_EACH_ENTRY(info, &sourcelist, struct media_info, entry) 1133 { 1134 if (info->index < index) 1135 continue; 1136 1137 size = (lstrlenW(info->path) + 1) * sizeof(WCHAR); 1138 rc = RegSetValueExW(typekey, info->szIndex, 0, 1139 REG_EXPAND_SZ, (LPBYTE)info->path, size); 1140 if (rc != ERROR_SUCCESS) 1141 goto done; 1142 } 1143 } 1144 1145 done: 1146 free_source_list(&sourcelist); 1147 free(source); 1148 RegCloseKey(typekey); 1149 RegCloseKey(sourcekey); 1150 return rc; 1151 } 1152 1153 /****************************************************************** 1154 * MsiSourceListAddMediaDiskA (MSI.@) 1155 */ 1156 UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR szProduct, LPCSTR szUserSid, 1157 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId, 1158 LPCSTR szVolumeLabel, LPCSTR szDiskPrompt) 1159 { 1160 UINT r; 1161 LPWSTR product = NULL; 1162 LPWSTR usersid = NULL; 1163 LPWSTR volume = NULL; 1164 LPWSTR prompt = NULL; 1165 1166 if (szProduct) product = strdupAtoW(szProduct); 1167 if (szUserSid) usersid = strdupAtoW(szUserSid); 1168 if (szVolumeLabel) volume = strdupAtoW(szVolumeLabel); 1169 if (szDiskPrompt) prompt = strdupAtoW(szDiskPrompt); 1170 1171 r = MsiSourceListAddMediaDiskW(product, usersid, dwContext, dwOptions, 1172 dwDiskId, volume, prompt); 1173 1174 free(product); 1175 free(usersid); 1176 free(volume); 1177 free(prompt); 1178 1179 return r; 1180 } 1181 1182 /****************************************************************** 1183 * MsiSourceListAddMediaDiskW (MSI.@) 1184 */ 1185 UINT WINAPI MsiSourceListAddMediaDiskW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext, 1186 DWORD dwOptions, DWORD dwDiskId, const WCHAR *szVolumeLabel, 1187 const WCHAR *szDiskPrompt ) 1188 { 1189 HKEY sourcekey, mediakey; 1190 UINT rc; 1191 WCHAR *buffer, squashed_pc[SQUASHED_GUID_SIZE], szIndex[10]; 1192 DWORD size; 1193 1194 TRACE( "%s, %s, %d, %#lx, %lu, %s, %s\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions, 1195 dwDiskId, debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt) ); 1196 1197 if (!szProduct || !squash_guid( szProduct, squashed_pc )) 1198 return ERROR_INVALID_PARAMETER; 1199 1200 if (dwOptions != MSICODE_PRODUCT && dwOptions != MSICODE_PATCH) 1201 return ERROR_INVALID_PARAMETER; 1202 1203 if ((szVolumeLabel && !*szVolumeLabel) || (szDiskPrompt && !*szDiskPrompt)) 1204 return ERROR_INVALID_PARAMETER; 1205 1206 if ((dwContext & MSIINSTALLCONTEXT_MACHINE) && szUserSid) 1207 return ERROR_INVALID_PARAMETER; 1208 1209 if (dwOptions & MSICODE_PATCH) 1210 { 1211 FIXME("Unhandled options MSICODE_PATCH\n"); 1212 return ERROR_FUNCTION_FAILED; 1213 } 1214 1215 rc = OpenSourceKey(szProduct, &sourcekey, MSICODE_PRODUCT, dwContext, FALSE); 1216 if (rc != ERROR_SUCCESS) 1217 return rc; 1218 1219 OpenMediaSubkey(sourcekey, &mediakey, TRUE); 1220 1221 swprintf(szIndex, ARRAY_SIZE(szIndex), L"%d", dwDiskId); 1222 1223 size = 2; 1224 if (szVolumeLabel) size += lstrlenW(szVolumeLabel); 1225 if (szDiskPrompt) size += lstrlenW(szDiskPrompt); 1226 1227 size *= sizeof(WCHAR); 1228 buffer = malloc(size); 1229 *buffer = '\0'; 1230 1231 if (szVolumeLabel) lstrcpyW(buffer, szVolumeLabel); 1232 lstrcatW(buffer, L";"); 1233 if (szDiskPrompt) lstrcatW(buffer, szDiskPrompt); 1234 1235 RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size); 1236 free(buffer); 1237 1238 RegCloseKey(sourcekey); 1239 RegCloseKey(mediakey); 1240 1241 return ERROR_SUCCESS; 1242 } 1243 1244 /****************************************************************** 1245 * MsiSourceListClearAllA (MSI.@) 1246 */ 1247 UINT WINAPI MsiSourceListClearAllA( const char *szProduct, const char *szUserName, DWORD dwReserved ) 1248 { 1249 FIXME( "%s, %s, %#lx\n", debugstr_a(szProduct), debugstr_a(szUserName), dwReserved ); 1250 return ERROR_SUCCESS; 1251 } 1252 1253 /****************************************************************** 1254 * MsiSourceListClearAllW (MSI.@) 1255 */ 1256 UINT WINAPI MsiSourceListClearAllW( const WCHAR *szProduct, const WCHAR *szUserName, DWORD dwReserved ) 1257 { 1258 FIXME( "%s, %s, %#lx\n", debugstr_w(szProduct), debugstr_w(szUserName), dwReserved ); 1259 return ERROR_SUCCESS; 1260 } 1261 1262 /****************************************************************** 1263 * MsiSourceListClearAllExA (MSI.@) 1264 */ 1265 UINT WINAPI MsiSourceListClearAllExA( const char *szProduct, const char *szUserSid, MSIINSTALLCONTEXT dwContext, 1266 DWORD dwOptions ) 1267 { 1268 FIXME( "%s, %s, %d, %#lx\n", debugstr_a(szProduct), debugstr_a(szUserSid), dwContext, dwOptions ); 1269 return ERROR_SUCCESS; 1270 } 1271 1272 /****************************************************************** 1273 * MsiSourceListClearAllExW (MSI.@) 1274 */ 1275 UINT WINAPI MsiSourceListClearAllExW( const WCHAR *szProduct, const WCHAR *szUserSid, MSIINSTALLCONTEXT dwContext, 1276 DWORD dwOptions ) 1277 { 1278 FIXME( "%s, %s, %d, %#lx\n", debugstr_w(szProduct), debugstr_w(szUserSid), dwContext, dwOptions ); 1279 return ERROR_SUCCESS; 1280 } 1281 1282 /****************************************************************** 1283 * MsiSourceListClearSourceA (MSI.@) 1284 */ 1285 UINT WINAPI MsiSourceListClearSourceA( const char *szProductCodeOrPatchCode, const char *szUserSid, 1286 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, const char *szSource ) 1287 { 1288 FIXME( "%s, %s, %d, %#lx, %s\n", debugstr_a(szProductCodeOrPatchCode), debugstr_a(szUserSid), dwContext, 1289 dwOptions, debugstr_a(szSource) ); 1290 return ERROR_SUCCESS; 1291 } 1292 1293 /****************************************************************** 1294 * MsiSourceListClearSourceW (MSI.@) 1295 */ 1296 UINT WINAPI MsiSourceListClearSourceW( const WCHAR *szProductCodeOrPatchCode, const WCHAR *szUserSid, 1297 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource ) 1298 { 1299 FIXME( "%s, %s, %d, %#lx, %s\n", debugstr_w(szProductCodeOrPatchCode), debugstr_w(szUserSid), dwContext, 1300 dwOptions, debugstr_w(szSource) ); 1301 return ERROR_SUCCESS; 1302 } 1303 1304 /****************************************************************** 1305 * MsiSourceListForceResolutionA (MSI.@) 1306 */ 1307 UINT WINAPI MsiSourceListForceResolutionA( const char *product, const char *user, DWORD reserved ) 1308 { 1309 FIXME( "%s, %s, %#lx\n", debugstr_a(product), debugstr_a(user), reserved ); 1310 return ERROR_SUCCESS; 1311 } 1312 1313 /****************************************************************** 1314 * MsiSourceListForceResolutionW (MSI.@) 1315 */ 1316 UINT WINAPI MsiSourceListForceResolutionW( const WCHAR *product, const WCHAR *user, DWORD reserved ) 1317 { 1318 FIXME( "%s, %s, %#lx\n", debugstr_w(product), debugstr_w(user), reserved ); 1319 return ERROR_SUCCESS; 1320 } 1321