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 void MSI_CloseView( MSIOBJECTHDR *arg )
43 MSIQUERY *query = (MSIQUERY*) arg;
45 if( query->view && query->view->ops->delete )
46 query->view->ops->delete( query->view );
47 msiobj_release( &query->db->hdr );
50 UINT VIEW_find_column( MSIVIEW *table, LPWSTR name, UINT *n )
55 r = table->ops->get_dimensions( table, NULL, &count );
56 if( r != ERROR_SUCCESS )
59 for( i=1; i<=count; i++ )
64 r = table->ops->get_column_info( table, i, &col_name, NULL );
65 if( r != ERROR_SUCCESS )
67 x = lstrcmpW( name, col_name );
68 HeapFree( GetProcessHeap(), 0, col_name );
76 return ERROR_INVALID_PARAMETER;
79 UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE hdb,
80 LPCSTR szQuery, MSIHANDLE *phView)
85 TRACE("%ld %s %p\n", hdb, debugstr_a(szQuery), phView);
89 szwQuery = strdupAtoW( szQuery );
91 return ERROR_FUNCTION_FAILED;
96 r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
98 HeapFree( GetProcessHeap(), 0, szwQuery );
102 UINT MSI_DatabaseOpenViewW(MSIDATABASE *db,
103 LPCWSTR szQuery, MSIQUERY **pView)
108 TRACE("%s %p\n", debugstr_w(szQuery), pView);
111 return ERROR_INVALID_PARAMETER;
113 /* pre allocate a handle to hold a pointer to the view */
114 query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY),
117 return ERROR_FUNCTION_FAILED;
119 msiobj_addref( &db->hdr );
124 r = MSI_ParseSQL( db, szQuery, &query->view );
125 if( r == ERROR_SUCCESS )
127 msiobj_addref( &query->hdr );
131 msiobj_release( &query->hdr );
135 UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
142 /* figure out how much space we need to allocate */
144 sz = strlenW(fmt) + 1;
154 case 's': /* a string */
155 sz += strlenW(va_arg(va,LPCWSTR));
158 case 'i': /* an integer -2147483648 seems to be longest */
160 (void)va_arg(va,int);
162 case '%': /* a single % - leave it alone */
165 FIXME("Unhandled character type %c\n",*p);
171 /* construct the string */
172 szQuery = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
174 vsnprintfW(szQuery, sz, fmt, va);
177 /* perform the query */
178 rc = MSI_DatabaseOpenViewW(db, szQuery, view);
179 HeapFree(GetProcessHeap(), 0, szQuery);
183 UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count,
184 record_func func, LPVOID param )
186 MSIRECORD *rec = NULL;
187 UINT r, n = 0, max = 0;
189 r = MSI_ViewExecute( view, NULL );
190 if( r != ERROR_SUCCESS )
196 /* iterate a query */
197 for( n = 0; (max == 0) || (n < max); n++ )
199 r = MSI_ViewFetch( view, &rec );
200 if( r != ERROR_SUCCESS )
202 r = func( rec, param );
203 msiobj_release( &rec->hdr );
204 if( r != ERROR_SUCCESS )
208 MSI_ViewClose( view );
213 if( r == ERROR_NO_MORE_ITEMS )
219 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
220 LPCWSTR szQuery, MSIHANDLE *phView)
223 MSIQUERY *query = NULL;
226 TRACE("%s %p\n", debugstr_w(szQuery), phView);
228 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
230 return ERROR_INVALID_HANDLE;
232 ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
233 if( ret == ERROR_SUCCESS )
235 *phView = alloc_msihandle( &query->hdr );
236 msiobj_release( &query->hdr );
238 msiobj_release( &db->hdr );
243 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
247 UINT row_count = 0, col_count = 0, i, ival, ret, type;
249 TRACE("%p %p\n", query, prec );
253 return ERROR_FUNCTION_FAILED;
255 ret = view->ops->get_dimensions( view, &row_count, &col_count );
259 return ERROR_INVALID_PARAMETER;
261 if( query->row >= row_count )
262 return ERROR_NO_MORE_ITEMS;
264 rec = MSI_CreateRecord( col_count );
266 return ERROR_FUNCTION_FAILED;
268 for( i=1; i<=col_count; i++ )
270 ret = view->ops->get_column_info( view, i, NULL, &type );
273 ERR("Error getting column type for %d\n", i );
276 if (( type != MSITYPE_BINARY) && (type != (MSITYPE_BINARY |
279 ret = view->ops->fetch_int( view, query->row, i, &ival );
282 ERR("Error fetching data for %d\n", i );
285 if( ! (type & MSITYPE_VALID ) )
286 ERR("Invalid type!\n");
288 /* check if it's nul (0) - if so, don't set anything */
292 if( type & MSITYPE_STRING )
296 sval = MSI_makestring( query->db, ival );
297 MSI_RecordSetStringW( rec, i, sval );
298 HeapFree( GetProcessHeap(), 0, sval );
302 if( (type & MSI_DATASIZEMASK) == 2 )
303 MSI_RecordSetInteger( rec, i, ival - (1<<15) );
305 MSI_RecordSetInteger( rec, i, ival - (1<<31) );
312 ret = view->ops->fetch_stream( view, query->row, i, &stm );
313 if( ( ret == ERROR_SUCCESS ) && stm )
315 MSI_RecordSetIStream( rec, i, stm );
316 IStream_Release( stm );
319 ERR("failed to get stream\n");
326 return ERROR_SUCCESS;
329 UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
332 MSIRECORD *rec = NULL;
335 TRACE("%ld %p\n", hView, record);
337 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
339 return ERROR_INVALID_HANDLE;
340 ret = MSI_ViewFetch( query, &rec );
341 if( ret == ERROR_SUCCESS )
343 *record = alloc_msihandle( &rec->hdr );
344 msiobj_release( &rec->hdr );
346 msiobj_release( &query->hdr );
350 UINT MSI_ViewClose(MSIQUERY *query)
354 TRACE("%p\n", query );
358 return ERROR_FUNCTION_FAILED;
359 if( !view->ops->close )
360 return ERROR_FUNCTION_FAILED;
362 return view->ops->close( view );
365 UINT WINAPI MsiViewClose(MSIHANDLE hView)
370 TRACE("%ld\n", hView );
372 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
374 return ERROR_INVALID_HANDLE;
376 ret = MSI_ViewClose( query );
377 msiobj_release( &query->hdr );
381 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
385 TRACE("%p %p\n", query, rec);
389 return ERROR_FUNCTION_FAILED;
390 if( !view->ops->execute )
391 return ERROR_FUNCTION_FAILED;
394 return view->ops->execute( view, rec );
397 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
400 MSIRECORD *rec = NULL;
403 TRACE("%ld %ld\n", hView, hRec);
405 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
407 return ERROR_INVALID_HANDLE;
411 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
414 ret = ERROR_INVALID_HANDLE;
419 msiobj_lock( &rec->hdr );
420 ret = MSI_ViewExecute( query, rec );
421 msiobj_unlock( &rec->hdr );
424 msiobj_release( &query->hdr );
426 msiobj_release( &rec->hdr );
431 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
433 MSIVIEW *view = NULL;
434 MSIQUERY *query = NULL;
435 MSIRECORD *rec = NULL;
436 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
439 TRACE("%ld %d %p\n", hView, info, hRec);
441 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
443 return ERROR_INVALID_HANDLE;
449 if( !view->ops->get_dimensions )
452 r = view->ops->get_dimensions( view, NULL, &count );
457 r = ERROR_INVALID_PARAMETER;
461 rec = MSI_CreateRecord( count );
464 r = ERROR_FUNCTION_FAILED;
468 for( i=0; i<count; i++ )
471 r = view->ops->get_column_info( view, i+1, &name, &type );
472 if( r != ERROR_SUCCESS )
474 MSI_RecordSetStringW( rec, i+1, name );
475 HeapFree( GetProcessHeap(), 0, name );
478 *hRec = alloc_msihandle( &rec->hdr );
481 msiobj_release( &query->hdr );
483 msiobj_release( &rec->hdr );
488 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode,
491 MSIVIEW *view = NULL;
492 MSIQUERY *query = NULL;
493 MSIRECORD *rec = NULL;
494 UINT r = ERROR_FUNCTION_FAILED;
496 TRACE("%ld %x %ld\n", hView, eModifyMode, hRecord);
498 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
500 return ERROR_INVALID_HANDLE;
506 if( !view->ops->modify )
509 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
512 r = ERROR_INVALID_HANDLE;
516 r = view->ops->modify( view, eModifyMode, rec );
519 msiobj_release( &query->hdr );
521 msiobj_release( &rec->hdr );
526 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
527 LPCSTR szTransformFile, int iErrorCond)
529 FIXME("%ld %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
530 return ERROR_CALL_NOT_IMPLEMENTED;
533 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb,
534 LPCWSTR szTransformFile, int iErrorCond)
536 FIXME("%ld %s %d\n", hdb, debugstr_w(szTransformFile), iErrorCond);
537 return ERROR_CALL_NOT_IMPLEMENTED;
540 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
541 LPCSTR szTransformFile, int iReserved1, int iReserved2 )
543 FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
544 debugstr_a(szTransformFile), iReserved1, iReserved2);
545 return ERROR_CALL_NOT_IMPLEMENTED;
548 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
549 LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
551 FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
552 debugstr_w(szTransformFile), iReserved1, iReserved2);
553 return ERROR_CALL_NOT_IMPLEMENTED;
556 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
563 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
565 return ERROR_INVALID_HANDLE;
567 /* FIXME: lock the database */
569 r = MSI_CommitTables( db );
571 /* FIXME: unlock the database */
573 msiobj_release( &db->hdr );
578 struct msi_primary_key_record_info
584 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param )
586 struct msi_primary_key_record_info *info = param;
590 type = MSI_RecordGetInteger( rec, 4 );
591 if( type & MSITYPE_KEY )
596 name = MSI_RecordGetString( rec, 3 );
597 MSI_RecordSetStringW( info->rec, info->n, name );
601 return ERROR_SUCCESS;
604 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db,
605 LPCWSTR table, MSIRECORD **prec )
607 static const WCHAR sql[] = {
608 's','e','l','e','c','t',' ','*',' ',
609 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
610 'w','h','e','r','e',' ',
611 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
612 struct msi_primary_key_record_info info;
613 MSIQUERY *query = NULL;
617 r = MSI_OpenQuery( db, &query, sql, table );
618 if( r != ERROR_SUCCESS )
623 /* count the number of primary key records */
626 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
627 if( r == ERROR_SUCCESS )
629 TRACE("Found %ld primary keys\n", info.n );
631 /* allocate a record and fill in the names of the tables */
632 info.rec = MSI_CreateRecord( info.n );
634 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
635 if( r == ERROR_SUCCESS )
638 msiobj_release( &info.rec->hdr );
640 msiobj_release( &query->hdr );
645 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb,
646 LPCWSTR table, MSIHANDLE* phRec )
648 MSIRECORD *rec = NULL;
652 TRACE("%ld %s %p\n", hdb, debugstr_w(table), phRec);
654 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
656 return ERROR_INVALID_HANDLE;
658 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
659 if( r == ERROR_SUCCESS )
661 *phRec = alloc_msihandle( &rec->hdr );
662 msiobj_release( &rec->hdr );
664 msiobj_release( &db->hdr );
669 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
670 LPCSTR table, MSIHANDLE* phRec)
672 LPWSTR szwTable = NULL;
675 TRACE("%ld %s %p\n", hdb, debugstr_a(table), phRec);
679 szwTable = strdupAtoW( table );
681 return ERROR_OUTOFMEMORY;
683 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
684 HeapFree( GetProcessHeap(), 0, szwTable );
689 UINT WINAPI MsiDatabaseIsTablePersistentA(
690 MSIHANDLE hDatabase, LPSTR szTableName)
692 FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName));
693 return ERROR_CALL_NOT_IMPLEMENTED;
696 UINT WINAPI MsiDatabaseIsTablePersistentW(
697 MSIHANDLE hDatabase, LPWSTR szTableName)
699 FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName));
700 return ERROR_CALL_NOT_IMPLEMENTED;