1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2005 Mike McCormack for CodeWeavers 5 * Copyright 2005 Aric Stewart for CodeWeavers 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include <stdarg.h> 23 #include <stdio.h> 24 25 #define COBJMACROS 26 27 #include "windef.h" 28 #include "winbase.h" 29 #include "winerror.h" 30 #include "wine/debug.h" 31 #include "msi.h" 32 #include "winnls.h" 33 #include "objbase.h" 34 #include "oleauto.h" 35 36 #include "msipriv.h" 37 #include "msiserver.h" 38 #include "wine/unicode.h" 39 40 WINE_DEFAULT_DEBUG_CHANNEL(msi); 41 42 /* types arranged by precedence */ 43 #define FORMAT_NULL 0x0001 44 #define FORMAT_LITERAL 0x0002 45 #define FORMAT_NUMBER 0x0004 46 #define FORMAT_LBRACK 0x0010 47 #define FORMAT_LBRACE 0x0020 48 #define FORMAT_RBRACK 0x0011 49 #define FORMAT_RBRACE 0x0021 50 #define FORMAT_ESCAPE 0x0040 51 #define FORMAT_PROPNULL 0x0080 52 #define FORMAT_ERROR 0x1000 53 #define FORMAT_FAIL 0x2000 54 55 #define left_type(x) (x & 0xF0) 56 57 typedef struct _tagFORMAT 58 { 59 MSIPACKAGE *package; 60 MSIRECORD *record; 61 LPWSTR deformatted; 62 int len; 63 int n; 64 BOOL propfailed; 65 BOOL groupfailed; 66 int groups; 67 } FORMAT; 68 69 typedef struct _tagFORMSTR 70 { 71 struct list entry; 72 int n; 73 int len; 74 int type; 75 BOOL propfound; 76 BOOL nonprop; 77 } FORMSTR; 78 79 typedef struct _tagSTACK 80 { 81 struct list items; 82 } STACK; 83 84 static STACK *create_stack(void) 85 { 86 STACK *stack = msi_alloc(sizeof(STACK)); 87 list_init(&stack->items); 88 return stack; 89 } 90 91 static void free_stack(STACK *stack) 92 { 93 while (!list_empty(&stack->items)) 94 { 95 FORMSTR *str = LIST_ENTRY(list_head(&stack->items), FORMSTR, entry); 96 list_remove(&str->entry); 97 msi_free(str); 98 } 99 100 msi_free(stack); 101 } 102 103 static void stack_push(STACK *stack, FORMSTR *str) 104 { 105 list_add_head(&stack->items, &str->entry); 106 } 107 108 static FORMSTR *stack_pop(STACK *stack) 109 { 110 FORMSTR *ret; 111 112 if (list_empty(&stack->items)) 113 return NULL; 114 115 ret = LIST_ENTRY(list_head(&stack->items), FORMSTR, entry); 116 list_remove(&ret->entry); 117 return ret; 118 } 119 120 static FORMSTR *stack_find(STACK *stack, int type) 121 { 122 FORMSTR *str; 123 124 LIST_FOR_EACH_ENTRY(str, &stack->items, FORMSTR, entry) 125 { 126 if (str->type == type) 127 return str; 128 } 129 130 return NULL; 131 } 132 133 static FORMSTR *stack_peek(STACK *stack) 134 { 135 return LIST_ENTRY(list_head(&stack->items), FORMSTR, entry); 136 } 137 138 static LPCWSTR get_formstr_data(FORMAT *format, FORMSTR *str) 139 { 140 return &format->deformatted[str->n]; 141 } 142 143 static LPWSTR dup_formstr(FORMAT *format, FORMSTR *str) 144 { 145 LPWSTR val; 146 LPCWSTR data; 147 148 if (str->len == 0) 149 return NULL; 150 151 val = msi_alloc((str->len + 1) * sizeof(WCHAR)); 152 data = get_formstr_data(format, str); 153 lstrcpynW(val, data, str->len + 1); 154 155 return val; 156 } 157 158 static LPWSTR deformat_index(FORMAT *format, FORMSTR *str) 159 { 160 LPWSTR val, ret; 161 162 val = msi_alloc((str->len + 1) * sizeof(WCHAR)); 163 lstrcpynW(val, get_formstr_data(format, str), str->len + 1); 164 165 ret = msi_dup_record_field(format->record, atoiW(val)); 166 167 msi_free(val); 168 return ret; 169 } 170 171 static LPWSTR deformat_property(FORMAT *format, FORMSTR *str) 172 { 173 LPWSTR val, ret; 174 175 val = msi_alloc((str->len + 1) * sizeof(WCHAR)); 176 lstrcpynW(val, get_formstr_data(format, str), str->len + 1); 177 178 ret = msi_dup_property(format->package->db, val); 179 180 msi_free(val); 181 return ret; 182 } 183 184 static LPWSTR deformat_component(FORMAT *format, FORMSTR *str) 185 { 186 LPWSTR key, ret = NULL; 187 MSICOMPONENT *comp; 188 189 key = msi_alloc((str->len + 1) * sizeof(WCHAR)); 190 lstrcpynW(key, get_formstr_data(format, str), str->len + 1); 191 192 comp = msi_get_loaded_component(format->package, key); 193 if (!comp) 194 goto done; 195 196 if (comp->Action == INSTALLSTATE_SOURCE) 197 ret = msi_resolve_source_folder( format->package, comp->Directory, NULL ); 198 else 199 ret = strdupW( msi_get_target_folder( format->package, comp->Directory ) ); 200 201 done: 202 msi_free(key); 203 return ret; 204 } 205 206 static LPWSTR deformat_file(FORMAT *format, FORMSTR *str, BOOL shortname) 207 { 208 LPWSTR key, ret = NULL; 209 MSIFILE *file; 210 DWORD size; 211 212 key = msi_alloc((str->len + 1) * sizeof(WCHAR)); 213 lstrcpynW(key, get_formstr_data(format, str), str->len + 1); 214 215 file = msi_get_loaded_file(format->package, key); 216 if (!file) 217 goto done; 218 219 if (!shortname) 220 { 221 ret = strdupW(file->TargetPath); 222 goto done; 223 } 224 225 size = GetShortPathNameW(file->TargetPath, NULL, 0); 226 if (size <= 0) 227 { 228 ret = strdupW(file->TargetPath); 229 goto done; 230 } 231 232 size++; 233 ret = msi_alloc(size * sizeof(WCHAR)); 234 GetShortPathNameW(file->TargetPath, ret, size); 235 236 done: 237 msi_free(key); 238 return ret; 239 } 240 241 static LPWSTR deformat_environment(FORMAT *format, FORMSTR *str) 242 { 243 LPWSTR key, ret = NULL; 244 DWORD sz; 245 246 key = msi_alloc((str->len + 1) * sizeof(WCHAR)); 247 lstrcpynW(key, get_formstr_data(format, str), str->len + 1); 248 249 sz = GetEnvironmentVariableW(key, NULL ,0); 250 if (sz <= 0) 251 goto done; 252 253 sz++; 254 ret = msi_alloc(sz * sizeof(WCHAR)); 255 GetEnvironmentVariableW(key, ret, sz); 256 257 done: 258 msi_free(key); 259 return ret; 260 } 261 262 static LPWSTR deformat_literal(FORMAT *format, FORMSTR *str, BOOL *propfound, 263 BOOL *nonprop, int *type) 264 { 265 LPCWSTR data = get_formstr_data(format, str); 266 LPWSTR replaced = NULL; 267 char ch = data[0]; 268 269 if (ch == '\\') 270 { 271 str->n++; 272 if (str->len == 1) 273 { 274 str->len = 0; 275 replaced = NULL; 276 } 277 else 278 { 279 str->len = 1; 280 replaced = dup_formstr(format, str); 281 } 282 } 283 else if (ch == '~') 284 { 285 if (str->len != 1) 286 replaced = NULL; 287 else 288 { 289 replaced = msi_alloc(sizeof(WCHAR)); 290 *replaced = '\0'; 291 } 292 } 293 else if (ch == '%' || ch == '#' || ch == '!' || ch == '$') 294 { 295 str->n++; 296 str->len--; 297 298 switch (ch) 299 { 300 case '%': 301 replaced = deformat_environment(format, str); break; 302 case '#': 303 replaced = deformat_file(format, str, FALSE); break; 304 case '!': 305 replaced = deformat_file(format, str, TRUE); break; 306 case '$': 307 replaced = deformat_component(format, str); break; 308 } 309 310 *type = FORMAT_LITERAL; 311 } 312 else 313 { 314 replaced = deformat_property(format, str); 315 *type = FORMAT_LITERAL; 316 317 if (replaced) 318 *propfound = TRUE; 319 else 320 format->propfailed = TRUE; 321 } 322 323 return replaced; 324 } 325 326 static LPWSTR build_default_format(const MSIRECORD* record) 327 { 328 int i; 329 int count; 330 LPWSTR rc, buf; 331 static const WCHAR fmt[] = {'%','i',':',' ','%','s',' ',0}; 332 static const WCHAR fmt_null[] = {'%','i',':',' ',' ',0}; 333 static const WCHAR fmt_index[] = {'%','i',0}; 334 LPCWSTR str; 335 WCHAR index[10]; 336 DWORD size, max_len, len; 337 338 count = MSI_RecordGetFieldCount(record); 339 340 max_len = MAX_PATH; 341 buf = msi_alloc((max_len + 1) * sizeof(WCHAR)); 342 343 rc = NULL; 344 size = 1; 345 for (i = 1; i <= count; i++) 346 { 347 sprintfW(index, fmt_index, i); 348 str = MSI_RecordGetString(record, i); 349 len = (str) ? lstrlenW(str) : 0; 350 len += (sizeof(fmt_null)/sizeof(fmt_null[0]) - 3) + lstrlenW(index); 351 size += len; 352 353 if (len > max_len) 354 { 355 max_len = len; 356 buf = msi_realloc(buf, (max_len + 1) * sizeof(WCHAR)); 357 if (!buf) return NULL; 358 } 359 360 if (str) 361 sprintfW(buf, fmt, i, str); 362 else 363 sprintfW(buf, fmt_null, i); 364 365 if (!rc) 366 { 367 rc = msi_alloc(size * sizeof(WCHAR)); 368 lstrcpyW(rc, buf); 369 } 370 else 371 { 372 rc = msi_realloc(rc, size * sizeof(WCHAR)); 373 lstrcatW(rc, buf); 374 } 375 } 376 377 msi_free(buf); 378 return rc; 379 } 380 381 static BOOL format_is_number(WCHAR x) 382 { 383 return ((x >= '0') && (x <= '9')); 384 } 385 386 static BOOL format_str_is_number(LPWSTR str) 387 { 388 LPWSTR ptr; 389 390 for (ptr = str; *ptr; ptr++) 391 if (!format_is_number(*ptr)) 392 return FALSE; 393 394 return TRUE; 395 } 396 397 static BOOL format_is_alpha(WCHAR x) 398 { 399 return (!format_is_number(x) && x != '\0' && 400 x != '[' && x != ']' && x != '{' && x != '}'); 401 } 402 403 static BOOL format_is_literal(WCHAR x) 404 { 405 return (format_is_alpha(x) || format_is_number(x)); 406 } 407 408 static int format_lex(FORMAT *format, FORMSTR **out) 409 { 410 int type, len = 1; 411 FORMSTR *str; 412 LPCWSTR data; 413 WCHAR ch; 414 415 *out = NULL; 416 417 if (!format->deformatted) 418 return FORMAT_NULL; 419 420 *out = msi_alloc_zero(sizeof(FORMSTR)); 421 if (!*out) 422 return FORMAT_FAIL; 423 424 str = *out; 425 str->n = format->n; 426 str->len = 1; 427 data = get_formstr_data(format, str); 428 429 ch = data[0]; 430 switch (ch) 431 { 432 case '{': type = FORMAT_LBRACE; break; 433 case '}': type = FORMAT_RBRACE; break; 434 case '[': type = FORMAT_LBRACK; break; 435 case ']': type = FORMAT_RBRACK; break; 436 case '~': type = FORMAT_PROPNULL; break; 437 case '\0': type = FORMAT_NULL; break; 438 439 default: 440 type = 0; 441 } 442 443 if (type) 444 { 445 str->type = type; 446 format->n++; 447 return type; 448 } 449 450 if (ch == '\\') 451 { 452 while (data[len] && data[len] != ']') 453 len++; 454 455 type = FORMAT_ESCAPE; 456 } 457 else if (format_is_alpha(ch)) 458 { 459 while (format_is_literal(data[len])) 460 len++; 461 462 type = FORMAT_LITERAL; 463 } 464 else if (format_is_number(ch)) 465 { 466 while (format_is_number(data[len])) 467 len++; 468 469 type = FORMAT_NUMBER; 470 471 if (data[len] != ']') 472 { 473 while (format_is_literal(data[len])) 474 len++; 475 476 type = FORMAT_LITERAL; 477 } 478 } 479 else 480 { 481 ERR("Got unknown character %c(%x)\n", ch, ch); 482 return FORMAT_ERROR; 483 } 484 485 format->n += len; 486 str->len = len; 487 str->type = type; 488 489 return type; 490 } 491 492 static FORMSTR *format_replace(FORMAT *format, BOOL propfound, BOOL nonprop, 493 int oldsize, int type, LPWSTR replace) 494 { 495 FORMSTR *ret; 496 LPWSTR str, ptr; 497 DWORD size = 0; 498 int n; 499 500 if (replace) 501 { 502 if (!*replace) 503 size = 1; 504 else 505 size = lstrlenW(replace); 506 } 507 508 size -= oldsize; 509 size = format->len + size + 1; 510 511 if (size <= 1) 512 { 513 msi_free(format->deformatted); 514 format->deformatted = NULL; 515 format->len = 0; 516 return NULL; 517 } 518 519 str = msi_alloc(size * sizeof(WCHAR)); 520 if (!str) 521 return NULL; 522 523 str[0] = '\0'; 524 memcpy(str, format->deformatted, format->n * sizeof(WCHAR)); 525 n = format->n; 526 527 if (replace) 528 { 529 if (!*replace) 530 { 531 str[n] = '\0'; 532 n++; 533 } 534 else 535 { 536 lstrcpyW(&str[n], replace); 537 n += lstrlenW(replace); 538 } 539 } 540 541 ptr = &format->deformatted[format->n + oldsize]; 542 memcpy(&str[n], ptr, (lstrlenW(ptr) + 1) * sizeof(WCHAR)); 543 544 msi_free(format->deformatted); 545 format->deformatted = str; 546 format->len = size - 1; 547 548 /* don't reformat the NULL */ 549 if (replace && !*replace) 550 format->n++; 551 552 if (!replace) 553 return NULL; 554 555 ret = msi_alloc_zero(sizeof(FORMSTR)); 556 if (!ret) 557 return NULL; 558 559 ret->len = lstrlenW(replace); 560 ret->type = type; 561 ret->n = format->n; 562 ret->propfound = propfound; 563 ret->nonprop = nonprop; 564 565 return ret; 566 } 567 568 static LPWSTR replace_stack_group(FORMAT *format, STACK *values, 569 BOOL *propfound, BOOL *nonprop, 570 int *oldsize, int *type) 571 { 572 LPWSTR replaced = NULL; 573 FORMSTR *content; 574 FORMSTR *node; 575 int n; 576 577 *nonprop = FALSE; 578 *propfound = FALSE; 579 580 node = stack_pop(values); 581 n = node->n; 582 *oldsize = node->len; 583 msi_free(node); 584 585 while ((node = stack_pop(values))) 586 { 587 *oldsize += node->len; 588 589 if (node->nonprop) 590 *nonprop = TRUE; 591 592 if (node->propfound) 593 *propfound = TRUE; 594 595 msi_free(node); 596 } 597 598 content = msi_alloc_zero(sizeof(FORMSTR)); 599 content->n = n; 600 content->len = *oldsize; 601 content->type = FORMAT_LITERAL; 602 603 if (!format->groupfailed && (*oldsize == 2 || 604 (format->propfailed && !*nonprop))) 605 { 606 msi_free(content); 607 return NULL; 608 } 609 else if (format->deformatted[content->n + 1] == '{' && 610 format->deformatted[content->n + content->len - 2] == '}') 611 { 612 format->groupfailed = FALSE; 613 content->len = 0; 614 } 615 else if (*propfound && !*nonprop && 616 !format->groupfailed && format->groups == 0) 617 { 618 content->n++; 619 content->len -= 2; 620 } 621 else 622 { 623 if (format->groups != 0) 624 format->groupfailed = TRUE; 625 626 *nonprop = TRUE; 627 } 628 629 replaced = dup_formstr(format, content); 630 *type = content->type; 631 msi_free(content); 632 633 if (format->groups == 0) 634 format->propfailed = FALSE; 635 636 return replaced; 637 } 638 639 static LPWSTR replace_stack_prop(FORMAT *format, STACK *values, 640 BOOL *propfound, BOOL *nonprop, 641 int *oldsize, int *type) 642 { 643 LPWSTR replaced = NULL; 644 FORMSTR *content; 645 FORMSTR *node; 646 int n; 647 648 *propfound = FALSE; 649 *nonprop = FALSE; 650 651 node = stack_pop(values); 652 n = node->n; 653 *oldsize = node->len; 654 *type = stack_peek(values)->type; 655 msi_free(node); 656 657 while ((node = stack_pop(values))) 658 { 659 *oldsize += node->len; 660 661 if (*type != FORMAT_ESCAPE && 662 stack_peek(values) && node->type != *type) 663 *type = FORMAT_LITERAL; 664 665 msi_free(node); 666 } 667 668 content = msi_alloc_zero(sizeof(FORMSTR)); 669 content->n = n + 1; 670 content->len = *oldsize - 2; 671 content->type = *type; 672 673 if (*type == FORMAT_NUMBER) 674 { 675 replaced = deformat_index(format, content); 676 if (replaced) 677 *propfound = TRUE; 678 else 679 format->propfailed = TRUE; 680 681 if (replaced) 682 *type = format_str_is_number(replaced) ? 683 FORMAT_NUMBER : FORMAT_LITERAL; 684 } 685 else if (format->package) 686 { 687 replaced = deformat_literal(format, content, propfound, nonprop, type); 688 } 689 else 690 { 691 *nonprop = TRUE; 692 content->n--; 693 content->len += 2; 694 replaced = dup_formstr(format, content); 695 } 696 697 msi_free(content); 698 return replaced; 699 } 700 701 static UINT replace_stack(FORMAT *format, STACK *stack, STACK *values) 702 { 703 LPWSTR replaced = NULL; 704 FORMSTR *beg; 705 FORMSTR *top; 706 FORMSTR *node; 707 BOOL propfound = FALSE; 708 BOOL nonprop = FALSE; 709 BOOL group = FALSE; 710 int oldsize = 0; 711 int type, n; 712 713 node = stack_peek(values); 714 type = node->type; 715 n = node->n; 716 717 if (type == FORMAT_LBRACK) 718 replaced = replace_stack_prop(format, values, &propfound, 719 &nonprop, &oldsize, &type); 720 else if (type == FORMAT_LBRACE) 721 { 722 replaced = replace_stack_group(format, values, &propfound, 723 &nonprop, &oldsize, &type); 724 group = TRUE; 725 } 726 727 format->n = n; 728 beg = format_replace(format, propfound, nonprop, oldsize, type, replaced); 729 if (!beg) 730 return ERROR_SUCCESS; 731 732 msi_free(replaced); 733 format->n = beg->n + beg->len; 734 735 top = stack_peek(stack); 736 if (top) 737 { 738 type = top->type; 739 740 if ((type == FORMAT_LITERAL || type == FORMAT_NUMBER) && 741 type == beg->type) 742 { 743 top->len += beg->len; 744 745 if (group) 746 top->nonprop = FALSE; 747 748 if (type == FORMAT_LITERAL) 749 top->nonprop = beg->nonprop; 750 751 if (beg->propfound) 752 top->propfound = TRUE; 753 754 msi_free(beg); 755 return ERROR_SUCCESS; 756 } 757 } 758 759 stack_push(stack, beg); 760 return ERROR_SUCCESS; 761 } 762 763 static BOOL verify_format(LPWSTR data) 764 { 765 int count = 0; 766 767 while (*data) 768 { 769 if (*data == '[' && *(data - 1) != '\\') 770 count++; 771 else if (*data == ']') 772 count--; 773 774 data++; 775 } 776 777 if (count > 0) 778 return FALSE; 779 780 return TRUE; 781 } 782 783 static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, 784 WCHAR** data, DWORD *len, 785 MSIRECORD* record, INT* failcount) 786 { 787 FORMAT format; 788 FORMSTR *str = NULL; 789 STACK *stack, *temp; 790 FORMSTR *node; 791 int type; 792 793 if (!ptr) 794 { 795 *data = NULL; 796 *len = 0; 797 return ERROR_SUCCESS; 798 } 799 800 *data = strdupW(ptr); 801 *len = lstrlenW(ptr); 802 803 ZeroMemory(&format, sizeof(FORMAT)); 804 format.package = package; 805 format.record = record; 806 format.deformatted = *data; 807 format.len = *len; 808 809 if (!verify_format(*data)) 810 return ERROR_SUCCESS; 811 812 stack = create_stack(); 813 temp = create_stack(); 814 815 while ((type = format_lex(&format, &str)) != FORMAT_NULL) 816 { 817 if (type == FORMAT_LBRACK || type == FORMAT_LBRACE || 818 type == FORMAT_LITERAL || type == FORMAT_NUMBER || 819 type == FORMAT_ESCAPE || type == FORMAT_PROPNULL) 820 { 821 if (type == FORMAT_LBRACE) 822 { 823 format.propfailed = FALSE; 824 format.groups++; 825 } 826 else if (type == FORMAT_ESCAPE && 827 !stack_find(stack, FORMAT_LBRACK)) 828 { 829 format.n -= str->len - 1; 830 str->len = 1; 831 } 832 833 stack_push(stack, str); 834 } 835 else if (type == FORMAT_RBRACK || type == FORMAT_RBRACE) 836 { 837 if (type == FORMAT_RBRACE) 838 format.groups--; 839 840 stack_push(stack, str); 841 842 if (stack_find(stack, left_type(type))) 843 { 844 do 845 { 846 node = stack_pop(stack); 847 stack_push(temp, node); 848 } while (node->type != left_type(type)); 849 850 replace_stack(&format, stack, temp); 851 } 852 } 853 } 854 855 *data = format.deformatted; 856 *len = format.len; 857 858 msi_free(str); 859 free_stack(stack); 860 free_stack(temp); 861 862 return ERROR_SUCCESS; 863 } 864 865 UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer, 866 LPDWORD size ) 867 { 868 LPWSTR deformated; 869 LPWSTR rec; 870 DWORD len; 871 UINT rc = ERROR_INVALID_PARAMETER; 872 873 TRACE("%p %p %p %p\n", package, record, buffer, size); 874 875 rec = msi_dup_record_field(record,0); 876 if (!rec) 877 rec = build_default_format(record); 878 879 TRACE("(%s)\n",debugstr_w(rec)); 880 881 deformat_string_internal(package, rec, &deformated, &len, record, NULL); 882 if (buffer) 883 { 884 if (*size>len) 885 { 886 memcpy(buffer,deformated,len*sizeof(WCHAR)); 887 rc = ERROR_SUCCESS; 888 buffer[len] = 0; 889 } 890 else 891 { 892 if (*size > 0) 893 { 894 memcpy(buffer,deformated,(*size)*sizeof(WCHAR)); 895 buffer[(*size)-1] = 0; 896 } 897 rc = ERROR_MORE_DATA; 898 } 899 } 900 else 901 rc = ERROR_SUCCESS; 902 903 *size = len; 904 905 msi_free(rec); 906 msi_free(deformated); 907 return rc; 908 } 909 910 UINT WINAPI MsiFormatRecordW( MSIHANDLE hInstall, MSIHANDLE hRecord, 911 LPWSTR szResult, LPDWORD sz ) 912 { 913 UINT r = ERROR_INVALID_HANDLE; 914 MSIPACKAGE *package; 915 MSIRECORD *record; 916 917 TRACE("%d %d %p %p\n", hInstall, hRecord, szResult, sz); 918 919 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); 920 if (!package) 921 { 922 HRESULT hr; 923 IWineMsiRemotePackage *remote_package; 924 BSTR value = NULL; 925 awstring wstr; 926 927 remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall ); 928 if (remote_package) 929 { 930 hr = IWineMsiRemotePackage_FormatRecord( remote_package, hRecord, 931 &value ); 932 if (FAILED(hr)) 933 goto done; 934 935 wstr.unicode = TRUE; 936 wstr.str.w = szResult; 937 r = msi_strcpy_to_awstring( value, &wstr, sz ); 938 939 done: 940 IWineMsiRemotePackage_Release( remote_package ); 941 SysFreeString( value ); 942 943 if (FAILED(hr)) 944 { 945 if (HRESULT_FACILITY(hr) == FACILITY_WIN32) 946 return HRESULT_CODE(hr); 947 948 return ERROR_FUNCTION_FAILED; 949 } 950 951 return r; 952 } 953 } 954 955 record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); 956 957 if (!record) 958 return ERROR_INVALID_HANDLE; 959 if (!sz) 960 { 961 msiobj_release( &record->hdr ); 962 if (szResult) 963 return ERROR_INVALID_PARAMETER; 964 else 965 return ERROR_SUCCESS; 966 } 967 968 r = MSI_FormatRecordW( package, record, szResult, sz ); 969 msiobj_release( &record->hdr ); 970 if (package) 971 msiobj_release( &package->hdr ); 972 return r; 973 } 974 975 UINT WINAPI MsiFormatRecordA( MSIHANDLE hInstall, MSIHANDLE hRecord, 976 LPSTR szResult, LPDWORD sz ) 977 { 978 UINT r; 979 DWORD len, save; 980 LPWSTR value; 981 982 TRACE("%d %d %p %p\n", hInstall, hRecord, szResult, sz); 983 984 if (!hRecord) 985 return ERROR_INVALID_HANDLE; 986 987 if (!sz) 988 { 989 if (szResult) 990 return ERROR_INVALID_PARAMETER; 991 else 992 return ERROR_SUCCESS; 993 } 994 995 r = MsiFormatRecordW( hInstall, hRecord, NULL, &len ); 996 if (r != ERROR_SUCCESS) 997 return r; 998 999 value = msi_alloc(++len * sizeof(WCHAR)); 1000 if (!value) 1001 return ERROR_OUTOFMEMORY; 1002 1003 r = MsiFormatRecordW( hInstall, hRecord, value, &len ); 1004 if (r != ERROR_SUCCESS) 1005 goto done; 1006 1007 save = len + 1; 1008 len = WideCharToMultiByte(CP_ACP, 0, value, len + 1, NULL, 0, NULL, NULL); 1009 WideCharToMultiByte(CP_ACP, 0, value, len, szResult, *sz, NULL, NULL); 1010 1011 if (szResult && len > *sz) 1012 { 1013 if (*sz) szResult[*sz - 1] = '\0'; 1014 r = ERROR_MORE_DATA; 1015 } 1016 1017 *sz = save - 1; 1018 1019 done: 1020 msi_free(value); 1021 return r; 1022 } 1023 1024 /* wrapper to resist a need for a full rewrite right now */ 1025 DWORD deformat_string( MSIPACKAGE *package, const WCHAR *ptr, WCHAR **data ) 1026 { 1027 if (ptr) 1028 { 1029 DWORD size = 0; 1030 MSIRECORD *rec = MSI_CreateRecord( 1 ); 1031 1032 MSI_RecordSetStringW( rec, 0, ptr ); 1033 MSI_FormatRecordW( package, rec, NULL, &size ); 1034 1035 size++; 1036 *data = msi_alloc( size * sizeof(WCHAR) ); 1037 if (size > 1) MSI_FormatRecordW( package, rec, *data, &size ); 1038 else *data[0] = 0; 1039 1040 msiobj_release( &rec->hdr ); 1041 return size * sizeof(WCHAR); 1042 } 1043 *data = NULL; 1044 return 0; 1045 } 1046