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/unicode.h" 30 #include "msi.h" 31 #include "msiquery.h" 32 #include "objbase.h" 33 #include "objidl.h" 34 #include "msipriv.h" 35 #include "winnls.h" 36 37 #include "query.h" 38 #include "msiserver.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 = strcmpW( name, col_name ); 77 if( table_name ) 78 x |= strcmpW( 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, 89 LPCSTR szQuery, MSIHANDLE *phView) 90 { 91 UINT r; 92 LPWSTR szwQuery; 93 94 TRACE("%d %s %p\n", hdb, debugstr_a(szQuery), phView); 95 96 if( szQuery ) 97 { 98 szwQuery = strdupAtoW( szQuery ); 99 if( !szwQuery ) 100 return ERROR_FUNCTION_FAILED; 101 } 102 else 103 szwQuery = NULL; 104 105 r = MsiDatabaseOpenViewW( hdb, szwQuery, phView); 106 107 msi_free( szwQuery ); 108 return r; 109 } 110 111 UINT MSI_DatabaseOpenViewW(MSIDATABASE *db, 112 LPCWSTR szQuery, MSIQUERY **pView) 113 { 114 MSIQUERY *query; 115 UINT r; 116 117 TRACE("%s %p\n", debugstr_w(szQuery), pView); 118 119 if( !szQuery) 120 return ERROR_INVALID_PARAMETER; 121 122 /* pre allocate a handle to hold a pointer to the view */ 123 query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY), 124 MSI_CloseView ); 125 if( !query ) 126 return ERROR_FUNCTION_FAILED; 127 128 msiobj_addref( &db->hdr ); 129 query->db = db; 130 list_init( &query->mem ); 131 132 r = MSI_ParseSQL( db, szQuery, &query->view, &query->mem ); 133 if( r == ERROR_SUCCESS ) 134 { 135 msiobj_addref( &query->hdr ); 136 *pView = query; 137 } 138 139 msiobj_release( &query->hdr ); 140 return r; 141 } 142 143 UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) 144 { 145 UINT r; 146 int size = 100, res; 147 LPWSTR query; 148 149 /* construct the string */ 150 for (;;) 151 { 152 va_list va; 153 query = msi_alloc( size*sizeof(WCHAR) ); 154 va_start(va, fmt); 155 res = vsnprintfW(query, size, fmt, va); 156 va_end(va); 157 if (res == -1) size *= 2; 158 else if (res >= size) size = res + 1; 159 else break; 160 msi_free( query ); 161 } 162 /* perform the query */ 163 r = MSI_DatabaseOpenViewW(db, query, view); 164 msi_free(query); 165 return r; 166 } 167 168 UINT MSI_IterateRecords( MSIQUERY *view, LPDWORD count, 169 record_func func, LPVOID param ) 170 { 171 MSIRECORD *rec = NULL; 172 UINT r, n = 0, max = 0; 173 174 r = MSI_ViewExecute( view, NULL ); 175 if( r != ERROR_SUCCESS ) 176 return r; 177 178 if( count ) 179 max = *count; 180 181 /* iterate a query */ 182 for( n = 0; (max == 0) || (n < max); n++ ) 183 { 184 r = MSI_ViewFetch( view, &rec ); 185 if( r != ERROR_SUCCESS ) 186 break; 187 if (func) 188 r = func( rec, param ); 189 msiobj_release( &rec->hdr ); 190 if( r != ERROR_SUCCESS ) 191 break; 192 } 193 194 MSI_ViewClose( view ); 195 196 if( count ) 197 *count = n; 198 199 if( r == ERROR_NO_MORE_ITEMS ) 200 r = ERROR_SUCCESS; 201 202 return r; 203 } 204 205 /* return a single record from a query */ 206 MSIRECORD *MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... ) 207 { 208 MSIRECORD *rec = NULL; 209 MSIQUERY *view = NULL; 210 UINT r; 211 int size = 100, res; 212 LPWSTR query; 213 214 /* construct the string */ 215 for (;;) 216 { 217 va_list va; 218 query = msi_alloc( size*sizeof(WCHAR) ); 219 va_start(va, fmt); 220 res = vsnprintfW(query, size, fmt, va); 221 va_end(va); 222 if (res == -1) size *= 2; 223 else if (res >= size) size = res + 1; 224 else break; 225 msi_free( query ); 226 } 227 /* perform the query */ 228 r = MSI_DatabaseOpenViewW(db, query, &view); 229 msi_free(query); 230 231 if( r == ERROR_SUCCESS ) 232 { 233 MSI_ViewExecute( view, NULL ); 234 MSI_ViewFetch( view, &rec ); 235 MSI_ViewClose( view ); 236 msiobj_release( &view->hdr ); 237 } 238 return rec; 239 } 240 241 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb, 242 LPCWSTR szQuery, MSIHANDLE *phView) 243 { 244 MSIDATABASE *db; 245 MSIQUERY *query = NULL; 246 UINT ret; 247 248 TRACE("%s %p\n", debugstr_w(szQuery), phView); 249 250 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); 251 if( !db ) 252 { 253 HRESULT hr; 254 IWineMsiRemoteDatabase *remote_database; 255 256 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hdb ); 257 if ( !remote_database ) 258 return ERROR_INVALID_HANDLE; 259 260 hr = IWineMsiRemoteDatabase_OpenView( remote_database, szQuery, phView ); 261 IWineMsiRemoteDatabase_Release( remote_database ); 262 263 if (FAILED(hr)) 264 { 265 if (HRESULT_FACILITY(hr) == FACILITY_WIN32) 266 return HRESULT_CODE(hr); 267 268 return ERROR_FUNCTION_FAILED; 269 } 270 271 return ERROR_SUCCESS; 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_get_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 if (row >= row_count) 301 return ERROR_NO_MORE_ITEMS; 302 303 *rec = MSI_CreateRecord(col_count); 304 if (!*rec) 305 return ERROR_FUNCTION_FAILED; 306 307 for (i = 1; i <= col_count; i++) 308 { 309 ret = view->ops->get_column_info(view, i, NULL, &type, NULL, NULL); 310 if (ret) 311 { 312 ERR("Error getting column type for %d\n", i); 313 continue; 314 } 315 316 if (MSITYPE_IS_BINARY(type)) 317 { 318 IStream *stm = NULL; 319 320 ret = view->ops->fetch_stream(view, row, i, &stm); 321 if ((ret == ERROR_SUCCESS) && stm) 322 { 323 MSI_RecordSetIStream(*rec, i, stm); 324 IStream_Release(stm); 325 } 326 else 327 WARN("failed to get stream\n"); 328 329 continue; 330 } 331 332 ret = view->ops->fetch_int(view, row, i, &ival); 333 if (ret) 334 { 335 ERR("Error fetching data for %d\n", i); 336 continue; 337 } 338 339 if (! (type & MSITYPE_VALID)) 340 ERR("Invalid type!\n"); 341 342 /* check if it's nul (0) - if so, don't set anything */ 343 if (!ival) 344 continue; 345 346 if (type & MSITYPE_STRING) 347 { 348 int len; 349 const WCHAR *sval = msi_string_lookup( db->strings, ival, &len ); 350 msi_record_set_string( *rec, i, sval, len ); 351 } 352 else 353 { 354 if ((type & MSI_DATASIZEMASK) == 2) 355 MSI_RecordSetInteger(*rec, i, ival - (1<<15)); 356 else 357 MSI_RecordSetInteger(*rec, i, ival - (1u<<31)); 358 } 359 } 360 361 return ERROR_SUCCESS; 362 } 363 364 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec) 365 { 366 MSIVIEW *view; 367 UINT r; 368 369 TRACE("%p %p\n", query, prec ); 370 371 view = query->view; 372 if( !view ) 373 return ERROR_FUNCTION_FAILED; 374 375 r = msi_view_get_row(query->db, view, query->row, prec); 376 if (r == ERROR_SUCCESS) 377 { 378 query->row ++; 379 MSI_RecordSetIntPtr(*prec, 0, (INT_PTR)query); 380 } 381 382 return r; 383 } 384 385 UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record) 386 { 387 MSIQUERY *query; 388 MSIRECORD *rec = NULL; 389 UINT ret; 390 391 TRACE("%d %p\n", hView, record); 392 393 if( !record ) 394 return ERROR_INVALID_PARAMETER; 395 *record = 0; 396 397 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); 398 if( !query ) 399 return ERROR_INVALID_HANDLE; 400 ret = MSI_ViewFetch( query, &rec ); 401 if( ret == ERROR_SUCCESS ) 402 { 403 *record = alloc_msihandle( &rec->hdr ); 404 if (! *record) 405 ret = ERROR_NOT_ENOUGH_MEMORY; 406 msiobj_release( &rec->hdr ); 407 } 408 msiobj_release( &query->hdr ); 409 return ret; 410 } 411 412 UINT MSI_ViewClose(MSIQUERY *query) 413 { 414 MSIVIEW *view; 415 416 TRACE("%p\n", query ); 417 418 view = query->view; 419 if( !view ) 420 return ERROR_FUNCTION_FAILED; 421 if( !view->ops->close ) 422 return ERROR_FUNCTION_FAILED; 423 424 return view->ops->close( view ); 425 } 426 427 UINT WINAPI MsiViewClose(MSIHANDLE hView) 428 { 429 MSIQUERY *query; 430 UINT ret; 431 432 TRACE("%d\n", hView ); 433 434 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); 435 if( !query ) 436 return ERROR_INVALID_HANDLE; 437 438 ret = MSI_ViewClose( query ); 439 msiobj_release( &query->hdr ); 440 return ret; 441 } 442 443 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec ) 444 { 445 MSIVIEW *view; 446 447 TRACE("%p %p\n", query, rec); 448 449 view = query->view; 450 if( !view ) 451 return ERROR_FUNCTION_FAILED; 452 if( !view->ops->execute ) 453 return ERROR_FUNCTION_FAILED; 454 query->row = 0; 455 456 return view->ops->execute( view, rec ); 457 } 458 459 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec) 460 { 461 MSIQUERY *query; 462 MSIRECORD *rec = NULL; 463 UINT ret; 464 465 TRACE("%d %d\n", hView, hRec); 466 467 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); 468 if( !query ) 469 return ERROR_INVALID_HANDLE; 470 471 if( hRec ) 472 { 473 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD ); 474 if( !rec ) 475 { 476 ret = ERROR_INVALID_HANDLE; 477 goto out; 478 } 479 } 480 481 msiobj_lock( &rec->hdr ); 482 ret = MSI_ViewExecute( query, rec ); 483 msiobj_unlock( &rec->hdr ); 484 485 out: 486 msiobj_release( &query->hdr ); 487 if( rec ) 488 msiobj_release( &rec->hdr ); 489 490 return ret; 491 } 492 493 static UINT msi_set_record_type_string( MSIRECORD *rec, UINT field, 494 UINT type, BOOL temporary ) 495 { 496 static const WCHAR fmt[] = { '%','d',0 }; 497 WCHAR szType[0x10]; 498 499 if (MSITYPE_IS_BINARY(type)) 500 szType[0] = 'v'; 501 else if (type & MSITYPE_LOCALIZABLE) 502 szType[0] = 'l'; 503 else if (type & MSITYPE_UNKNOWN) 504 szType[0] = 'f'; 505 else if (type & MSITYPE_STRING) 506 { 507 if (temporary) 508 szType[0] = 'g'; 509 else 510 szType[0] = 's'; 511 } 512 else 513 { 514 if (temporary) 515 szType[0] = 'j'; 516 else 517 szType[0] = 'i'; 518 } 519 520 if (type & MSITYPE_NULLABLE) 521 szType[0] &= ~0x20; 522 523 sprintfW( &szType[1], fmt, (type&0xff) ); 524 525 TRACE("type %04x -> %s\n", type, debugstr_w(szType) ); 526 527 return MSI_RecordSetStringW( rec, field, szType ); 528 } 529 530 UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec ) 531 { 532 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type; 533 MSIRECORD *rec; 534 MSIVIEW *view = query->view; 535 LPCWSTR name; 536 BOOL temporary; 537 538 if( !view ) 539 return ERROR_FUNCTION_FAILED; 540 541 if( !view->ops->get_dimensions ) 542 return ERROR_FUNCTION_FAILED; 543 544 r = view->ops->get_dimensions( view, NULL, &count ); 545 if( r != ERROR_SUCCESS ) 546 return r; 547 if( !count ) 548 return ERROR_INVALID_PARAMETER; 549 550 rec = MSI_CreateRecord( count ); 551 if( !rec ) 552 return ERROR_FUNCTION_FAILED; 553 554 for( i=0; i<count; i++ ) 555 { 556 name = NULL; 557 r = view->ops->get_column_info( view, i+1, &name, &type, &temporary, NULL ); 558 if( r != ERROR_SUCCESS ) 559 continue; 560 if (info == MSICOLINFO_NAMES) 561 MSI_RecordSetStringW( rec, i+1, name ); 562 else 563 msi_set_record_type_string( rec, i+1, type, temporary ); 564 } 565 *prec = rec; 566 return ERROR_SUCCESS; 567 } 568 569 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec) 570 { 571 MSIQUERY *query = NULL; 572 MSIRECORD *rec = NULL; 573 UINT r; 574 575 TRACE("%d %d %p\n", hView, info, hRec); 576 577 if( !hRec ) 578 return ERROR_INVALID_PARAMETER; 579 580 if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES ) 581 return ERROR_INVALID_PARAMETER; 582 583 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); 584 if( !query ) 585 return ERROR_INVALID_HANDLE; 586 587 r = MSI_ViewGetColumnInfo( query, info, &rec ); 588 if ( r == ERROR_SUCCESS ) 589 { 590 *hRec = alloc_msihandle( &rec->hdr ); 591 if ( !*hRec ) 592 r = ERROR_NOT_ENOUGH_MEMORY; 593 msiobj_release( &rec->hdr ); 594 } 595 596 msiobj_release( &query->hdr ); 597 598 return r; 599 } 600 601 UINT MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec ) 602 { 603 MSIVIEW *view = NULL; 604 UINT r; 605 606 if ( !query || !rec ) 607 return ERROR_INVALID_HANDLE; 608 609 view = query->view; 610 if ( !view || !view->ops->modify) 611 return ERROR_FUNCTION_FAILED; 612 613 if ( mode == MSIMODIFY_UPDATE && MSI_RecordGetIntPtr( rec, 0 ) != (INT_PTR)query ) 614 return ERROR_FUNCTION_FAILED; 615 616 r = view->ops->modify( view, mode, rec, query->row ); 617 if (mode == MSIMODIFY_DELETE && r == ERROR_SUCCESS) 618 query->row--; 619 620 return r; 621 } 622 623 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode, 624 MSIHANDLE hRecord) 625 { 626 MSIQUERY *query = NULL; 627 MSIRECORD *rec = NULL; 628 UINT r = ERROR_FUNCTION_FAILED; 629 630 TRACE("%d %x %d\n", hView, eModifyMode, hRecord); 631 632 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); 633 if( !query ) 634 return ERROR_INVALID_HANDLE; 635 636 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); 637 r = MSI_ViewModify( query, eModifyMode, rec ); 638 639 msiobj_release( &query->hdr ); 640 if( rec ) 641 msiobj_release( &rec->hdr ); 642 643 return r; 644 } 645 646 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR buffer, LPDWORD buflen ) 647 { 648 MSIQUERY *query; 649 const WCHAR *column; 650 MSIDBERROR r; 651 DWORD len; 652 653 TRACE("%u %p %p\n", handle, buffer, buflen); 654 655 if (!buflen) 656 return MSIDBERROR_INVALIDARG; 657 658 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW ); 659 if( !query ) 660 return MSIDBERROR_INVALIDARG; 661 662 if ((r = query->view->error)) column = query->view->error_column; 663 else column = szEmpty; 664 665 len = strlenW( column ); 666 if (buffer) 667 { 668 if (*buflen > len) 669 strcpyW( buffer, column ); 670 else 671 r = MSIDBERROR_MOREDATA; 672 } 673 *buflen = len; 674 msiobj_release( &query->hdr ); 675 return r; 676 } 677 678 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR buffer, LPDWORD buflen ) 679 { 680 MSIQUERY *query; 681 const WCHAR *column; 682 MSIDBERROR r; 683 DWORD len; 684 685 TRACE("%u %p %p\n", handle, buffer, buflen); 686 687 if (!buflen) 688 return MSIDBERROR_INVALIDARG; 689 690 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW ); 691 if (!query) 692 return MSIDBERROR_INVALIDARG; 693 694 if ((r = query->view->error)) column = query->view->error_column; 695 else column = szEmpty; 696 697 len = WideCharToMultiByte( CP_ACP, 0, column, -1, NULL, 0, NULL, NULL ); 698 if (buffer) 699 { 700 if (*buflen >= len) 701 WideCharToMultiByte( CP_ACP, 0, column, -1, buffer, *buflen, NULL, NULL ); 702 else 703 r = MSIDBERROR_MOREDATA; 704 } 705 *buflen = len - 1; 706 msiobj_release( &query->hdr ); 707 return r; 708 } 709 710 MSIHANDLE WINAPI MsiGetLastErrorRecord( void ) 711 { 712 FIXME("\n"); 713 return 0; 714 } 715 716 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db, 717 LPCWSTR szTransformFile, int iErrorCond ) 718 { 719 HRESULT r; 720 UINT ret = ERROR_FUNCTION_FAILED; 721 IStorage *stg = NULL; 722 STATSTG stat; 723 724 TRACE("%p %s %d\n", db, debugstr_w(szTransformFile), iErrorCond); 725 726 r = StgOpenStorage( szTransformFile, NULL, 727 STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg); 728 if ( FAILED(r) ) 729 { 730 WARN("failed to open transform 0x%08x\n", r); 731 return ret; 732 } 733 734 r = IStorage_Stat( stg, &stat, STATFLAG_NONAME ); 735 if ( FAILED( r ) ) 736 goto end; 737 738 if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiTransform ) ) 739 goto end; 740 741 if( TRACE_ON( msi ) ) 742 enum_stream_names( stg ); 743 744 ret = msi_table_apply_transform( db, stg ); 745 746 end: 747 IStorage_Release( stg ); 748 749 return ret; 750 } 751 752 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, 753 LPCWSTR szTransformFile, int iErrorCond) 754 { 755 MSIDATABASE *db; 756 UINT r; 757 758 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); 759 if( !db ) 760 { 761 IWineMsiRemoteDatabase *remote_database; 762 763 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hdb ); 764 if ( !remote_database ) 765 return ERROR_INVALID_HANDLE; 766 767 IWineMsiRemoteDatabase_Release( remote_database ); 768 WARN("MsiDatabaseApplyTransform not allowed during a custom action!\n"); 769 770 return ERROR_SUCCESS; 771 } 772 773 r = MSI_DatabaseApplyTransformW( db, szTransformFile, iErrorCond ); 774 msiobj_release( &db->hdr ); 775 return r; 776 } 777 778 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, 779 LPCSTR szTransformFile, int iErrorCond) 780 { 781 LPWSTR wstr; 782 UINT ret; 783 784 TRACE("%d %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond); 785 786 wstr = strdupAtoW( szTransformFile ); 787 if( szTransformFile && !wstr ) 788 return ERROR_NOT_ENOUGH_MEMORY; 789 790 ret = MsiDatabaseApplyTransformW( hdb, wstr, iErrorCond); 791 792 msi_free( wstr ); 793 794 return ret; 795 } 796 797 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref, 798 LPCSTR szTransformFile, int iReserved1, int iReserved2 ) 799 { 800 FIXME("%d %d %s %d %d\n", hdb, hdbref, 801 debugstr_a(szTransformFile), iReserved1, iReserved2); 802 return ERROR_CALL_NOT_IMPLEMENTED; 803 } 804 805 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref, 806 LPCWSTR szTransformFile, int iReserved1, int iReserved2 ) 807 { 808 FIXME("%d %d %s %d %d\n", hdb, hdbref, 809 debugstr_w(szTransformFile), iReserved1, iReserved2); 810 return ERROR_CALL_NOT_IMPLEMENTED; 811 } 812 813 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb ) 814 { 815 MSIDATABASE *db; 816 UINT r; 817 818 TRACE("%d\n", hdb); 819 820 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); 821 if( !db ) 822 { 823 IWineMsiRemoteDatabase *remote_database; 824 825 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hdb ); 826 if ( !remote_database ) 827 return ERROR_INVALID_HANDLE; 828 829 IWineMsiRemoteDatabase_Release( remote_database ); 830 WARN("not allowed during a custom action!\n"); 831 832 return ERROR_SUCCESS; 833 } 834 835 if (db->mode == MSIDBOPEN_READONLY) 836 { 837 msiobj_release( &db->hdr ); 838 return ERROR_SUCCESS; 839 } 840 841 /* FIXME: lock the database */ 842 843 r = msi_commit_streams( db ); 844 if (r != ERROR_SUCCESS) ERR("Failed to commit streams!\n"); 845 else 846 { 847 r = MSI_CommitTables( db ); 848 if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n"); 849 } 850 851 /* FIXME: unlock the database */ 852 853 msiobj_release( &db->hdr ); 854 855 if (r == ERROR_SUCCESS) 856 { 857 msi_free( db->deletefile ); 858 db->deletefile = NULL; 859 } 860 861 return r; 862 } 863 864 struct msi_primary_key_record_info 865 { 866 DWORD n; 867 MSIRECORD *rec; 868 }; 869 870 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param ) 871 { 872 struct msi_primary_key_record_info *info = param; 873 LPCWSTR name, table; 874 DWORD type; 875 876 type = MSI_RecordGetInteger( rec, 4 ); 877 if( type & MSITYPE_KEY ) 878 { 879 info->n++; 880 if( info->rec ) 881 { 882 if ( info->n == 1 ) 883 { 884 table = MSI_RecordGetString( rec, 1 ); 885 MSI_RecordSetStringW( info->rec, 0, table); 886 } 887 888 name = MSI_RecordGetString( rec, 3 ); 889 MSI_RecordSetStringW( info->rec, info->n, name ); 890 } 891 } 892 893 return ERROR_SUCCESS; 894 } 895 896 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db, 897 LPCWSTR table, MSIRECORD **prec ) 898 { 899 static const WCHAR sql[] = { 900 's','e','l','e','c','t',' ','*',' ', 901 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ', 902 'w','h','e','r','e',' ', 903 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 }; 904 struct msi_primary_key_record_info info; 905 MSIQUERY *query = NULL; 906 UINT r; 907 908 if (!TABLE_Exists( db, table )) 909 return ERROR_INVALID_TABLE; 910 911 r = MSI_OpenQuery( db, &query, sql, table ); 912 if( r != ERROR_SUCCESS ) 913 return r; 914 915 /* count the number of primary key records */ 916 info.n = 0; 917 info.rec = 0; 918 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info ); 919 if( r == ERROR_SUCCESS ) 920 { 921 TRACE("Found %d primary keys\n", info.n ); 922 923 /* allocate a record and fill in the names of the tables */ 924 info.rec = MSI_CreateRecord( info.n ); 925 info.n = 0; 926 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info ); 927 if( r == ERROR_SUCCESS ) 928 *prec = info.rec; 929 else 930 msiobj_release( &info.rec->hdr ); 931 } 932 msiobj_release( &query->hdr ); 933 934 return r; 935 } 936 937 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb, 938 LPCWSTR table, MSIHANDLE* phRec ) 939 { 940 MSIRECORD *rec = NULL; 941 MSIDATABASE *db; 942 UINT r; 943 944 TRACE("%d %s %p\n", hdb, debugstr_w(table), phRec); 945 946 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); 947 if( !db ) 948 { 949 HRESULT hr; 950 IWineMsiRemoteDatabase *remote_database; 951 952 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hdb ); 953 if ( !remote_database ) 954 return ERROR_INVALID_HANDLE; 955 956 hr = IWineMsiRemoteDatabase_GetPrimaryKeys( remote_database, table, phRec ); 957 IWineMsiRemoteDatabase_Release( remote_database ); 958 959 if (FAILED(hr)) 960 { 961 if (HRESULT_FACILITY(hr) == FACILITY_WIN32) 962 return HRESULT_CODE(hr); 963 964 return ERROR_FUNCTION_FAILED; 965 } 966 967 return ERROR_SUCCESS; 968 } 969 970 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec ); 971 if( r == ERROR_SUCCESS ) 972 { 973 *phRec = alloc_msihandle( &rec->hdr ); 974 if (! *phRec) 975 r = ERROR_NOT_ENOUGH_MEMORY; 976 msiobj_release( &rec->hdr ); 977 } 978 msiobj_release( &db->hdr ); 979 980 return r; 981 } 982 983 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb, 984 LPCSTR table, MSIHANDLE* phRec) 985 { 986 LPWSTR szwTable = NULL; 987 UINT r; 988 989 TRACE("%d %s %p\n", hdb, debugstr_a(table), phRec); 990 991 if( table ) 992 { 993 szwTable = strdupAtoW( table ); 994 if( !szwTable ) 995 return ERROR_OUTOFMEMORY; 996 } 997 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec ); 998 msi_free( szwTable ); 999 1000 return r; 1001 } 1002 1003 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA( 1004 MSIHANDLE hDatabase, LPCSTR szTableName) 1005 { 1006 LPWSTR szwTableName = NULL; 1007 MSICONDITION r; 1008 1009 TRACE("%x %s\n", hDatabase, debugstr_a(szTableName)); 1010 1011 if( szTableName ) 1012 { 1013 szwTableName = strdupAtoW( szTableName ); 1014 if( !szwTableName ) 1015 return MSICONDITION_ERROR; 1016 } 1017 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName ); 1018 msi_free( szwTableName ); 1019 1020 return r; 1021 } 1022 1023 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW( 1024 MSIHANDLE hDatabase, LPCWSTR szTableName) 1025 { 1026 MSIDATABASE *db; 1027 MSICONDITION r; 1028 1029 TRACE("%x %s\n", hDatabase, debugstr_w(szTableName)); 1030 1031 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE ); 1032 if( !db ) 1033 { 1034 HRESULT hr; 1035 MSICONDITION condition; 1036 IWineMsiRemoteDatabase *remote_database; 1037 1038 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hDatabase ); 1039 if ( !remote_database ) 1040 return MSICONDITION_ERROR; 1041 1042 hr = IWineMsiRemoteDatabase_IsTablePersistent( remote_database, 1043 szTableName, &condition ); 1044 IWineMsiRemoteDatabase_Release( remote_database ); 1045 1046 if (FAILED(hr)) 1047 return MSICONDITION_ERROR; 1048 1049 return condition; 1050 } 1051 1052 r = MSI_DatabaseIsTablePersistent( db, szTableName ); 1053 1054 msiobj_release( &db->hdr ); 1055 1056 return r; 1057 } 1058