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
)
61 LPCWSTR col_name
, haystack_table_name
;
64 r
= table
->ops
->get_dimensions( table
, NULL
, &count
);
65 if( r
!= ERROR_SUCCESS
)
68 for( i
=1; i
<=count
; i
++ )
72 r
= table
->ops
->get_column_info( table
, i
, &col_name
, NULL
,
73 NULL
, &haystack_table_name
);
74 if( r
!= ERROR_SUCCESS
)
76 x
= strcmpW( name
, col_name
);
78 x
|= strcmpW( table_name
, haystack_table_name
);
85 return ERROR_INVALID_PARAMETER
;
88 UINT WINAPI
MsiDatabaseOpenViewA(MSIHANDLE hdb
,
89 LPCSTR szQuery
, MSIHANDLE
*phView
)
94 TRACE("%d %s %p\n", hdb
, debugstr_a(szQuery
), phView
);
98 szwQuery
= strdupAtoW( szQuery
);
100 return ERROR_FUNCTION_FAILED
;
105 r
= MsiDatabaseOpenViewW( hdb
, szwQuery
, phView
);
107 msi_free( szwQuery
);
111 UINT
MSI_DatabaseOpenViewW(MSIDATABASE
*db
,
112 LPCWSTR szQuery
, MSIQUERY
**pView
)
117 TRACE("%s %p\n", debugstr_w(szQuery
), pView
);
120 return ERROR_INVALID_PARAMETER
;
122 /* pre allocate a handle to hold a pointer to the view */
123 query
= alloc_msiobject( MSIHANDLETYPE_VIEW
, sizeof (MSIQUERY
),
126 return ERROR_FUNCTION_FAILED
;
128 msiobj_addref( &db
->hdr
);
130 list_init( &query
->mem
);
132 r
= MSI_ParseSQL( db
, szQuery
, &query
->view
, &query
->mem
);
133 if( r
== ERROR_SUCCESS
)
135 msiobj_addref( &query
->hdr
);
139 msiobj_release( &query
->hdr
);
143 UINT
MSI_OpenQuery( MSIDATABASE
*db
, MSIQUERY
**view
, LPCWSTR fmt
, ... )
149 /* construct the string */
153 query
= msi_alloc( size
*sizeof(WCHAR
) );
155 res
= vsnprintfW(query
, size
, fmt
, va
);
157 if (res
== -1) size
*= 2;
158 else if (res
>= size
) size
= res
+ 1;
162 /* perform the query */
163 r
= MSI_DatabaseOpenViewW(db
, query
, view
);
168 UINT
MSI_IterateRecords( MSIQUERY
*view
, LPDWORD count
,
169 record_func func
, LPVOID param
)
171 MSIRECORD
*rec
= NULL
;
172 UINT r
, n
= 0, max
= 0;
174 r
= MSI_ViewExecute( view
, NULL
);
175 if( r
!= ERROR_SUCCESS
)
181 /* iterate a query */
182 for( n
= 0; (max
== 0) || (n
< max
); n
++ )
184 r
= MSI_ViewFetch( view
, &rec
);
185 if( r
!= ERROR_SUCCESS
)
188 r
= func( rec
, param
);
189 msiobj_release( &rec
->hdr
);
190 if( r
!= ERROR_SUCCESS
)
194 MSI_ViewClose( view
);
199 if( r
== ERROR_NO_MORE_ITEMS
)
205 /* return a single record from a query */
206 MSIRECORD
*MSI_QueryGetRecord( MSIDATABASE
*db
, LPCWSTR fmt
, ... )
208 MSIRECORD
*rec
= NULL
;
209 MSIQUERY
*view
= NULL
;
214 /* construct the string */
218 query
= msi_alloc( size
*sizeof(WCHAR
) );
220 res
= vsnprintfW(query
, size
, fmt
, va
);
222 if (res
== -1) size
*= 2;
223 else if (res
>= size
) size
= res
+ 1;
227 /* perform the query */
228 r
= MSI_DatabaseOpenViewW(db
, query
, &view
);
231 if( r
== ERROR_SUCCESS
)
233 MSI_ViewExecute( view
, NULL
);
234 MSI_ViewFetch( view
, &rec
);
235 MSI_ViewClose( view
);
236 msiobj_release( &view
->hdr
);
241 UINT WINAPI
MsiDatabaseOpenViewW(MSIHANDLE hdb
,
242 LPCWSTR szQuery
, MSIHANDLE
*phView
)
245 MSIQUERY
*query
= NULL
;
248 TRACE("%s %p\n", debugstr_w(szQuery
), phView
);
250 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
254 IWineMsiRemoteDatabase
*remote_database
;
256 remote_database
= (IWineMsiRemoteDatabase
*)msi_get_remote( hdb
);
257 if ( !remote_database
)
258 return ERROR_INVALID_HANDLE
;
260 hr
= IWineMsiRemoteDatabase_OpenView( remote_database
, szQuery
, phView
);
261 IWineMsiRemoteDatabase_Release( remote_database
);
265 if (HRESULT_FACILITY(hr
) == FACILITY_WIN32
)
266 return HRESULT_CODE(hr
);
268 return ERROR_FUNCTION_FAILED
;
271 return ERROR_SUCCESS
;
274 ret
= MSI_DatabaseOpenViewW( db
, szQuery
, &query
);
275 if( ret
== ERROR_SUCCESS
)
277 *phView
= alloc_msihandle( &query
->hdr
);
279 ret
= ERROR_NOT_ENOUGH_MEMORY
;
280 msiobj_release( &query
->hdr
);
282 msiobj_release( &db
->hdr
);
287 UINT
msi_view_get_row(MSIDATABASE
*db
, MSIVIEW
*view
, UINT row
, MSIRECORD
**rec
)
289 UINT row_count
= 0, col_count
= 0, i
, ival
, ret
, type
;
291 TRACE("%p %p %d %p\n", db
, view
, row
, rec
);
293 ret
= view
->ops
->get_dimensions(view
, &row_count
, &col_count
);
298 return ERROR_INVALID_PARAMETER
;
300 if (row
>= row_count
)
301 return ERROR_NO_MORE_ITEMS
;
303 *rec
= MSI_CreateRecord(col_count
);
305 return ERROR_FUNCTION_FAILED
;
307 for (i
= 1; i
<= col_count
; i
++)
309 ret
= view
->ops
->get_column_info(view
, i
, NULL
, &type
, NULL
, NULL
);
312 ERR("Error getting column type for %d\n", i
);
316 if (MSITYPE_IS_BINARY(type
))
320 ret
= view
->ops
->fetch_stream(view
, row
, i
, &stm
);
321 if ((ret
== ERROR_SUCCESS
) && stm
)
323 MSI_RecordSetIStream(*rec
, i
, stm
);
324 IStream_Release(stm
);
327 WARN("failed to get stream\n");
332 ret
= view
->ops
->fetch_int(view
, row
, i
, &ival
);
335 ERR("Error fetching data for %d\n", i
);
339 if (! (type
& MSITYPE_VALID
))
340 ERR("Invalid type!\n");
342 /* check if it's nul (0) - if so, don't set anything */
346 if (type
& MSITYPE_STRING
)
350 sval
= msi_string_lookup_id(db
->strings
, ival
);
351 MSI_RecordSetStringW(*rec
, i
, sval
);
355 if ((type
& MSI_DATASIZEMASK
) == 2)
356 MSI_RecordSetInteger(*rec
, i
, ival
- (1<<15));
358 MSI_RecordSetInteger(*rec
, i
, ival
- (1<<31));
362 return ERROR_SUCCESS
;
365 UINT
MSI_ViewFetch(MSIQUERY
*query
, MSIRECORD
**prec
)
370 TRACE("%p %p\n", query
, prec
);
374 return ERROR_FUNCTION_FAILED
;
376 r
= msi_view_get_row(query
->db
, view
, query
->row
, prec
);
377 if (r
== ERROR_SUCCESS
)
380 MSI_RecordSetIntPtr(*prec
, 0, (INT_PTR
)query
);
386 UINT WINAPI
MsiViewFetch(MSIHANDLE hView
, MSIHANDLE
*record
)
389 MSIRECORD
*rec
= NULL
;
392 TRACE("%d %p\n", hView
, record
);
395 return ERROR_INVALID_PARAMETER
;
398 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
400 return ERROR_INVALID_HANDLE
;
401 ret
= MSI_ViewFetch( query
, &rec
);
402 if( ret
== ERROR_SUCCESS
)
404 *record
= alloc_msihandle( &rec
->hdr
);
406 ret
= ERROR_NOT_ENOUGH_MEMORY
;
407 msiobj_release( &rec
->hdr
);
409 msiobj_release( &query
->hdr
);
413 UINT
MSI_ViewClose(MSIQUERY
*query
)
417 TRACE("%p\n", query
);
421 return ERROR_FUNCTION_FAILED
;
422 if( !view
->ops
->close
)
423 return ERROR_FUNCTION_FAILED
;
425 return view
->ops
->close( view
);
428 UINT WINAPI
MsiViewClose(MSIHANDLE hView
)
433 TRACE("%d\n", hView
);
435 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
437 return ERROR_INVALID_HANDLE
;
439 ret
= MSI_ViewClose( query
);
440 msiobj_release( &query
->hdr
);
444 UINT
MSI_ViewExecute(MSIQUERY
*query
, MSIRECORD
*rec
)
448 TRACE("%p %p\n", query
, rec
);
452 return ERROR_FUNCTION_FAILED
;
453 if( !view
->ops
->execute
)
454 return ERROR_FUNCTION_FAILED
;
457 return view
->ops
->execute( view
, rec
);
460 UINT WINAPI
MsiViewExecute(MSIHANDLE hView
, MSIHANDLE hRec
)
463 MSIRECORD
*rec
= NULL
;
466 TRACE("%d %d\n", hView
, hRec
);
468 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
470 return ERROR_INVALID_HANDLE
;
474 rec
= msihandle2msiinfo( hRec
, MSIHANDLETYPE_RECORD
);
477 ret
= ERROR_INVALID_HANDLE
;
482 msiobj_lock( &rec
->hdr
);
483 ret
= MSI_ViewExecute( query
, rec
);
484 msiobj_unlock( &rec
->hdr
);
487 msiobj_release( &query
->hdr
);
489 msiobj_release( &rec
->hdr
);
494 static UINT
msi_set_record_type_string( MSIRECORD
*rec
, UINT field
,
495 UINT type
, BOOL temporary
)
497 static const WCHAR fmt
[] = { '%','d',0 };
500 if (MSITYPE_IS_BINARY(type
))
502 else if (type
& MSITYPE_LOCALIZABLE
)
504 else if (type
& MSITYPE_STRING
)
519 if (type
& MSITYPE_NULLABLE
)
522 sprintfW( &szType
[1], fmt
, (type
&0xff) );
524 TRACE("type %04x -> %s\n", type
, debugstr_w(szType
) );
526 return MSI_RecordSetStringW( rec
, field
, szType
);
529 UINT
MSI_ViewGetColumnInfo( MSIQUERY
*query
, MSICOLINFO info
, MSIRECORD
**prec
)
531 UINT r
= ERROR_FUNCTION_FAILED
, i
, count
= 0, type
;
533 MSIVIEW
*view
= query
->view
;
538 return ERROR_FUNCTION_FAILED
;
540 if( !view
->ops
->get_dimensions
)
541 return ERROR_FUNCTION_FAILED
;
543 r
= view
->ops
->get_dimensions( view
, NULL
, &count
);
544 if( r
!= ERROR_SUCCESS
)
547 return ERROR_INVALID_PARAMETER
;
549 rec
= MSI_CreateRecord( count
);
551 return ERROR_FUNCTION_FAILED
;
553 for( i
=0; i
<count
; i
++ )
556 r
= view
->ops
->get_column_info( view
, i
+1, &name
, &type
, &temporary
, NULL
);
557 if( r
!= ERROR_SUCCESS
)
559 if (info
== MSICOLINFO_NAMES
)
560 MSI_RecordSetStringW( rec
, i
+1, name
);
562 msi_set_record_type_string( rec
, i
+1, type
, temporary
);
565 return ERROR_SUCCESS
;
568 UINT WINAPI
MsiViewGetColumnInfo(MSIHANDLE hView
, MSICOLINFO info
, MSIHANDLE
*hRec
)
570 MSIQUERY
*query
= NULL
;
571 MSIRECORD
*rec
= NULL
;
574 TRACE("%d %d %p\n", hView
, info
, hRec
);
577 return ERROR_INVALID_PARAMETER
;
579 if( info
!= MSICOLINFO_NAMES
&& info
!= MSICOLINFO_TYPES
)
580 return ERROR_INVALID_PARAMETER
;
582 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
584 return ERROR_INVALID_HANDLE
;
586 r
= MSI_ViewGetColumnInfo( query
, info
, &rec
);
587 if ( r
== ERROR_SUCCESS
)
589 *hRec
= alloc_msihandle( &rec
->hdr
);
591 r
= ERROR_NOT_ENOUGH_MEMORY
;
592 msiobj_release( &rec
->hdr
);
595 msiobj_release( &query
->hdr
);
600 UINT
MSI_ViewModify( MSIQUERY
*query
, MSIMODIFY mode
, MSIRECORD
*rec
)
602 MSIVIEW
*view
= NULL
;
605 if ( !query
|| !rec
)
606 return ERROR_INVALID_HANDLE
;
609 if ( !view
|| !view
->ops
->modify
)
610 return ERROR_FUNCTION_FAILED
;
612 if ( mode
== MSIMODIFY_UPDATE
&& MSI_RecordGetIntPtr( rec
, 0 ) != (INT_PTR
)query
)
613 return ERROR_FUNCTION_FAILED
;
615 r
= view
->ops
->modify( view
, mode
, rec
, query
->row
);
616 if (mode
== MSIMODIFY_DELETE
&& r
== ERROR_SUCCESS
)
622 UINT WINAPI
MsiViewModify( MSIHANDLE hView
, MSIMODIFY eModifyMode
,
625 MSIQUERY
*query
= NULL
;
626 MSIRECORD
*rec
= NULL
;
627 UINT r
= ERROR_FUNCTION_FAILED
;
629 TRACE("%d %x %d\n", hView
, eModifyMode
, hRecord
);
631 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
633 return ERROR_INVALID_HANDLE
;
635 rec
= msihandle2msiinfo( hRecord
, MSIHANDLETYPE_RECORD
);
636 r
= MSI_ViewModify( query
, eModifyMode
, rec
);
638 msiobj_release( &query
->hdr
);
640 msiobj_release( &rec
->hdr
);
645 MSIDBERROR WINAPI
MsiViewGetErrorW( MSIHANDLE handle
, LPWSTR buffer
, LPDWORD buflen
)
652 TRACE("%u %p %p\n", handle
, buffer
, buflen
);
655 return MSIDBERROR_INVALIDARG
;
657 query
= msihandle2msiinfo( handle
, MSIHANDLETYPE_VIEW
);
659 return MSIDBERROR_INVALIDARG
;
661 if ((r
= query
->view
->error
)) column
= query
->view
->error_column
;
662 else column
= szEmpty
;
664 len
= strlenW( column
);
668 strcpyW( buffer
, column
);
670 r
= MSIDBERROR_MOREDATA
;
673 msiobj_release( &query
->hdr
);
677 MSIDBERROR WINAPI
MsiViewGetErrorA( MSIHANDLE handle
, LPSTR buffer
, LPDWORD buflen
)
684 TRACE("%u %p %p\n", handle
, buffer
, buflen
);
687 return MSIDBERROR_INVALIDARG
;
689 query
= msihandle2msiinfo( handle
, MSIHANDLETYPE_VIEW
);
691 return MSIDBERROR_INVALIDARG
;
693 if ((r
= query
->view
->error
)) column
= query
->view
->error_column
;
694 else column
= szEmpty
;
696 len
= WideCharToMultiByte( CP_ACP
, 0, column
, -1, NULL
, 0, NULL
, NULL
);
700 WideCharToMultiByte( CP_ACP
, 0, column
, -1, buffer
, *buflen
, NULL
, NULL
);
702 r
= MSIDBERROR_MOREDATA
;
705 msiobj_release( &query
->hdr
);
709 MSIHANDLE WINAPI
MsiGetLastErrorRecord( void )
715 UINT
MSI_DatabaseApplyTransformW( MSIDATABASE
*db
,
716 LPCWSTR szTransformFile
, int iErrorCond
)
719 UINT ret
= ERROR_FUNCTION_FAILED
;
720 IStorage
*stg
= NULL
;
723 TRACE("%p %s %d\n", db
, debugstr_w(szTransformFile
), iErrorCond
);
725 r
= StgOpenStorage( szTransformFile
, NULL
,
726 STGM_DIRECT
|STGM_READ
|STGM_SHARE_DENY_WRITE
, NULL
, 0, &stg
);
729 WARN("failed to open transform 0x%08x\n", r
);
733 r
= IStorage_Stat( stg
, &stat
, STATFLAG_NONAME
);
737 if ( !IsEqualGUID( &stat
.clsid
, &CLSID_MsiTransform
) )
740 if( TRACE_ON( msi
) )
741 enum_stream_names( stg
);
743 ret
= msi_table_apply_transform( db
, stg
);
746 IStorage_Release( stg
);
751 UINT WINAPI
MsiDatabaseApplyTransformW( MSIHANDLE hdb
,
752 LPCWSTR szTransformFile
, int iErrorCond
)
757 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
760 IWineMsiRemoteDatabase
*remote_database
;
762 remote_database
= (IWineMsiRemoteDatabase
*)msi_get_remote( hdb
);
763 if ( !remote_database
)
764 return ERROR_INVALID_HANDLE
;
766 IWineMsiRemoteDatabase_Release( remote_database
);
767 WARN("MsiDatabaseApplyTransform not allowed during a custom action!\n");
769 return ERROR_SUCCESS
;
772 r
= MSI_DatabaseApplyTransformW( db
, szTransformFile
, iErrorCond
);
773 msiobj_release( &db
->hdr
);
777 UINT WINAPI
MsiDatabaseApplyTransformA( MSIHANDLE hdb
,
778 LPCSTR szTransformFile
, int iErrorCond
)
783 TRACE("%d %s %d\n", hdb
, debugstr_a(szTransformFile
), iErrorCond
);
785 wstr
= strdupAtoW( szTransformFile
);
786 if( szTransformFile
&& !wstr
)
787 return ERROR_NOT_ENOUGH_MEMORY
;
789 ret
= MsiDatabaseApplyTransformW( hdb
, wstr
, iErrorCond
);
796 UINT WINAPI
MsiDatabaseGenerateTransformA( MSIHANDLE hdb
, MSIHANDLE hdbref
,
797 LPCSTR szTransformFile
, int iReserved1
, int iReserved2
)
799 FIXME("%d %d %s %d %d\n", hdb
, hdbref
,
800 debugstr_a(szTransformFile
), iReserved1
, iReserved2
);
801 return ERROR_CALL_NOT_IMPLEMENTED
;
804 UINT WINAPI
MsiDatabaseGenerateTransformW( MSIHANDLE hdb
, MSIHANDLE hdbref
,
805 LPCWSTR szTransformFile
, int iReserved1
, int iReserved2
)
807 FIXME("%d %d %s %d %d\n", hdb
, hdbref
,
808 debugstr_w(szTransformFile
), iReserved1
, iReserved2
);
809 return ERROR_CALL_NOT_IMPLEMENTED
;
812 UINT WINAPI
MsiDatabaseCommit( MSIHANDLE hdb
)
819 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
822 IWineMsiRemoteDatabase
*remote_database
;
824 remote_database
= (IWineMsiRemoteDatabase
*)msi_get_remote( hdb
);
825 if ( !remote_database
)
826 return ERROR_INVALID_HANDLE
;
828 IWineMsiRemoteDatabase_Release( remote_database
);
829 WARN("not allowed during a custom action!\n");
831 return ERROR_SUCCESS
;
834 if (db
->mode
== MSIDBOPEN_READONLY
)
836 msiobj_release( &db
->hdr
);
837 return ERROR_SUCCESS
;
840 /* FIXME: lock the database */
842 r
= MSI_CommitTables( db
);
843 if (r
!= ERROR_SUCCESS
) ERR("Failed to commit tables!\n");
845 /* FIXME: unlock the database */
847 msiobj_release( &db
->hdr
);
849 if (r
== ERROR_SUCCESS
)
851 msi_free( db
->deletefile
);
852 db
->deletefile
= NULL
;
858 struct msi_primary_key_record_info
864 static UINT
msi_primary_key_iterator( MSIRECORD
*rec
, LPVOID param
)
866 struct msi_primary_key_record_info
*info
= param
;
870 type
= MSI_RecordGetInteger( rec
, 4 );
871 if( type
& MSITYPE_KEY
)
878 table
= MSI_RecordGetString( rec
, 1 );
879 MSI_RecordSetStringW( info
->rec
, 0, table
);
882 name
= MSI_RecordGetString( rec
, 3 );
883 MSI_RecordSetStringW( info
->rec
, info
->n
, name
);
887 return ERROR_SUCCESS
;
890 UINT
MSI_DatabaseGetPrimaryKeys( MSIDATABASE
*db
,
891 LPCWSTR table
, MSIRECORD
**prec
)
893 static const WCHAR sql
[] = {
894 's','e','l','e','c','t',' ','*',' ',
895 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
896 'w','h','e','r','e',' ',
897 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
898 struct msi_primary_key_record_info info
;
899 MSIQUERY
*query
= NULL
;
902 if (!TABLE_Exists( db
, table
))
903 return ERROR_INVALID_TABLE
;
905 r
= MSI_OpenQuery( db
, &query
, sql
, table
);
906 if( r
!= ERROR_SUCCESS
)
909 /* count the number of primary key records */
912 r
= MSI_IterateRecords( query
, 0, msi_primary_key_iterator
, &info
);
913 if( r
== ERROR_SUCCESS
)
915 TRACE("Found %d primary keys\n", info
.n
);
917 /* allocate a record and fill in the names of the tables */
918 info
.rec
= MSI_CreateRecord( info
.n
);
920 r
= MSI_IterateRecords( query
, 0, msi_primary_key_iterator
, &info
);
921 if( r
== ERROR_SUCCESS
)
924 msiobj_release( &info
.rec
->hdr
);
926 msiobj_release( &query
->hdr
);
931 UINT WINAPI
MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb
,
932 LPCWSTR table
, MSIHANDLE
* phRec
)
934 MSIRECORD
*rec
= NULL
;
938 TRACE("%d %s %p\n", hdb
, debugstr_w(table
), phRec
);
940 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
944 IWineMsiRemoteDatabase
*remote_database
;
946 remote_database
= (IWineMsiRemoteDatabase
*)msi_get_remote( hdb
);
947 if ( !remote_database
)
948 return ERROR_INVALID_HANDLE
;
950 hr
= IWineMsiRemoteDatabase_GetPrimaryKeys( remote_database
, table
, phRec
);
951 IWineMsiRemoteDatabase_Release( remote_database
);
955 if (HRESULT_FACILITY(hr
) == FACILITY_WIN32
)
956 return HRESULT_CODE(hr
);
958 return ERROR_FUNCTION_FAILED
;
961 return ERROR_SUCCESS
;
964 r
= MSI_DatabaseGetPrimaryKeys( db
, table
, &rec
);
965 if( r
== ERROR_SUCCESS
)
967 *phRec
= alloc_msihandle( &rec
->hdr
);
969 r
= ERROR_NOT_ENOUGH_MEMORY
;
970 msiobj_release( &rec
->hdr
);
972 msiobj_release( &db
->hdr
);
977 UINT WINAPI
MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb
,
978 LPCSTR table
, MSIHANDLE
* phRec
)
980 LPWSTR szwTable
= NULL
;
983 TRACE("%d %s %p\n", hdb
, debugstr_a(table
), phRec
);
987 szwTable
= strdupAtoW( table
);
989 return ERROR_OUTOFMEMORY
;
991 r
= MsiDatabaseGetPrimaryKeysW( hdb
, szwTable
, phRec
);
992 msi_free( szwTable
);
997 MSICONDITION WINAPI
MsiDatabaseIsTablePersistentA(
998 MSIHANDLE hDatabase
, LPCSTR szTableName
)
1000 LPWSTR szwTableName
= NULL
;
1003 TRACE("%x %s\n", hDatabase
, debugstr_a(szTableName
));
1007 szwTableName
= strdupAtoW( szTableName
);
1009 return MSICONDITION_ERROR
;
1011 r
= MsiDatabaseIsTablePersistentW( hDatabase
, szwTableName
);
1012 msi_free( szwTableName
);
1017 MSICONDITION WINAPI
MsiDatabaseIsTablePersistentW(
1018 MSIHANDLE hDatabase
, LPCWSTR szTableName
)
1023 TRACE("%x %s\n", hDatabase
, debugstr_w(szTableName
));
1025 db
= msihandle2msiinfo( hDatabase
, MSIHANDLETYPE_DATABASE
);
1029 MSICONDITION condition
;
1030 IWineMsiRemoteDatabase
*remote_database
;
1032 remote_database
= (IWineMsiRemoteDatabase
*)msi_get_remote( hDatabase
);
1033 if ( !remote_database
)
1034 return MSICONDITION_ERROR
;
1036 hr
= IWineMsiRemoteDatabase_IsTablePersistent( remote_database
,
1037 szTableName
, &condition
);
1038 IWineMsiRemoteDatabase_Release( remote_database
);
1041 return MSICONDITION_ERROR
;
1046 r
= MSI_DatabaseIsTablePersistent( db
, szTableName
);
1048 msiobj_release( &db
->hdr
);