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/exception.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
= wcscmp( name
, col_name
);
78 x
|= wcscmp( table_name
, haystack_table_name
);
85 return ERROR_INVALID_PARAMETER
;
88 UINT WINAPI
MsiDatabaseOpenViewA( MSIHANDLE hdb
, const char *szQuery
, MSIHANDLE
*phView
)
93 TRACE( "%lu, %s, %p\n", hdb
, debugstr_a(szQuery
), phView
);
97 szwQuery
= strdupAtoW( szQuery
);
99 return ERROR_FUNCTION_FAILED
;
104 r
= MsiDatabaseOpenViewW( hdb
, szwQuery
, phView
);
106 msi_free( szwQuery
);
110 UINT
MSI_DatabaseOpenViewW( MSIDATABASE
*db
, const WCHAR
*szQuery
, MSIQUERY
**pView
)
115 TRACE( "%s, %p\n", debugstr_w(szQuery
), pView
);
117 /* pre allocate a handle to hold a pointer to the view */
118 query
= alloc_msiobject( MSIHANDLETYPE_VIEW
, sizeof (MSIQUERY
),
121 return ERROR_FUNCTION_FAILED
;
123 msiobj_addref( &db
->hdr
);
125 list_init( &query
->mem
);
127 r
= MSI_ParseSQL( db
, szQuery
, &query
->view
, &query
->mem
);
128 if( r
== ERROR_SUCCESS
)
130 msiobj_addref( &query
->hdr
);
134 msiobj_release( &query
->hdr
);
138 UINT WINAPIV
MSI_OpenQuery( MSIDATABASE
*db
, MSIQUERY
**view
, LPCWSTR fmt
, ... )
144 /* construct the string */
148 query
= msi_alloc( size
*sizeof(WCHAR
) );
150 res
= vswprintf(query
, size
, fmt
, va
);
152 if (res
== -1) size
*= 2;
153 else if (res
>= size
) size
= res
+ 1;
157 /* perform the query */
158 r
= MSI_DatabaseOpenViewW(db
, query
, view
);
163 UINT
MSI_IterateRecords( MSIQUERY
*view
, LPDWORD count
,
164 record_func func
, LPVOID param
)
166 MSIRECORD
*rec
= NULL
;
167 UINT r
, n
= 0, max
= 0;
169 r
= MSI_ViewExecute( view
, NULL
);
170 if( r
!= ERROR_SUCCESS
)
176 /* iterate a query */
177 for( n
= 0; (max
== 0) || (n
< max
); n
++ )
179 r
= MSI_ViewFetch( view
, &rec
);
180 if( r
!= ERROR_SUCCESS
)
183 r
= func( rec
, param
);
184 msiobj_release( &rec
->hdr
);
185 if( r
!= ERROR_SUCCESS
)
189 MSI_ViewClose( view
);
194 if( r
== ERROR_NO_MORE_ITEMS
)
200 /* return a single record from a query */
201 MSIRECORD
* WINAPIV
MSI_QueryGetRecord( MSIDATABASE
*db
, LPCWSTR fmt
, ... )
203 MSIRECORD
*rec
= NULL
;
204 MSIQUERY
*view
= NULL
;
209 /* construct the string */
213 query
= msi_alloc( size
*sizeof(WCHAR
) );
215 res
= vswprintf(query
, size
, fmt
, va
);
217 if (res
== -1) size
*= 2;
218 else if (res
>= size
) size
= res
+ 1;
222 /* perform the query */
223 r
= MSI_DatabaseOpenViewW(db
, query
, &view
);
226 if( r
== ERROR_SUCCESS
)
228 MSI_ViewExecute( view
, NULL
);
229 MSI_ViewFetch( view
, &rec
);
230 MSI_ViewClose( view
);
231 msiobj_release( &view
->hdr
);
236 UINT WINAPI
MsiDatabaseOpenViewW(MSIHANDLE hdb
,
237 LPCWSTR szQuery
, MSIHANDLE
*phView
)
240 MSIQUERY
*query
= NULL
;
243 TRACE("%s %p\n", debugstr_w(szQuery
), phView
);
246 return ERROR_INVALID_PARAMETER
;
249 return ERROR_BAD_QUERY_SYNTAX
;
251 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
254 MSIHANDLE remote
, remote_view
;
256 if (!(remote
= msi_get_remote(hdb
)))
257 return ERROR_INVALID_HANDLE
;
261 ret
= remote_DatabaseOpenView(remote
, szQuery
, &remote_view
);
265 ret
= GetExceptionCode();
270 *phView
= alloc_msi_remote_handle(remote_view
);
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_refresh_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 for (i
= 1; i
<= col_count
; i
++)
302 ret
= view
->ops
->get_column_info(view
, i
, NULL
, &type
, NULL
, NULL
);
305 ERR("Error getting column type for %d\n", i
);
309 if (MSITYPE_IS_BINARY(type
))
313 ret
= view
->ops
->fetch_stream(view
, row
, i
, &stm
);
314 if ((ret
== ERROR_SUCCESS
) && stm
)
316 MSI_RecordSetIStream(rec
, i
, stm
);
317 IStream_Release(stm
);
320 WARN("failed to get stream\n");
325 ret
= view
->ops
->fetch_int(view
, row
, i
, &ival
);
328 ERR("Error fetching data for %d\n", i
);
332 if (! (type
& MSITYPE_VALID
))
333 ERR("Invalid type!\n");
335 if (type
& MSITYPE_STRING
)
338 const WCHAR
*sval
= msi_string_lookup(db
->strings
, ival
, &len
);
339 msi_record_set_string(rec
, i
, sval
, len
);
343 if ((type
& MSI_DATASIZEMASK
) == 2)
344 MSI_RecordSetInteger(rec
, i
, ival
? ival
- (1<<15) : MSI_NULL_INTEGER
);
346 MSI_RecordSetInteger(rec
, i
, ival
- (1u<<31));
350 return ERROR_SUCCESS
;
353 UINT
msi_view_get_row(MSIDATABASE
*db
, MSIVIEW
*view
, UINT row
, MSIRECORD
**rec
)
355 UINT row_count
= 0, col_count
= 0, r
;
358 TRACE("view %p, row %u, rec %p.\n", view
, row
, rec
);
360 if ((r
= view
->ops
->get_dimensions(view
, &row_count
, &col_count
)))
363 if (row
>= row_count
)
364 return ERROR_NO_MORE_ITEMS
;
366 if (!(object
= MSI_CreateRecord( col_count
)))
367 return ERROR_OUTOFMEMORY
;
369 if ((r
= msi_view_refresh_row(db
, view
, row
, object
)))
370 msiobj_release( &object
->hdr
);
377 UINT
MSI_ViewFetch(MSIQUERY
*query
, MSIRECORD
**prec
)
382 TRACE("%p %p\n", query
, prec
);
386 return ERROR_FUNCTION_FAILED
;
388 r
= msi_view_get_row(query
->db
, view
, query
->row
, prec
);
389 if (r
== ERROR_SUCCESS
)
392 (*prec
)->cookie
= (UINT64
)(ULONG_PTR
)query
;
393 MSI_RecordSetInteger(*prec
, 0, 1);
395 else if (r
== ERROR_NO_MORE_ITEMS
)
397 /* end of view; reset cursor to first row */
404 UINT WINAPI
MsiViewFetch( MSIHANDLE hView
, MSIHANDLE
*record
)
407 MSIRECORD
*rec
= NULL
;
410 TRACE( "%lu, %p\n", hView
, record
);
413 return ERROR_INVALID_PARAMETER
;
416 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
419 struct wire_record
*wire_rec
= NULL
;
422 if (!(remote
= msi_get_remote(hView
)))
423 return ERROR_INVALID_HANDLE
;
427 ret
= remote_ViewFetch(remote
, &wire_rec
);
431 ret
= GetExceptionCode();
437 ret
= unmarshal_record(wire_rec
, record
);
438 free_remote_record(wire_rec
);
442 ret
= MSI_ViewFetch( query
, &rec
);
443 if( ret
== ERROR_SUCCESS
)
445 *record
= alloc_msihandle( &rec
->hdr
);
447 ret
= ERROR_NOT_ENOUGH_MEMORY
;
448 msiobj_release( &rec
->hdr
);
450 msiobj_release( &query
->hdr
);
454 UINT
MSI_ViewClose(MSIQUERY
*query
)
458 TRACE("%p\n", query
);
462 return ERROR_FUNCTION_FAILED
;
463 if( !view
->ops
->close
)
464 return ERROR_FUNCTION_FAILED
;
466 return view
->ops
->close( view
);
469 UINT WINAPI
MsiViewClose( MSIHANDLE hView
)
474 TRACE( "%lu\n", hView
);
476 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
481 if (!(remote
= msi_get_remote(hView
)))
482 return ERROR_INVALID_HANDLE
;
486 ret
= remote_ViewClose(remote
);
490 ret
= GetExceptionCode();
497 ret
= MSI_ViewClose( query
);
498 msiobj_release( &query
->hdr
);
502 UINT
MSI_ViewExecute(MSIQUERY
*query
, MSIRECORD
*rec
)
506 TRACE("%p %p\n", query
, rec
);
510 return ERROR_FUNCTION_FAILED
;
511 if( !view
->ops
->execute
)
512 return ERROR_FUNCTION_FAILED
;
515 return view
->ops
->execute( view
, rec
);
518 UINT WINAPI
MsiViewExecute( MSIHANDLE hView
, MSIHANDLE hRec
)
521 MSIRECORD
*rec
= NULL
;
524 TRACE( "%lu, %lu\n", hView
, hRec
);
528 rec
= msihandle2msiinfo( hRec
, MSIHANDLETYPE_RECORD
);
530 return ERROR_INVALID_HANDLE
;
533 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
538 if (!(remote
= msi_get_remote(hView
)))
539 return ERROR_INVALID_HANDLE
;
543 ret
= remote_ViewExecute(remote
, rec
? (struct wire_record
*)&rec
->count
: NULL
);
547 ret
= GetExceptionCode();
552 msiobj_release(&rec
->hdr
);
556 msiobj_lock( &rec
->hdr
);
557 ret
= MSI_ViewExecute( query
, rec
);
558 msiobj_unlock( &rec
->hdr
);
560 msiobj_release( &query
->hdr
);
562 msiobj_release( &rec
->hdr
);
567 static UINT
msi_set_record_type_string( MSIRECORD
*rec
, UINT field
,
568 UINT type
, BOOL temporary
)
572 if (MSITYPE_IS_BINARY(type
))
574 else if (type
& MSITYPE_LOCALIZABLE
)
576 else if (type
& MSITYPE_UNKNOWN
)
578 else if (type
& MSITYPE_STRING
)
593 if (type
& MSITYPE_NULLABLE
)
596 swprintf( &szType
[1], ARRAY_SIZE(szType
) - 1, L
"%d", (type
&0xff) );
598 TRACE("type %04x -> %s\n", type
, debugstr_w(szType
) );
600 return MSI_RecordSetStringW( rec
, field
, szType
);
603 UINT
MSI_ViewGetColumnInfo( MSIQUERY
*query
, MSICOLINFO info
, MSIRECORD
**prec
)
605 UINT r
= ERROR_FUNCTION_FAILED
, i
, count
= 0, type
;
607 MSIVIEW
*view
= query
->view
;
612 return ERROR_FUNCTION_FAILED
;
614 if( !view
->ops
->get_dimensions
)
615 return ERROR_FUNCTION_FAILED
;
617 r
= view
->ops
->get_dimensions( view
, NULL
, &count
);
618 if( r
!= ERROR_SUCCESS
)
621 return ERROR_INVALID_PARAMETER
;
623 rec
= MSI_CreateRecord( count
);
625 return ERROR_FUNCTION_FAILED
;
627 for( i
=0; i
<count
; i
++ )
630 r
= view
->ops
->get_column_info( view
, i
+1, &name
, &type
, &temporary
, NULL
);
631 if( r
!= ERROR_SUCCESS
)
633 if (info
== MSICOLINFO_NAMES
)
634 MSI_RecordSetStringW( rec
, i
+1, name
);
636 msi_set_record_type_string( rec
, i
+1, type
, temporary
);
639 return ERROR_SUCCESS
;
642 UINT WINAPI
MsiViewGetColumnInfo( MSIHANDLE hView
, MSICOLINFO info
, MSIHANDLE
*hRec
)
644 MSIQUERY
*query
= NULL
;
645 MSIRECORD
*rec
= NULL
;
648 TRACE( "%lu, %d, %p\n", hView
, info
, hRec
);
651 return ERROR_INVALID_PARAMETER
;
653 if( info
!= MSICOLINFO_NAMES
&& info
!= MSICOLINFO_TYPES
)
654 return ERROR_INVALID_PARAMETER
;
656 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
659 struct wire_record
*wire_rec
= NULL
;
662 if (!(remote
= msi_get_remote(hView
)))
663 return ERROR_INVALID_HANDLE
;
667 r
= remote_ViewGetColumnInfo(remote
, info
, &wire_rec
);
671 r
= GetExceptionCode();
677 r
= unmarshal_record(wire_rec
, hRec
);
678 free_remote_record(wire_rec
);
684 r
= MSI_ViewGetColumnInfo( query
, info
, &rec
);
685 if ( r
== ERROR_SUCCESS
)
687 *hRec
= alloc_msihandle( &rec
->hdr
);
689 r
= ERROR_NOT_ENOUGH_MEMORY
;
690 msiobj_release( &rec
->hdr
);
693 msiobj_release( &query
->hdr
);
698 UINT
MSI_ViewModify( MSIQUERY
*query
, MSIMODIFY mode
, MSIRECORD
*rec
)
700 MSIVIEW
*view
= NULL
;
703 if ( !query
|| !rec
)
704 return ERROR_INVALID_HANDLE
;
707 if ( !view
|| !view
->ops
->modify
)
708 return ERROR_FUNCTION_FAILED
;
710 if ( mode
== MSIMODIFY_UPDATE
&& rec
->cookie
!= (UINT64
)(ULONG_PTR
)query
)
711 return ERROR_FUNCTION_FAILED
;
713 r
= view
->ops
->modify( view
, mode
, rec
, query
->row
- 1 );
714 if (mode
== MSIMODIFY_DELETE
&& r
== ERROR_SUCCESS
)
720 UINT WINAPI
MsiViewModify( MSIHANDLE hView
, MSIMODIFY eModifyMode
, MSIHANDLE hRecord
)
722 MSIQUERY
*query
= NULL
;
723 MSIRECORD
*rec
= NULL
;
724 UINT r
= ERROR_FUNCTION_FAILED
;
726 TRACE( "%lu, %#x, %lu\n", hView
, eModifyMode
, hRecord
);
728 rec
= msihandle2msiinfo( hRecord
, MSIHANDLETYPE_RECORD
);
731 return ERROR_INVALID_HANDLE
;
733 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
736 struct wire_record
*wire_refreshed
= NULL
;
739 if (!(remote
= msi_get_remote(hView
)))
740 return ERROR_INVALID_HANDLE
;
744 r
= remote_ViewModify(remote
, eModifyMode
,
745 (struct wire_record
*)&rec
->count
, &wire_refreshed
);
749 r
= GetExceptionCode();
753 if (!r
&& (eModifyMode
== MSIMODIFY_REFRESH
|| eModifyMode
== MSIMODIFY_SEEK
))
755 r
= copy_remote_record(wire_refreshed
, hRecord
);
756 free_remote_record(wire_refreshed
);
759 msiobj_release(&rec
->hdr
);
763 r
= MSI_ViewModify( query
, eModifyMode
, rec
);
765 msiobj_release( &query
->hdr
);
766 msiobj_release(&rec
->hdr
);
770 MSIDBERROR WINAPI
MsiViewGetErrorW( MSIHANDLE handle
, WCHAR
*buffer
, DWORD
*buflen
)
776 TRACE( "%lu, %p, %p\n", handle
, buffer
, buflen
);
779 return MSIDBERROR_INVALIDARG
;
781 if (!(query
= msihandle2msiinfo(handle
, MSIHANDLETYPE_VIEW
)))
783 WCHAR
*remote_column
= NULL
;
786 if (!(remote
= msi_get_remote(handle
)))
787 return MSIDBERROR_INVALIDARG
;
790 return MSIDBERROR_FUNCTIONERROR
;
794 r
= remote_ViewGetError(remote
, &remote_column
);
798 r
= GetExceptionCode();
802 if (msi_strncpyW(remote_column
? remote_column
: L
"", -1, buffer
, buflen
) == ERROR_MORE_DATA
)
803 r
= MSIDBERROR_MOREDATA
;
806 midl_user_free(remote_column
);
811 if ((r
= query
->view
->error
)) column
= query
->view
->error_column
;
814 if (msi_strncpyW(column
, -1, buffer
, buflen
) == ERROR_MORE_DATA
)
815 r
= MSIDBERROR_MOREDATA
;
817 msiobj_release( &query
->hdr
);
821 MSIDBERROR WINAPI
MsiViewGetErrorA( MSIHANDLE handle
, char *buffer
, DWORD
*buflen
)
827 TRACE( "%lu, %p, %p\n", handle
, buffer
, buflen
);
830 return MSIDBERROR_INVALIDARG
;
832 if (!(query
= msihandle2msiinfo(handle
, MSIHANDLETYPE_VIEW
)))
834 WCHAR
*remote_column
= NULL
;
837 if (!(remote
= msi_get_remote(handle
)))
838 return MSIDBERROR_INVALIDARG
;
841 return MSIDBERROR_FUNCTIONERROR
;
845 r
= remote_ViewGetError(remote
, &remote_column
);
849 r
= GetExceptionCode();
853 if (msi_strncpyWtoA(remote_column
? remote_column
: L
"", -1, buffer
, buflen
, FALSE
) == ERROR_MORE_DATA
)
854 r
= MSIDBERROR_MOREDATA
;
857 midl_user_free(remote_column
);
862 if ((r
= query
->view
->error
)) column
= query
->view
->error_column
;
865 if (msi_strncpyWtoA(column
, -1, buffer
, buflen
, FALSE
) == ERROR_MORE_DATA
)
866 r
= MSIDBERROR_MOREDATA
;
868 msiobj_release( &query
->hdr
);
872 MSIHANDLE WINAPI
MsiGetLastErrorRecord( void )
878 UINT
MSI_DatabaseApplyTransformW( MSIDATABASE
*db
, const WCHAR
*transform
, int error_cond
)
881 UINT ret
= ERROR_FUNCTION_FAILED
;
885 TRACE( "%p %s %08x\n", db
, debugstr_w(transform
), error_cond
);
887 if (*transform
== ':')
889 hr
= IStorage_OpenStorage( db
->storage
, transform
+ 1, NULL
, STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
892 WARN( "failed to open substorage transform %#lx\n", hr
);
893 return ERROR_FUNCTION_FAILED
;
898 hr
= StgOpenStorage( transform
, NULL
, STGM_DIRECT
|STGM_READ
|STGM_SHARE_DENY_WRITE
, NULL
, 0, &stg
);
901 WARN( "failed to open file transform %#lx\n", hr
);
902 return ERROR_FUNCTION_FAILED
;
906 hr
= IStorage_Stat( stg
, &stat
, STATFLAG_NONAME
);
907 if (FAILED( hr
)) goto end
;
908 if (!IsEqualGUID( &stat
.clsid
, &CLSID_MsiTransform
)) goto end
;
909 if (TRACE_ON( msi
)) enum_stream_names( stg
);
911 ret
= msi_table_apply_transform( db
, stg
, error_cond
);
914 IStorage_Release( stg
);
918 UINT WINAPI
MsiDatabaseApplyTransformW( MSIHANDLE hdb
, const WCHAR
*transform
, int error_cond
)
923 if (error_cond
& ~MSITRANSFORM_ERROR_VIEWTRANSFORM
) FIXME( "ignoring error conditions\n" );
925 if (!(db
= msihandle2msiinfo(hdb
, MSIHANDLETYPE_DATABASE
)))
926 return ERROR_INVALID_HANDLE
;
928 r
= MSI_DatabaseApplyTransformW( db
, transform
, error_cond
);
929 msiobj_release( &db
->hdr
);
933 UINT WINAPI
MsiDatabaseApplyTransformA( MSIHANDLE hdb
, const char *transform
, int error_cond
)
938 TRACE( "%lu, %s, %#x\n", hdb
, debugstr_a(transform
), error_cond
);
940 wstr
= strdupAtoW( transform
);
941 if (transform
&& !wstr
)
942 return ERROR_NOT_ENOUGH_MEMORY
;
944 ret
= MsiDatabaseApplyTransformW( hdb
, wstr
, error_cond
);
949 UINT WINAPI
MsiDatabaseGenerateTransformA( MSIHANDLE hdb
, MSIHANDLE hdbref
, const char *szTransformFile
,
950 int iReserved1
, int iReserved2
)
952 FIXME( "%lu, %lu, %s, %d, %d\n", hdb
, hdbref
, debugstr_a(szTransformFile
), iReserved1
, iReserved2
);
953 return ERROR_CALL_NOT_IMPLEMENTED
;
956 UINT WINAPI
MsiDatabaseGenerateTransformW( MSIHANDLE hdb
, MSIHANDLE hdbref
, const WCHAR
*szTransformFile
,
957 int iReserved1
, int iReserved2
)
959 FIXME( "%lu, %lu, %s, %d, %d\n", hdb
, hdbref
, debugstr_w(szTransformFile
), iReserved1
, iReserved2
);
960 return ERROR_CALL_NOT_IMPLEMENTED
;
963 UINT WINAPI
MsiDatabaseCommit( MSIHANDLE hdb
)
968 TRACE( "%lu\n", hdb
);
970 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
975 if (!(remote
= msi_get_remote(hdb
)))
976 return ERROR_INVALID_HANDLE
;
978 WARN("not allowed during a custom action!\n");
980 return ERROR_SUCCESS
;
983 if (db
->mode
== MSI_OPEN_READONLY
)
985 msiobj_release( &db
->hdr
);
986 return ERROR_SUCCESS
;
989 /* FIXME: lock the database */
991 r
= msi_commit_streams( db
);
992 if (r
!= ERROR_SUCCESS
) ERR("Failed to commit streams!\n");
995 r
= MSI_CommitTables( db
);
996 if (r
!= ERROR_SUCCESS
) ERR("Failed to commit tables!\n");
999 /* FIXME: unlock the database */
1001 msiobj_release( &db
->hdr
);
1003 if (r
== ERROR_SUCCESS
)
1005 msi_free( db
->deletefile
);
1006 db
->deletefile
= NULL
;
1012 struct msi_primary_key_record_info
1018 static UINT
msi_primary_key_iterator( MSIRECORD
*rec
, LPVOID param
)
1020 struct msi_primary_key_record_info
*info
= param
;
1021 LPCWSTR name
, table
;
1024 type
= MSI_RecordGetInteger( rec
, 4 );
1025 if( type
& MSITYPE_KEY
)
1032 table
= MSI_RecordGetString( rec
, 1 );
1033 MSI_RecordSetStringW( info
->rec
, 0, table
);
1036 name
= MSI_RecordGetString( rec
, 3 );
1037 MSI_RecordSetStringW( info
->rec
, info
->n
, name
);
1041 return ERROR_SUCCESS
;
1044 UINT
MSI_DatabaseGetPrimaryKeys( MSIDATABASE
*db
,
1045 LPCWSTR table
, MSIRECORD
**prec
)
1047 struct msi_primary_key_record_info info
;
1048 MSIQUERY
*query
= NULL
;
1051 if (!TABLE_Exists( db
, table
))
1052 return ERROR_INVALID_TABLE
;
1054 r
= MSI_OpenQuery( db
, &query
, L
"SELECT * FROM `_Columns` WHERE `Table` = '%s'", table
);
1055 if( r
!= ERROR_SUCCESS
)
1058 /* count the number of primary key records */
1061 r
= MSI_IterateRecords( query
, 0, msi_primary_key_iterator
, &info
);
1062 if( r
== ERROR_SUCCESS
)
1064 TRACE( "found %lu primary keys\n", info
.n
);
1066 /* allocate a record and fill in the names of the tables */
1067 info
.rec
= MSI_CreateRecord( info
.n
);
1069 r
= MSI_IterateRecords( query
, 0, msi_primary_key_iterator
, &info
);
1070 if( r
== ERROR_SUCCESS
)
1073 msiobj_release( &info
.rec
->hdr
);
1075 msiobj_release( &query
->hdr
);
1080 UINT WINAPI
MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb
, const WCHAR
*table
, MSIHANDLE
*phRec
)
1082 MSIRECORD
*rec
= NULL
;
1086 TRACE( "%lu, %s, %p\n", hdb
, debugstr_w(table
), phRec
);
1088 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
1091 struct wire_record
*wire_rec
= NULL
;
1094 if (!(remote
= msi_get_remote(hdb
)))
1095 return ERROR_INVALID_HANDLE
;
1099 r
= remote_DatabaseGetPrimaryKeys(remote
, table
, &wire_rec
);
1101 __EXCEPT(rpc_filter
)
1103 r
= GetExceptionCode();
1109 r
= unmarshal_record(wire_rec
, phRec
);
1110 free_remote_record(wire_rec
);
1116 r
= MSI_DatabaseGetPrimaryKeys( db
, table
, &rec
);
1117 if( r
== ERROR_SUCCESS
)
1119 *phRec
= alloc_msihandle( &rec
->hdr
);
1121 r
= ERROR_NOT_ENOUGH_MEMORY
;
1122 msiobj_release( &rec
->hdr
);
1124 msiobj_release( &db
->hdr
);
1129 UINT WINAPI
MsiDatabaseGetPrimaryKeysA( MSIHANDLE hdb
, const char *table
, MSIHANDLE
*phRec
)
1131 WCHAR
*szwTable
= NULL
;
1134 TRACE( "%lu, %s, %p\n", hdb
, debugstr_a(table
), phRec
);
1138 szwTable
= strdupAtoW( table
);
1140 return ERROR_OUTOFMEMORY
;
1142 r
= MsiDatabaseGetPrimaryKeysW( hdb
, szwTable
, phRec
);
1143 msi_free( szwTable
);
1148 MSICONDITION WINAPI
MsiDatabaseIsTablePersistentA( MSIHANDLE hDatabase
, const char *szTableName
)
1150 WCHAR
*szwTableName
= NULL
;
1153 TRACE( "%lu, %s\n", hDatabase
, debugstr_a(szTableName
) );
1157 szwTableName
= strdupAtoW( szTableName
);
1159 return MSICONDITION_ERROR
;
1161 r
= MsiDatabaseIsTablePersistentW( hDatabase
, szwTableName
);
1162 msi_free( szwTableName
);
1167 MSICONDITION WINAPI
MsiDatabaseIsTablePersistentW( MSIHANDLE hDatabase
, const WCHAR
*szTableName
)
1172 TRACE( "%lu, %s\n", hDatabase
, debugstr_w(szTableName
) );
1174 db
= msihandle2msiinfo( hDatabase
, MSIHANDLETYPE_DATABASE
);
1179 if (!(remote
= msi_get_remote(hDatabase
)))
1180 return MSICONDITION_ERROR
;
1184 r
= remote_DatabaseIsTablePersistent(remote
, szTableName
);
1186 __EXCEPT(rpc_filter
)
1188 r
= MSICONDITION_ERROR
;
1195 r
= MSI_DatabaseIsTablePersistent( db
, szTableName
);
1197 msiobj_release( &db
->hdr
);
1202 UINT __cdecl
s_remote_ViewClose(MSIHANDLE view
)
1204 return MsiViewClose(view
);
1207 UINT __cdecl
s_remote_ViewExecute(MSIHANDLE view
, struct wire_record
*remote_rec
)
1212 if ((r
= unmarshal_record(remote_rec
, &rec
)))
1215 r
= MsiViewExecute(view
, rec
);
1217 MsiCloseHandle(rec
);
1221 UINT __cdecl
s_remote_ViewFetch(MSIHANDLE view
, struct wire_record
**rec
)
1224 UINT r
= MsiViewFetch(view
, &handle
);
1227 *rec
= marshal_record(handle
);
1228 MsiCloseHandle(handle
);
1232 UINT __cdecl
s_remote_ViewGetColumnInfo(MSIHANDLE view
, MSICOLINFO info
, struct wire_record
**rec
)
1235 UINT r
= MsiViewGetColumnInfo(view
, info
, &handle
);
1238 *rec
= marshal_record(handle
);
1239 MsiCloseHandle(handle
);
1243 MSIDBERROR __cdecl
s_remote_ViewGetError(MSIHANDLE view
, LPWSTR
*column
)
1249 r
= MsiViewGetErrorW(view
, empty
, &size
);
1250 if (r
== MSIDBERROR_MOREDATA
)
1252 if (!(*column
= midl_user_allocate(++size
* sizeof(WCHAR
))))
1253 return MSIDBERROR_FUNCTIONERROR
;
1254 r
= MsiViewGetErrorW(view
, *column
, &size
);
1259 UINT __cdecl
s_remote_ViewModify(MSIHANDLE view
, MSIMODIFY mode
,
1260 struct wire_record
*remote_rec
, struct wire_record
**remote_refreshed
)
1262 MSIHANDLE handle
= 0;
1265 if ((r
= unmarshal_record(remote_rec
, &handle
)))
1268 r
= MsiViewModify(view
, mode
, handle
);
1269 *remote_refreshed
= NULL
;
1270 if (!r
&& (mode
== MSIMODIFY_REFRESH
|| mode
== MSIMODIFY_SEEK
))
1271 *remote_refreshed
= marshal_record(handle
);
1273 MsiCloseHandle(handle
);