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
23 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
25 static void MSI_CloseView( MSIOBJECTHDR
*arg
)
27 MSIQUERY
*query
= (MSIQUERY
*) arg
;
30 if( query
->view
&& query
->view
->ops
->delete )
31 query
->view
->ops
->delete( query
->view
);
32 msiobj_release( &query
->db
->hdr
);
34 LIST_FOR_EACH_SAFE( ptr
, t
, &query
->mem
)
40 UINT
VIEW_find_column( MSIVIEW
*table
, LPCWSTR name
, LPCWSTR table_name
, UINT
*n
)
42 LPCWSTR col_name
, haystack_table_name
;
45 r
= table
->ops
->get_dimensions( table
, NULL
, &count
);
46 if( r
!= ERROR_SUCCESS
)
49 for( i
=1; i
<=count
; i
++ )
53 r
= table
->ops
->get_column_info( table
, i
, &col_name
, NULL
,
54 NULL
, &haystack_table_name
);
55 if( r
!= ERROR_SUCCESS
)
57 x
= strcmpW( name
, col_name
);
59 x
|= strcmpW( table_name
, haystack_table_name
);
66 return ERROR_INVALID_PARAMETER
;
69 UINT WINAPI
MsiDatabaseOpenViewA(MSIHANDLE hdb
,
70 LPCSTR szQuery
, MSIHANDLE
*phView
)
75 TRACE("%d %s %p\n", hdb
, debugstr_a(szQuery
), phView
);
79 szwQuery
= strdupAtoW( szQuery
);
81 return ERROR_FUNCTION_FAILED
;
86 r
= MsiDatabaseOpenViewW( hdb
, szwQuery
, phView
);
92 UINT
MSI_DatabaseOpenViewW(MSIDATABASE
*db
,
93 LPCWSTR szQuery
, MSIQUERY
**pView
)
98 TRACE("%s %p\n", debugstr_w(szQuery
), pView
);
101 return ERROR_INVALID_PARAMETER
;
103 /* pre allocate a handle to hold a pointer to the view */
104 query
= alloc_msiobject( MSIHANDLETYPE_VIEW
, sizeof (MSIQUERY
),
107 return ERROR_FUNCTION_FAILED
;
109 msiobj_addref( &db
->hdr
);
111 list_init( &query
->mem
);
113 r
= MSI_ParseSQL( db
, szQuery
, &query
->view
, &query
->mem
);
114 if( r
== ERROR_SUCCESS
)
116 msiobj_addref( &query
->hdr
);
120 msiobj_release( &query
->hdr
);
124 UINT
MSI_OpenQuery( MSIDATABASE
*db
, MSIQUERY
**view
, LPCWSTR fmt
, ... )
130 /* construct the string */
134 query
= msi_alloc( size
*sizeof(WCHAR
) );
136 res
= vsnprintfW(query
, size
, fmt
, va
);
138 if (res
== -1) size
*= 2;
139 else if (res
>= size
) size
= res
+ 1;
143 /* perform the query */
144 r
= MSI_DatabaseOpenViewW(db
, query
, view
);
149 UINT
MSI_IterateRecords( MSIQUERY
*view
, LPDWORD count
,
150 record_func func
, LPVOID param
)
152 MSIRECORD
*rec
= NULL
;
153 UINT r
, n
= 0, max
= 0;
155 r
= MSI_ViewExecute( view
, NULL
);
156 if( r
!= ERROR_SUCCESS
)
162 /* iterate a query */
163 for( n
= 0; (max
== 0) || (n
< max
); n
++ )
165 r
= MSI_ViewFetch( view
, &rec
);
166 if( r
!= ERROR_SUCCESS
)
169 r
= func( rec
, param
);
170 msiobj_release( &rec
->hdr
);
171 if( r
!= ERROR_SUCCESS
)
175 MSI_ViewClose( view
);
180 if( r
== ERROR_NO_MORE_ITEMS
)
186 /* return a single record from a query */
187 MSIRECORD
*MSI_QueryGetRecord( MSIDATABASE
*db
, LPCWSTR fmt
, ... )
189 MSIRECORD
*rec
= NULL
;
190 MSIQUERY
*view
= NULL
;
195 /* construct the string */
199 query
= msi_alloc( size
*sizeof(WCHAR
) );
201 res
= vsnprintfW(query
, size
, fmt
, va
);
203 if (res
== -1) size
*= 2;
204 else if (res
>= size
) size
= res
+ 1;
208 /* perform the query */
209 r
= MSI_DatabaseOpenViewW(db
, query
, &view
);
212 if( r
== ERROR_SUCCESS
)
214 MSI_ViewExecute( view
, NULL
);
215 MSI_ViewFetch( view
, &rec
);
216 MSI_ViewClose( view
);
217 msiobj_release( &view
->hdr
);
222 UINT WINAPI
MsiDatabaseOpenViewW(MSIHANDLE hdb
,
223 LPCWSTR szQuery
, MSIHANDLE
*phView
)
226 MSIQUERY
*query
= NULL
;
229 TRACE("%s %p\n", debugstr_w(szQuery
), phView
);
231 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
235 IWineMsiRemoteDatabase
*remote_database
;
237 remote_database
= (IWineMsiRemoteDatabase
*)msi_get_remote( hdb
);
238 if ( !remote_database
)
239 return ERROR_INVALID_HANDLE
;
241 hr
= IWineMsiRemoteDatabase_OpenView( remote_database
, szQuery
, phView
);
242 IWineMsiRemoteDatabase_Release( remote_database
);
246 if (HRESULT_FACILITY(hr
) == FACILITY_WIN32
)
247 return HRESULT_CODE(hr
);
249 return ERROR_FUNCTION_FAILED
;
252 return ERROR_SUCCESS
;
255 ret
= MSI_DatabaseOpenViewW( db
, szQuery
, &query
);
256 if( ret
== ERROR_SUCCESS
)
258 *phView
= alloc_msihandle( &query
->hdr
);
260 ret
= ERROR_NOT_ENOUGH_MEMORY
;
261 msiobj_release( &query
->hdr
);
263 msiobj_release( &db
->hdr
);
268 UINT
msi_view_get_row(MSIDATABASE
*db
, MSIVIEW
*view
, UINT row
, MSIRECORD
**rec
)
270 UINT row_count
= 0, col_count
= 0, i
, ival
, ret
, type
;
272 TRACE("%p %p %d %p\n", db
, view
, row
, rec
);
274 ret
= view
->ops
->get_dimensions(view
, &row_count
, &col_count
);
279 return ERROR_INVALID_PARAMETER
;
281 if (row
>= row_count
)
282 return ERROR_NO_MORE_ITEMS
;
284 *rec
= MSI_CreateRecord(col_count
);
286 return ERROR_FUNCTION_FAILED
;
288 for (i
= 1; i
<= col_count
; i
++)
290 ret
= view
->ops
->get_column_info(view
, i
, NULL
, &type
, NULL
, NULL
);
293 ERR("Error getting column type for %d\n", i
);
297 if (MSITYPE_IS_BINARY(type
))
301 ret
= view
->ops
->fetch_stream(view
, row
, i
, &stm
);
302 if ((ret
== ERROR_SUCCESS
) && stm
)
304 MSI_RecordSetIStream(*rec
, i
, stm
);
305 IStream_Release(stm
);
308 WARN("failed to get stream\n");
313 ret
= view
->ops
->fetch_int(view
, row
, i
, &ival
);
316 ERR("Error fetching data for %d\n", i
);
320 if (! (type
& MSITYPE_VALID
))
321 ERR("Invalid type!\n");
323 /* check if it's nul (0) - if so, don't set anything */
327 if (type
& MSITYPE_STRING
)
330 const WCHAR
*sval
= msi_string_lookup( db
->strings
, ival
, &len
);
331 msi_record_set_string( *rec
, i
, sval
, len
);
335 if ((type
& MSI_DATASIZEMASK
) == 2)
336 MSI_RecordSetInteger(*rec
, i
, ival
- (1<<15));
338 MSI_RecordSetInteger(*rec
, i
, ival
- (1u<<31));
342 return ERROR_SUCCESS
;
345 UINT
MSI_ViewFetch(MSIQUERY
*query
, MSIRECORD
**prec
)
350 TRACE("%p %p\n", query
, prec
);
354 return ERROR_FUNCTION_FAILED
;
356 r
= msi_view_get_row(query
->db
, view
, query
->row
, prec
);
357 if (r
== ERROR_SUCCESS
)
360 MSI_RecordSetIntPtr(*prec
, 0, (INT_PTR
)query
);
366 UINT WINAPI
MsiViewFetch(MSIHANDLE hView
, MSIHANDLE
*record
)
369 MSIRECORD
*rec
= NULL
;
372 TRACE("%d %p\n", hView
, record
);
375 return ERROR_INVALID_PARAMETER
;
378 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
380 return ERROR_INVALID_HANDLE
;
381 ret
= MSI_ViewFetch( query
, &rec
);
382 if( ret
== ERROR_SUCCESS
)
384 *record
= alloc_msihandle( &rec
->hdr
);
386 ret
= ERROR_NOT_ENOUGH_MEMORY
;
387 msiobj_release( &rec
->hdr
);
389 msiobj_release( &query
->hdr
);
393 UINT
MSI_ViewClose(MSIQUERY
*query
)
397 TRACE("%p\n", query
);
401 return ERROR_FUNCTION_FAILED
;
402 if( !view
->ops
->close
)
403 return ERROR_FUNCTION_FAILED
;
405 return view
->ops
->close( view
);
408 UINT WINAPI
MsiViewClose(MSIHANDLE hView
)
413 TRACE("%d\n", hView
);
415 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
417 return ERROR_INVALID_HANDLE
;
419 ret
= MSI_ViewClose( query
);
420 msiobj_release( &query
->hdr
);
424 UINT
MSI_ViewExecute(MSIQUERY
*query
, MSIRECORD
*rec
)
428 TRACE("%p %p\n", query
, rec
);
432 return ERROR_FUNCTION_FAILED
;
433 if( !view
->ops
->execute
)
434 return ERROR_FUNCTION_FAILED
;
437 return view
->ops
->execute( view
, rec
);
440 UINT WINAPI
MsiViewExecute(MSIHANDLE hView
, MSIHANDLE hRec
)
443 MSIRECORD
*rec
= NULL
;
446 TRACE("%d %d\n", hView
, hRec
);
448 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
450 return ERROR_INVALID_HANDLE
;
454 rec
= msihandle2msiinfo( hRec
, MSIHANDLETYPE_RECORD
);
457 ret
= ERROR_INVALID_HANDLE
;
462 msiobj_lock( &rec
->hdr
);
463 ret
= MSI_ViewExecute( query
, rec
);
464 msiobj_unlock( &rec
->hdr
);
467 msiobj_release( &query
->hdr
);
469 msiobj_release( &rec
->hdr
);
474 static UINT
msi_set_record_type_string( MSIRECORD
*rec
, UINT field
,
475 UINT type
, BOOL temporary
)
477 static const WCHAR fmt
[] = { '%','d',0 };
480 if (MSITYPE_IS_BINARY(type
))
482 else if (type
& MSITYPE_LOCALIZABLE
)
484 else if (type
& MSITYPE_UNKNOWN
)
486 else if (type
& MSITYPE_STRING
)
501 if (type
& MSITYPE_NULLABLE
)
504 sprintfW( &szType
[1], fmt
, (type
&0xff) );
506 TRACE("type %04x -> %s\n", type
, debugstr_w(szType
) );
508 return MSI_RecordSetStringW( rec
, field
, szType
);
511 UINT
MSI_ViewGetColumnInfo( MSIQUERY
*query
, MSICOLINFO info
, MSIRECORD
**prec
)
513 UINT r
= ERROR_FUNCTION_FAILED
, i
, count
= 0, type
;
515 MSIVIEW
*view
= query
->view
;
520 return ERROR_FUNCTION_FAILED
;
522 if( !view
->ops
->get_dimensions
)
523 return ERROR_FUNCTION_FAILED
;
525 r
= view
->ops
->get_dimensions( view
, NULL
, &count
);
526 if( r
!= ERROR_SUCCESS
)
529 return ERROR_INVALID_PARAMETER
;
531 rec
= MSI_CreateRecord( count
);
533 return ERROR_FUNCTION_FAILED
;
535 for( i
=0; i
<count
; i
++ )
538 r
= view
->ops
->get_column_info( view
, i
+1, &name
, &type
, &temporary
, NULL
);
539 if( r
!= ERROR_SUCCESS
)
541 if (info
== MSICOLINFO_NAMES
)
542 MSI_RecordSetStringW( rec
, i
+1, name
);
544 msi_set_record_type_string( rec
, i
+1, type
, temporary
);
547 return ERROR_SUCCESS
;
550 UINT WINAPI
MsiViewGetColumnInfo(MSIHANDLE hView
, MSICOLINFO info
, MSIHANDLE
*hRec
)
552 MSIQUERY
*query
= NULL
;
553 MSIRECORD
*rec
= NULL
;
556 TRACE("%d %d %p\n", hView
, info
, hRec
);
559 return ERROR_INVALID_PARAMETER
;
561 if( info
!= MSICOLINFO_NAMES
&& info
!= MSICOLINFO_TYPES
)
562 return ERROR_INVALID_PARAMETER
;
564 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
566 return ERROR_INVALID_HANDLE
;
568 r
= MSI_ViewGetColumnInfo( query
, info
, &rec
);
569 if ( r
== ERROR_SUCCESS
)
571 *hRec
= alloc_msihandle( &rec
->hdr
);
573 r
= ERROR_NOT_ENOUGH_MEMORY
;
574 msiobj_release( &rec
->hdr
);
577 msiobj_release( &query
->hdr
);
582 UINT
MSI_ViewModify( MSIQUERY
*query
, MSIMODIFY mode
, MSIRECORD
*rec
)
584 MSIVIEW
*view
= NULL
;
587 if ( !query
|| !rec
)
588 return ERROR_INVALID_HANDLE
;
591 if ( !view
|| !view
->ops
->modify
)
592 return ERROR_FUNCTION_FAILED
;
594 if ( mode
== MSIMODIFY_UPDATE
&& MSI_RecordGetIntPtr( rec
, 0 ) != (INT_PTR
)query
)
595 return ERROR_FUNCTION_FAILED
;
597 r
= view
->ops
->modify( view
, mode
, rec
, query
->row
);
598 if (mode
== MSIMODIFY_DELETE
&& r
== ERROR_SUCCESS
)
604 UINT WINAPI
MsiViewModify( MSIHANDLE hView
, MSIMODIFY eModifyMode
,
607 MSIQUERY
*query
= NULL
;
608 MSIRECORD
*rec
= NULL
;
609 UINT r
= ERROR_FUNCTION_FAILED
;
611 TRACE("%d %x %d\n", hView
, eModifyMode
, hRecord
);
613 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
615 return ERROR_INVALID_HANDLE
;
617 rec
= msihandle2msiinfo( hRecord
, MSIHANDLETYPE_RECORD
);
618 r
= MSI_ViewModify( query
, eModifyMode
, rec
);
620 msiobj_release( &query
->hdr
);
622 msiobj_release( &rec
->hdr
);
627 MSIDBERROR WINAPI
MsiViewGetErrorW( MSIHANDLE handle
, LPWSTR buffer
, LPDWORD buflen
)
634 TRACE("%u %p %p\n", handle
, buffer
, buflen
);
637 return MSIDBERROR_INVALIDARG
;
639 query
= msihandle2msiinfo( handle
, MSIHANDLETYPE_VIEW
);
641 return MSIDBERROR_INVALIDARG
;
643 if ((r
= query
->view
->error
)) column
= query
->view
->error_column
;
644 else column
= szEmpty
;
646 len
= strlenW( column
);
650 strcpyW( buffer
, column
);
652 r
= MSIDBERROR_MOREDATA
;
655 msiobj_release( &query
->hdr
);
659 MSIDBERROR WINAPI
MsiViewGetErrorA( MSIHANDLE handle
, LPSTR buffer
, LPDWORD buflen
)
666 TRACE("%u %p %p\n", handle
, buffer
, buflen
);
669 return MSIDBERROR_INVALIDARG
;
671 query
= msihandle2msiinfo( handle
, MSIHANDLETYPE_VIEW
);
673 return MSIDBERROR_INVALIDARG
;
675 if ((r
= query
->view
->error
)) column
= query
->view
->error_column
;
676 else column
= szEmpty
;
678 len
= WideCharToMultiByte( CP_ACP
, 0, column
, -1, NULL
, 0, NULL
, NULL
);
682 WideCharToMultiByte( CP_ACP
, 0, column
, -1, buffer
, *buflen
, NULL
, NULL
);
684 r
= MSIDBERROR_MOREDATA
;
687 msiobj_release( &query
->hdr
);
691 MSIHANDLE WINAPI
MsiGetLastErrorRecord( void )
697 UINT
MSI_DatabaseApplyTransformW( MSIDATABASE
*db
,
698 LPCWSTR szTransformFile
, int iErrorCond
)
701 UINT ret
= ERROR_FUNCTION_FAILED
;
702 IStorage
*stg
= NULL
;
705 TRACE("%p %s %d\n", db
, debugstr_w(szTransformFile
), iErrorCond
);
707 r
= StgOpenStorage( szTransformFile
, NULL
,
708 STGM_DIRECT
|STGM_READ
|STGM_SHARE_DENY_WRITE
, NULL
, 0, &stg
);
711 WARN("failed to open transform 0x%08x\n", r
);
715 r
= IStorage_Stat( stg
, &stat
, STATFLAG_NONAME
);
719 if ( !IsEqualGUID( &stat
.clsid
, &CLSID_MsiTransform
) )
722 if( TRACE_ON( msi
) )
723 enum_stream_names( stg
);
725 ret
= msi_table_apply_transform( db
, stg
);
728 IStorage_Release( stg
);
733 UINT WINAPI
MsiDatabaseApplyTransformW( MSIHANDLE hdb
,
734 LPCWSTR szTransformFile
, int iErrorCond
)
739 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
742 IWineMsiRemoteDatabase
*remote_database
;
744 remote_database
= (IWineMsiRemoteDatabase
*)msi_get_remote( hdb
);
745 if ( !remote_database
)
746 return ERROR_INVALID_HANDLE
;
748 IWineMsiRemoteDatabase_Release( remote_database
);
749 WARN("MsiDatabaseApplyTransform not allowed during a custom action!\n");
751 return ERROR_SUCCESS
;
754 r
= MSI_DatabaseApplyTransformW( db
, szTransformFile
, iErrorCond
);
755 msiobj_release( &db
->hdr
);
759 UINT WINAPI
MsiDatabaseApplyTransformA( MSIHANDLE hdb
,
760 LPCSTR szTransformFile
, int iErrorCond
)
765 TRACE("%d %s %d\n", hdb
, debugstr_a(szTransformFile
), iErrorCond
);
767 wstr
= strdupAtoW( szTransformFile
);
768 if( szTransformFile
&& !wstr
)
769 return ERROR_NOT_ENOUGH_MEMORY
;
771 ret
= MsiDatabaseApplyTransformW( hdb
, wstr
, iErrorCond
);
778 UINT WINAPI
MsiDatabaseGenerateTransformA( MSIHANDLE hdb
, MSIHANDLE hdbref
,
779 LPCSTR szTransformFile
, int iReserved1
, int iReserved2
)
781 FIXME("%d %d %s %d %d\n", hdb
, hdbref
,
782 debugstr_a(szTransformFile
), iReserved1
, iReserved2
);
783 return ERROR_CALL_NOT_IMPLEMENTED
;
786 UINT WINAPI
MsiDatabaseGenerateTransformW( MSIHANDLE hdb
, MSIHANDLE hdbref
,
787 LPCWSTR szTransformFile
, int iReserved1
, int iReserved2
)
789 FIXME("%d %d %s %d %d\n", hdb
, hdbref
,
790 debugstr_w(szTransformFile
), iReserved1
, iReserved2
);
791 return ERROR_CALL_NOT_IMPLEMENTED
;
794 UINT WINAPI
MsiDatabaseCommit( MSIHANDLE hdb
)
801 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
804 IWineMsiRemoteDatabase
*remote_database
;
806 remote_database
= (IWineMsiRemoteDatabase
*)msi_get_remote( hdb
);
807 if ( !remote_database
)
808 return ERROR_INVALID_HANDLE
;
810 IWineMsiRemoteDatabase_Release( remote_database
);
811 WARN("not allowed during a custom action!\n");
813 return ERROR_SUCCESS
;
816 if (db
->mode
== MSIDBOPEN_READONLY
)
818 msiobj_release( &db
->hdr
);
819 return ERROR_SUCCESS
;
822 /* FIXME: lock the database */
824 r
= msi_commit_streams( db
);
825 if (r
!= ERROR_SUCCESS
) ERR("Failed to commit streams!\n");
828 r
= MSI_CommitTables( db
);
829 if (r
!= ERROR_SUCCESS
) ERR("Failed to commit tables!\n");
832 /* FIXME: unlock the database */
834 msiobj_release( &db
->hdr
);
836 if (r
== ERROR_SUCCESS
)
838 msi_free( db
->deletefile
);
839 db
->deletefile
= NULL
;
845 struct msi_primary_key_record_info
851 static UINT
msi_primary_key_iterator( MSIRECORD
*rec
, LPVOID param
)
853 struct msi_primary_key_record_info
*info
= param
;
857 type
= MSI_RecordGetInteger( rec
, 4 );
858 if( type
& MSITYPE_KEY
)
865 table
= MSI_RecordGetString( rec
, 1 );
866 MSI_RecordSetStringW( info
->rec
, 0, table
);
869 name
= MSI_RecordGetString( rec
, 3 );
870 MSI_RecordSetStringW( info
->rec
, info
->n
, name
);
874 return ERROR_SUCCESS
;
877 UINT
MSI_DatabaseGetPrimaryKeys( MSIDATABASE
*db
,
878 LPCWSTR table
, MSIRECORD
**prec
)
880 static const WCHAR sql
[] = {
881 's','e','l','e','c','t',' ','*',' ',
882 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
883 'w','h','e','r','e',' ',
884 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
885 struct msi_primary_key_record_info info
;
886 MSIQUERY
*query
= NULL
;
889 if (!TABLE_Exists( db
, table
))
890 return ERROR_INVALID_TABLE
;
892 r
= MSI_OpenQuery( db
, &query
, sql
, table
);
893 if( r
!= ERROR_SUCCESS
)
896 /* count the number of primary key records */
899 r
= MSI_IterateRecords( query
, 0, msi_primary_key_iterator
, &info
);
900 if( r
== ERROR_SUCCESS
)
902 TRACE("Found %d primary keys\n", info
.n
);
904 /* allocate a record and fill in the names of the tables */
905 info
.rec
= MSI_CreateRecord( info
.n
);
907 r
= MSI_IterateRecords( query
, 0, msi_primary_key_iterator
, &info
);
908 if( r
== ERROR_SUCCESS
)
911 msiobj_release( &info
.rec
->hdr
);
913 msiobj_release( &query
->hdr
);
918 UINT WINAPI
MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb
,
919 LPCWSTR table
, MSIHANDLE
* phRec
)
921 MSIRECORD
*rec
= NULL
;
925 TRACE("%d %s %p\n", hdb
, debugstr_w(table
), phRec
);
927 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
931 IWineMsiRemoteDatabase
*remote_database
;
933 remote_database
= (IWineMsiRemoteDatabase
*)msi_get_remote( hdb
);
934 if ( !remote_database
)
935 return ERROR_INVALID_HANDLE
;
937 hr
= IWineMsiRemoteDatabase_GetPrimaryKeys( remote_database
, table
, phRec
);
938 IWineMsiRemoteDatabase_Release( remote_database
);
942 if (HRESULT_FACILITY(hr
) == FACILITY_WIN32
)
943 return HRESULT_CODE(hr
);
945 return ERROR_FUNCTION_FAILED
;
948 return ERROR_SUCCESS
;
951 r
= MSI_DatabaseGetPrimaryKeys( db
, table
, &rec
);
952 if( r
== ERROR_SUCCESS
)
954 *phRec
= alloc_msihandle( &rec
->hdr
);
956 r
= ERROR_NOT_ENOUGH_MEMORY
;
957 msiobj_release( &rec
->hdr
);
959 msiobj_release( &db
->hdr
);
964 UINT WINAPI
MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb
,
965 LPCSTR table
, MSIHANDLE
* phRec
)
967 LPWSTR szwTable
= NULL
;
970 TRACE("%d %s %p\n", hdb
, debugstr_a(table
), phRec
);
974 szwTable
= strdupAtoW( table
);
976 return ERROR_OUTOFMEMORY
;
978 r
= MsiDatabaseGetPrimaryKeysW( hdb
, szwTable
, phRec
);
979 msi_free( szwTable
);
984 MSICONDITION WINAPI
MsiDatabaseIsTablePersistentA(
985 MSIHANDLE hDatabase
, LPCSTR szTableName
)
987 LPWSTR szwTableName
= NULL
;
990 TRACE("%x %s\n", hDatabase
, debugstr_a(szTableName
));
994 szwTableName
= strdupAtoW( szTableName
);
996 return MSICONDITION_ERROR
;
998 r
= MsiDatabaseIsTablePersistentW( hDatabase
, szwTableName
);
999 msi_free( szwTableName
);
1004 MSICONDITION WINAPI
MsiDatabaseIsTablePersistentW(
1005 MSIHANDLE hDatabase
, LPCWSTR szTableName
)
1010 TRACE("%x %s\n", hDatabase
, debugstr_w(szTableName
));
1012 db
= msihandle2msiinfo( hDatabase
, MSIHANDLETYPE_DATABASE
);
1016 MSICONDITION condition
;
1017 IWineMsiRemoteDatabase
*remote_database
;
1019 remote_database
= (IWineMsiRemoteDatabase
*)msi_get_remote( hDatabase
);
1020 if ( !remote_database
)
1021 return MSICONDITION_ERROR
;
1023 hr
= IWineMsiRemoteDatabase_IsTablePersistent( remote_database
,
1024 szTableName
, &condition
);
1025 IWineMsiRemoteDatabase_Release( remote_database
);
1028 return MSICONDITION_ERROR
;
1033 r
= MSI_DatabaseIsTablePersistent( db
, szTableName
);
1035 msiobj_release( &db
->hdr
);