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"
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
);
119 /* pre allocate a handle to hold a pointer to the view */
120 query
= alloc_msiobject( MSIHANDLETYPE_VIEW
, sizeof (MSIQUERY
),
123 return ERROR_FUNCTION_FAILED
;
125 msiobj_addref( &db
->hdr
);
127 list_init( &query
->mem
);
129 r
= MSI_ParseSQL( db
, szQuery
, &query
->view
, &query
->mem
);
130 if( r
== ERROR_SUCCESS
)
132 msiobj_addref( &query
->hdr
);
136 msiobj_release( &query
->hdr
);
140 UINT
MSI_OpenQuery( MSIDATABASE
*db
, MSIQUERY
**view
, LPCWSTR fmt
, ... )
146 /* construct the string */
150 query
= msi_alloc( size
*sizeof(WCHAR
) );
152 res
= vsnprintfW(query
, size
, fmt
, va
);
154 if (res
== -1) size
*= 2;
155 else if (res
>= size
) size
= res
+ 1;
159 /* perform the query */
160 r
= MSI_DatabaseOpenViewW(db
, query
, view
);
165 UINT
MSI_IterateRecords( MSIQUERY
*view
, LPDWORD count
,
166 record_func func
, LPVOID param
)
168 MSIRECORD
*rec
= NULL
;
169 UINT r
, n
= 0, max
= 0;
171 r
= MSI_ViewExecute( view
, NULL
);
172 if( r
!= ERROR_SUCCESS
)
178 /* iterate a query */
179 for( n
= 0; (max
== 0) || (n
< max
); n
++ )
181 r
= MSI_ViewFetch( view
, &rec
);
182 if( r
!= ERROR_SUCCESS
)
185 r
= func( rec
, param
);
186 msiobj_release( &rec
->hdr
);
187 if( r
!= ERROR_SUCCESS
)
191 MSI_ViewClose( view
);
196 if( r
== ERROR_NO_MORE_ITEMS
)
202 /* return a single record from a query */
203 MSIRECORD
*MSI_QueryGetRecord( MSIDATABASE
*db
, LPCWSTR fmt
, ... )
205 MSIRECORD
*rec
= NULL
;
206 MSIQUERY
*view
= NULL
;
211 /* construct the string */
215 query
= msi_alloc( size
*sizeof(WCHAR
) );
217 res
= vsnprintfW(query
, size
, fmt
, va
);
219 if (res
== -1) size
*= 2;
220 else if (res
>= size
) size
= res
+ 1;
224 /* perform the query */
225 r
= MSI_DatabaseOpenViewW(db
, query
, &view
);
228 if( r
== ERROR_SUCCESS
)
230 MSI_ViewExecute( view
, NULL
);
231 MSI_ViewFetch( view
, &rec
);
232 MSI_ViewClose( view
);
233 msiobj_release( &view
->hdr
);
238 UINT WINAPI
MsiDatabaseOpenViewW(MSIHANDLE hdb
,
239 LPCWSTR szQuery
, MSIHANDLE
*phView
)
242 MSIQUERY
*query
= NULL
;
245 TRACE("%s %p\n", debugstr_w(szQuery
), phView
);
248 return ERROR_INVALID_PARAMETER
;
251 return ERROR_BAD_QUERY_SYNTAX
;
253 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
256 MSIHANDLE remote
, remote_view
;
258 if (!(remote
= msi_get_remote(hdb
)))
259 return ERROR_INVALID_HANDLE
;
261 ret
= remote_DatabaseOpenView(remote
, szQuery
, &remote_view
);
263 *phView
= alloc_msi_remote_handle(remote_view
);
267 ret
= MSI_DatabaseOpenViewW( db
, szQuery
, &query
);
268 if( ret
== ERROR_SUCCESS
)
270 *phView
= alloc_msihandle( &query
->hdr
);
272 ret
= ERROR_NOT_ENOUGH_MEMORY
;
273 msiobj_release( &query
->hdr
);
275 msiobj_release( &db
->hdr
);
280 UINT
msi_view_get_row(MSIDATABASE
*db
, MSIVIEW
*view
, UINT row
, MSIRECORD
**rec
)
282 UINT row_count
= 0, col_count
= 0, i
, ival
, ret
, type
;
284 TRACE("%p %p %d %p\n", db
, view
, row
, rec
);
286 ret
= view
->ops
->get_dimensions(view
, &row_count
, &col_count
);
291 return ERROR_INVALID_PARAMETER
;
293 if (row
>= row_count
)
294 return ERROR_NO_MORE_ITEMS
;
296 *rec
= MSI_CreateRecord(col_count
);
298 return ERROR_FUNCTION_FAILED
;
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 /* check if it's nul (0) - if so, don't set anything */
339 if (type
& MSITYPE_STRING
)
342 const WCHAR
*sval
= msi_string_lookup( db
->strings
, ival
, &len
);
343 msi_record_set_string( *rec
, i
, sval
, len
);
347 if ((type
& MSI_DATASIZEMASK
) == 2)
348 MSI_RecordSetInteger(*rec
, i
, ival
- (1<<15));
350 MSI_RecordSetInteger(*rec
, i
, ival
- (1u<<31));
354 return ERROR_SUCCESS
;
357 UINT
MSI_ViewFetch(MSIQUERY
*query
, MSIRECORD
**prec
)
362 TRACE("%p %p\n", query
, prec
);
366 return ERROR_FUNCTION_FAILED
;
368 r
= msi_view_get_row(query
->db
, view
, query
->row
, prec
);
369 if (r
== ERROR_SUCCESS
)
372 (*prec
)->query
= query
;
373 MSI_RecordSetInteger(*prec
, 0, 1);
379 UINT WINAPI
MsiViewFetch(MSIHANDLE hView
, MSIHANDLE
*record
)
382 MSIRECORD
*rec
= NULL
;
385 TRACE("%d %p\n", hView
, record
);
388 return ERROR_INVALID_PARAMETER
;
391 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
394 struct wire_record
*wire_rec
= NULL
;
397 if (!(remote
= msi_get_remote(hView
)))
398 return ERROR_INVALID_HANDLE
;
400 ret
= remote_ViewFetch(remote
, &wire_rec
);
403 ret
= unmarshal_record(wire_rec
, record
);
404 free_remote_record(wire_rec
);
408 ret
= MSI_ViewFetch( query
, &rec
);
409 if( ret
== ERROR_SUCCESS
)
411 *record
= alloc_msihandle( &rec
->hdr
);
413 ret
= ERROR_NOT_ENOUGH_MEMORY
;
414 msiobj_release( &rec
->hdr
);
416 msiobj_release( &query
->hdr
);
420 UINT
MSI_ViewClose(MSIQUERY
*query
)
424 TRACE("%p\n", query
);
428 return ERROR_FUNCTION_FAILED
;
429 if( !view
->ops
->close
)
430 return ERROR_FUNCTION_FAILED
;
432 return view
->ops
->close( view
);
435 UINT WINAPI
MsiViewClose(MSIHANDLE hView
)
440 TRACE("%d\n", hView
);
442 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
447 if (!(remote
= msi_get_remote(hView
)))
448 return ERROR_INVALID_HANDLE
;
450 return remote_ViewClose(remote
);
453 ret
= MSI_ViewClose( query
);
454 msiobj_release( &query
->hdr
);
458 UINT
MSI_ViewExecute(MSIQUERY
*query
, MSIRECORD
*rec
)
462 TRACE("%p %p\n", query
, rec
);
466 return ERROR_FUNCTION_FAILED
;
467 if( !view
->ops
->execute
)
468 return ERROR_FUNCTION_FAILED
;
471 return view
->ops
->execute( view
, rec
);
474 UINT WINAPI
MsiViewExecute(MSIHANDLE hView
, MSIHANDLE hRec
)
477 MSIRECORD
*rec
= NULL
;
480 TRACE("%d %d\n", hView
, hRec
);
484 rec
= msihandle2msiinfo( hRec
, MSIHANDLETYPE_RECORD
);
486 return ERROR_INVALID_HANDLE
;
489 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
494 if (!(remote
= msi_get_remote(hView
)))
495 return ERROR_INVALID_HANDLE
;
497 ret
= remote_ViewExecute(remote
, rec
? (struct wire_record
*)&rec
->count
: NULL
);
500 msiobj_release(&rec
->hdr
);
504 msiobj_lock( &rec
->hdr
);
505 ret
= MSI_ViewExecute( query
, rec
);
506 msiobj_unlock( &rec
->hdr
);
508 msiobj_release( &query
->hdr
);
510 msiobj_release( &rec
->hdr
);
515 static UINT
msi_set_record_type_string( MSIRECORD
*rec
, UINT field
,
516 UINT type
, BOOL temporary
)
518 static const WCHAR fmt
[] = { '%','d',0 };
521 if (MSITYPE_IS_BINARY(type
))
523 else if (type
& MSITYPE_LOCALIZABLE
)
525 else if (type
& MSITYPE_UNKNOWN
)
527 else if (type
& MSITYPE_STRING
)
542 if (type
& MSITYPE_NULLABLE
)
545 sprintfW( &szType
[1], fmt
, (type
&0xff) );
547 TRACE("type %04x -> %s\n", type
, debugstr_w(szType
) );
549 return MSI_RecordSetStringW( rec
, field
, szType
);
552 UINT
MSI_ViewGetColumnInfo( MSIQUERY
*query
, MSICOLINFO info
, MSIRECORD
**prec
)
554 UINT r
= ERROR_FUNCTION_FAILED
, i
, count
= 0, type
;
556 MSIVIEW
*view
= query
->view
;
561 return ERROR_FUNCTION_FAILED
;
563 if( !view
->ops
->get_dimensions
)
564 return ERROR_FUNCTION_FAILED
;
566 r
= view
->ops
->get_dimensions( view
, NULL
, &count
);
567 if( r
!= ERROR_SUCCESS
)
570 return ERROR_INVALID_PARAMETER
;
572 rec
= MSI_CreateRecord( count
);
574 return ERROR_FUNCTION_FAILED
;
576 for( i
=0; i
<count
; i
++ )
579 r
= view
->ops
->get_column_info( view
, i
+1, &name
, &type
, &temporary
, NULL
);
580 if( r
!= ERROR_SUCCESS
)
582 if (info
== MSICOLINFO_NAMES
)
583 MSI_RecordSetStringW( rec
, i
+1, name
);
585 msi_set_record_type_string( rec
, i
+1, type
, temporary
);
588 return ERROR_SUCCESS
;
591 UINT WINAPI
MsiViewGetColumnInfo(MSIHANDLE hView
, MSICOLINFO info
, MSIHANDLE
*hRec
)
593 MSIQUERY
*query
= NULL
;
594 MSIRECORD
*rec
= NULL
;
597 TRACE("%d %d %p\n", hView
, info
, hRec
);
600 return ERROR_INVALID_PARAMETER
;
602 if( info
!= MSICOLINFO_NAMES
&& info
!= MSICOLINFO_TYPES
)
603 return ERROR_INVALID_PARAMETER
;
605 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
608 struct wire_record
*wire_rec
= NULL
;
611 if (!(remote
= msi_get_remote(hView
)))
612 return ERROR_INVALID_HANDLE
;
614 r
= remote_ViewGetColumnInfo(remote
, info
, &wire_rec
);
617 r
= unmarshal_record(wire_rec
, hRec
);
618 free_remote_record(wire_rec
);
624 r
= MSI_ViewGetColumnInfo( query
, info
, &rec
);
625 if ( r
== ERROR_SUCCESS
)
627 *hRec
= alloc_msihandle( &rec
->hdr
);
629 r
= ERROR_NOT_ENOUGH_MEMORY
;
630 msiobj_release( &rec
->hdr
);
633 msiobj_release( &query
->hdr
);
638 UINT
MSI_ViewModify( MSIQUERY
*query
, MSIMODIFY mode
, MSIRECORD
*rec
)
640 MSIVIEW
*view
= NULL
;
643 if ( !query
|| !rec
)
644 return ERROR_INVALID_HANDLE
;
647 if ( !view
|| !view
->ops
->modify
)
648 return ERROR_FUNCTION_FAILED
;
650 if ( mode
== MSIMODIFY_UPDATE
&& rec
->query
!= query
)
651 return ERROR_FUNCTION_FAILED
;
653 r
= view
->ops
->modify( view
, mode
, rec
, query
->row
);
654 if (mode
== MSIMODIFY_DELETE
&& r
== ERROR_SUCCESS
)
660 UINT WINAPI
MsiViewModify( MSIHANDLE hView
, MSIMODIFY eModifyMode
,
663 MSIQUERY
*query
= NULL
;
664 MSIRECORD
*rec
= NULL
;
665 UINT r
= ERROR_FUNCTION_FAILED
;
667 TRACE("%d %x %d\n", hView
, eModifyMode
, hRecord
);
669 rec
= msihandle2msiinfo( hRecord
, MSIHANDLETYPE_RECORD
);
672 return ERROR_INVALID_HANDLE
;
674 query
= msihandle2msiinfo( hView
, MSIHANDLETYPE_VIEW
);
677 struct wire_record
*wire_refreshed
= NULL
;
680 if (!(remote
= msi_get_remote(hView
)))
681 return ERROR_INVALID_HANDLE
;
683 r
= remote_ViewModify(remote
, eModifyMode
,
684 (struct wire_record
*)&rec
->count
, &wire_refreshed
);
685 if (!r
&& (eModifyMode
== MSIMODIFY_REFRESH
|| eModifyMode
== MSIMODIFY_SEEK
))
687 r
= copy_remote_record(wire_refreshed
, hRecord
);
688 free_remote_record(wire_refreshed
);
691 msiobj_release(&rec
->hdr
);
695 r
= MSI_ViewModify( query
, eModifyMode
, rec
);
697 msiobj_release( &query
->hdr
);
698 msiobj_release(&rec
->hdr
);
702 MSIDBERROR WINAPI
MsiViewGetErrorW( MSIHANDLE handle
, LPWSTR buffer
, LPDWORD buflen
)
709 TRACE("%u %p %p\n", handle
, buffer
, buflen
);
712 return MSIDBERROR_INVALIDARG
;
714 query
= msihandle2msiinfo( handle
, MSIHANDLETYPE_VIEW
);
716 return MSIDBERROR_INVALIDARG
;
718 if ((r
= query
->view
->error
)) column
= query
->view
->error_column
;
719 else column
= szEmpty
;
721 len
= strlenW( column
);
725 strcpyW( buffer
, column
);
727 r
= MSIDBERROR_MOREDATA
;
730 msiobj_release( &query
->hdr
);
734 MSIDBERROR WINAPI
MsiViewGetErrorA( MSIHANDLE handle
, LPSTR buffer
, LPDWORD buflen
)
741 TRACE("%u %p %p\n", handle
, buffer
, buflen
);
744 return MSIDBERROR_INVALIDARG
;
746 query
= msihandle2msiinfo( handle
, MSIHANDLETYPE_VIEW
);
748 return MSIDBERROR_INVALIDARG
;
750 if ((r
= query
->view
->error
)) column
= query
->view
->error_column
;
751 else column
= szEmpty
;
753 len
= WideCharToMultiByte( CP_ACP
, 0, column
, -1, NULL
, 0, NULL
, NULL
);
757 WideCharToMultiByte( CP_ACP
, 0, column
, -1, buffer
, *buflen
, NULL
, NULL
);
759 r
= MSIDBERROR_MOREDATA
;
762 msiobj_release( &query
->hdr
);
766 MSIHANDLE WINAPI
MsiGetLastErrorRecord( void )
772 UINT
MSI_DatabaseApplyTransformW( MSIDATABASE
*db
,
773 LPCWSTR szTransformFile
, int iErrorCond
)
776 UINT ret
= ERROR_FUNCTION_FAILED
;
777 IStorage
*stg
= NULL
;
780 TRACE("%p %s %d\n", db
, debugstr_w(szTransformFile
), iErrorCond
);
782 r
= StgOpenStorage( szTransformFile
, NULL
,
783 STGM_DIRECT
|STGM_READ
|STGM_SHARE_DENY_WRITE
, NULL
, 0, &stg
);
786 WARN("failed to open transform 0x%08x\n", r
);
790 r
= IStorage_Stat( stg
, &stat
, STATFLAG_NONAME
);
794 if ( !IsEqualGUID( &stat
.clsid
, &CLSID_MsiTransform
) )
797 if( TRACE_ON( msi
) )
798 enum_stream_names( stg
);
800 ret
= msi_table_apply_transform( db
, stg
);
803 IStorage_Release( stg
);
808 UINT WINAPI
MsiDatabaseApplyTransformW( MSIHANDLE hdb
,
809 LPCWSTR szTransformFile
, int iErrorCond
)
814 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
819 if (!(remote
= msi_get_remote(hdb
)))
820 return ERROR_INVALID_HANDLE
;
822 WARN("MsiDatabaseApplyTransform not allowed during a custom action!\n");
824 return ERROR_SUCCESS
;
827 r
= MSI_DatabaseApplyTransformW( db
, szTransformFile
, iErrorCond
);
828 msiobj_release( &db
->hdr
);
832 UINT WINAPI
MsiDatabaseApplyTransformA( MSIHANDLE hdb
,
833 LPCSTR szTransformFile
, int iErrorCond
)
838 TRACE("%d %s %d\n", hdb
, debugstr_a(szTransformFile
), iErrorCond
);
840 wstr
= strdupAtoW( szTransformFile
);
841 if( szTransformFile
&& !wstr
)
842 return ERROR_NOT_ENOUGH_MEMORY
;
844 ret
= MsiDatabaseApplyTransformW( hdb
, wstr
, iErrorCond
);
851 UINT WINAPI
MsiDatabaseGenerateTransformA( MSIHANDLE hdb
, MSIHANDLE hdbref
,
852 LPCSTR szTransformFile
, int iReserved1
, int iReserved2
)
854 FIXME("%d %d %s %d %d\n", hdb
, hdbref
,
855 debugstr_a(szTransformFile
), iReserved1
, iReserved2
);
856 return ERROR_CALL_NOT_IMPLEMENTED
;
859 UINT WINAPI
MsiDatabaseGenerateTransformW( MSIHANDLE hdb
, MSIHANDLE hdbref
,
860 LPCWSTR szTransformFile
, int iReserved1
, int iReserved2
)
862 FIXME("%d %d %s %d %d\n", hdb
, hdbref
,
863 debugstr_w(szTransformFile
), iReserved1
, iReserved2
);
864 return ERROR_CALL_NOT_IMPLEMENTED
;
867 UINT WINAPI
MsiDatabaseCommit( MSIHANDLE hdb
)
874 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
879 if (!(remote
= msi_get_remote(hdb
)))
880 return ERROR_INVALID_HANDLE
;
882 WARN("not allowed during a custom action!\n");
884 return ERROR_SUCCESS
;
887 if (db
->mode
== MSIDBOPEN_READONLY
)
889 msiobj_release( &db
->hdr
);
890 return ERROR_SUCCESS
;
893 /* FIXME: lock the database */
895 r
= msi_commit_streams( db
);
896 if (r
!= ERROR_SUCCESS
) ERR("Failed to commit streams!\n");
899 r
= MSI_CommitTables( db
);
900 if (r
!= ERROR_SUCCESS
) ERR("Failed to commit tables!\n");
903 /* FIXME: unlock the database */
905 msiobj_release( &db
->hdr
);
907 if (r
== ERROR_SUCCESS
)
909 msi_free( db
->deletefile
);
910 db
->deletefile
= NULL
;
916 struct msi_primary_key_record_info
922 static UINT
msi_primary_key_iterator( MSIRECORD
*rec
, LPVOID param
)
924 struct msi_primary_key_record_info
*info
= param
;
928 type
= MSI_RecordGetInteger( rec
, 4 );
929 if( type
& MSITYPE_KEY
)
936 table
= MSI_RecordGetString( rec
, 1 );
937 MSI_RecordSetStringW( info
->rec
, 0, table
);
940 name
= MSI_RecordGetString( rec
, 3 );
941 MSI_RecordSetStringW( info
->rec
, info
->n
, name
);
945 return ERROR_SUCCESS
;
948 UINT
MSI_DatabaseGetPrimaryKeys( MSIDATABASE
*db
,
949 LPCWSTR table
, MSIRECORD
**prec
)
951 static const WCHAR sql
[] = {
952 's','e','l','e','c','t',' ','*',' ',
953 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
954 'w','h','e','r','e',' ',
955 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
956 struct msi_primary_key_record_info info
;
957 MSIQUERY
*query
= NULL
;
960 if (!TABLE_Exists( db
, table
))
961 return ERROR_INVALID_TABLE
;
963 r
= MSI_OpenQuery( db
, &query
, sql
, table
);
964 if( r
!= ERROR_SUCCESS
)
967 /* count the number of primary key records */
970 r
= MSI_IterateRecords( query
, 0, msi_primary_key_iterator
, &info
);
971 if( r
== ERROR_SUCCESS
)
973 TRACE("Found %d primary keys\n", info
.n
);
975 /* allocate a record and fill in the names of the tables */
976 info
.rec
= MSI_CreateRecord( info
.n
);
978 r
= MSI_IterateRecords( query
, 0, msi_primary_key_iterator
, &info
);
979 if( r
== ERROR_SUCCESS
)
982 msiobj_release( &info
.rec
->hdr
);
984 msiobj_release( &query
->hdr
);
989 UINT WINAPI
MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb
,
990 LPCWSTR table
, MSIHANDLE
* phRec
)
992 MSIRECORD
*rec
= NULL
;
996 TRACE("%d %s %p\n", hdb
, debugstr_w(table
), phRec
);
998 db
= msihandle2msiinfo( hdb
, MSIHANDLETYPE_DATABASE
);
1001 struct wire_record
*wire_rec
= NULL
;
1004 if (!(remote
= msi_get_remote(hdb
)))
1005 return ERROR_INVALID_HANDLE
;
1007 r
= remote_DatabaseGetPrimaryKeys(remote
, table
, &wire_rec
);
1010 r
= unmarshal_record(wire_rec
, phRec
);
1011 free_remote_record(wire_rec
);
1017 r
= MSI_DatabaseGetPrimaryKeys( db
, table
, &rec
);
1018 if( r
== ERROR_SUCCESS
)
1020 *phRec
= alloc_msihandle( &rec
->hdr
);
1022 r
= ERROR_NOT_ENOUGH_MEMORY
;
1023 msiobj_release( &rec
->hdr
);
1025 msiobj_release( &db
->hdr
);
1030 UINT WINAPI
MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb
,
1031 LPCSTR table
, MSIHANDLE
* phRec
)
1033 LPWSTR szwTable
= NULL
;
1036 TRACE("%d %s %p\n", hdb
, debugstr_a(table
), phRec
);
1040 szwTable
= strdupAtoW( table
);
1042 return ERROR_OUTOFMEMORY
;
1044 r
= MsiDatabaseGetPrimaryKeysW( hdb
, szwTable
, phRec
);
1045 msi_free( szwTable
);
1050 MSICONDITION WINAPI
MsiDatabaseIsTablePersistentA(
1051 MSIHANDLE hDatabase
, LPCSTR szTableName
)
1053 LPWSTR szwTableName
= NULL
;
1056 TRACE("%x %s\n", hDatabase
, debugstr_a(szTableName
));
1060 szwTableName
= strdupAtoW( szTableName
);
1062 return MSICONDITION_ERROR
;
1064 r
= MsiDatabaseIsTablePersistentW( hDatabase
, szwTableName
);
1065 msi_free( szwTableName
);
1070 MSICONDITION WINAPI
MsiDatabaseIsTablePersistentW(
1071 MSIHANDLE hDatabase
, LPCWSTR szTableName
)
1076 TRACE("%x %s\n", hDatabase
, debugstr_w(szTableName
));
1078 db
= msihandle2msiinfo( hDatabase
, MSIHANDLETYPE_DATABASE
);
1083 if (!(remote
= msi_get_remote(hDatabase
)))
1084 return MSICONDITION_ERROR
;
1086 return remote_DatabaseIsTablePersistent(remote
, szTableName
);
1089 r
= MSI_DatabaseIsTablePersistent( db
, szTableName
);
1091 msiobj_release( &db
->hdr
);
1096 UINT __cdecl
remote_ViewClose(MSIHANDLE view
)
1098 return MsiViewClose(view
);
1101 UINT __cdecl
remote_ViewExecute(MSIHANDLE view
, struct wire_record
*remote_rec
)
1106 if ((r
= unmarshal_record(remote_rec
, &rec
)))
1109 r
= MsiViewExecute(view
, rec
);
1111 MsiCloseHandle(rec
);
1115 UINT __cdecl
remote_ViewFetch(MSIHANDLE view
, struct wire_record
**rec
)
1118 UINT r
= MsiViewFetch(view
, &handle
);
1121 *rec
= marshal_record(handle
);
1122 MsiCloseHandle(handle
);
1126 UINT __cdecl
remote_ViewGetColumnInfo(MSIHANDLE view
, MSICOLINFO info
, struct wire_record
**rec
)
1129 UINT r
= MsiViewGetColumnInfo(view
, info
, &handle
);
1132 *rec
= marshal_record(handle
);
1133 MsiCloseHandle(handle
);
1137 UINT __cdecl
remote_ViewModify(MSIHANDLE view
, MSIMODIFY mode
,
1138 struct wire_record
*remote_rec
, struct wire_record
**remote_refreshed
)
1140 MSIHANDLE handle
= 0;
1143 if ((r
= unmarshal_record(remote_rec
, &handle
)))
1146 r
= MsiViewModify(view
, mode
, handle
);
1147 *remote_refreshed
= NULL
;
1148 if (!r
&& (mode
== MSIMODIFY_REFRESH
|| mode
== MSIMODIFY_SEEK
))
1149 *remote_refreshed
= marshal_record(handle
);
1151 MsiCloseHandle(handle
);