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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "wine/debug.h"
29 #include "wine/unicode.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
41 static void MSI_CloseView( MSIOBJECTHDR
*arg
)
43 MSIQUERY
*query
= (MSIQUERY
*) arg
;
46 if( query
->view
&& query
->view
->ops
->delete )
47 query
->view
->ops
->delete( query
->view
);
48 msiobj_release( &query
->db
->hdr
);
50 LIST_FOR_EACH_SAFE( ptr
, t
, &query
->mem
)
56 UINT
VIEW_find_column( MSIVIEW
*table
, LPCWSTR name
, UINT
*n
)
61 r
= table
->ops
->get_dimensions( table
, NULL
, &count
);
62 if( r
!= ERROR_SUCCESS
)
65 for( i
=1; i
<=count
; i
++ )
70 r
= table
->ops
->get_column_info( table
, i
, &col_name
, NULL
);
71 if( r
!= ERROR_SUCCESS
)
73 x
= lstrcmpW( name
, col_name
);
82 return ERROR_INVALID_PARAMETER
;
85 UINT WINAPI
MsiDatabaseOpenViewA(MSIHANDLE hdb
,
86 LPCSTR szQuery
, MSIHANDLE
*phView
)
91 TRACE("%ld %s %p\n", hdb
, debugstr_a(szQuery
), phView
);
95 szwQuery
= strdupAtoW( szQuery
);
97 return ERROR_FUNCTION_FAILED
;
102 r
= MsiDatabaseOpenViewW( hdb
, szwQuery
, phView
);
104 msi_free( szwQuery
);
108 UINT
MSI_DatabaseOpenViewW(MSIDATABASE
*db
,
109 LPCWSTR szQuery
, MSIQUERY
**pView
)
114 TRACE("%s %p\n", debugstr_w(szQuery
), pView
);
117 return ERROR_INVALID_PARAMETER
;
119 /* pre allocate a handle to hold a pointer to the view */
120 query
= alloc_msiobject( MSIHANDLETYPE_VIEW
, sizeof (MSIQUERY
),
123 return ERROR_FUNCTION_FAILED
;
125 msiobj_addref( &db
->hdr
);
129 list_init( &query
->mem
);
131 r
= MSI_ParseSQL( db
, szQuery
, &query
->view
, &query
->mem
);
132 if( r
== ERROR_SUCCESS
)
134 msiobj_addref( &query
->hdr
);
138 msiobj_release( &query
->hdr
);
142 UINT
MSI_OpenQuery( MSIDATABASE
*db
, MSIQUERY
**view
, LPCWSTR fmt
, ... )
148 /* construct the string */
152 query
= msi_alloc( size
*sizeof(WCHAR
) );
154 res
= vsnprintfW(query
, size
, fmt
, va
);
156 if (res
== -1) size
*= 2;
157 else if (res
>= size
) size
= res
+ 1;
161 /* perform the query */
162 r
= MSI_DatabaseOpenViewW(db
, query
, view
);
167 UINT
MSI_IterateRecords( MSIQUERY
*view
, DWORD
*count
,
168 record_func func
, LPVOID param
)
170 MSIRECORD
*rec
= NULL
;
171 UINT r
, n
= 0, max
= 0;
173 r
= MSI_ViewExecute( view
, NULL
);
174 if( r
!= ERROR_SUCCESS
)
180 /* iterate a query */
181 for( n
= 0; (max
== 0) || (n
< max
); n
++ )
183 r
= MSI_ViewFetch( view
, &rec
);
184 if( r
!= ERROR_SUCCESS
)
187 r
= func( rec
, param
);
188 msiobj_release( &rec
->hdr
);
189 if( r
!= ERROR_SUCCESS
)
193 MSI_ViewClose( view
);
198 if( r
== ERROR_NO_MORE_ITEMS
)
204 /* return a single record from a query */
205 MSIRECORD
*MSI_QueryGetRecord( MSIDATABASE
*db
, LPCWSTR fmt
, ... )
207 MSIRECORD
*rec
= NULL
;
208 MSIQUERY
*view
= NULL
;
213 /* construct the string */
217 query
= msi_alloc( size
*sizeof(WCHAR
) );
219 res
= vsnprintfW(query
, size
, fmt
, va
);
221 if (res
== -1) size
*= 2;
222 else if (res
>= size
) size
= res
+ 1;
226 /* perform the query */
227 r
= MSI_DatabaseOpenViewW(db
, query
, &view
);
230 if( r
== ERROR_SUCCESS
)
232 MSI_ViewExecute( view
, NULL
);
233 MSI_ViewFetch( view
, &rec
);
234 MSI_ViewClose( view
);
235 msiobj_release( &view
->hdr
);
240 UINT WINAPI
MsiDatabaseOpenViewW(MSIHANDLE hdb
,
241 LPCWSTR szQuery
, MSIHANDLE
*phView
)
244 MSIQUERY
*query
= NULL
;
247 TRACE("%s %p\n", debugstr_w(szQuery
), phView
);
249 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
251 return ERROR_INVALID_HANDLE
;
253 ret
= MSI_DatabaseOpenViewW( db
, szQuery
, &query
);
254 if( ret
== ERROR_SUCCESS
)
256 *phView
= alloc_msihandle( &query
->hdr
);
257 msiobj_release( &query
->hdr
);
259 msiobj_release( &db
->hdr
);
264 UINT
MSI_ViewFetch(MSIQUERY
*query
, MSIRECORD
**prec
)
268 UINT row_count
= 0, col_count
= 0, i
, ival
, ret
, type
;
270 TRACE("%p %p\n", query
, prec
);
274 return ERROR_FUNCTION_FAILED
;
276 ret
= view
->ops
->get_dimensions( view
, &row_count
, &col_count
);
280 return ERROR_INVALID_PARAMETER
;
282 if( query
->row
>= row_count
)
283 return ERROR_NO_MORE_ITEMS
;
285 rec
= MSI_CreateRecord( col_count
);
287 return ERROR_FUNCTION_FAILED
;
289 for( i
=1; i
<=col_count
; i
++ )
291 ret
= view
->ops
->get_column_info( view
, i
, NULL
, &type
);
294 ERR("Error getting column type for %d\n", i
);
297 if (!MSITYPE_IS_BINARY(type
))
299 ret
= view
->ops
->fetch_int( view
, query
->row
, i
, &ival
);
302 ERR("Error fetching data for %d\n", i
);
305 if( ! (type
& MSITYPE_VALID
) )
306 ERR("Invalid type!\n");
308 /* check if it's nul (0) - if so, don't set anything */
312 if( type
& MSITYPE_STRING
)
316 sval
= MSI_makestring( query
->db
, ival
);
317 MSI_RecordSetStringW( rec
, i
, sval
);
322 if( (type
& MSI_DATASIZEMASK
) == 2 )
323 MSI_RecordSetInteger( rec
, i
, ival
- (1<<15) );
325 MSI_RecordSetInteger( rec
, i
, ival
- (1<<31) );
332 ret
= view
->ops
->fetch_stream( view
, query
->row
, i
, &stm
);
333 if( ( ret
== ERROR_SUCCESS
) && stm
)
335 MSI_RecordSetIStream( rec
, i
, stm
);
336 IStream_Release( stm
);
339 ERR("failed to get stream\n");
346 return ERROR_SUCCESS
;
349 UINT WINAPI
MsiViewFetch(MSIHANDLE hView
, MSIHANDLE
*record
)
352 MSIRECORD
*rec
= NULL
;
355 TRACE("%ld %p\n", hView
, record
);
357 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
359 return ERROR_INVALID_HANDLE
;
360 ret
= MSI_ViewFetch( query
, &rec
);
361 if( ret
== ERROR_SUCCESS
)
363 *record
= alloc_msihandle( &rec
->hdr
);
364 msiobj_release( &rec
->hdr
);
366 msiobj_release( &query
->hdr
);
370 UINT
MSI_ViewClose(MSIQUERY
*query
)
374 TRACE("%p\n", query
);
378 return ERROR_FUNCTION_FAILED
;
379 if( !view
->ops
->close
)
380 return ERROR_FUNCTION_FAILED
;
382 return view
->ops
->close( view
);
385 UINT WINAPI
MsiViewClose(MSIHANDLE hView
)
390 TRACE("%ld\n", hView
);
392 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
394 return ERROR_INVALID_HANDLE
;
396 ret
= MSI_ViewClose( query
);
397 msiobj_release( &query
->hdr
);
401 UINT
MSI_ViewExecute(MSIQUERY
*query
, MSIRECORD
*rec
)
405 TRACE("%p %p\n", query
, rec
);
409 return ERROR_FUNCTION_FAILED
;
410 if( !view
->ops
->execute
)
411 return ERROR_FUNCTION_FAILED
;
414 return view
->ops
->execute( view
, rec
);
417 UINT WINAPI
MsiViewExecute(MSIHANDLE hView
, MSIHANDLE hRec
)
420 MSIRECORD
*rec
= NULL
;
423 TRACE("%ld %ld\n", hView
, hRec
);
425 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
427 return ERROR_INVALID_HANDLE
;
431 rec
= msihandle2msiinfo( hRec
, MSIHANDLETYPE_RECORD
);
434 ret
= ERROR_INVALID_HANDLE
;
439 msiobj_lock( &rec
->hdr
);
440 ret
= MSI_ViewExecute( query
, rec
);
441 msiobj_unlock( &rec
->hdr
);
444 msiobj_release( &query
->hdr
);
446 msiobj_release( &rec
->hdr
);
451 static UINT
msi_set_record_type_string( MSIRECORD
*rec
, UINT field
, UINT type
)
453 static const WCHAR fmt
[] = { '%','d',0 };
456 if (MSITYPE_IS_BINARY(type
))
458 else if (type
& MSITYPE_LOCALIZABLE
)
460 else if (type
& MSITYPE_STRING
)
464 if (type
& MSITYPE_NULLABLE
)
467 sprintfW( &szType
[1], fmt
, (type
&0xff) );
469 TRACE("type %04x -> %s\n", type
, debugstr_w(szType
) );
471 return MSI_RecordSetStringW( rec
, field
, szType
);
474 UINT WINAPI
MsiViewGetColumnInfo(MSIHANDLE hView
, MSICOLINFO info
, MSIHANDLE
*hRec
)
476 MSIVIEW
*view
= NULL
;
477 MSIQUERY
*query
= NULL
;
478 MSIRECORD
*rec
= NULL
;
479 UINT r
= ERROR_FUNCTION_FAILED
, i
, count
= 0, type
;
482 TRACE("%ld %d %p\n", hView
, info
, hRec
);
485 return ERROR_INVALID_PARAMETER
;
487 if( info
!= MSICOLINFO_NAMES
&& info
!= MSICOLINFO_TYPES
)
488 return ERROR_INVALID_PARAMETER
;
490 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
492 return ERROR_INVALID_HANDLE
;
498 if( !view
->ops
->get_dimensions
)
501 r
= view
->ops
->get_dimensions( view
, NULL
, &count
);
506 r
= ERROR_INVALID_PARAMETER
;
510 rec
= MSI_CreateRecord( count
);
513 r
= ERROR_FUNCTION_FAILED
;
517 for( i
=0; i
<count
; i
++ )
520 r
= view
->ops
->get_column_info( view
, i
+1, &name
, &type
);
521 if( r
!= ERROR_SUCCESS
)
523 if (info
== MSICOLINFO_NAMES
)
524 MSI_RecordSetStringW( rec
, i
+1, name
);
526 msi_set_record_type_string( rec
, i
+1, type
);
530 *hRec
= alloc_msihandle( &rec
->hdr
);
533 msiobj_release( &query
->hdr
);
535 msiobj_release( &rec
->hdr
);
540 UINT WINAPI
MsiViewModify( MSIHANDLE hView
, MSIMODIFY eModifyMode
,
543 MSIVIEW
*view
= NULL
;
544 MSIQUERY
*query
= NULL
;
545 MSIRECORD
*rec
= NULL
;
546 UINT r
= ERROR_FUNCTION_FAILED
;
548 TRACE("%ld %x %ld\n", hView
, eModifyMode
, hRecord
);
550 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
552 return ERROR_INVALID_HANDLE
;
558 if( !view
->ops
->modify
)
561 rec
= msihandle2msiinfo( hRecord
, MSIHANDLETYPE_RECORD
);
564 r
= ERROR_INVALID_HANDLE
;
568 r
= view
->ops
->modify( view
, eModifyMode
, rec
);
571 msiobj_release( &query
->hdr
);
573 msiobj_release( &rec
->hdr
);
578 MSIDBERROR WINAPI
MsiViewGetErrorW( MSIHANDLE handle
, LPWSTR szColumnNameBuffer
,
581 MSIQUERY
*query
= NULL
;
582 static const WCHAR szError
[] = { 0 };
583 MSIDBERROR r
= MSIDBERROR_NOERROR
;
586 FIXME("%ld %p %p - returns empty error string\n",
587 handle
, szColumnNameBuffer
, pcchBuf
);
590 return MSIDBERROR_INVALIDARG
;
592 query
= msihandle2msiinfo( handle
, MSIHANDLETYPE_VIEW
);
594 return MSIDBERROR_INVALIDARG
;
596 len
= lstrlenW( szError
);
597 if( szColumnNameBuffer
)
600 lstrcpyW( szColumnNameBuffer
, szError
);
602 r
= MSIDBERROR_MOREDATA
;
606 msiobj_release( &query
->hdr
);
610 MSIDBERROR WINAPI
MsiViewGetErrorA( MSIHANDLE handle
, LPSTR szColumnNameBuffer
,
613 static const CHAR szError
[] = { 0 };
614 MSIQUERY
*query
= NULL
;
615 MSIDBERROR r
= MSIDBERROR_NOERROR
;
618 FIXME("%ld %p %p - returns empty error string\n",
619 handle
, szColumnNameBuffer
, pcchBuf
);
622 return MSIDBERROR_INVALIDARG
;
624 query
= msihandle2msiinfo( handle
, MSIHANDLETYPE_VIEW
);
626 return MSIDBERROR_INVALIDARG
;
628 len
= lstrlenA( szError
);
629 if( szColumnNameBuffer
)
632 lstrcpyA( szColumnNameBuffer
, szError
);
634 r
= MSIDBERROR_MOREDATA
;
638 msiobj_release( &query
->hdr
);
642 MSIHANDLE WINAPI
MsiGetLastErrorRecord( void )
648 DEFINE_GUID( CLSID_MsiTransform
, 0x000c1082, 0x0000, 0x0000, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
650 UINT
MSI_DatabaseApplyTransformW( MSIDATABASE
*db
,
651 LPCWSTR szTransformFile
, int iErrorCond
)
654 IStorage
*stg
= NULL
;
656 TRACE("%p %s %d\n", db
, debugstr_w(szTransformFile
), iErrorCond
);
658 r
= StgOpenStorage( szTransformFile
, NULL
,
659 STGM_DIRECT
|STGM_READ
|STGM_SHARE_DENY_WRITE
, NULL
, 0, &stg
);
663 if( TRACE_ON( msi
) )
664 enum_stream_names( stg
);
666 r
= msi_table_apply_transform( db
, stg
);
668 IStorage_Release( stg
);
673 UINT WINAPI
MsiDatabaseApplyTransformW( MSIHANDLE hdb
,
674 LPCWSTR szTransformFile
, int iErrorCond
)
679 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
681 return ERROR_INVALID_HANDLE
;
683 r
= MSI_DatabaseApplyTransformW( db
, szTransformFile
, iErrorCond
);
684 msiobj_release( &db
->hdr
);
688 UINT WINAPI
MsiDatabaseApplyTransformA( MSIHANDLE hdb
,
689 LPCSTR szTransformFile
, int iErrorCond
)
694 TRACE("%ld %s %d\n", hdb
, debugstr_a(szTransformFile
), iErrorCond
);
696 wstr
= strdupAtoW( szTransformFile
);
697 if( szTransformFile
&& !wstr
)
698 return ERROR_NOT_ENOUGH_MEMORY
;
700 ret
= MsiDatabaseApplyTransformW( hdb
, wstr
, iErrorCond
);
707 UINT WINAPI
MsiDatabaseGenerateTransformA( MSIHANDLE hdb
, MSIHANDLE hdbref
,
708 LPCSTR szTransformFile
, int iReserved1
, int iReserved2
)
710 FIXME("%ld %ld %s %d %d\n", hdb
, hdbref
,
711 debugstr_a(szTransformFile
), iReserved1
, iReserved2
);
712 return ERROR_CALL_NOT_IMPLEMENTED
;
715 UINT WINAPI
MsiDatabaseGenerateTransformW( MSIHANDLE hdb
, MSIHANDLE hdbref
,
716 LPCWSTR szTransformFile
, int iReserved1
, int iReserved2
)
718 FIXME("%ld %ld %s %d %d\n", hdb
, hdbref
,
719 debugstr_w(szTransformFile
), iReserved1
, iReserved2
);
720 return ERROR_CALL_NOT_IMPLEMENTED
;
723 UINT WINAPI
MsiDatabaseCommit( MSIHANDLE hdb
)
730 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
732 return ERROR_INVALID_HANDLE
;
734 /* FIXME: lock the database */
736 r
= MSI_CommitTables( db
);
738 /* FIXME: unlock the database */
740 msiobj_release( &db
->hdr
);
745 struct msi_primary_key_record_info
751 static UINT
msi_primary_key_iterator( MSIRECORD
*rec
, LPVOID param
)
753 struct msi_primary_key_record_info
*info
= param
;
757 type
= MSI_RecordGetInteger( rec
, 4 );
758 if( type
& MSITYPE_KEY
)
763 name
= MSI_RecordGetString( rec
, 3 );
764 MSI_RecordSetStringW( info
->rec
, info
->n
, name
);
768 return ERROR_SUCCESS
;
771 UINT
MSI_DatabaseGetPrimaryKeys( MSIDATABASE
*db
,
772 LPCWSTR table
, MSIRECORD
**prec
)
774 static const WCHAR sql
[] = {
775 's','e','l','e','c','t',' ','*',' ',
776 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
777 'w','h','e','r','e',' ',
778 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
779 struct msi_primary_key_record_info info
;
780 MSIQUERY
*query
= NULL
;
784 r
= MSI_OpenQuery( db
, &query
, sql
, table
);
785 if( r
!= ERROR_SUCCESS
)
790 /* count the number of primary key records */
793 r
= MSI_IterateRecords( query
, 0, msi_primary_key_iterator
, &info
);
794 if( r
== ERROR_SUCCESS
)
796 TRACE("Found %ld primary keys\n", info
.n
);
798 /* allocate a record and fill in the names of the tables */
799 info
.rec
= MSI_CreateRecord( info
.n
);
801 r
= MSI_IterateRecords( query
, 0, msi_primary_key_iterator
, &info
);
802 if( r
== ERROR_SUCCESS
)
805 msiobj_release( &info
.rec
->hdr
);
807 msiobj_release( &query
->hdr
);
812 UINT WINAPI
MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb
,
813 LPCWSTR table
, MSIHANDLE
* phRec
)
815 MSIRECORD
*rec
= NULL
;
819 TRACE("%ld %s %p\n", hdb
, debugstr_w(table
), phRec
);
821 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
823 return ERROR_INVALID_HANDLE
;
825 r
= MSI_DatabaseGetPrimaryKeys( db
, table
, &rec
);
826 if( r
== ERROR_SUCCESS
)
828 *phRec
= alloc_msihandle( &rec
->hdr
);
829 msiobj_release( &rec
->hdr
);
831 msiobj_release( &db
->hdr
);
836 UINT WINAPI
MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb
,
837 LPCSTR table
, MSIHANDLE
* phRec
)
839 LPWSTR szwTable
= NULL
;
842 TRACE("%ld %s %p\n", hdb
, debugstr_a(table
), phRec
);
846 szwTable
= strdupAtoW( table
);
848 return ERROR_OUTOFMEMORY
;
850 r
= MsiDatabaseGetPrimaryKeysW( hdb
, szwTable
, phRec
);
851 msi_free( szwTable
);
856 UINT WINAPI
MsiDatabaseIsTablePersistentA(
857 MSIHANDLE hDatabase
, LPSTR szTableName
)
859 FIXME("%lx %s\n", hDatabase
, debugstr_a(szTableName
));
860 return ERROR_CALL_NOT_IMPLEMENTED
;
863 UINT WINAPI
MsiDatabaseIsTablePersistentW(
864 MSIHANDLE hDatabase
, LPWSTR szTableName
)
866 FIXME("%lx %s\n", hDatabase
, debugstr_w(szTableName
));
867 return ERROR_CALL_NOT_IMPLEMENTED
;