/* * Implementation of the Microsoft Installer (msi.dll) * * Copyright 2002-2004 Mike McCormack for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "windef.h" #include "winbase.h" #include "winerror.h" #include "wine/debug.h" #include "wine/unicode.h" #include "msi.h" #include "msiquery.h" #include "objbase.h" #include "objidl.h" #include "msipriv.h" #include "winnls.h" #include "query.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); #if 0 typedef struct tagMSIQUERY { MSIOBJECTHDR hdr; MSIVIEW *view; UINT row; MSIDATABASE *db; } MSIQUERY; #endif UINT WINAPI MsiDatabaseIsTablePersistentA( MSIHANDLE hDatabase, LPSTR szTableName) { FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName)); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiDatabaseIsTablePersistentW( MSIHANDLE hDatabase, LPWSTR szTableName) { FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName)); return ERROR_CALL_NOT_IMPLEMENTED; } void MSI_CloseView( MSIOBJECTHDR *arg ) { MSIQUERY *query = (MSIQUERY*) arg; if( query->view && query->view->ops->delete ) query->view->ops->delete( query->view ); msiobj_release( &query->db->hdr ); } UINT VIEW_find_column( MSIVIEW *table, LPWSTR name, UINT *n ) { LPWSTR col_name; UINT i, count, r; r = table->ops->get_dimensions( table, NULL, &count ); if( r != ERROR_SUCCESS ) return r; for( i=1; i<=count; i++ ) { INT x; col_name = NULL; r = table->ops->get_column_info( table, i, &col_name, NULL ); if( r != ERROR_SUCCESS ) return r; x = lstrcmpW( name, col_name ); HeapFree( GetProcessHeap(), 0, col_name ); if( !x ) { *n = i; return ERROR_SUCCESS; } } return ERROR_INVALID_PARAMETER; } UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE hdb, LPCSTR szQuery, MSIHANDLE *phView) { UINT r; LPWSTR szwQuery; TRACE("%ld %s %p\n", hdb, debugstr_a(szQuery), phView); if( szQuery ) { UINT len = MultiByteToWideChar( CP_ACP, 0, szQuery, -1, NULL, 0 ); szwQuery = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); if( !szwQuery ) return ERROR_FUNCTION_FAILED; MultiByteToWideChar( CP_ACP, 0, szQuery, -1, szwQuery, len ); } else szwQuery = NULL; r = MsiDatabaseOpenViewW( hdb, szwQuery, phView); return r; } UINT MSI_DatabaseOpenViewW(MSIDATABASE *db, LPCWSTR szQuery, MSIQUERY **pView) { MSIQUERY *query; UINT r; TRACE("%s %p\n", debugstr_w(szQuery), pView); if( !szQuery) return ERROR_INVALID_PARAMETER; /* pre allocate a handle to hold a pointer to the view */ query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY), MSI_CloseView ); if( !query ) return ERROR_FUNCTION_FAILED; msiobj_addref( &db->hdr ); query->row = 0; query->db = db; query->view = NULL; r = MSI_ParseSQL( db, szQuery, &query->view ); if( r == ERROR_SUCCESS ) { msiobj_addref( &query->hdr ); *pView = query; } msiobj_release( &query->hdr ); return r; } UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb, LPCWSTR szQuery, MSIHANDLE *phView) { MSIDATABASE *db; MSIQUERY *query = NULL; UINT ret; TRACE("%s %p\n", debugstr_w(szQuery), phView); db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); if( !db ) return ERROR_INVALID_HANDLE; ret = MSI_DatabaseOpenViewW( db, szQuery, &query ); if( ret == ERROR_SUCCESS ) { *phView = alloc_msihandle( &query->hdr ); msiobj_release( &query->hdr ); } msiobj_release( &db->hdr ); return ret; } UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec) { MSIVIEW *view; MSIRECORD *rec; UINT row_count = 0, col_count = 0, i, ival, ret, type; TRACE("%p %p\n", query, prec ); view = query->view; if( !view ) return ERROR_FUNCTION_FAILED; ret = view->ops->get_dimensions( view, &row_count, &col_count ); if( ret ) return ret; if( !col_count ) return ERROR_INVALID_PARAMETER; if( query->row >= row_count ) return ERROR_NO_MORE_ITEMS; rec = MSI_CreateRecord( col_count ); if( !rec ) return ERROR_FUNCTION_FAILED; for( i=1; i<=col_count; i++ ) { ret = view->ops->get_column_info( view, i, NULL, &type ); if( ret ) { ERR("Error getting column type for %d\n", i ); continue; } if (( type != MSITYPE_BINARY) && (type != (MSITYPE_BINARY | MSITYPE_NULLABLE))) { ret = view->ops->fetch_int( view, query->row, i, &ival ); if( ret ) { ERR("Error fetching data for %d\n", i ); continue; } if( ! (type & MSITYPE_VALID ) ) ERR("Invalid type!\n"); /* check if it's nul (0) - if so, don't set anything */ if( !ival ) continue; if( type & MSITYPE_STRING ) { LPWSTR sval; sval = MSI_makestring( query->db, ival ); MSI_RecordSetStringW( rec, i, sval ); HeapFree( GetProcessHeap(), 0, sval ); } else { if( (type & MSI_DATASIZEMASK) == 2 ) MSI_RecordSetInteger( rec, i, ival - (1<<15) ); else MSI_RecordSetInteger( rec, i, ival - (1<<31) ); } } else { IStream *stm = NULL; ret = view->ops->fetch_stream( view, query->row, i, &stm ); if( ( ret == ERROR_SUCCESS ) && stm ) { MSI_RecordSetIStream( rec, i, stm ); IStream_Release( stm ); } else ERR("failed to get stream\n"); } } query->row ++; *prec = rec; return ERROR_SUCCESS; } UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record) { MSIQUERY *query; MSIRECORD *rec = NULL; UINT ret; TRACE("%ld %p\n", hView, record); query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); if( !query ) return ERROR_INVALID_HANDLE; ret = MSI_ViewFetch( query, &rec ); if( ret == ERROR_SUCCESS ) { *record = alloc_msihandle( &rec->hdr ); msiobj_release( &rec->hdr ); } msiobj_release( &query->hdr ); return ret; } UINT MSI_ViewClose(MSIQUERY *query) { MSIVIEW *view; TRACE("%p\n", query ); view = query->view; if( !view ) return ERROR_FUNCTION_FAILED; if( !view->ops->close ) return ERROR_FUNCTION_FAILED; return view->ops->close( view ); } UINT WINAPI MsiViewClose(MSIHANDLE hView) { MSIQUERY *query; UINT ret; TRACE("%ld\n", hView ); query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); if( !query ) return ERROR_INVALID_HANDLE; ret = MSI_ViewClose( query ); msiobj_release( &query->hdr ); return ret; } UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec ) { MSIVIEW *view; TRACE("%p %p\n", query, rec); view = query->view; if( !view ) return ERROR_FUNCTION_FAILED; if( !view->ops->execute ) return ERROR_FUNCTION_FAILED; query->row = 0; return view->ops->execute( view, rec ); } UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec) { MSIQUERY *query; MSIRECORD *rec = NULL; UINT ret; TRACE("%ld %ld\n", hView, hRec); query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); if( !query ) return ERROR_INVALID_HANDLE; if( hRec ) { rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD ); if( !rec ) { ret = ERROR_INVALID_HANDLE; goto out; } } ret = MSI_ViewExecute( query, rec ); out: if( query ) msiobj_release( &query->hdr ); if( rec ) msiobj_release( &rec->hdr ); return ret; } UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec) { MSIVIEW *view; MSIQUERY *query; MSIHANDLE handle; UINT ret, i, count = 0, type; LPWSTR name; TRACE("%ld %d %p\n", hView, info, hRec); query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); if( !query ) return ERROR_INVALID_HANDLE; view = query->view; if( !view ) return ERROR_FUNCTION_FAILED; if( !view->ops->get_dimensions ) return ERROR_FUNCTION_FAILED; ret = view->ops->get_dimensions( view, NULL, &count ); if( ret ) return ret; if( !count ) return ERROR_INVALID_PARAMETER; handle = MsiCreateRecord( count ); if( !handle ) return ERROR_FUNCTION_FAILED; for( i=0; iops->get_column_info( view, i+1, &name, &type ); if( ret != ERROR_SUCCESS ) continue; MsiRecordSetStringW( handle, i+1, name ); HeapFree( GetProcessHeap(), 0, name ); } *hRec = handle; return ERROR_SUCCESS; } UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, LPCSTR szTransformFile, int iErrorCond) { FIXME("%ld %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, LPCWSTR szTransformFile, int iErrorCond) { FIXME("%ld %s %d\n", hdb, debugstr_w(szTransformFile), iErrorCond); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref, LPCSTR szTransformFile, int iReserved1, int iReserved2 ) { FIXME("%ld %ld %s %d %d\n", hdb, hdbref, debugstr_a(szTransformFile), iReserved1, iReserved2); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref, LPCWSTR szTransformFile, int iReserved1, int iReserved2 ) { FIXME("%ld %ld %s %d %d\n", hdb, hdbref, debugstr_w(szTransformFile), iReserved1, iReserved2); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb ) { MSIDATABASE *db; UINT r; TRACE("%ld\n", hdb); db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); if( !db ) return ERROR_INVALID_HANDLE; /* FIXME: lock the database */ r = MSI_CommitTables( db ); /* FIXME: unlock the database */ return r; } UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb, LPCSTR table, MSIHANDLE* rec) { FIXME("%ld %s %p\n", hdb, debugstr_a(table), rec); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiDatabaseGetPrimaryKeysW(MSIHANDLE hdb, LPCWSTR table, MSIHANDLE* rec) { FIXME("%ld %s %p\n", hdb, debugstr_w(table), rec); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiViewModify(MSIHANDLE hView, MSIMODIFY eModifyMode, MSIHANDLE hRecord) { FIXME("%ld %x %ld\n",hView, eModifyMode, hRecord); return ERROR_CALL_NOT_IMPLEMENTED; }