2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2002-2005 Mike McCormack for CodeWeavers
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.
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.
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
28 #include "wine/debug.h"
29 #include "wine/unicode.h"
30 #include "wine/list.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42 static void MSI_CloseView( MSIOBJECTHDR *arg )
44 MSIQUERY *query = (MSIQUERY*) arg;
47 if( query->view && query->view->ops->delete )
48 query->view->ops->delete( query->view );
49 msiobj_release( &query->db->hdr );
51 LIST_FOR_EACH_SAFE( ptr, t, &query->mem )
57 UINT VIEW_find_column( MSIVIEW *table, LPCWSTR name, UINT *n )
62 r = table->ops->get_dimensions( table, NULL, &count );
63 if( r != ERROR_SUCCESS )
66 for( i=1; i<=count; i++ )
71 r = table->ops->get_column_info( table, i, &col_name, NULL );
72 if( r != ERROR_SUCCESS )
74 x = lstrcmpW( name, col_name );
83 return ERROR_INVALID_PARAMETER;
86 UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE hdb,
87 LPCSTR szQuery, MSIHANDLE *phView)
92 TRACE("%ld %s %p\n", hdb, debugstr_a(szQuery), phView);
96 szwQuery = strdupAtoW( szQuery );
98 return ERROR_FUNCTION_FAILED;
103 r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
105 msi_free( szwQuery );
109 UINT MSI_DatabaseOpenViewW(MSIDATABASE *db,
110 LPCWSTR szQuery, MSIQUERY **pView)
115 TRACE("%s %p\n", debugstr_w(szQuery), pView);
118 return ERROR_INVALID_PARAMETER;
120 /* pre allocate a handle to hold a pointer to the view */
121 query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY),
124 return ERROR_FUNCTION_FAILED;
126 msiobj_addref( &db->hdr );
130 list_init( &query->mem );
132 r = MSI_ParseSQL( db, szQuery, &query->view, &query->mem );
133 if( r == ERROR_SUCCESS )
135 msiobj_addref( &query->hdr );
139 msiobj_release( &query->hdr );
143 UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
149 /* construct the string */
153 query = msi_alloc( size*sizeof(WCHAR) );
155 res = vsnprintfW(query, size, fmt, va);
157 if (res == -1) size *= 2;
158 else if (res >= size) size = res + 1;
162 /* perform the query */
163 r = MSI_DatabaseOpenViewW(db, query, view);
174 UINT MSI_ReverseIterateRecords( MSIQUERY *view, DWORD *count,
175 record_func func, LPVOID param )
177 MSIRECORD *rec = NULL;
178 struct rec_list *add_rec;
180 UINT r, n = 0, max = 0;
182 r = MSI_ViewExecute( view, NULL );
183 if( r != ERROR_SUCCESS )
186 list_init( &records );
191 /* reverse the query */
192 for( n = 0; (max == 0) || (n < max); n++ )
194 r = MSI_ViewFetch( view, &rec );
195 if( r != ERROR_SUCCESS )
197 if ( r == ERROR_NO_MORE_ITEMS )
203 add_rec = msi_alloc( sizeof( *add_rec ) );
208 list_add_head( &records, &add_rec->entry );
211 /* iterate over the reversed records */
213 LIST_FOR_EACH_ENTRY( add_rec, &records, struct rec_list, entry )
216 r = func( add_rec->rec, param );
218 msiobj_release( &add_rec->rec->hdr );
219 if ( r != ERROR_SUCCESS )
226 MSI_ViewClose( view );
228 while ( !list_empty( &records ) )
230 add_rec = LIST_ENTRY( list_head( &records ), struct rec_list, entry );
231 list_remove( &add_rec->entry );
238 if( r == ERROR_NO_MORE_ITEMS )
244 UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count,
245 record_func func, LPVOID param )
247 MSIRECORD *rec = NULL;
248 UINT r, n = 0, max = 0;
250 r = MSI_ViewExecute( view, NULL );
251 if( r != ERROR_SUCCESS )
257 /* iterate a query */
258 for( n = 0; (max == 0) || (n < max); n++ )
260 r = MSI_ViewFetch( view, &rec );
261 if( r != ERROR_SUCCESS )
264 r = func( rec, param );
265 msiobj_release( &rec->hdr );
266 if( r != ERROR_SUCCESS )
270 MSI_ViewClose( view );
275 if( r == ERROR_NO_MORE_ITEMS )
281 /* return a single record from a query */
282 MSIRECORD *MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... )
284 MSIRECORD *rec = NULL;
285 MSIQUERY *view = NULL;
290 /* construct the string */
294 query = msi_alloc( size*sizeof(WCHAR) );
296 res = vsnprintfW(query, size, fmt, va);
298 if (res == -1) size *= 2;
299 else if (res >= size) size = res + 1;
303 /* perform the query */
304 r = MSI_DatabaseOpenViewW(db, query, &view);
307 if( r == ERROR_SUCCESS )
309 MSI_ViewExecute( view, NULL );
310 MSI_ViewFetch( view, &rec );
311 MSI_ViewClose( view );
312 msiobj_release( &view->hdr );
317 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
318 LPCWSTR szQuery, MSIHANDLE *phView)
321 MSIQUERY *query = NULL;
324 TRACE("%s %p\n", debugstr_w(szQuery), phView);
326 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
328 return ERROR_INVALID_HANDLE;
330 ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
331 if( ret == ERROR_SUCCESS )
333 *phView = alloc_msihandle( &query->hdr );
335 ret = ERROR_NOT_ENOUGH_MEMORY;
336 msiobj_release( &query->hdr );
338 msiobj_release( &db->hdr );
343 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
347 UINT row_count = 0, col_count = 0, i, ival, ret, type;
349 TRACE("%p %p\n", query, prec );
353 return ERROR_FUNCTION_FAILED;
355 ret = view->ops->get_dimensions( view, &row_count, &col_count );
359 return ERROR_INVALID_PARAMETER;
361 if( query->row >= row_count )
362 return ERROR_NO_MORE_ITEMS;
364 rec = MSI_CreateRecord( col_count );
366 return ERROR_FUNCTION_FAILED;
368 for( i=1; i<=col_count; i++ )
370 ret = view->ops->get_column_info( view, i, NULL, &type );
373 ERR("Error getting column type for %d\n", i );
376 if (!MSITYPE_IS_BINARY(type))
378 ret = view->ops->fetch_int( view, query->row, i, &ival );
381 ERR("Error fetching data for %d\n", i );
384 if( ! (type & MSITYPE_VALID ) )
385 ERR("Invalid type!\n");
387 /* check if it's nul (0) - if so, don't set anything */
391 if( type & MSITYPE_STRING )
395 sval = MSI_makestring( query->db, ival );
396 MSI_RecordSetStringW( rec, i, sval );
401 if( (type & MSI_DATASIZEMASK) == 2 )
402 MSI_RecordSetInteger( rec, i, ival - (1<<15) );
404 MSI_RecordSetInteger( rec, i, ival - (1<<31) );
411 ret = view->ops->fetch_stream( view, query->row, i, &stm );
412 if( ( ret == ERROR_SUCCESS ) && stm )
414 MSI_RecordSetIStream( rec, i, stm );
415 IStream_Release( stm );
418 ERR("failed to get stream\n");
425 return ERROR_SUCCESS;
428 UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
431 MSIRECORD *rec = NULL;
434 TRACE("%ld %p\n", hView, record);
437 return ERROR_INVALID_PARAMETER;
440 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
442 return ERROR_INVALID_HANDLE;
443 ret = MSI_ViewFetch( query, &rec );
444 if( ret == ERROR_SUCCESS )
446 *record = alloc_msihandle( &rec->hdr );
448 ret = ERROR_NOT_ENOUGH_MEMORY;
449 msiobj_release( &rec->hdr );
451 msiobj_release( &query->hdr );
455 UINT MSI_ViewClose(MSIQUERY *query)
459 TRACE("%p\n", query );
463 return ERROR_FUNCTION_FAILED;
464 if( !view->ops->close )
465 return ERROR_FUNCTION_FAILED;
467 return view->ops->close( view );
470 UINT WINAPI MsiViewClose(MSIHANDLE hView)
475 TRACE("%ld\n", hView );
477 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
479 return ERROR_INVALID_HANDLE;
481 ret = MSI_ViewClose( query );
482 msiobj_release( &query->hdr );
486 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
490 TRACE("%p %p\n", query, rec);
494 return ERROR_FUNCTION_FAILED;
495 if( !view->ops->execute )
496 return ERROR_FUNCTION_FAILED;
499 return view->ops->execute( view, rec );
502 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
505 MSIRECORD *rec = NULL;
508 TRACE("%ld %ld\n", hView, hRec);
510 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
512 return ERROR_INVALID_HANDLE;
516 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
519 ret = ERROR_INVALID_HANDLE;
524 msiobj_lock( &rec->hdr );
525 ret = MSI_ViewExecute( query, rec );
526 msiobj_unlock( &rec->hdr );
529 msiobj_release( &query->hdr );
531 msiobj_release( &rec->hdr );
536 static UINT msi_set_record_type_string( MSIRECORD *rec, UINT field, UINT type )
538 static const WCHAR fmt[] = { '%','d',0 };
541 if (MSITYPE_IS_BINARY(type))
543 else if (type & MSITYPE_LOCALIZABLE)
545 else if (type & MSITYPE_STRING)
549 if (type & MSITYPE_NULLABLE)
552 sprintfW( &szType[1], fmt, (type&0xff) );
554 TRACE("type %04x -> %s\n", type, debugstr_w(szType) );
556 return MSI_RecordSetStringW( rec, field, szType );
559 UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec )
561 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
563 MSIVIEW *view = query->view;
567 return ERROR_FUNCTION_FAILED;
569 if( !view->ops->get_dimensions )
570 return ERROR_FUNCTION_FAILED;
572 r = view->ops->get_dimensions( view, NULL, &count );
573 if( r != ERROR_SUCCESS )
576 return ERROR_INVALID_PARAMETER;
578 rec = MSI_CreateRecord( count );
580 return ERROR_FUNCTION_FAILED;
582 for( i=0; i<count; i++ )
585 r = view->ops->get_column_info( view, i+1, &name, &type );
586 if( r != ERROR_SUCCESS )
588 if (info == MSICOLINFO_NAMES)
589 MSI_RecordSetStringW( rec, i+1, name );
591 msi_set_record_type_string( rec, i+1, type);
596 return ERROR_SUCCESS;
599 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
601 MSIQUERY *query = NULL;
602 MSIRECORD *rec = NULL;
605 TRACE("%ld %d %p\n", hView, info, hRec);
608 return ERROR_INVALID_PARAMETER;
610 if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
611 return ERROR_INVALID_PARAMETER;
613 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
615 return ERROR_INVALID_HANDLE;
617 r = MSI_ViewGetColumnInfo( query, info, &rec );
618 if ( r == ERROR_SUCCESS )
620 *hRec = alloc_msihandle( &rec->hdr );
622 r = ERROR_NOT_ENOUGH_MEMORY;
623 msiobj_release( &rec->hdr );
626 msiobj_release( &query->hdr );
631 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode,
634 MSIVIEW *view = NULL;
635 MSIQUERY *query = NULL;
636 MSIRECORD *rec = NULL;
637 UINT r = ERROR_FUNCTION_FAILED;
639 TRACE("%ld %x %ld\n", hView, eModifyMode, hRecord);
641 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
643 return ERROR_INVALID_HANDLE;
649 if( !view->ops->modify )
652 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
655 r = ERROR_INVALID_HANDLE;
659 r = view->ops->modify( view, eModifyMode, rec );
662 msiobj_release( &query->hdr );
664 msiobj_release( &rec->hdr );
669 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR szColumnNameBuffer,
672 MSIQUERY *query = NULL;
673 static const WCHAR szError[] = { 0 };
674 MSIDBERROR r = MSIDBERROR_NOERROR;
677 FIXME("%ld %p %p - returns empty error string\n",
678 handle, szColumnNameBuffer, pcchBuf );
681 return MSIDBERROR_INVALIDARG;
683 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
685 return MSIDBERROR_INVALIDARG;
687 len = lstrlenW( szError );
688 if( szColumnNameBuffer )
691 lstrcpyW( szColumnNameBuffer, szError );
693 r = MSIDBERROR_MOREDATA;
697 msiobj_release( &query->hdr );
701 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR szColumnNameBuffer,
704 static const CHAR szError[] = { 0 };
705 MSIQUERY *query = NULL;
706 MSIDBERROR r = MSIDBERROR_NOERROR;
709 FIXME("%ld %p %p - returns empty error string\n",
710 handle, szColumnNameBuffer, pcchBuf );
713 return MSIDBERROR_INVALIDARG;
715 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
717 return MSIDBERROR_INVALIDARG;
719 len = lstrlenA( szError );
720 if( szColumnNameBuffer )
723 lstrcpyA( szColumnNameBuffer, szError );
725 r = MSIDBERROR_MOREDATA;
729 msiobj_release( &query->hdr );
733 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
739 DEFINE_GUID( CLSID_MsiTransform, 0x000c1082, 0x0000, 0x0000, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
741 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
742 LPCWSTR szTransformFile, int iErrorCond )
745 IStorage *stg = NULL;
747 TRACE("%p %s %d\n", db, debugstr_w(szTransformFile), iErrorCond);
749 r = StgOpenStorage( szTransformFile, NULL,
750 STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
754 if( TRACE_ON( msi ) )
755 enum_stream_names( stg );
757 r = msi_table_apply_transform( db, stg );
759 IStorage_Release( stg );
764 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb,
765 LPCWSTR szTransformFile, int iErrorCond)
770 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
772 return ERROR_INVALID_HANDLE;
774 r = MSI_DatabaseApplyTransformW( db, szTransformFile, iErrorCond );
775 msiobj_release( &db->hdr );
779 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
780 LPCSTR szTransformFile, int iErrorCond)
785 TRACE("%ld %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
787 wstr = strdupAtoW( szTransformFile );
788 if( szTransformFile && !wstr )
789 return ERROR_NOT_ENOUGH_MEMORY;
791 ret = MsiDatabaseApplyTransformW( hdb, wstr, iErrorCond);
798 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
799 LPCSTR szTransformFile, int iReserved1, int iReserved2 )
801 FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
802 debugstr_a(szTransformFile), iReserved1, iReserved2);
803 return ERROR_CALL_NOT_IMPLEMENTED;
806 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
807 LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
809 FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
810 debugstr_w(szTransformFile), iReserved1, iReserved2);
811 return ERROR_CALL_NOT_IMPLEMENTED;
814 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
821 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
823 return ERROR_INVALID_HANDLE;
825 /* FIXME: lock the database */
827 r = MSI_CommitTables( db );
829 /* FIXME: unlock the database */
831 msiobj_release( &db->hdr );
833 if (r == ERROR_SUCCESS)
835 msi_free( db->deletefile );
836 db->deletefile = NULL;
842 struct msi_primary_key_record_info
848 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param )
850 struct msi_primary_key_record_info *info = param;
854 type = MSI_RecordGetInteger( rec, 4 );
855 if( type & MSITYPE_KEY )
860 name = MSI_RecordGetString( rec, 3 );
861 MSI_RecordSetStringW( info->rec, info->n, name );
865 return ERROR_SUCCESS;
868 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db,
869 LPCWSTR table, MSIRECORD **prec )
871 static const WCHAR sql[] = {
872 's','e','l','e','c','t',' ','*',' ',
873 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
874 'w','h','e','r','e',' ',
875 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
876 struct msi_primary_key_record_info info;
877 MSIQUERY *query = NULL;
881 r = MSI_OpenQuery( db, &query, sql, table );
882 if( r != ERROR_SUCCESS )
887 /* count the number of primary key records */
890 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
891 if( r == ERROR_SUCCESS )
893 TRACE("Found %d primary keys\n", info.n );
895 /* allocate a record and fill in the names of the tables */
896 info.rec = MSI_CreateRecord( info.n );
898 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
899 if( r == ERROR_SUCCESS )
902 msiobj_release( &info.rec->hdr );
904 msiobj_release( &query->hdr );
909 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb,
910 LPCWSTR table, MSIHANDLE* phRec )
912 MSIRECORD *rec = NULL;
916 TRACE("%ld %s %p\n", hdb, debugstr_w(table), phRec);
918 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
920 return ERROR_INVALID_HANDLE;
922 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
923 if( r == ERROR_SUCCESS )
925 *phRec = alloc_msihandle( &rec->hdr );
927 r = ERROR_NOT_ENOUGH_MEMORY;
928 msiobj_release( &rec->hdr );
930 msiobj_release( &db->hdr );
935 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
936 LPCSTR table, MSIHANDLE* phRec)
938 LPWSTR szwTable = NULL;
941 TRACE("%ld %s %p\n", hdb, debugstr_a(table), phRec);
945 szwTable = strdupAtoW( table );
947 return ERROR_OUTOFMEMORY;
949 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
950 msi_free( szwTable );
955 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA(
956 MSIHANDLE hDatabase, LPCSTR szTableName)
958 LPWSTR szwTableName = NULL;
961 TRACE("%lx %s\n", hDatabase, debugstr_a(szTableName));
965 szwTableName = strdupAtoW( szTableName );
967 return MSICONDITION_ERROR;
969 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
970 msi_free( szwTableName );
975 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(
976 MSIHANDLE hDatabase, LPCWSTR szTableName)
981 TRACE("%lx %s\n", hDatabase, debugstr_w(szTableName));
983 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
985 return MSICONDITION_ERROR;
987 r = MSI_DatabaseIsTablePersistent( db, szTableName );
989 msiobj_release( &db->hdr );