1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2002-2004 Mike McCormack 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 "winuser.h" 28 #include "winerror.h" 29 #include "wine/debug.h" 30 #include "msi.h" 31 #include "msiquery.h" 32 #include "msipriv.h" 33 #include "objidl.h" 34 #include "winnls.h" 35 #include "ole2.h" 36 37 #include "winreg.h" 38 #include "shlwapi.h" 39 40 #include "query.h" 41 42 WINE_DEFAULT_DEBUG_CHANNEL(msidb); 43 44 #define MSIFIELD_NULL 0 45 #define MSIFIELD_INT 1 46 #define MSIFIELD_WSTR 3 47 #define MSIFIELD_STREAM 4 48 49 static void MSI_FreeField( MSIFIELD *field ) 50 { 51 switch( field->type ) 52 { 53 case MSIFIELD_NULL: 54 case MSIFIELD_INT: 55 break; 56 case MSIFIELD_WSTR: 57 msi_free( field->u.szwVal); 58 break; 59 case MSIFIELD_STREAM: 60 IStream_Release( field->u.stream ); 61 break; 62 default: 63 ERR("Invalid field type %d\n", field->type); 64 } 65 } 66 67 void MSI_CloseRecord( MSIOBJECTHDR *arg ) 68 { 69 MSIRECORD *rec = (MSIRECORD *) arg; 70 UINT i; 71 72 for( i=0; i<=rec->count; i++ ) 73 MSI_FreeField( &rec->fields[i] ); 74 } 75 76 MSIRECORD *MSI_CreateRecord( UINT cParams ) 77 { 78 MSIRECORD *rec; 79 80 TRACE("%d\n", cParams); 81 82 if( cParams>65535 ) 83 return NULL; 84 85 rec = alloc_msiobject( MSIHANDLETYPE_RECORD, FIELD_OFFSET(MSIRECORD, fields[cParams + 1]), 86 MSI_CloseRecord ); 87 if( rec ) 88 rec->count = cParams; 89 return rec; 90 } 91 92 MSIHANDLE WINAPI MsiCreateRecord( UINT cParams ) 93 { 94 MSIRECORD *rec; 95 MSIHANDLE ret = 0; 96 97 TRACE("%d\n", cParams); 98 99 rec = MSI_CreateRecord( cParams ); 100 if( rec ) 101 { 102 ret = alloc_msihandle( &rec->hdr ); 103 msiobj_release( &rec->hdr ); 104 } 105 return ret; 106 } 107 108 UINT MSI_RecordGetFieldCount( const MSIRECORD *rec ) 109 { 110 return rec->count; 111 } 112 113 UINT WINAPI MsiRecordGetFieldCount( MSIHANDLE handle ) 114 { 115 MSIRECORD *rec; 116 UINT ret; 117 118 TRACE( "%lu\n", handle ); 119 120 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 121 if( !rec ) 122 return -1; 123 124 msiobj_lock( &rec->hdr ); 125 ret = MSI_RecordGetFieldCount( rec ); 126 msiobj_unlock( &rec->hdr ); 127 msiobj_release( &rec->hdr ); 128 129 return ret; 130 } 131 132 static BOOL string2intW( LPCWSTR str, int *out ) 133 { 134 int x = 0; 135 LPCWSTR p = str; 136 137 if( *p == '-' ) /* skip the minus sign */ 138 p++; 139 while ( *p ) 140 { 141 if( (*p < '0') || (*p > '9') ) 142 return FALSE; 143 x *= 10; 144 x += (*p - '0'); 145 p++; 146 } 147 148 if( str[0] == '-' ) /* check if it's negative */ 149 x = -x; 150 *out = x; 151 152 return TRUE; 153 } 154 155 WCHAR *msi_strdupW( const WCHAR *value, int len ) 156 { 157 WCHAR *ret; 158 159 if (!value) return NULL; 160 if (!(ret = msi_alloc( (len + 1) * sizeof(WCHAR) ))) return NULL; 161 memcpy( ret, value, len * sizeof(WCHAR) ); 162 ret[len] = 0; 163 return ret; 164 } 165 166 UINT MSI_RecordCopyField( MSIRECORD *in_rec, UINT in_n, 167 MSIRECORD *out_rec, UINT out_n ) 168 { 169 UINT r = ERROR_SUCCESS; 170 171 msiobj_lock( &in_rec->hdr ); 172 173 if ( in_n > in_rec->count || out_n > out_rec->count ) 174 r = ERROR_FUNCTION_FAILED; 175 else if ( in_rec != out_rec || in_n != out_n ) 176 { 177 LPWSTR str; 178 MSIFIELD *in, *out; 179 180 in = &in_rec->fields[in_n]; 181 out = &out_rec->fields[out_n]; 182 183 switch ( in->type ) 184 { 185 case MSIFIELD_NULL: 186 break; 187 case MSIFIELD_INT: 188 out->u.iVal = in->u.iVal; 189 break; 190 case MSIFIELD_WSTR: 191 if ((str = msi_strdupW( in->u.szwVal, in->len ))) 192 { 193 out->u.szwVal = str; 194 out->len = in->len; 195 } 196 else r = ERROR_OUTOFMEMORY; 197 break; 198 case MSIFIELD_STREAM: 199 IStream_AddRef( in->u.stream ); 200 out->u.stream = in->u.stream; 201 break; 202 default: 203 ERR("invalid field type %d\n", in->type); 204 } 205 if (r == ERROR_SUCCESS) 206 out->type = in->type; 207 } 208 209 msiobj_unlock( &in_rec->hdr ); 210 return r; 211 } 212 213 int MSI_RecordGetInteger( MSIRECORD *rec, UINT iField) 214 { 215 int ret = 0; 216 217 TRACE("%p %d\n", rec, iField ); 218 219 if( iField > rec->count ) 220 return MSI_NULL_INTEGER; 221 222 switch( rec->fields[iField].type ) 223 { 224 case MSIFIELD_INT: 225 return rec->fields[iField].u.iVal; 226 case MSIFIELD_WSTR: 227 if( string2intW( rec->fields[iField].u.szwVal, &ret ) ) 228 return ret; 229 return MSI_NULL_INTEGER; 230 default: 231 break; 232 } 233 234 return MSI_NULL_INTEGER; 235 } 236 237 int WINAPI MsiRecordGetInteger( MSIHANDLE handle, UINT iField) 238 { 239 MSIRECORD *rec; 240 UINT ret; 241 242 TRACE( "%lu, %u\n", handle, iField ); 243 244 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 245 if( !rec ) 246 return MSI_NULL_INTEGER; 247 248 msiobj_lock( &rec->hdr ); 249 ret = MSI_RecordGetInteger( rec, iField ); 250 msiobj_unlock( &rec->hdr ); 251 msiobj_release( &rec->hdr ); 252 253 return ret; 254 } 255 256 UINT WINAPI MsiRecordClearData( MSIHANDLE handle ) 257 { 258 MSIRECORD *rec; 259 UINT i; 260 261 TRACE( "%lu\n", handle ); 262 263 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 264 if( !rec ) 265 return ERROR_INVALID_HANDLE; 266 267 msiobj_lock( &rec->hdr ); 268 for( i=0; i<=rec->count; i++) 269 { 270 MSI_FreeField( &rec->fields[i] ); 271 rec->fields[i].type = MSIFIELD_NULL; 272 rec->fields[i].u.iVal = 0; 273 } 274 msiobj_unlock( &rec->hdr ); 275 msiobj_release( &rec->hdr ); 276 277 return ERROR_SUCCESS; 278 } 279 280 UINT MSI_RecordSetInteger( MSIRECORD *rec, UINT iField, int iVal ) 281 { 282 TRACE("%p %u %d\n", rec, iField, iVal); 283 284 if( iField > rec->count ) 285 return ERROR_INVALID_PARAMETER; 286 287 MSI_FreeField( &rec->fields[iField] ); 288 289 if (iVal == MSI_NULL_INTEGER) 290 { 291 rec->fields[iField].type = MSIFIELD_NULL; 292 rec->fields[iField].u.szwVal = NULL; 293 } 294 else 295 { 296 rec->fields[iField].type = MSIFIELD_INT; 297 rec->fields[iField].u.iVal = iVal; 298 } 299 300 return ERROR_SUCCESS; 301 } 302 303 UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, UINT iField, int iVal ) 304 { 305 MSIRECORD *rec; 306 UINT ret; 307 308 TRACE( "%lu, %u, %d\n", handle, iField, iVal ); 309 310 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 311 if( !rec ) 312 return ERROR_INVALID_HANDLE; 313 314 msiobj_lock( &rec->hdr ); 315 ret = MSI_RecordSetInteger( rec, iField, iVal ); 316 msiobj_unlock( &rec->hdr ); 317 msiobj_release( &rec->hdr ); 318 return ret; 319 } 320 321 BOOL MSI_RecordIsNull( MSIRECORD *rec, UINT iField ) 322 { 323 BOOL r = TRUE; 324 325 TRACE("%p %d\n", rec, iField ); 326 327 r = ( iField > rec->count ) || 328 ( rec->fields[iField].type == MSIFIELD_NULL ); 329 330 return r; 331 } 332 333 BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, UINT iField ) 334 { 335 MSIRECORD *rec; 336 UINT ret; 337 338 TRACE( "%lu, %u\n", handle, iField ); 339 340 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 341 if( !rec ) 342 return FALSE; 343 msiobj_lock( &rec->hdr ); 344 ret = MSI_RecordIsNull( rec, iField ); 345 msiobj_unlock( &rec->hdr ); 346 msiobj_release( &rec->hdr ); 347 return ret; 348 349 } 350 351 UINT MSI_RecordGetStringA(MSIRECORD *rec, UINT iField, 352 LPSTR szValue, LPDWORD pcchValue) 353 { 354 UINT len = 0, ret = ERROR_SUCCESS; 355 CHAR buffer[16]; 356 357 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue); 358 359 if( iField > rec->count ) 360 { 361 if ( szValue && *pcchValue > 0 ) 362 szValue[0] = 0; 363 364 *pcchValue = 0; 365 return ERROR_SUCCESS; 366 } 367 368 switch( rec->fields[iField].type ) 369 { 370 case MSIFIELD_INT: 371 wsprintfA(buffer, "%d", rec->fields[iField].u.iVal); 372 len = lstrlenA( buffer ); 373 if (szValue) 374 lstrcpynA(szValue, buffer, *pcchValue); 375 break; 376 case MSIFIELD_WSTR: 377 len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, 378 rec->fields[iField].len + 1, NULL, 0 , NULL, NULL ); 379 if (szValue) 380 WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, 381 rec->fields[iField].len + 1, szValue, *pcchValue, NULL, NULL ); 382 if( szValue && *pcchValue && len>*pcchValue ) 383 szValue[*pcchValue-1] = 0; 384 if( len ) 385 len--; 386 break; 387 case MSIFIELD_NULL: 388 if( szValue && *pcchValue > 0 ) 389 szValue[0] = 0; 390 break; 391 default: 392 ret = ERROR_INVALID_PARAMETER; 393 break; 394 } 395 396 if( szValue && *pcchValue <= len ) 397 ret = ERROR_MORE_DATA; 398 *pcchValue = len; 399 400 return ret; 401 } 402 403 UINT WINAPI MsiRecordGetStringA( MSIHANDLE handle, UINT iField, char *szValue, DWORD *pcchValue ) 404 { 405 MSIRECORD *rec; 406 UINT ret; 407 408 TRACE( "%lu, %d, %p, %p\n", handle, iField, szValue, pcchValue ); 409 410 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 411 if( !rec ) 412 return ERROR_INVALID_HANDLE; 413 msiobj_lock( &rec->hdr ); 414 ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue); 415 msiobj_unlock( &rec->hdr ); 416 msiobj_release( &rec->hdr ); 417 return ret; 418 } 419 420 const WCHAR *msi_record_get_string( const MSIRECORD *rec, UINT field, int *len ) 421 { 422 if (field > rec->count) 423 return NULL; 424 425 if (rec->fields[field].type != MSIFIELD_WSTR) 426 return NULL; 427 428 if (len) *len = rec->fields[field].len; 429 430 return rec->fields[field].u.szwVal; 431 } 432 433 const WCHAR *MSI_RecordGetString( const MSIRECORD *rec, UINT iField ) 434 { 435 return msi_record_get_string( rec, iField, NULL ); 436 } 437 438 UINT MSI_RecordGetStringW( MSIRECORD *rec, UINT iField, WCHAR *szValue, DWORD *pcchValue ) 439 { 440 UINT len = 0, ret = ERROR_SUCCESS; 441 WCHAR buffer[16]; 442 443 TRACE( "%p, %u, %p, %p\n", rec, iField, szValue, pcchValue ); 444 445 if( iField > rec->count ) 446 { 447 if ( szValue && *pcchValue > 0 ) 448 szValue[0] = 0; 449 450 *pcchValue = 0; 451 return ERROR_SUCCESS; 452 } 453 454 switch( rec->fields[iField].type ) 455 { 456 case MSIFIELD_INT: 457 wsprintfW(buffer, L"%d", rec->fields[iField].u.iVal); 458 len = lstrlenW( buffer ); 459 if (szValue) 460 lstrcpynW(szValue, buffer, *pcchValue); 461 break; 462 case MSIFIELD_WSTR: 463 len = rec->fields[iField].len; 464 if (szValue) 465 memcpy( szValue, rec->fields[iField].u.szwVal, min(len + 1, *pcchValue) * sizeof(WCHAR) ); 466 break; 467 case MSIFIELD_NULL: 468 if( szValue && *pcchValue > 0 ) 469 szValue[0] = 0; 470 break; 471 default: 472 break; 473 } 474 475 if( szValue && *pcchValue <= len ) 476 ret = ERROR_MORE_DATA; 477 *pcchValue = len; 478 479 return ret; 480 } 481 482 UINT WINAPI MsiRecordGetStringW( MSIHANDLE handle, UINT iField, WCHAR *szValue, DWORD *pcchValue ) 483 { 484 MSIRECORD *rec; 485 UINT ret; 486 487 TRACE( "%lu, %u, %p, %p\n", handle, iField, szValue, pcchValue ); 488 489 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 490 if( !rec ) 491 return ERROR_INVALID_HANDLE; 492 493 msiobj_lock( &rec->hdr ); 494 ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue ); 495 msiobj_unlock( &rec->hdr ); 496 msiobj_release( &rec->hdr ); 497 return ret; 498 } 499 500 static UINT msi_get_stream_size( IStream *stm ) 501 { 502 STATSTG stat; 503 HRESULT r; 504 505 r = IStream_Stat( stm, &stat, STATFLAG_NONAME ); 506 if( FAILED(r) ) 507 return 0; 508 return stat.cbSize.QuadPart; 509 } 510 511 static UINT MSI_RecordDataSize(MSIRECORD *rec, UINT iField) 512 { 513 TRACE("%p %d\n", rec, iField); 514 515 if( iField > rec->count ) 516 return 0; 517 518 switch( rec->fields[iField].type ) 519 { 520 case MSIFIELD_INT: 521 return sizeof (INT); 522 case MSIFIELD_WSTR: 523 return rec->fields[iField].len; 524 case MSIFIELD_NULL: 525 break; 526 case MSIFIELD_STREAM: 527 return msi_get_stream_size( rec->fields[iField].u.stream ); 528 } 529 return 0; 530 } 531 532 UINT WINAPI MsiRecordDataSize( MSIHANDLE handle, UINT iField ) 533 { 534 MSIRECORD *rec; 535 UINT ret; 536 537 TRACE( "%lu, %u\n", handle, iField ); 538 539 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 540 if( !rec ) 541 return 0; 542 msiobj_lock( &rec->hdr ); 543 ret = MSI_RecordDataSize( rec, iField); 544 msiobj_unlock( &rec->hdr ); 545 msiobj_release( &rec->hdr ); 546 return ret; 547 } 548 549 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, const char *szValue ) 550 { 551 WCHAR *valueW = NULL; 552 MSIRECORD *rec; 553 UINT ret; 554 555 TRACE( "%lu, %u %s\n", handle, iField, debugstr_a(szValue) ); 556 557 if (szValue && !(valueW = strdupAtoW( szValue ))) return ERROR_OUTOFMEMORY; 558 559 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 560 if( !rec ) 561 { 562 msi_free( valueW ); 563 return ERROR_INVALID_HANDLE; 564 } 565 msiobj_lock( &rec->hdr ); 566 ret = MSI_RecordSetStringW( rec, iField, valueW ); 567 msiobj_unlock( &rec->hdr ); 568 msiobj_release( &rec->hdr ); 569 msi_free( valueW ); 570 return ret; 571 } 572 573 UINT msi_record_set_string( MSIRECORD *rec, UINT field, const WCHAR *value, int len ) 574 { 575 if (field > rec->count) 576 return ERROR_INVALID_FIELD; 577 578 MSI_FreeField( &rec->fields[field] ); 579 580 if (value && len < 0) len = lstrlenW( value ); 581 582 if (value && len) 583 { 584 rec->fields[field].type = MSIFIELD_WSTR; 585 rec->fields[field].u.szwVal = msi_strdupW( value, len ); 586 rec->fields[field].len = len; 587 } 588 else 589 { 590 rec->fields[field].type = MSIFIELD_NULL; 591 rec->fields[field].u.szwVal = NULL; 592 rec->fields[field].len = 0; 593 } 594 return 0; 595 } 596 597 UINT MSI_RecordSetStringW( MSIRECORD *rec, UINT iField, LPCWSTR szValue ) 598 { 599 TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue)); 600 601 return msi_record_set_string( rec, iField, szValue, -1 ); 602 } 603 604 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, UINT iField, const WCHAR *szValue ) 605 { 606 MSIRECORD *rec; 607 UINT ret; 608 609 TRACE( "%lu, %u, %s\n", handle, iField, debugstr_w(szValue) ); 610 611 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 612 if( !rec ) 613 return ERROR_INVALID_HANDLE; 614 615 msiobj_lock( &rec->hdr ); 616 ret = MSI_RecordSetStringW( rec, iField, szValue ); 617 msiobj_unlock( &rec->hdr ); 618 msiobj_release( &rec->hdr ); 619 return ret; 620 } 621 622 /* read the data in a file into an IStream */ 623 static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm) 624 { 625 DWORD sz, szHighWord = 0, read; 626 HANDLE handle; 627 HGLOBAL hGlob = 0; 628 HRESULT hr; 629 ULARGE_INTEGER ulSize; 630 631 TRACE("reading %s\n", debugstr_w(szFile)); 632 633 /* read the file into memory */ 634 handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 635 if( handle == INVALID_HANDLE_VALUE ) 636 return GetLastError(); 637 sz = GetFileSize(handle, &szHighWord); 638 if( sz != INVALID_FILE_SIZE && szHighWord == 0 ) 639 { 640 hGlob = GlobalAlloc(GMEM_FIXED, sz); 641 if( hGlob ) 642 { 643 BOOL r = ReadFile(handle, hGlob, sz, &read, NULL) && read == sz; 644 if( !r ) 645 { 646 GlobalFree(hGlob); 647 hGlob = 0; 648 } 649 } 650 } 651 CloseHandle(handle); 652 if( !hGlob ) 653 return ERROR_FUNCTION_FAILED; 654 655 /* make a stream out of it, and set the correct file size */ 656 hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm); 657 if( FAILED( hr ) ) 658 { 659 GlobalFree(hGlob); 660 return ERROR_FUNCTION_FAILED; 661 } 662 663 /* set the correct size - CreateStreamOnHGlobal screws it up */ 664 ulSize.QuadPart = sz; 665 IStream_SetSize(*pstm, ulSize); 666 667 TRACE( "read %s, %lu bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm ); 668 return ERROR_SUCCESS; 669 } 670 671 UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream) 672 { 673 if ( (iField == 0) || (iField > rec->count) ) 674 return ERROR_INVALID_PARAMETER; 675 676 MSI_FreeField( &rec->fields[iField] ); 677 rec->fields[iField].type = MSIFIELD_STREAM; 678 rec->fields[iField].u.stream = stream; 679 680 return ERROR_SUCCESS; 681 } 682 683 UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename) 684 { 685 IStream *stm = NULL; 686 HRESULT hr; 687 UINT ret; 688 689 if( (iField == 0) || (iField > rec->count) ) 690 return ERROR_INVALID_PARAMETER; 691 692 /* no filename means we should seek back to the start of the stream */ 693 if( !szFilename ) 694 { 695 LARGE_INTEGER ofs; 696 ULARGE_INTEGER cur; 697 698 if( rec->fields[iField].type != MSIFIELD_STREAM ) 699 return ERROR_INVALID_FIELD; 700 701 stm = rec->fields[iField].u.stream; 702 if( !stm ) 703 return ERROR_INVALID_FIELD; 704 705 ofs.QuadPart = 0; 706 hr = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur ); 707 if (FAILED( hr )) 708 return ERROR_FUNCTION_FAILED; 709 } 710 else 711 { 712 /* read the file into a stream and save the stream in the record */ 713 ret = RECORD_StreamFromFile(szFilename, &stm); 714 if (ret != ERROR_SUCCESS) 715 return ret; 716 717 /* if all's good, store it in the record */ 718 MSI_RecordSetStream(rec, iField, stm); 719 } 720 721 return ERROR_SUCCESS; 722 } 723 724 UINT WINAPI MsiRecordSetStreamA( MSIHANDLE hRecord, UINT iField, const char *szFilename ) 725 { 726 WCHAR *wstr = NULL; 727 UINT ret; 728 729 TRACE( "%lu, %u, %s\n", hRecord, iField, debugstr_a(szFilename) ); 730 731 if( szFilename ) 732 { 733 wstr = strdupAtoW( szFilename ); 734 if( !wstr ) 735 return ERROR_OUTOFMEMORY; 736 } 737 ret = MsiRecordSetStreamW(hRecord, iField, wstr); 738 msi_free(wstr); 739 740 return ret; 741 } 742 743 UINT WINAPI MsiRecordSetStreamW( MSIHANDLE handle, UINT iField, const WCHAR *szFilename ) 744 { 745 MSIRECORD *rec; 746 UINT ret; 747 748 TRACE( "%lu, %u, %s\n", handle, iField, debugstr_w(szFilename) ); 749 750 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 751 if( !rec ) 752 return ERROR_INVALID_HANDLE; 753 754 msiobj_lock( &rec->hdr ); 755 ret = MSI_RecordSetStreamFromFileW( rec, iField, szFilename ); 756 msiobj_unlock( &rec->hdr ); 757 msiobj_release( &rec->hdr ); 758 return ret; 759 } 760 761 UINT MSI_RecordReadStream(MSIRECORD *rec, UINT iField, char *buf, LPDWORD sz) 762 { 763 ULONG count; 764 HRESULT r; 765 IStream *stm; 766 767 TRACE("%p %d %p %p\n", rec, iField, buf, sz); 768 769 if( !sz ) 770 return ERROR_INVALID_PARAMETER; 771 772 if( iField > rec->count) 773 return ERROR_INVALID_PARAMETER; 774 775 if ( rec->fields[iField].type == MSIFIELD_NULL ) 776 { 777 *sz = 0; 778 return ERROR_INVALID_DATA; 779 } 780 781 if( rec->fields[iField].type != MSIFIELD_STREAM ) 782 return ERROR_INVALID_DATATYPE; 783 784 stm = rec->fields[iField].u.stream; 785 if( !stm ) 786 return ERROR_INVALID_PARAMETER; 787 788 /* if there's no buffer pointer, calculate the length to the end */ 789 if( !buf ) 790 { 791 LARGE_INTEGER ofs; 792 ULARGE_INTEGER end, cur; 793 794 ofs.QuadPart = cur.QuadPart = 0; 795 end.QuadPart = 0; 796 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur ); 797 IStream_Seek( stm, ofs, STREAM_SEEK_END, &end ); 798 ofs.QuadPart = cur.QuadPart; 799 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur ); 800 *sz = end.QuadPart - cur.QuadPart; 801 802 return ERROR_SUCCESS; 803 } 804 805 /* read the data */ 806 count = 0; 807 r = IStream_Read( stm, buf, *sz, &count ); 808 if( FAILED( r ) ) 809 { 810 *sz = 0; 811 return ERROR_FUNCTION_FAILED; 812 } 813 814 *sz = count; 815 816 return ERROR_SUCCESS; 817 } 818 819 UINT WINAPI MsiRecordReadStream( MSIHANDLE handle, UINT iField, char *buf, DWORD *sz ) 820 { 821 MSIRECORD *rec; 822 UINT ret; 823 824 TRACE( "%lu, %u, %p, %p\n", handle, iField, buf, sz ); 825 826 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 827 if( !rec ) 828 return ERROR_INVALID_HANDLE; 829 msiobj_lock( &rec->hdr ); 830 ret = MSI_RecordReadStream( rec, iField, buf, sz ); 831 msiobj_unlock( &rec->hdr ); 832 msiobj_release( &rec->hdr ); 833 return ret; 834 } 835 836 UINT MSI_RecordSetIStream( MSIRECORD *rec, UINT iField, IStream *stm ) 837 { 838 TRACE("%p %d %p\n", rec, iField, stm); 839 840 if( iField > rec->count ) 841 return ERROR_INVALID_FIELD; 842 843 MSI_FreeField( &rec->fields[iField] ); 844 845 rec->fields[iField].type = MSIFIELD_STREAM; 846 rec->fields[iField].u.stream = stm; 847 IStream_AddRef( stm ); 848 849 return ERROR_SUCCESS; 850 } 851 852 UINT MSI_RecordGetIStream( MSIRECORD *rec, UINT iField, IStream **pstm) 853 { 854 TRACE("%p %d %p\n", rec, iField, pstm); 855 856 if( iField > rec->count ) 857 return ERROR_INVALID_FIELD; 858 859 if( rec->fields[iField].type != MSIFIELD_STREAM ) 860 return ERROR_INVALID_FIELD; 861 862 *pstm = rec->fields[iField].u.stream; 863 IStream_AddRef( *pstm ); 864 865 return ERROR_SUCCESS; 866 } 867 868 static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name ) 869 { 870 ULARGE_INTEGER size; 871 LARGE_INTEGER pos; 872 IStream *out; 873 DWORD stgm; 874 HRESULT r; 875 876 stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE; 877 r = SHCreateStreamOnFileW( name, stgm, &out ); 878 if( FAILED( r ) ) 879 return ERROR_FUNCTION_FAILED; 880 881 pos.QuadPart = 0; 882 r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size ); 883 if( FAILED( r ) ) 884 goto end; 885 886 pos.QuadPart = 0; 887 r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL ); 888 if( FAILED( r ) ) 889 goto end; 890 891 r = IStream_CopyTo( stm, out, size, NULL, NULL ); 892 893 end: 894 IStream_Release( out ); 895 if( FAILED( r ) ) 896 return ERROR_FUNCTION_FAILED; 897 return ERROR_SUCCESS; 898 } 899 900 UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name ) 901 { 902 IStream *stm = NULL; 903 UINT r; 904 905 TRACE("%p %u %s\n", rec, iField, debugstr_w(name)); 906 907 msiobj_lock( &rec->hdr ); 908 909 r = MSI_RecordGetIStream( rec, iField, &stm ); 910 if( r == ERROR_SUCCESS ) 911 { 912 r = msi_dump_stream_to_file( stm, name ); 913 IStream_Release( stm ); 914 } 915 916 msiobj_unlock( &rec->hdr ); 917 918 return r; 919 } 920 921 MSIRECORD *MSI_CloneRecord(MSIRECORD *rec) 922 { 923 MSIRECORD *clone; 924 UINT r, i, count; 925 926 count = MSI_RecordGetFieldCount(rec); 927 clone = MSI_CreateRecord(count); 928 if (!clone) 929 return NULL; 930 931 for (i = 0; i <= count; i++) 932 { 933 if (rec->fields[i].type == MSIFIELD_STREAM) 934 { 935 if (FAILED(IStream_Clone(rec->fields[i].u.stream, 936 &clone->fields[i].u.stream))) 937 { 938 msiobj_release(&clone->hdr); 939 return NULL; 940 } 941 clone->fields[i].type = MSIFIELD_STREAM; 942 } 943 else 944 { 945 r = MSI_RecordCopyField(rec, i, clone, i); 946 if (r != ERROR_SUCCESS) 947 { 948 msiobj_release(&clone->hdr); 949 return NULL; 950 } 951 } 952 } 953 954 return clone; 955 } 956 957 BOOL MSI_RecordsAreFieldsEqual(MSIRECORD *a, MSIRECORD *b, UINT field) 958 { 959 if (a->fields[field].type != b->fields[field].type) 960 return FALSE; 961 962 switch (a->fields[field].type) 963 { 964 case MSIFIELD_NULL: 965 break; 966 967 case MSIFIELD_INT: 968 if (a->fields[field].u.iVal != b->fields[field].u.iVal) 969 return FALSE; 970 break; 971 972 case MSIFIELD_WSTR: 973 if (a->fields[field].len != b->fields[field].len) return FALSE; 974 if (memcmp( a->fields[field].u.szwVal, b->fields[field].u.szwVal, 975 a->fields[field].len * sizeof(WCHAR) )) return FALSE; 976 break; 977 978 case MSIFIELD_STREAM: 979 default: 980 return FALSE; 981 } 982 return TRUE; 983 } 984 985 986 BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b) 987 { 988 UINT i; 989 990 if (a->count != b->count) 991 return FALSE; 992 993 for (i = 0; i <= a->count; i++) 994 { 995 if (!MSI_RecordsAreFieldsEqual( a, b, i )) 996 return FALSE; 997 } 998 999 return TRUE; 1000 } 1001 1002 WCHAR *msi_dup_record_field( MSIRECORD *rec, INT field ) 1003 { 1004 DWORD sz = 0; 1005 WCHAR *str; 1006 UINT r; 1007 1008 if (MSI_RecordIsNull( rec, field )) return NULL; 1009 1010 r = MSI_RecordGetStringW( rec, field, NULL, &sz ); 1011 if (r != ERROR_SUCCESS) 1012 return NULL; 1013 1014 sz++; 1015 str = msi_alloc( sz * sizeof(WCHAR) ); 1016 if (!str) return NULL; 1017 str[0] = 0; 1018 r = MSI_RecordGetStringW( rec, field, str, &sz ); 1019 if (r != ERROR_SUCCESS) 1020 { 1021 ERR("failed to get string!\n"); 1022 msi_free( str ); 1023 return NULL; 1024 } 1025 return str; 1026 } 1027 1028 void dump_record(MSIRECORD *rec) 1029 { 1030 int i; 1031 if (!rec) 1032 { 1033 TRACE("(null)\n"); 1034 return; 1035 } 1036 1037 TRACE("["); 1038 for (i = 0; i <= rec->count; i++) 1039 { 1040 switch(rec->fields[i].type) 1041 { 1042 case MSIFIELD_NULL: TRACE("(null)"); break; 1043 case MSIFIELD_INT: TRACE("%d", rec->fields[i].u.iVal); break; 1044 case MSIFIELD_WSTR: TRACE("%s", debugstr_w(rec->fields[i].u.szwVal)); break; 1045 case MSIFIELD_STREAM: TRACE("%p", rec->fields[i].u.stream); break; 1046 } 1047 if (i < rec->count) TRACE(", "); 1048 } 1049 TRACE("]\n"); 1050 } 1051 1052 UINT copy_remote_record(const struct wire_record *in, MSIHANDLE out) 1053 { 1054 MSIRECORD *rec; 1055 unsigned int i; 1056 UINT r = ERROR_SUCCESS; 1057 1058 if (!(rec = msihandle2msiinfo(out, MSIHANDLETYPE_RECORD))) 1059 return ERROR_INVALID_HANDLE; 1060 1061 rec->cookie = in->cookie; 1062 for (i = 0; i <= in->count; i++) 1063 { 1064 switch (in->fields[i].type) 1065 { 1066 case MSIFIELD_NULL: 1067 MSI_FreeField(&rec->fields[i]); 1068 rec->fields[i].type = MSIFIELD_NULL; 1069 break; 1070 case MSIFIELD_INT: 1071 r = MSI_RecordSetInteger(rec, i, in->fields[i].u.iVal); 1072 break; 1073 case MSIFIELD_WSTR: 1074 r = MSI_RecordSetStringW(rec, i, in->fields[i].u.szwVal); 1075 break; 1076 case MSIFIELD_STREAM: 1077 r = MSI_RecordSetIStream(rec, i, in->fields[i].u.stream); 1078 break; 1079 default: 1080 ERR("invalid field type %d\n", in->fields[i].type); 1081 break; 1082 } 1083 1084 if (r) 1085 { 1086 msiobj_release(&rec->hdr); 1087 return r; 1088 } 1089 } 1090 1091 msiobj_release(&rec->hdr); 1092 return ERROR_SUCCESS; 1093 } 1094 1095 UINT unmarshal_record(const struct wire_record *in, MSIHANDLE *out) 1096 { 1097 if (!in) 1098 { 1099 *out = 0; 1100 return ERROR_SUCCESS; 1101 } 1102 1103 *out = MsiCreateRecord(in->count); 1104 if (!*out) return ERROR_OUTOFMEMORY; 1105 1106 return copy_remote_record(in, *out); 1107 } 1108 1109 struct wire_record *marshal_record(MSIHANDLE handle) 1110 { 1111 struct wire_record *ret; 1112 unsigned int i; 1113 MSIRECORD *rec; 1114 1115 if (!(rec = msihandle2msiinfo(handle, MSIHANDLETYPE_RECORD))) 1116 return NULL; 1117 1118 ret = midl_user_allocate(sizeof(*ret) + rec->count * sizeof(ret->fields[0])); 1119 ret->count = rec->count; 1120 ret->cookie = rec->cookie; 1121 1122 for (i = 0; i <= rec->count; i++) 1123 { 1124 switch (rec->fields[i].type) 1125 { 1126 case MSIFIELD_NULL: 1127 break; 1128 case MSIFIELD_INT: 1129 ret->fields[i].u.iVal = rec->fields[i].u.iVal; 1130 break; 1131 case MSIFIELD_WSTR: 1132 ret->fields[i].u.szwVal = strdupW(rec->fields[i].u.szwVal); 1133 break; 1134 case MSIFIELD_STREAM: 1135 IStream_AddRef(rec->fields[i].u.stream); 1136 ret->fields[i].u.stream = rec->fields[i].u.stream; 1137 break; 1138 default: 1139 ERR("invalid field type %d\n", rec->fields[i].type); 1140 break; 1141 } 1142 ret->fields[i].type = rec->fields[i].type; 1143 } 1144 1145 msiobj_release(&rec->hdr); 1146 return ret; 1147 } 1148 1149 void free_remote_record(struct wire_record *rec) 1150 { 1151 int i; 1152 1153 for (i = 0; i <= rec->count; i++) 1154 { 1155 if (rec->fields[i].type == MSIFIELD_WSTR) 1156 midl_user_free(rec->fields[i].u.szwVal); 1157 else if (rec->fields[i].type == MSIFIELD_STREAM) 1158 IStream_Release(rec->fields[i].u.stream); 1159 } 1160 1161 midl_user_free(rec); 1162 } 1163