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"
38 #include "msiserver.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
44 static void MSI_CloseView( MSIOBJECTHDR
*arg
)
46 MSIQUERY
*query
= (MSIQUERY
*) arg
;
49 if( query
->view
&& query
->view
->ops
->delete )
50 query
->view
->ops
->delete( query
->view
);
51 msiobj_release( &query
->db
->hdr
);
53 LIST_FOR_EACH_SAFE( ptr
, t
, &query
->mem
)
59 UINT
VIEW_find_column( MSIVIEW
*table
, LPCWSTR name
, LPCWSTR table_name
, UINT
*n
)
62 LPWSTR haystack_table_name
;
65 r
= table
->ops
->get_dimensions( table
, NULL
, &count
);
66 if( r
!= ERROR_SUCCESS
)
69 for( i
=1; i
<=count
; i
++ )
74 r
= table
->ops
->get_column_info( table
, i
, &col_name
, NULL
,
75 NULL
, &haystack_table_name
);
76 if( r
!= ERROR_SUCCESS
)
78 x
= lstrcmpW( name
, col_name
);
80 x
|= lstrcmpW( table_name
, haystack_table_name
);
82 msi_free( haystack_table_name
);
90 return ERROR_INVALID_PARAMETER
;
93 UINT WINAPI
MsiDatabaseOpenViewA(MSIHANDLE hdb
,
94 LPCSTR szQuery
, MSIHANDLE
*phView
)
99 TRACE("%d %s %p\n", hdb
, debugstr_a(szQuery
), phView
);
103 szwQuery
= strdupAtoW( szQuery
);
105 return ERROR_FUNCTION_FAILED
;
110 r
= MsiDatabaseOpenViewW( hdb
, szwQuery
, phView
);
112 msi_free( szwQuery
);
116 UINT
MSI_DatabaseOpenViewW(MSIDATABASE
*db
,
117 LPCWSTR szQuery
, MSIQUERY
**pView
)
122 TRACE("%s %p\n", debugstr_w(szQuery
), pView
);
125 return ERROR_INVALID_PARAMETER
;
127 /* pre allocate a handle to hold a pointer to the view */
128 query
= alloc_msiobject( MSIHANDLETYPE_VIEW
, sizeof (MSIQUERY
),
131 return ERROR_FUNCTION_FAILED
;
133 msiobj_addref( &db
->hdr
);
135 list_init( &query
->mem
);
137 r
= MSI_ParseSQL( db
, szQuery
, &query
->view
, &query
->mem
);
138 if( r
== ERROR_SUCCESS
)
140 msiobj_addref( &query
->hdr
);
144 msiobj_release( &query
->hdr
);
148 UINT
MSI_OpenQuery( MSIDATABASE
*db
, MSIQUERY
**view
, LPCWSTR fmt
, ... )
154 /* construct the string */
158 query
= msi_alloc( size
*sizeof(WCHAR
) );
160 res
= vsnprintfW(query
, size
, fmt
, va
);
162 if (res
== -1) size
*= 2;
163 else if (res
>= size
) size
= res
+ 1;
167 /* perform the query */
168 r
= MSI_DatabaseOpenViewW(db
, query
, view
);
173 UINT
MSI_IterateRecords( MSIQUERY
*view
, LPDWORD count
,
174 record_func func
, LPVOID param
)
176 MSIRECORD
*rec
= NULL
;
177 UINT r
, n
= 0, max
= 0;
179 r
= MSI_ViewExecute( view
, NULL
);
180 if( r
!= ERROR_SUCCESS
)
186 /* iterate a query */
187 for( n
= 0; (max
== 0) || (n
< max
); n
++ )
189 r
= MSI_ViewFetch( view
, &rec
);
190 if( r
!= ERROR_SUCCESS
)
193 r
= func( rec
, param
);
194 msiobj_release( &rec
->hdr
);
195 if( r
!= ERROR_SUCCESS
)
199 MSI_ViewClose( view
);
204 if( r
== ERROR_NO_MORE_ITEMS
)
210 /* return a single record from a query */
211 MSIRECORD
*MSI_QueryGetRecord( MSIDATABASE
*db
, LPCWSTR fmt
, ... )
213 MSIRECORD
*rec
= NULL
;
214 MSIQUERY
*view
= NULL
;
219 /* construct the string */
223 query
= msi_alloc( size
*sizeof(WCHAR
) );
225 res
= vsnprintfW(query
, size
, fmt
, va
);
227 if (res
== -1) size
*= 2;
228 else if (res
>= size
) size
= res
+ 1;
232 /* perform the query */
233 r
= MSI_DatabaseOpenViewW(db
, query
, &view
);
236 if( r
== ERROR_SUCCESS
)
238 MSI_ViewExecute( view
, NULL
);
239 MSI_ViewFetch( view
, &rec
);
240 MSI_ViewClose( view
);
241 msiobj_release( &view
->hdr
);
246 UINT WINAPI
MsiDatabaseOpenViewW(MSIHANDLE hdb
,
247 LPCWSTR szQuery
, MSIHANDLE
*phView
)
250 MSIQUERY
*query
= NULL
;
253 TRACE("%s %p\n", debugstr_w(szQuery
), phView
);
255 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
259 IWineMsiRemoteDatabase
*remote_database
;
261 remote_database
= (IWineMsiRemoteDatabase
*)msi_get_remote( hdb
);
262 if ( !remote_database
)
263 return ERROR_INVALID_HANDLE
;
265 hr
= IWineMsiRemoteDatabase_OpenView( remote_database
, szQuery
, phView
);
266 IWineMsiRemoteDatabase_Release( remote_database
);
270 if (HRESULT_FACILITY(hr
) == FACILITY_WIN32
)
271 return HRESULT_CODE(hr
);
273 return ERROR_FUNCTION_FAILED
;
276 return ERROR_SUCCESS
;
279 ret
= MSI_DatabaseOpenViewW( db
, szQuery
, &query
);
280 if( ret
== ERROR_SUCCESS
)
282 *phView
= alloc_msihandle( &query
->hdr
);
284 ret
= ERROR_NOT_ENOUGH_MEMORY
;
285 msiobj_release( &query
->hdr
);
287 msiobj_release( &db
->hdr
);
292 UINT
msi_view_get_row(MSIDATABASE
*db
, MSIVIEW
*view
, UINT row
, MSIRECORD
**rec
)
294 UINT row_count
= 0, col_count
= 0, i
, ival
, ret
, type
;
296 TRACE("%p %p %d %p\n", db
, view
, row
, rec
);
298 ret
= view
->ops
->get_dimensions(view
, &row_count
, &col_count
);
303 return ERROR_INVALID_PARAMETER
;
305 if (row
>= row_count
)
306 return ERROR_NO_MORE_ITEMS
;
308 *rec
= MSI_CreateRecord(col_count
);
310 return ERROR_FUNCTION_FAILED
;
312 for (i
= 1; i
<= col_count
; i
++)
314 ret
= view
->ops
->get_column_info(view
, i
, NULL
, &type
, NULL
, NULL
);
317 ERR("Error getting column type for %d\n", i
);
321 if (MSITYPE_IS_BINARY(type
))
325 ret
= view
->ops
->fetch_stream(view
, row
, i
, &stm
);
326 if ((ret
== ERROR_SUCCESS
) && stm
)
328 MSI_RecordSetIStream(*rec
, i
, stm
);
329 IStream_Release(stm
);
332 WARN("failed to get stream\n");
337 ret
= view
->ops
->fetch_int(view
, row
, i
, &ival
);
340 ERR("Error fetching data for %d\n", i
);
344 if (! (type
& MSITYPE_VALID
))
345 ERR("Invalid type!\n");
347 /* check if it's nul (0) - if so, don't set anything */
351 if (type
& MSITYPE_STRING
)
355 sval
= msi_string_lookup_id(db
->strings
, ival
);
356 MSI_RecordSetStringW(*rec
, i
, sval
);
360 if ((type
& MSI_DATASIZEMASK
) == 2)
361 MSI_RecordSetInteger(*rec
, i
, ival
- (1<<15));
363 MSI_RecordSetInteger(*rec
, i
, ival
- (1<<31));
367 return ERROR_SUCCESS
;
370 UINT
MSI_ViewFetch(MSIQUERY
*query
, MSIRECORD
**prec
)
375 TRACE("%p %p\n", query
, prec
);
379 return ERROR_FUNCTION_FAILED
;
381 r
= msi_view_get_row(query
->db
, view
, query
->row
, prec
);
382 if (r
== ERROR_SUCCESS
)
385 MSI_RecordSetInteger(*prec
, 0, (int)query
);
391 UINT WINAPI
MsiViewFetch(MSIHANDLE hView
, MSIHANDLE
*record
)
394 MSIRECORD
*rec
= NULL
;
397 TRACE("%d %p\n", hView
, record
);
400 return ERROR_INVALID_PARAMETER
;
403 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
405 return ERROR_INVALID_HANDLE
;
406 ret
= MSI_ViewFetch( query
, &rec
);
407 if( ret
== ERROR_SUCCESS
)
409 *record
= alloc_msihandle( &rec
->hdr
);
411 ret
= ERROR_NOT_ENOUGH_MEMORY
;
412 msiobj_release( &rec
->hdr
);
414 msiobj_release( &query
->hdr
);
418 UINT
MSI_ViewClose(MSIQUERY
*query
)
422 TRACE("%p\n", query
);
426 return ERROR_FUNCTION_FAILED
;
427 if( !view
->ops
->close
)
428 return ERROR_FUNCTION_FAILED
;
430 return view
->ops
->close( view
);
433 UINT WINAPI
MsiViewClose(MSIHANDLE hView
)
438 TRACE("%d\n", hView
);
440 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
442 return ERROR_INVALID_HANDLE
;
444 ret
= MSI_ViewClose( query
);
445 msiobj_release( &query
->hdr
);
449 UINT
MSI_ViewExecute(MSIQUERY
*query
, MSIRECORD
*rec
)
453 TRACE("%p %p\n", query
, rec
);
457 return ERROR_FUNCTION_FAILED
;
458 if( !view
->ops
->execute
)
459 return ERROR_FUNCTION_FAILED
;
462 return view
->ops
->execute( view
, rec
);
465 UINT WINAPI
MsiViewExecute(MSIHANDLE hView
, MSIHANDLE hRec
)
468 MSIRECORD
*rec
= NULL
;
471 TRACE("%d %d\n", hView
, hRec
);
473 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
475 return ERROR_INVALID_HANDLE
;
479 rec
= msihandle2msiinfo( hRec
, MSIHANDLETYPE_RECORD
);
482 ret
= ERROR_INVALID_HANDLE
;
487 msiobj_lock( &rec
->hdr
);
488 ret
= MSI_ViewExecute( query
, rec
);
489 msiobj_unlock( &rec
->hdr
);
492 msiobj_release( &query
->hdr
);
494 msiobj_release( &rec
->hdr
);
499 static UINT
msi_set_record_type_string( MSIRECORD
*rec
, UINT field
,
500 UINT type
, BOOL temporary
)
502 static const WCHAR fmt
[] = { '%','d',0 };
505 if (MSITYPE_IS_BINARY(type
))
507 else if (type
& MSITYPE_LOCALIZABLE
)
509 else if (type
& MSITYPE_STRING
)
524 if (type
& MSITYPE_NULLABLE
)
527 sprintfW( &szType
[1], fmt
, (type
&0xff) );
529 TRACE("type %04x -> %s\n", type
, debugstr_w(szType
) );
531 return MSI_RecordSetStringW( rec
, field
, szType
);
534 UINT
MSI_ViewGetColumnInfo( MSIQUERY
*query
, MSICOLINFO info
, MSIRECORD
**prec
)
536 UINT r
= ERROR_FUNCTION_FAILED
, i
, count
= 0, type
;
538 MSIVIEW
*view
= query
->view
;
543 return ERROR_FUNCTION_FAILED
;
545 if( !view
->ops
->get_dimensions
)
546 return ERROR_FUNCTION_FAILED
;
548 r
= view
->ops
->get_dimensions( view
, NULL
, &count
);
549 if( r
!= ERROR_SUCCESS
)
552 return ERROR_INVALID_PARAMETER
;
554 rec
= MSI_CreateRecord( count
);
556 return ERROR_FUNCTION_FAILED
;
558 for( i
=0; i
<count
; i
++ )
561 r
= view
->ops
->get_column_info( view
, i
+1, &name
, &type
, &temporary
,
563 if( r
!= ERROR_SUCCESS
)
565 if (info
== MSICOLINFO_NAMES
)
566 MSI_RecordSetStringW( rec
, i
+1, name
);
568 msi_set_record_type_string( rec
, i
+1, type
, temporary
);
573 return ERROR_SUCCESS
;
576 UINT WINAPI
MsiViewGetColumnInfo(MSIHANDLE hView
, MSICOLINFO info
, MSIHANDLE
*hRec
)
578 MSIQUERY
*query
= NULL
;
579 MSIRECORD
*rec
= NULL
;
582 TRACE("%d %d %p\n", hView
, info
, hRec
);
585 return ERROR_INVALID_PARAMETER
;
587 if( info
!= MSICOLINFO_NAMES
&& info
!= MSICOLINFO_TYPES
)
588 return ERROR_INVALID_PARAMETER
;
590 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
592 return ERROR_INVALID_HANDLE
;
594 r
= MSI_ViewGetColumnInfo( query
, info
, &rec
);
595 if ( r
== ERROR_SUCCESS
)
597 *hRec
= alloc_msihandle( &rec
->hdr
);
599 r
= ERROR_NOT_ENOUGH_MEMORY
;
600 msiobj_release( &rec
->hdr
);
603 msiobj_release( &query
->hdr
);
608 UINT
MSI_ViewModify( MSIQUERY
*query
, MSIMODIFY mode
, MSIRECORD
*rec
)
610 MSIVIEW
*view
= NULL
;
613 if ( !query
|| !rec
)
614 return ERROR_INVALID_HANDLE
;
617 if ( !view
|| !view
->ops
->modify
)
618 return ERROR_FUNCTION_FAILED
;
620 if ( mode
== MSIMODIFY_UPDATE
&& MSI_RecordGetInteger( rec
, 0 ) != (int)query
)
621 return ERROR_FUNCTION_FAILED
;
623 r
= view
->ops
->modify( view
, mode
, rec
, query
->row
);
624 if (mode
== MSIMODIFY_DELETE
&& r
== ERROR_SUCCESS
)
630 UINT WINAPI
MsiViewModify( MSIHANDLE hView
, MSIMODIFY eModifyMode
,
633 MSIQUERY
*query
= NULL
;
634 MSIRECORD
*rec
= NULL
;
635 UINT r
= ERROR_FUNCTION_FAILED
;
637 TRACE("%d %x %d\n", hView
, eModifyMode
, hRecord
);
639 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
641 return ERROR_INVALID_HANDLE
;
643 rec
= msihandle2msiinfo( hRecord
, MSIHANDLETYPE_RECORD
);
644 r
= MSI_ViewModify( query
, eModifyMode
, rec
);
646 msiobj_release( &query
->hdr
);
648 msiobj_release( &rec
->hdr
);
653 MSIDBERROR WINAPI
MsiViewGetErrorW( MSIHANDLE handle
, LPWSTR szColumnNameBuffer
,
656 MSIQUERY
*query
= NULL
;
657 static const WCHAR szError
[] = { 0 };
658 MSIDBERROR r
= MSIDBERROR_NOERROR
;
661 FIXME("%d %p %p - returns empty error string\n",
662 handle
, szColumnNameBuffer
, pcchBuf
);
665 return MSIDBERROR_INVALIDARG
;
667 query
= msihandle2msiinfo( handle
, MSIHANDLETYPE_VIEW
);
669 return MSIDBERROR_INVALIDARG
;
671 len
= strlenW( szError
);
672 if( szColumnNameBuffer
)
675 lstrcpyW( szColumnNameBuffer
, szError
);
677 r
= MSIDBERROR_MOREDATA
;
681 msiobj_release( &query
->hdr
);
685 MSIDBERROR WINAPI
MsiViewGetErrorA( MSIHANDLE handle
, LPSTR szColumnNameBuffer
,
688 static const CHAR szError
[] = { 0 };
689 MSIQUERY
*query
= NULL
;
690 MSIDBERROR r
= MSIDBERROR_NOERROR
;
693 FIXME("%d %p %p - returns empty error string\n",
694 handle
, szColumnNameBuffer
, pcchBuf
);
697 return MSIDBERROR_INVALIDARG
;
699 query
= msihandle2msiinfo( handle
, MSIHANDLETYPE_VIEW
);
701 return MSIDBERROR_INVALIDARG
;
703 len
= strlen( szError
);
704 if( szColumnNameBuffer
)
707 lstrcpyA( szColumnNameBuffer
, szError
);
709 r
= MSIDBERROR_MOREDATA
;
713 msiobj_release( &query
->hdr
);
717 MSIHANDLE WINAPI
MsiGetLastErrorRecord( void )
723 UINT
MSI_DatabaseApplyTransformW( MSIDATABASE
*db
,
724 LPCWSTR szTransformFile
, int iErrorCond
)
727 UINT ret
= ERROR_FUNCTION_FAILED
;
728 IStorage
*stg
= NULL
;
731 TRACE("%p %s %d\n", db
, debugstr_w(szTransformFile
), iErrorCond
);
733 r
= StgOpenStorage( szTransformFile
, NULL
,
734 STGM_DIRECT
|STGM_READ
|STGM_SHARE_DENY_WRITE
, NULL
, 0, &stg
);
737 WARN("failed to open transform 0x%08x\n", r
);
741 r
= IStorage_Stat( stg
, &stat
, STATFLAG_NONAME
);
745 if ( !IsEqualGUID( &stat
.clsid
, &CLSID_MsiTransform
) )
748 if( TRACE_ON( msi
) )
749 enum_stream_names( stg
);
751 ret
= msi_table_apply_transform( db
, stg
);
754 IStorage_Release( stg
);
759 UINT WINAPI
MsiDatabaseApplyTransformW( MSIHANDLE hdb
,
760 LPCWSTR szTransformFile
, int iErrorCond
)
765 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
768 IWineMsiRemoteDatabase
*remote_database
;
770 remote_database
= (IWineMsiRemoteDatabase
*)msi_get_remote( hdb
);
771 if ( !remote_database
)
772 return ERROR_INVALID_HANDLE
;
774 IWineMsiRemoteDatabase_Release( remote_database
);
775 WARN("MsiDatabaseApplyTransform not allowed during a custom action!\n");
777 return ERROR_SUCCESS
;
780 r
= MSI_DatabaseApplyTransformW( db
, szTransformFile
, iErrorCond
);
781 msiobj_release( &db
->hdr
);
785 UINT WINAPI
MsiDatabaseApplyTransformA( MSIHANDLE hdb
,
786 LPCSTR szTransformFile
, int iErrorCond
)
791 TRACE("%d %s %d\n", hdb
, debugstr_a(szTransformFile
), iErrorCond
);
793 wstr
= strdupAtoW( szTransformFile
);
794 if( szTransformFile
&& !wstr
)
795 return ERROR_NOT_ENOUGH_MEMORY
;
797 ret
= MsiDatabaseApplyTransformW( hdb
, wstr
, iErrorCond
);
804 UINT WINAPI
MsiDatabaseGenerateTransformA( MSIHANDLE hdb
, MSIHANDLE hdbref
,
805 LPCSTR szTransformFile
, int iReserved1
, int iReserved2
)
807 FIXME("%d %d %s %d %d\n", hdb
, hdbref
,
808 debugstr_a(szTransformFile
), iReserved1
, iReserved2
);
809 return ERROR_CALL_NOT_IMPLEMENTED
;
812 UINT WINAPI
MsiDatabaseGenerateTransformW( MSIHANDLE hdb
, MSIHANDLE hdbref
,
813 LPCWSTR szTransformFile
, int iReserved1
, int iReserved2
)
815 FIXME("%d %d %s %d %d\n", hdb
, hdbref
,
816 debugstr_w(szTransformFile
), iReserved1
, iReserved2
);
817 return ERROR_CALL_NOT_IMPLEMENTED
;
820 UINT WINAPI
MsiDatabaseCommit( MSIHANDLE hdb
)
827 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
830 IWineMsiRemoteDatabase
*remote_database
;
832 remote_database
= (IWineMsiRemoteDatabase
*)msi_get_remote( hdb
);
833 if ( !remote_database
)
834 return ERROR_INVALID_HANDLE
;
836 IWineMsiRemoteDatabase_Release( remote_database
);
837 WARN("not allowed during a custom action!\n");
839 return ERROR_SUCCESS
;
842 /* FIXME: lock the database */
844 r
= MSI_CommitTables( db
);
845 if (r
!= ERROR_SUCCESS
) ERR("Failed to commit tables!\n");
847 /* FIXME: unlock the database */
849 msiobj_release( &db
->hdr
);
851 if (r
== ERROR_SUCCESS
)
853 msi_free( db
->deletefile
);
854 db
->deletefile
= NULL
;
860 struct msi_primary_key_record_info
866 static UINT
msi_primary_key_iterator( MSIRECORD
*rec
, LPVOID param
)
868 struct msi_primary_key_record_info
*info
= param
;
872 type
= MSI_RecordGetInteger( rec
, 4 );
873 if( type
& MSITYPE_KEY
)
880 table
= MSI_RecordGetString( rec
, 1 );
881 MSI_RecordSetStringW( info
->rec
, 0, table
);
884 name
= MSI_RecordGetString( rec
, 3 );
885 MSI_RecordSetStringW( info
->rec
, info
->n
, name
);
889 return ERROR_SUCCESS
;
892 UINT
MSI_DatabaseGetPrimaryKeys( MSIDATABASE
*db
,
893 LPCWSTR table
, MSIRECORD
**prec
)
895 static const WCHAR sql
[] = {
896 's','e','l','e','c','t',' ','*',' ',
897 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
898 'w','h','e','r','e',' ',
899 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
900 struct msi_primary_key_record_info info
;
901 MSIQUERY
*query
= NULL
;
904 r
= MSI_OpenQuery( db
, &query
, sql
, table
);
905 if( r
!= ERROR_SUCCESS
)
908 /* count the number of primary key records */
911 r
= MSI_IterateRecords( query
, 0, msi_primary_key_iterator
, &info
);
912 if( r
== ERROR_SUCCESS
)
914 TRACE("Found %d primary keys\n", info
.n
);
916 /* allocate a record and fill in the names of the tables */
917 info
.rec
= MSI_CreateRecord( info
.n
);
919 r
= MSI_IterateRecords( query
, 0, msi_primary_key_iterator
, &info
);
920 if( r
== ERROR_SUCCESS
)
923 msiobj_release( &info
.rec
->hdr
);
925 msiobj_release( &query
->hdr
);
930 UINT WINAPI
MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb
,
931 LPCWSTR table
, MSIHANDLE
* phRec
)
933 MSIRECORD
*rec
= NULL
;
937 TRACE("%d %s %p\n", hdb
, debugstr_w(table
), phRec
);
939 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
943 IWineMsiRemoteDatabase
*remote_database
;
945 remote_database
= (IWineMsiRemoteDatabase
*)msi_get_remote( hdb
);
946 if ( !remote_database
)
947 return ERROR_INVALID_HANDLE
;
949 hr
= IWineMsiRemoteDatabase_GetPrimaryKeys( remote_database
, table
, phRec
);
950 IWineMsiRemoteDatabase_Release( remote_database
);
954 if (HRESULT_FACILITY(hr
) == FACILITY_WIN32
)
955 return HRESULT_CODE(hr
);
957 return ERROR_FUNCTION_FAILED
;
960 return ERROR_SUCCESS
;
963 r
= MSI_DatabaseGetPrimaryKeys( db
, table
, &rec
);
964 if( r
== ERROR_SUCCESS
)
966 *phRec
= alloc_msihandle( &rec
->hdr
);
968 r
= ERROR_NOT_ENOUGH_MEMORY
;
969 msiobj_release( &rec
->hdr
);
971 msiobj_release( &db
->hdr
);
976 UINT WINAPI
MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb
,
977 LPCSTR table
, MSIHANDLE
* phRec
)
979 LPWSTR szwTable
= NULL
;
982 TRACE("%d %s %p\n", hdb
, debugstr_a(table
), phRec
);
986 szwTable
= strdupAtoW( table
);
988 return ERROR_OUTOFMEMORY
;
990 r
= MsiDatabaseGetPrimaryKeysW( hdb
, szwTable
, phRec
);
991 msi_free( szwTable
);
996 MSICONDITION WINAPI
MsiDatabaseIsTablePersistentA(
997 MSIHANDLE hDatabase
, LPCSTR szTableName
)
999 LPWSTR szwTableName
= NULL
;
1002 TRACE("%x %s\n", hDatabase
, debugstr_a(szTableName
));
1006 szwTableName
= strdupAtoW( szTableName
);
1008 return MSICONDITION_ERROR
;
1010 r
= MsiDatabaseIsTablePersistentW( hDatabase
, szwTableName
);
1011 msi_free( szwTableName
);
1016 MSICONDITION WINAPI
MsiDatabaseIsTablePersistentW(
1017 MSIHANDLE hDatabase
, LPCWSTR szTableName
)
1022 TRACE("%x %s\n", hDatabase
, debugstr_w(szTableName
));
1024 db
= msihandle2msiinfo( hDatabase
, MSIHANDLETYPE_DATABASE
);
1028 MSICONDITION condition
;
1029 IWineMsiRemoteDatabase
*remote_database
;
1031 remote_database
= (IWineMsiRemoteDatabase
*)msi_get_remote( hDatabase
);
1032 if ( !remote_database
)
1033 return MSICONDITION_ERROR
;
1035 hr
= IWineMsiRemoteDatabase_IsTablePersistent( remote_database
,
1036 szTableName
, &condition
);
1037 IWineMsiRemoteDatabase_Release( remote_database
);
1040 return MSICONDITION_ERROR
;
1045 r
= MSI_DatabaseIsTablePersistent( db
, szTableName
);
1047 msiobj_release( &db
->hdr
);