1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2002-2005 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 "winerror.h" 28 #include "wine/debug.h" 29 #include "wine/exception.h" 30 #include "msi.h" 31 #include "msiquery.h" 32 #include "objbase.h" 33 #include "objidl.h" 34 #include "winnls.h" 35 36 #include "msipriv.h" 37 #include "query.h" 38 #include "winemsi_s.h" 39 40 #include "initguid.h" 41 42 WINE_DEFAULT_DEBUG_CHANNEL(msi); 43 44 static void MSI_CloseView( MSIOBJECTHDR *arg ) 45 { 46 MSIQUERY *query = (MSIQUERY*) arg; 47 struct list *ptr, *t; 48 49 if( query->view && query->view->ops->delete ) 50 query->view->ops->delete( query->view ); 51 msiobj_release( &query->db->hdr ); 52 53 LIST_FOR_EACH_SAFE( ptr, t, &query->mem ) 54 { 55 msi_free( ptr ); 56 } 57 } 58 59 UINT VIEW_find_column( MSIVIEW *table, LPCWSTR name, LPCWSTR table_name, UINT *n ) 60 { 61 LPCWSTR col_name, haystack_table_name; 62 UINT i, count, r; 63 64 r = table->ops->get_dimensions( table, NULL, &count ); 65 if( r != ERROR_SUCCESS ) 66 return r; 67 68 for( i=1; i<=count; i++ ) 69 { 70 INT x; 71 72 r = table->ops->get_column_info( table, i, &col_name, NULL, 73 NULL, &haystack_table_name ); 74 if( r != ERROR_SUCCESS ) 75 return r; 76 x = wcscmp( name, col_name ); 77 if( table_name ) 78 x |= wcscmp( table_name, haystack_table_name ); 79 if( !x ) 80 { 81 *n = i; 82 return ERROR_SUCCESS; 83 } 84 } 85 return ERROR_INVALID_PARAMETER; 86 } 87 88 UINT WINAPI MsiDatabaseOpenViewA( MSIHANDLE hdb, const char *szQuery, MSIHANDLE *phView ) 89 { 90 UINT r; 91 WCHAR *szwQuery; 92 93 TRACE( "%lu, %s, %p\n", hdb, debugstr_a(szQuery), phView ); 94 95 if( szQuery ) 96 { 97 szwQuery = strdupAtoW( szQuery ); 98 if( !szwQuery ) 99 return ERROR_FUNCTION_FAILED; 100 } 101 else 102 szwQuery = NULL; 103 104 r = MsiDatabaseOpenViewW( hdb, szwQuery, phView); 105 106 msi_free( szwQuery ); 107 return r; 108 } 109 110 UINT MSI_DatabaseOpenViewW( MSIDATABASE *db, const WCHAR *szQuery, MSIQUERY **pView ) 111 { 112 MSIQUERY *query; 113 UINT r; 114 115 TRACE( "%s, %p\n", debugstr_w(szQuery), pView ); 116 117 /* pre allocate a handle to hold a pointer to the view */ 118 query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY), 119 MSI_CloseView ); 120 if( !query ) 121 return ERROR_FUNCTION_FAILED; 122 123 msiobj_addref( &db->hdr ); 124 query->db = db; 125 list_init( &query->mem ); 126 127 r = MSI_ParseSQL( db, szQuery, &query->view, &query->mem ); 128 if( r == ERROR_SUCCESS ) 129 { 130 msiobj_addref( &query->hdr ); 131 *pView = query; 132 } 133 134 msiobj_release( &query->hdr ); 135 return r; 136 } 137 138 UINT WINAPIV MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) 139 { 140 UINT r; 141 int size = 100, res; 142 LPWSTR query; 143 144 /* construct the string */ 145 for (;;) 146 { 147 va_list va; 148 query = msi_alloc( size*sizeof(WCHAR) ); 149 va_start(va, fmt); 150 res = vswprintf(query, size, fmt, va); 151 va_end(va); 152 if (res == -1) size *= 2; 153 else if (res >= size) size = res + 1; 154 else break; 155 msi_free( query ); 156 } 157 /* perform the query */ 158 r = MSI_DatabaseOpenViewW(db, query, view); 159 msi_free(query); 160 return r; 161 } 162 163 UINT MSI_IterateRecords( MSIQUERY *view, LPDWORD count, 164 record_func func, LPVOID param ) 165 { 166 MSIRECORD *rec = NULL; 167 UINT r, n = 0, max = 0; 168 169 r = MSI_ViewExecute( view, NULL ); 170 if( r != ERROR_SUCCESS ) 171 return r; 172 173 if( count ) 174 max = *count; 175 176 /* iterate a query */ 177 for( n = 0; (max == 0) || (n < max); n++ ) 178 { 179 r = MSI_ViewFetch( view, &rec ); 180 if( r != ERROR_SUCCESS ) 181 break; 182 if (func) 183 r = func( rec, param ); 184 msiobj_release( &rec->hdr ); 185 if( r != ERROR_SUCCESS ) 186 break; 187 } 188 189 MSI_ViewClose( view ); 190 191 if( count ) 192 *count = n; 193 194 if( r == ERROR_NO_MORE_ITEMS ) 195 r = ERROR_SUCCESS; 196 197 return r; 198 } 199 200 /* return a single record from a query */ 201 MSIRECORD * WINAPIV MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... ) 202 { 203 MSIRECORD *rec = NULL; 204 MSIQUERY *view = NULL; 205 UINT r; 206 int size = 100, res; 207 LPWSTR query; 208 209 /* construct the string */ 210 for (;;) 211 { 212 va_list va; 213 query = msi_alloc( size*sizeof(WCHAR) ); 214 va_start(va, fmt); 215 res = vswprintf(query, size, fmt, va); 216 va_end(va); 217 if (res == -1) size *= 2; 218 else if (res >= size) size = res + 1; 219 else break; 220 msi_free( query ); 221 } 222 /* perform the query */ 223 r = MSI_DatabaseOpenViewW(db, query, &view); 224 msi_free(query); 225 226 if( r == ERROR_SUCCESS ) 227 { 228 MSI_ViewExecute( view, NULL ); 229 MSI_ViewFetch( view, &rec ); 230 MSI_ViewClose( view ); 231 msiobj_release( &view->hdr ); 232 } 233 return rec; 234 } 235 236 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb, 237 LPCWSTR szQuery, MSIHANDLE *phView) 238 { 239 MSIDATABASE *db; 240 MSIQUERY *query = NULL; 241 UINT ret; 242 243 TRACE("%s %p\n", debugstr_w(szQuery), phView); 244 245 if (!phView) 246 return ERROR_INVALID_PARAMETER; 247 248 if (!szQuery) 249 return ERROR_BAD_QUERY_SYNTAX; 250 251 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); 252 if( !db ) 253 { 254 MSIHANDLE remote, remote_view; 255 256 if (!(remote = msi_get_remote(hdb))) 257 return ERROR_INVALID_HANDLE; 258 259 __TRY 260 { 261 ret = remote_DatabaseOpenView(remote, szQuery, &remote_view); 262 } 263 __EXCEPT(rpc_filter) 264 { 265 ret = GetExceptionCode(); 266 } 267 __ENDTRY 268 269 if (!ret) 270 *phView = alloc_msi_remote_handle(remote_view); 271 return ret; 272 } 273 274 ret = MSI_DatabaseOpenViewW( db, szQuery, &query ); 275 if( ret == ERROR_SUCCESS ) 276 { 277 *phView = alloc_msihandle( &query->hdr ); 278 if (! *phView) 279 ret = ERROR_NOT_ENOUGH_MEMORY; 280 msiobj_release( &query->hdr ); 281 } 282 msiobj_release( &db->hdr ); 283 284 return ret; 285 } 286 287 UINT msi_view_refresh_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD *rec) 288 { 289 UINT row_count = 0, col_count = 0, i, ival, ret, type; 290 291 TRACE("%p %p %d %p\n", db, view, row, rec); 292 293 ret = view->ops->get_dimensions(view, &row_count, &col_count); 294 if (ret) 295 return ret; 296 297 if (!col_count) 298 return ERROR_INVALID_PARAMETER; 299 300 for (i = 1; i <= col_count; i++) 301 { 302 ret = view->ops->get_column_info(view, i, NULL, &type, NULL, NULL); 303 if (ret) 304 { 305 ERR("Error getting column type for %d\n", i); 306 continue; 307 } 308 309 if (MSITYPE_IS_BINARY(type)) 310 { 311 IStream *stm = NULL; 312 313 ret = view->ops->fetch_stream(view, row, i, &stm); 314 if ((ret == ERROR_SUCCESS) && stm) 315 { 316 MSI_RecordSetIStream(rec, i, stm); 317 IStream_Release(stm); 318 } 319 else 320 WARN("failed to get stream\n"); 321 322 continue; 323 } 324 325 ret = view->ops->fetch_int(view, row, i, &ival); 326 if (ret) 327 { 328 ERR("Error fetching data for %d\n", i); 329 continue; 330 } 331 332 if (! (type & MSITYPE_VALID)) 333 ERR("Invalid type!\n"); 334 335 if (type & MSITYPE_STRING) 336 { 337 int len; 338 const WCHAR *sval = msi_string_lookup(db->strings, ival, &len); 339 msi_record_set_string(rec, i, sval, len); 340 } 341 else 342 { 343 if ((type & MSI_DATASIZEMASK) == 2) 344 MSI_RecordSetInteger(rec, i, ival ? ival - (1<<15) : MSI_NULL_INTEGER); 345 else 346 MSI_RecordSetInteger(rec, i, ival - (1u<<31)); 347 } 348 } 349 350 return ERROR_SUCCESS; 351 } 352 353 UINT msi_view_get_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD **rec) 354 { 355 UINT row_count = 0, col_count = 0, r; 356 MSIRECORD *object; 357 358 TRACE("view %p, row %u, rec %p.\n", view, row, rec); 359 360 if ((r = view->ops->get_dimensions(view, &row_count, &col_count))) 361 return r; 362 363 if (row >= row_count) 364 return ERROR_NO_MORE_ITEMS; 365 366 if (!(object = MSI_CreateRecord( col_count ))) 367 return ERROR_OUTOFMEMORY; 368 369 if ((r = msi_view_refresh_row(db, view, row, object))) 370 msiobj_release( &object->hdr ); 371 else 372 *rec = object; 373 374 return r; 375 } 376 377 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec) 378 { 379 MSIVIEW *view; 380 UINT r; 381 382 TRACE("%p %p\n", query, prec ); 383 384 view = query->view; 385 if( !view ) 386 return ERROR_FUNCTION_FAILED; 387 388 r = msi_view_get_row(query->db, view, query->row, prec); 389 if (r == ERROR_SUCCESS) 390 { 391 query->row ++; 392 (*prec)->cookie = (UINT64)(ULONG_PTR)query; 393 MSI_RecordSetInteger(*prec, 0, 1); 394 } 395 else if (r == ERROR_NO_MORE_ITEMS) 396 { 397 /* end of view; reset cursor to first row */ 398 query->row = 0; 399 } 400 401 return r; 402 } 403 404 UINT WINAPI MsiViewFetch( MSIHANDLE hView, MSIHANDLE *record ) 405 { 406 MSIQUERY *query; 407 MSIRECORD *rec = NULL; 408 UINT ret; 409 410 TRACE( "%lu, %p\n", hView, record ); 411 412 if( !record ) 413 return ERROR_INVALID_PARAMETER; 414 *record = 0; 415 416 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); 417 if (!query) 418 { 419 struct wire_record *wire_rec = NULL; 420 MSIHANDLE remote; 421 422 if (!(remote = msi_get_remote(hView))) 423 return ERROR_INVALID_HANDLE; 424 425 __TRY 426 { 427 ret = remote_ViewFetch(remote, &wire_rec); 428 } 429 __EXCEPT(rpc_filter) 430 { 431 ret = GetExceptionCode(); 432 } 433 __ENDTRY 434 435 if (!ret) 436 { 437 ret = unmarshal_record(wire_rec, record); 438 free_remote_record(wire_rec); 439 } 440 return ret; 441 } 442 ret = MSI_ViewFetch( query, &rec ); 443 if( ret == ERROR_SUCCESS ) 444 { 445 *record = alloc_msihandle( &rec->hdr ); 446 if (! *record) 447 ret = ERROR_NOT_ENOUGH_MEMORY; 448 msiobj_release( &rec->hdr ); 449 } 450 msiobj_release( &query->hdr ); 451 return ret; 452 } 453 454 UINT MSI_ViewClose(MSIQUERY *query) 455 { 456 MSIVIEW *view; 457 458 TRACE("%p\n", query ); 459 460 view = query->view; 461 if( !view ) 462 return ERROR_FUNCTION_FAILED; 463 if( !view->ops->close ) 464 return ERROR_FUNCTION_FAILED; 465 466 return view->ops->close( view ); 467 } 468 469 UINT WINAPI MsiViewClose( MSIHANDLE hView ) 470 { 471 MSIQUERY *query; 472 UINT ret; 473 474 TRACE( "%lu\n", hView ); 475 476 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); 477 if (!query) 478 { 479 MSIHANDLE remote; 480 481 if (!(remote = msi_get_remote(hView))) 482 return ERROR_INVALID_HANDLE; 483 484 __TRY 485 { 486 ret = remote_ViewClose(remote); 487 } 488 __EXCEPT(rpc_filter) 489 { 490 ret = GetExceptionCode(); 491 } 492 __ENDTRY 493 494 return ret; 495 } 496 497 ret = MSI_ViewClose( query ); 498 msiobj_release( &query->hdr ); 499 return ret; 500 } 501 502 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec ) 503 { 504 MSIVIEW *view; 505 506 TRACE("%p %p\n", query, rec); 507 508 view = query->view; 509 if( !view ) 510 return ERROR_FUNCTION_FAILED; 511 if( !view->ops->execute ) 512 return ERROR_FUNCTION_FAILED; 513 query->row = 0; 514 515 return view->ops->execute( view, rec ); 516 } 517 518 UINT WINAPI MsiViewExecute( MSIHANDLE hView, MSIHANDLE hRec ) 519 { 520 MSIQUERY *query; 521 MSIRECORD *rec = NULL; 522 UINT ret; 523 524 TRACE( "%lu, %lu\n", hView, hRec ); 525 526 if( hRec ) 527 { 528 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD ); 529 if( !rec ) 530 return ERROR_INVALID_HANDLE; 531 } 532 533 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); 534 if( !query ) 535 { 536 MSIHANDLE remote; 537 538 if (!(remote = msi_get_remote(hView))) 539 return ERROR_INVALID_HANDLE; 540 541 __TRY 542 { 543 ret = remote_ViewExecute(remote, rec ? (struct wire_record *)&rec->count : NULL); 544 } 545 __EXCEPT(rpc_filter) 546 { 547 ret = GetExceptionCode(); 548 } 549 __ENDTRY 550 551 if (rec) 552 msiobj_release(&rec->hdr); 553 return ret; 554 } 555 556 msiobj_lock( &rec->hdr ); 557 ret = MSI_ViewExecute( query, rec ); 558 msiobj_unlock( &rec->hdr ); 559 560 msiobj_release( &query->hdr ); 561 if( rec ) 562 msiobj_release( &rec->hdr ); 563 564 return ret; 565 } 566 567 static UINT msi_set_record_type_string( MSIRECORD *rec, UINT field, 568 UINT type, BOOL temporary ) 569 { 570 WCHAR szType[0x10]; 571 572 if (MSITYPE_IS_BINARY(type)) 573 szType[0] = 'v'; 574 else if (type & MSITYPE_LOCALIZABLE) 575 szType[0] = 'l'; 576 else if (type & MSITYPE_UNKNOWN) 577 szType[0] = 'f'; 578 else if (type & MSITYPE_STRING) 579 { 580 if (temporary) 581 szType[0] = 'g'; 582 else 583 szType[0] = 's'; 584 } 585 else 586 { 587 if (temporary) 588 szType[0] = 'j'; 589 else 590 szType[0] = 'i'; 591 } 592 593 if (type & MSITYPE_NULLABLE) 594 szType[0] &= ~0x20; 595 596 swprintf( &szType[1], ARRAY_SIZE(szType) - 1, L"%d", (type&0xff) ); 597 598 TRACE("type %04x -> %s\n", type, debugstr_w(szType) ); 599 600 return MSI_RecordSetStringW( rec, field, szType ); 601 } 602 603 UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec ) 604 { 605 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type; 606 MSIRECORD *rec; 607 MSIVIEW *view = query->view; 608 LPCWSTR name; 609 BOOL temporary; 610 611 if( !view ) 612 return ERROR_FUNCTION_FAILED; 613 614 if( !view->ops->get_dimensions ) 615 return ERROR_FUNCTION_FAILED; 616 617 r = view->ops->get_dimensions( view, NULL, &count ); 618 if( r != ERROR_SUCCESS ) 619 return r; 620 if( !count ) 621 return ERROR_INVALID_PARAMETER; 622 623 rec = MSI_CreateRecord( count ); 624 if( !rec ) 625 return ERROR_FUNCTION_FAILED; 626 627 for( i=0; i<count; i++ ) 628 { 629 name = NULL; 630 r = view->ops->get_column_info( view, i+1, &name, &type, &temporary, NULL ); 631 if( r != ERROR_SUCCESS ) 632 continue; 633 if (info == MSICOLINFO_NAMES) 634 MSI_RecordSetStringW( rec, i+1, name ); 635 else 636 msi_set_record_type_string( rec, i+1, type, temporary ); 637 } 638 *prec = rec; 639 return ERROR_SUCCESS; 640 } 641 642 UINT WINAPI MsiViewGetColumnInfo( MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec ) 643 { 644 MSIQUERY *query = NULL; 645 MSIRECORD *rec = NULL; 646 UINT r; 647 648 TRACE( "%lu, %d, %p\n", hView, info, hRec ); 649 650 if( !hRec ) 651 return ERROR_INVALID_PARAMETER; 652 653 if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES ) 654 return ERROR_INVALID_PARAMETER; 655 656 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); 657 if (!query) 658 { 659 struct wire_record *wire_rec = NULL; 660 MSIHANDLE remote; 661 662 if (!(remote = msi_get_remote(hView))) 663 return ERROR_INVALID_HANDLE; 664 665 __TRY 666 { 667 r = remote_ViewGetColumnInfo(remote, info, &wire_rec); 668 } 669 __EXCEPT(rpc_filter) 670 { 671 r = GetExceptionCode(); 672 } 673 __ENDTRY 674 675 if (!r) 676 { 677 r = unmarshal_record(wire_rec, hRec); 678 free_remote_record(wire_rec); 679 } 680 681 return r; 682 } 683 684 r = MSI_ViewGetColumnInfo( query, info, &rec ); 685 if ( r == ERROR_SUCCESS ) 686 { 687 *hRec = alloc_msihandle( &rec->hdr ); 688 if ( !*hRec ) 689 r = ERROR_NOT_ENOUGH_MEMORY; 690 msiobj_release( &rec->hdr ); 691 } 692 693 msiobj_release( &query->hdr ); 694 695 return r; 696 } 697 698 UINT MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec ) 699 { 700 MSIVIEW *view = NULL; 701 UINT r; 702 703 if ( !query || !rec ) 704 return ERROR_INVALID_HANDLE; 705 706 view = query->view; 707 if ( !view || !view->ops->modify) 708 return ERROR_FUNCTION_FAILED; 709 710 if ( mode == MSIMODIFY_UPDATE && rec->cookie != (UINT64)(ULONG_PTR)query ) 711 return ERROR_FUNCTION_FAILED; 712 713 r = view->ops->modify( view, mode, rec, query->row - 1 ); 714 if (mode == MSIMODIFY_DELETE && r == ERROR_SUCCESS) 715 query->row--; 716 717 return r; 718 } 719 720 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode, MSIHANDLE hRecord ) 721 { 722 MSIQUERY *query = NULL; 723 MSIRECORD *rec = NULL; 724 UINT r = ERROR_FUNCTION_FAILED; 725 726 TRACE( "%lu, %#x, %lu\n", hView, eModifyMode, hRecord ); 727 728 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); 729 730 if (!rec) 731 return ERROR_INVALID_HANDLE; 732 733 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); 734 if (!query) 735 { 736 struct wire_record *wire_refreshed = NULL; 737 MSIHANDLE remote; 738 739 if (!(remote = msi_get_remote(hView))) 740 return ERROR_INVALID_HANDLE; 741 742 __TRY 743 { 744 r = remote_ViewModify(remote, eModifyMode, 745 (struct wire_record *)&rec->count, &wire_refreshed); 746 } 747 __EXCEPT(rpc_filter) 748 { 749 r = GetExceptionCode(); 750 } 751 __ENDTRY 752 753 if (!r && (eModifyMode == MSIMODIFY_REFRESH || eModifyMode == MSIMODIFY_SEEK)) 754 { 755 r = copy_remote_record(wire_refreshed, hRecord); 756 free_remote_record(wire_refreshed); 757 } 758 759 msiobj_release(&rec->hdr); 760 return r; 761 } 762 763 r = MSI_ViewModify( query, eModifyMode, rec ); 764 765 msiobj_release( &query->hdr ); 766 msiobj_release(&rec->hdr); 767 return r; 768 } 769 770 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, WCHAR *buffer, DWORD *buflen ) 771 { 772 MSIQUERY *query; 773 const WCHAR *column; 774 MSIDBERROR r; 775 776 TRACE( "%lu, %p, %p\n", handle, buffer, buflen ); 777 778 if (!buflen) 779 return MSIDBERROR_INVALIDARG; 780 781 if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW))) 782 { 783 WCHAR *remote_column = NULL; 784 MSIHANDLE remote; 785 786 if (!(remote = msi_get_remote(handle))) 787 return MSIDBERROR_INVALIDARG; 788 789 if (!*buflen) 790 return MSIDBERROR_FUNCTIONERROR; 791 792 __TRY 793 { 794 r = remote_ViewGetError(remote, &remote_column); 795 } 796 __EXCEPT(rpc_filter) 797 { 798 r = GetExceptionCode(); 799 } 800 __ENDTRY; 801 802 if (msi_strncpyW(remote_column ? remote_column : L"", -1, buffer, buflen) == ERROR_MORE_DATA) 803 r = MSIDBERROR_MOREDATA; 804 805 if (remote_column) 806 midl_user_free(remote_column); 807 808 return r; 809 } 810 811 if ((r = query->view->error)) column = query->view->error_column; 812 else column = L""; 813 814 if (msi_strncpyW(column, -1, buffer, buflen) == ERROR_MORE_DATA) 815 r = MSIDBERROR_MOREDATA; 816 817 msiobj_release( &query->hdr ); 818 return r; 819 } 820 821 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, char *buffer, DWORD *buflen ) 822 { 823 MSIQUERY *query; 824 const WCHAR *column; 825 MSIDBERROR r; 826 827 TRACE( "%lu, %p, %p\n", handle, buffer, buflen ); 828 829 if (!buflen) 830 return MSIDBERROR_INVALIDARG; 831 832 if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW))) 833 { 834 WCHAR *remote_column = NULL; 835 MSIHANDLE remote; 836 837 if (!(remote = msi_get_remote(handle))) 838 return MSIDBERROR_INVALIDARG; 839 840 if (!*buflen) 841 return MSIDBERROR_FUNCTIONERROR; 842 843 __TRY 844 { 845 r = remote_ViewGetError(remote, &remote_column); 846 } 847 __EXCEPT(rpc_filter) 848 { 849 r = GetExceptionCode(); 850 } 851 __ENDTRY; 852 853 if (msi_strncpyWtoA(remote_column ? remote_column : L"", -1, buffer, buflen, FALSE) == ERROR_MORE_DATA) 854 r = MSIDBERROR_MOREDATA; 855 856 if (remote_column) 857 midl_user_free(remote_column); 858 859 return r; 860 } 861 862 if ((r = query->view->error)) column = query->view->error_column; 863 else column = L""; 864 865 if (msi_strncpyWtoA(column, -1, buffer, buflen, FALSE) == ERROR_MORE_DATA) 866 r = MSIDBERROR_MOREDATA; 867 868 msiobj_release( &query->hdr ); 869 return r; 870 } 871 872 MSIHANDLE WINAPI MsiGetLastErrorRecord( void ) 873 { 874 FIXME("\n"); 875 return 0; 876 } 877 878 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db, const WCHAR *transform, int error_cond ) 879 { 880 HRESULT hr; 881 UINT ret = ERROR_FUNCTION_FAILED; 882 IStorage *stg; 883 STATSTG stat; 884 885 TRACE( "%p %s %08x\n", db, debugstr_w(transform), error_cond ); 886 887 if (*transform == ':') 888 { 889 hr = IStorage_OpenStorage( db->storage, transform + 1, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg ); 890 if (FAILED( hr )) 891 { 892 WARN( "failed to open substorage transform %#lx\n", hr ); 893 return ERROR_FUNCTION_FAILED; 894 } 895 } 896 else 897 { 898 hr = StgOpenStorage( transform, NULL, STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg ); 899 if (FAILED( hr )) 900 { 901 WARN( "failed to open file transform %#lx\n", hr ); 902 return ERROR_FUNCTION_FAILED; 903 } 904 } 905 906 hr = IStorage_Stat( stg, &stat, STATFLAG_NONAME ); 907 if (FAILED( hr )) goto end; 908 if (!IsEqualGUID( &stat.clsid, &CLSID_MsiTransform )) goto end; 909 if (TRACE_ON( msi )) enum_stream_names( stg ); 910 911 ret = msi_table_apply_transform( db, stg, error_cond ); 912 913 end: 914 IStorage_Release( stg ); 915 return ret; 916 } 917 918 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, const WCHAR *transform, int error_cond ) 919 { 920 MSIDATABASE *db; 921 UINT r; 922 923 if (error_cond & ~MSITRANSFORM_ERROR_VIEWTRANSFORM) FIXME( "ignoring error conditions\n" ); 924 925 if (!(db = msihandle2msiinfo(hdb, MSIHANDLETYPE_DATABASE))) 926 return ERROR_INVALID_HANDLE; 927 928 r = MSI_DatabaseApplyTransformW( db, transform, error_cond ); 929 msiobj_release( &db->hdr ); 930 return r; 931 } 932 933 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, const char *transform, int error_cond ) 934 { 935 WCHAR *wstr; 936 UINT ret; 937 938 TRACE( "%lu, %s, %#x\n", hdb, debugstr_a(transform), error_cond ); 939 940 wstr = strdupAtoW( transform ); 941 if (transform && !wstr) 942 return ERROR_NOT_ENOUGH_MEMORY; 943 944 ret = MsiDatabaseApplyTransformW( hdb, wstr, error_cond ); 945 msi_free( wstr ); 946 return ret; 947 } 948 949 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref, const char *szTransformFile, 950 int iReserved1, int iReserved2 ) 951 { 952 FIXME( "%lu, %lu, %s, %d, %d\n", hdb, hdbref, debugstr_a(szTransformFile), iReserved1, iReserved2 ); 953 return ERROR_CALL_NOT_IMPLEMENTED; 954 } 955 956 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref, const WCHAR *szTransformFile, 957 int iReserved1, int iReserved2 ) 958 { 959 FIXME( "%lu, %lu, %s, %d, %d\n", hdb, hdbref, debugstr_w(szTransformFile), iReserved1, iReserved2 ); 960 return ERROR_CALL_NOT_IMPLEMENTED; 961 } 962 963 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb ) 964 { 965 MSIDATABASE *db; 966 UINT r; 967 968 TRACE( "%lu\n", hdb ); 969 970 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); 971 if( !db ) 972 { 973 MSIHANDLE remote; 974 975 if (!(remote = msi_get_remote(hdb))) 976 return ERROR_INVALID_HANDLE; 977 978 WARN("not allowed during a custom action!\n"); 979 980 return ERROR_SUCCESS; 981 } 982 983 if (db->mode == MSI_OPEN_READONLY) 984 { 985 msiobj_release( &db->hdr ); 986 return ERROR_SUCCESS; 987 } 988 989 /* FIXME: lock the database */ 990 991 r = msi_commit_streams( db ); 992 if (r != ERROR_SUCCESS) ERR("Failed to commit streams!\n"); 993 else 994 { 995 r = MSI_CommitTables( db ); 996 if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n"); 997 } 998 999 /* FIXME: unlock the database */ 1000 1001 msiobj_release( &db->hdr ); 1002 1003 if (r == ERROR_SUCCESS) 1004 { 1005 msi_free( db->deletefile ); 1006 db->deletefile = NULL; 1007 } 1008 1009 return r; 1010 } 1011 1012 struct msi_primary_key_record_info 1013 { 1014 DWORD n; 1015 MSIRECORD *rec; 1016 }; 1017 1018 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param ) 1019 { 1020 struct msi_primary_key_record_info *info = param; 1021 LPCWSTR name, table; 1022 DWORD type; 1023 1024 type = MSI_RecordGetInteger( rec, 4 ); 1025 if( type & MSITYPE_KEY ) 1026 { 1027 info->n++; 1028 if( info->rec ) 1029 { 1030 if ( info->n == 1 ) 1031 { 1032 table = MSI_RecordGetString( rec, 1 ); 1033 MSI_RecordSetStringW( info->rec, 0, table); 1034 } 1035 1036 name = MSI_RecordGetString( rec, 3 ); 1037 MSI_RecordSetStringW( info->rec, info->n, name ); 1038 } 1039 } 1040 1041 return ERROR_SUCCESS; 1042 } 1043 1044 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db, 1045 LPCWSTR table, MSIRECORD **prec ) 1046 { 1047 struct msi_primary_key_record_info info; 1048 MSIQUERY *query = NULL; 1049 UINT r; 1050 1051 if (!TABLE_Exists( db, table )) 1052 return ERROR_INVALID_TABLE; 1053 1054 r = MSI_OpenQuery( db, &query, L"SELECT * FROM `_Columns` WHERE `Table` = '%s'", table ); 1055 if( r != ERROR_SUCCESS ) 1056 return r; 1057 1058 /* count the number of primary key records */ 1059 info.n = 0; 1060 info.rec = 0; 1061 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info ); 1062 if( r == ERROR_SUCCESS ) 1063 { 1064 TRACE( "found %lu primary keys\n", info.n ); 1065 1066 /* allocate a record and fill in the names of the tables */ 1067 info.rec = MSI_CreateRecord( info.n ); 1068 info.n = 0; 1069 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info ); 1070 if( r == ERROR_SUCCESS ) 1071 *prec = info.rec; 1072 else 1073 msiobj_release( &info.rec->hdr ); 1074 } 1075 msiobj_release( &query->hdr ); 1076 1077 return r; 1078 } 1079 1080 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb, const WCHAR *table, MSIHANDLE *phRec ) 1081 { 1082 MSIRECORD *rec = NULL; 1083 MSIDATABASE *db; 1084 UINT r; 1085 1086 TRACE( "%lu, %s, %p\n", hdb, debugstr_w(table), phRec ); 1087 1088 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); 1089 if( !db ) 1090 { 1091 struct wire_record *wire_rec = NULL; 1092 MSIHANDLE remote; 1093 1094 if (!(remote = msi_get_remote(hdb))) 1095 return ERROR_INVALID_HANDLE; 1096 1097 __TRY 1098 { 1099 r = remote_DatabaseGetPrimaryKeys(remote, table, &wire_rec); 1100 } 1101 __EXCEPT(rpc_filter) 1102 { 1103 r = GetExceptionCode(); 1104 } 1105 __ENDTRY 1106 1107 if (!r) 1108 { 1109 r = unmarshal_record(wire_rec, phRec); 1110 free_remote_record(wire_rec); 1111 } 1112 1113 return r; 1114 } 1115 1116 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec ); 1117 if( r == ERROR_SUCCESS ) 1118 { 1119 *phRec = alloc_msihandle( &rec->hdr ); 1120 if (! *phRec) 1121 r = ERROR_NOT_ENOUGH_MEMORY; 1122 msiobj_release( &rec->hdr ); 1123 } 1124 msiobj_release( &db->hdr ); 1125 1126 return r; 1127 } 1128 1129 UINT WINAPI MsiDatabaseGetPrimaryKeysA( MSIHANDLE hdb, const char *table, MSIHANDLE *phRec ) 1130 { 1131 WCHAR *szwTable = NULL; 1132 UINT r; 1133 1134 TRACE( "%lu, %s, %p\n", hdb, debugstr_a(table), phRec ); 1135 1136 if( table ) 1137 { 1138 szwTable = strdupAtoW( table ); 1139 if( !szwTable ) 1140 return ERROR_OUTOFMEMORY; 1141 } 1142 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec ); 1143 msi_free( szwTable ); 1144 1145 return r; 1146 } 1147 1148 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA( MSIHANDLE hDatabase, const char *szTableName ) 1149 { 1150 WCHAR *szwTableName = NULL; 1151 MSICONDITION r; 1152 1153 TRACE( "%lu, %s\n", hDatabase, debugstr_a(szTableName) ); 1154 1155 if( szTableName ) 1156 { 1157 szwTableName = strdupAtoW( szTableName ); 1158 if( !szwTableName ) 1159 return MSICONDITION_ERROR; 1160 } 1161 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName ); 1162 msi_free( szwTableName ); 1163 1164 return r; 1165 } 1166 1167 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW( MSIHANDLE hDatabase, const WCHAR *szTableName ) 1168 { 1169 MSIDATABASE *db; 1170 MSICONDITION r; 1171 1172 TRACE( "%lu, %s\n", hDatabase, debugstr_w(szTableName) ); 1173 1174 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE ); 1175 if( !db ) 1176 { 1177 MSIHANDLE remote; 1178 1179 if (!(remote = msi_get_remote(hDatabase))) 1180 return MSICONDITION_ERROR; 1181 1182 __TRY 1183 { 1184 r = remote_DatabaseIsTablePersistent(remote, szTableName); 1185 } 1186 __EXCEPT(rpc_filter) 1187 { 1188 r = MSICONDITION_ERROR; 1189 } 1190 __ENDTRY 1191 1192 return r; 1193 } 1194 1195 r = MSI_DatabaseIsTablePersistent( db, szTableName ); 1196 1197 msiobj_release( &db->hdr ); 1198 1199 return r; 1200 } 1201 1202 UINT __cdecl s_remote_ViewClose(MSIHANDLE view) 1203 { 1204 return MsiViewClose(view); 1205 } 1206 1207 UINT __cdecl s_remote_ViewExecute(MSIHANDLE view, struct wire_record *remote_rec) 1208 { 1209 MSIHANDLE rec = 0; 1210 UINT r; 1211 1212 if ((r = unmarshal_record(remote_rec, &rec))) 1213 return r; 1214 1215 r = MsiViewExecute(view, rec); 1216 1217 MsiCloseHandle(rec); 1218 return r; 1219 } 1220 1221 UINT __cdecl s_remote_ViewFetch(MSIHANDLE view, struct wire_record **rec) 1222 { 1223 MSIHANDLE handle; 1224 UINT r = MsiViewFetch(view, &handle); 1225 *rec = NULL; 1226 if (!r) 1227 *rec = marshal_record(handle); 1228 MsiCloseHandle(handle); 1229 return r; 1230 } 1231 1232 UINT __cdecl s_remote_ViewGetColumnInfo(MSIHANDLE view, MSICOLINFO info, struct wire_record **rec) 1233 { 1234 MSIHANDLE handle; 1235 UINT r = MsiViewGetColumnInfo(view, info, &handle); 1236 *rec = NULL; 1237 if (!r) 1238 *rec = marshal_record(handle); 1239 MsiCloseHandle(handle); 1240 return r; 1241 } 1242 1243 MSIDBERROR __cdecl s_remote_ViewGetError(MSIHANDLE view, LPWSTR *column) 1244 { 1245 WCHAR empty[1]; 1246 DWORD size = 1; 1247 UINT r; 1248 1249 r = MsiViewGetErrorW(view, empty, &size); 1250 if (r == MSIDBERROR_MOREDATA) 1251 { 1252 if (!(*column = midl_user_allocate(++size * sizeof(WCHAR)))) 1253 return MSIDBERROR_FUNCTIONERROR; 1254 r = MsiViewGetErrorW(view, *column, &size); 1255 } 1256 return r; 1257 } 1258 1259 UINT __cdecl s_remote_ViewModify(MSIHANDLE view, MSIMODIFY mode, 1260 struct wire_record *remote_rec, struct wire_record **remote_refreshed) 1261 { 1262 MSIHANDLE handle = 0; 1263 UINT r; 1264 1265 if ((r = unmarshal_record(remote_rec, &handle))) 1266 return r; 1267 1268 r = MsiViewModify(view, mode, handle); 1269 *remote_refreshed = NULL; 1270 if (!r && (mode == MSIMODIFY_REFRESH || mode == MSIMODIFY_SEEK)) 1271 *remote_refreshed = marshal_record(handle); 1272 1273 MsiCloseHandle(handle); 1274 return r; 1275 } 1276