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
)
52 HeapFree( GetProcessHeap(), 0, ptr
);
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
);
74 HeapFree( GetProcessHeap(), 0, 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 HeapFree( GetProcessHeap(), 0, 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 static UINT
MSI_OpenQueryV( MSIDATABASE
*db
, MSIQUERY
**view
,
143 LPCWSTR fmt
, va_list args
)
150 /* figure out how much space we need to allocate */
152 sz
= lstrlenW(fmt
) + 1;
162 case 's': /* a string */
163 sz
+= lstrlenW(va_arg(va
,LPCWSTR
));
166 case 'i': /* an integer -2147483648 seems to be longest */
168 (void)va_arg(va
,int);
170 case '%': /* a single % - leave it alone */
173 FIXME("Unhandled character type %c\n",*p
);
178 /* construct the string */
179 szQuery
= HeapAlloc(GetProcessHeap(), 0, sz
*sizeof(WCHAR
));
181 vsnprintfW(szQuery
, sz
, fmt
, va
);
183 /* perform the query */
184 rc
= MSI_DatabaseOpenViewW(db
, szQuery
, view
);
185 HeapFree(GetProcessHeap(), 0, szQuery
);
189 UINT
MSI_OpenQuery( MSIDATABASE
*db
, MSIQUERY
**view
, LPCWSTR fmt
, ... )
195 r
= MSI_OpenQueryV( db
, view
, fmt
, va
);
201 UINT
MSI_IterateRecords( MSIQUERY
*view
, DWORD
*count
,
202 record_func func
, LPVOID param
)
204 MSIRECORD
*rec
= NULL
;
205 UINT r
, n
= 0, max
= 0;
207 r
= MSI_ViewExecute( view
, NULL
);
208 if( r
!= ERROR_SUCCESS
)
214 /* iterate a query */
215 for( n
= 0; (max
== 0) || (n
< max
); n
++ )
217 r
= MSI_ViewFetch( view
, &rec
);
218 if( r
!= ERROR_SUCCESS
)
220 r
= func( rec
, param
);
221 msiobj_release( &rec
->hdr
);
222 if( r
!= ERROR_SUCCESS
)
226 MSI_ViewClose( view
);
231 if( r
== ERROR_NO_MORE_ITEMS
)
237 /* return a single record from a query */
238 MSIRECORD
*MSI_QueryGetRecord( MSIDATABASE
*db
, LPCWSTR fmt
, ... )
240 MSIRECORD
*rec
= NULL
;
241 MSIQUERY
*view
= NULL
;
246 r
= MSI_OpenQueryV( db
, &view
, fmt
, va
);
249 if( r
== ERROR_SUCCESS
)
251 MSI_ViewExecute( view
, NULL
);
252 MSI_ViewFetch( view
, &rec
);
253 MSI_ViewClose( view
);
254 msiobj_release( &view
->hdr
);
259 UINT WINAPI
MsiDatabaseOpenViewW(MSIHANDLE hdb
,
260 LPCWSTR szQuery
, MSIHANDLE
*phView
)
263 MSIQUERY
*query
= NULL
;
266 TRACE("%s %p\n", debugstr_w(szQuery
), phView
);
268 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
270 return ERROR_INVALID_HANDLE
;
272 ret
= MSI_DatabaseOpenViewW( db
, szQuery
, &query
);
273 if( ret
== ERROR_SUCCESS
)
275 *phView
= alloc_msihandle( &query
->hdr
);
276 msiobj_release( &query
->hdr
);
278 msiobj_release( &db
->hdr
);
283 UINT
MSI_ViewFetch(MSIQUERY
*query
, MSIRECORD
**prec
)
287 UINT row_count
= 0, col_count
= 0, i
, ival
, ret
, type
;
289 TRACE("%p %p\n", query
, prec
);
293 return ERROR_FUNCTION_FAILED
;
295 ret
= view
->ops
->get_dimensions( view
, &row_count
, &col_count
);
299 return ERROR_INVALID_PARAMETER
;
301 if( query
->row
>= row_count
)
302 return ERROR_NO_MORE_ITEMS
;
304 rec
= MSI_CreateRecord( col_count
);
306 return ERROR_FUNCTION_FAILED
;
308 for( i
=1; i
<=col_count
; i
++ )
310 ret
= view
->ops
->get_column_info( view
, i
, NULL
, &type
);
313 ERR("Error getting column type for %d\n", i
);
316 if (( type
!= MSITYPE_BINARY
) && (type
!= (MSITYPE_BINARY
|
319 ret
= view
->ops
->fetch_int( view
, query
->row
, i
, &ival
);
322 ERR("Error fetching data for %d\n", i
);
325 if( ! (type
& MSITYPE_VALID
) )
326 ERR("Invalid type!\n");
328 /* check if it's nul (0) - if so, don't set anything */
332 if( type
& MSITYPE_STRING
)
336 sval
= MSI_makestring( query
->db
, ival
);
337 MSI_RecordSetStringW( rec
, i
, sval
);
338 HeapFree( GetProcessHeap(), 0, sval
);
342 if( (type
& MSI_DATASIZEMASK
) == 2 )
343 MSI_RecordSetInteger( rec
, i
, ival
- (1<<15) );
345 MSI_RecordSetInteger( rec
, i
, ival
- (1<<31) );
352 ret
= view
->ops
->fetch_stream( view
, query
->row
, i
, &stm
);
353 if( ( ret
== ERROR_SUCCESS
) && stm
)
355 MSI_RecordSetIStream( rec
, i
, stm
);
356 IStream_Release( stm
);
359 ERR("failed to get stream\n");
366 return ERROR_SUCCESS
;
369 UINT WINAPI
MsiViewFetch(MSIHANDLE hView
, MSIHANDLE
*record
)
372 MSIRECORD
*rec
= NULL
;
375 TRACE("%ld %p\n", hView
, record
);
377 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
379 return ERROR_INVALID_HANDLE
;
380 ret
= MSI_ViewFetch( query
, &rec
);
381 if( ret
== ERROR_SUCCESS
)
383 *record
= alloc_msihandle( &rec
->hdr
);
384 msiobj_release( &rec
->hdr
);
386 msiobj_release( &query
->hdr
);
390 UINT
MSI_ViewClose(MSIQUERY
*query
)
394 TRACE("%p\n", query
);
398 return ERROR_FUNCTION_FAILED
;
399 if( !view
->ops
->close
)
400 return ERROR_FUNCTION_FAILED
;
402 return view
->ops
->close( view
);
405 UINT WINAPI
MsiViewClose(MSIHANDLE hView
)
410 TRACE("%ld\n", hView
);
412 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
414 return ERROR_INVALID_HANDLE
;
416 ret
= MSI_ViewClose( query
);
417 msiobj_release( &query
->hdr
);
421 UINT
MSI_ViewExecute(MSIQUERY
*query
, MSIRECORD
*rec
)
425 TRACE("%p %p\n", query
, rec
);
429 return ERROR_FUNCTION_FAILED
;
430 if( !view
->ops
->execute
)
431 return ERROR_FUNCTION_FAILED
;
434 return view
->ops
->execute( view
, rec
);
437 UINT WINAPI
MsiViewExecute(MSIHANDLE hView
, MSIHANDLE hRec
)
440 MSIRECORD
*rec
= NULL
;
443 TRACE("%ld %ld\n", hView
, hRec
);
445 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
447 return ERROR_INVALID_HANDLE
;
451 rec
= msihandle2msiinfo( hRec
, MSIHANDLETYPE_RECORD
);
454 ret
= ERROR_INVALID_HANDLE
;
459 msiobj_lock( &rec
->hdr
);
460 ret
= MSI_ViewExecute( query
, rec
);
461 msiobj_unlock( &rec
->hdr
);
464 msiobj_release( &query
->hdr
);
466 msiobj_release( &rec
->hdr
);
471 UINT WINAPI
MsiViewGetColumnInfo(MSIHANDLE hView
, MSICOLINFO info
, MSIHANDLE
*hRec
)
473 MSIVIEW
*view
= NULL
;
474 MSIQUERY
*query
= NULL
;
475 MSIRECORD
*rec
= NULL
;
476 UINT r
= ERROR_FUNCTION_FAILED
, i
, count
= 0, type
;
479 TRACE("%ld %d %p\n", hView
, info
, hRec
);
481 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
483 return ERROR_INVALID_HANDLE
;
489 if( !view
->ops
->get_dimensions
)
492 r
= view
->ops
->get_dimensions( view
, NULL
, &count
);
497 r
= ERROR_INVALID_PARAMETER
;
501 rec
= MSI_CreateRecord( count
);
504 r
= ERROR_FUNCTION_FAILED
;
508 for( i
=0; i
<count
; i
++ )
511 r
= view
->ops
->get_column_info( view
, i
+1, &name
, &type
);
512 if( r
!= ERROR_SUCCESS
)
514 MSI_RecordSetStringW( rec
, i
+1, name
);
515 HeapFree( GetProcessHeap(), 0, name
);
518 *hRec
= alloc_msihandle( &rec
->hdr
);
521 msiobj_release( &query
->hdr
);
523 msiobj_release( &rec
->hdr
);
528 UINT WINAPI
MsiViewModify( MSIHANDLE hView
, MSIMODIFY eModifyMode
,
531 MSIVIEW
*view
= NULL
;
532 MSIQUERY
*query
= NULL
;
533 MSIRECORD
*rec
= NULL
;
534 UINT r
= ERROR_FUNCTION_FAILED
;
536 TRACE("%ld %x %ld\n", hView
, eModifyMode
, hRecord
);
538 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
540 return ERROR_INVALID_HANDLE
;
546 if( !view
->ops
->modify
)
549 rec
= msihandle2msiinfo( hRecord
, MSIHANDLETYPE_RECORD
);
552 r
= ERROR_INVALID_HANDLE
;
556 r
= view
->ops
->modify( view
, eModifyMode
, rec
);
559 msiobj_release( &query
->hdr
);
561 msiobj_release( &rec
->hdr
);
566 UINT WINAPI
MsiViewGetErrorW( MSIHANDLE handle
, LPWSTR szColumnNameBuffer
,
569 MSIQUERY
*query
= NULL
;
571 FIXME("%ld %p %p\n", handle
, szColumnNameBuffer
, pcchBuf
);
574 return MSIDBERROR_INVALIDARG
;
576 query
= msihandle2msiinfo( handle
, MSIHANDLETYPE_VIEW
);
578 return MSIDBERROR_INVALIDARG
;
580 msiobj_release( &query
->hdr
);
581 return MSIDBERROR_NOERROR
;
584 UINT WINAPI
MsiViewGetErrorA( MSIHANDLE handle
, LPSTR szColumnNameBuffer
,
587 MSIQUERY
*query
= NULL
;
589 FIXME("%ld %p %p\n", handle
, szColumnNameBuffer
, pcchBuf
);
592 return MSIDBERROR_INVALIDARG
;
594 query
= msihandle2msiinfo( handle
, MSIHANDLETYPE_VIEW
);
596 return MSIDBERROR_INVALIDARG
;
598 msiobj_release( &query
->hdr
);
599 return MSIDBERROR_NOERROR
;
602 UINT WINAPI
MsiDatabaseApplyTransformA( MSIHANDLE hdb
,
603 LPCSTR szTransformFile
, int iErrorCond
)
605 FIXME("%ld %s %d\n", hdb
, debugstr_a(szTransformFile
), iErrorCond
);
606 return ERROR_CALL_NOT_IMPLEMENTED
;
609 UINT WINAPI
MsiDatabaseApplyTransformW( MSIHANDLE hdb
,
610 LPCWSTR szTransformFile
, int iErrorCond
)
612 FIXME("%ld %s %d\n", hdb
, debugstr_w(szTransformFile
), iErrorCond
);
613 return ERROR_CALL_NOT_IMPLEMENTED
;
616 UINT WINAPI
MsiDatabaseGenerateTransformA( MSIHANDLE hdb
, MSIHANDLE hdbref
,
617 LPCSTR szTransformFile
, int iReserved1
, int iReserved2
)
619 FIXME("%ld %ld %s %d %d\n", hdb
, hdbref
,
620 debugstr_a(szTransformFile
), iReserved1
, iReserved2
);
621 return ERROR_CALL_NOT_IMPLEMENTED
;
624 UINT WINAPI
MsiDatabaseGenerateTransformW( MSIHANDLE hdb
, MSIHANDLE hdbref
,
625 LPCWSTR szTransformFile
, int iReserved1
, int iReserved2
)
627 FIXME("%ld %ld %s %d %d\n", hdb
, hdbref
,
628 debugstr_w(szTransformFile
), iReserved1
, iReserved2
);
629 return ERROR_CALL_NOT_IMPLEMENTED
;
632 UINT WINAPI
MsiDatabaseCommit( MSIHANDLE hdb
)
639 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
641 return ERROR_INVALID_HANDLE
;
643 /* FIXME: lock the database */
645 r
= MSI_CommitTables( db
);
647 /* FIXME: unlock the database */
649 msiobj_release( &db
->hdr
);
654 struct msi_primary_key_record_info
660 static UINT
msi_primary_key_iterator( MSIRECORD
*rec
, LPVOID param
)
662 struct msi_primary_key_record_info
*info
= param
;
666 type
= MSI_RecordGetInteger( rec
, 4 );
667 if( type
& MSITYPE_KEY
)
672 name
= MSI_RecordGetString( rec
, 3 );
673 MSI_RecordSetStringW( info
->rec
, info
->n
, name
);
677 return ERROR_SUCCESS
;
680 UINT
MSI_DatabaseGetPrimaryKeys( MSIDATABASE
*db
,
681 LPCWSTR table
, MSIRECORD
**prec
)
683 static const WCHAR sql
[] = {
684 's','e','l','e','c','t',' ','*',' ',
685 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
686 'w','h','e','r','e',' ',
687 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
688 struct msi_primary_key_record_info info
;
689 MSIQUERY
*query
= NULL
;
693 r
= MSI_OpenQuery( db
, &query
, sql
, table
);
694 if( r
!= ERROR_SUCCESS
)
699 /* count the number of primary key records */
702 r
= MSI_IterateRecords( query
, 0, msi_primary_key_iterator
, &info
);
703 if( r
== ERROR_SUCCESS
)
705 TRACE("Found %ld primary keys\n", info
.n
);
707 /* allocate a record and fill in the names of the tables */
708 info
.rec
= MSI_CreateRecord( info
.n
);
710 r
= MSI_IterateRecords( query
, 0, msi_primary_key_iterator
, &info
);
711 if( r
== ERROR_SUCCESS
)
714 msiobj_release( &info
.rec
->hdr
);
716 msiobj_release( &query
->hdr
);
721 UINT WINAPI
MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb
,
722 LPCWSTR table
, MSIHANDLE
* phRec
)
724 MSIRECORD
*rec
= NULL
;
728 TRACE("%ld %s %p\n", hdb
, debugstr_w(table
), phRec
);
730 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
732 return ERROR_INVALID_HANDLE
;
734 r
= MSI_DatabaseGetPrimaryKeys( db
, table
, &rec
);
735 if( r
== ERROR_SUCCESS
)
737 *phRec
= alloc_msihandle( &rec
->hdr
);
738 msiobj_release( &rec
->hdr
);
740 msiobj_release( &db
->hdr
);
745 UINT WINAPI
MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb
,
746 LPCSTR table
, MSIHANDLE
* phRec
)
748 LPWSTR szwTable
= NULL
;
751 TRACE("%ld %s %p\n", hdb
, debugstr_a(table
), phRec
);
755 szwTable
= strdupAtoW( table
);
757 return ERROR_OUTOFMEMORY
;
759 r
= MsiDatabaseGetPrimaryKeysW( hdb
, szwTable
, phRec
);
760 HeapFree( GetProcessHeap(), 0, szwTable
);
765 UINT WINAPI
MsiDatabaseIsTablePersistentA(
766 MSIHANDLE hDatabase
, LPSTR szTableName
)
768 FIXME("%lx %s\n", hDatabase
, debugstr_a(szTableName
));
769 return ERROR_CALL_NOT_IMPLEMENTED
;
772 UINT WINAPI
MsiDatabaseIsTablePersistentW(
773 MSIHANDLE hDatabase
, LPWSTR szTableName
)
775 FIXME("%lx %s\n", hDatabase
, debugstr_w(szTableName
));
776 return ERROR_CALL_NOT_IMPLEMENTED
;