msvcrt: Use EnumSystemLocalesEx instead of directly accessing kernel32 resources.
[wine.git] / dlls / msi / msiquery.c
blob00135a0317a067562d1dab080c242de7a7763149
1 /*
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
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "wine/debug.h"
29 #include "wine/exception.h"
30 #include "msi.h"
31 #include "msiquery.h"
32 #include "objbase.h"
33 #include "objidl.h"
34 #include "winnls.h"
36 #include "msipriv.h"
37 #include "query.h"
38 #include "winemsi.h"
40 #include "initguid.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(msi);
44 static void MSI_CloseView( MSIOBJECTHDR *arg )
46 MSIQUERY *query = (MSIQUERY*) arg;
47 struct list *ptr, *t;
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 )
55 msi_free( ptr );
59 UINT VIEW_find_column( MSIVIEW *table, LPCWSTR name, LPCWSTR table_name, UINT *n )
61 LPCWSTR col_name, haystack_table_name;
62 UINT i, count, r;
64 r = table->ops->get_dimensions( table, NULL, &count );
65 if( r != ERROR_SUCCESS )
66 return r;
68 for( i=1; i<=count; i++ )
70 INT x;
72 r = table->ops->get_column_info( table, i, &col_name, NULL,
73 NULL, &haystack_table_name );
74 if( r != ERROR_SUCCESS )
75 return r;
76 x = wcscmp( name, col_name );
77 if( table_name )
78 x |= wcscmp( table_name, haystack_table_name );
79 if( !x )
81 *n = i;
82 return ERROR_SUCCESS;
85 return ERROR_INVALID_PARAMETER;
88 UINT WINAPI MsiDatabaseOpenViewA( MSIHANDLE hdb, const char *szQuery, MSIHANDLE *phView )
90 UINT r;
91 WCHAR *szwQuery;
93 TRACE( "%lu, %s, %p\n", hdb, debugstr_a(szQuery), phView );
95 if( szQuery )
97 szwQuery = strdupAtoW( szQuery );
98 if( !szwQuery )
99 return ERROR_FUNCTION_FAILED;
101 else
102 szwQuery = NULL;
104 r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
106 msi_free( szwQuery );
107 return r;
110 UINT MSI_DatabaseOpenViewW( MSIDATABASE *db, const WCHAR *szQuery, MSIQUERY **pView )
112 MSIQUERY *query;
113 UINT r;
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),
119 MSI_CloseView );
120 if( !query )
121 return ERROR_FUNCTION_FAILED;
123 msiobj_addref( &db->hdr );
124 query->db = db;
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 );
131 *pView = query;
134 msiobj_release( &query->hdr );
135 return r;
138 UINT WINAPIV MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
140 UINT r;
141 int size = 100, res;
142 LPWSTR query;
144 /* construct the string */
145 for (;;)
147 va_list va;
148 query = msi_alloc( size*sizeof(WCHAR) );
149 va_start(va, fmt);
150 res = vswprintf(query, size, fmt, va);
151 va_end(va);
152 if (res == -1) size *= 2;
153 else if (res >= size) size = res + 1;
154 else break;
155 msi_free( query );
157 /* perform the query */
158 r = MSI_DatabaseOpenViewW(db, query, view);
159 msi_free(query);
160 return r;
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 )
171 return r;
173 if( count )
174 max = *count;
176 /* iterate a query */
177 for( n = 0; (max == 0) || (n < max); n++ )
179 r = MSI_ViewFetch( view, &rec );
180 if( r != ERROR_SUCCESS )
181 break;
182 if (func)
183 r = func( rec, param );
184 msiobj_release( &rec->hdr );
185 if( r != ERROR_SUCCESS )
186 break;
189 MSI_ViewClose( view );
191 if( count )
192 *count = n;
194 if( r == ERROR_NO_MORE_ITEMS )
195 r = ERROR_SUCCESS;
197 return r;
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;
205 UINT r;
206 int size = 100, res;
207 LPWSTR query;
209 /* construct the string */
210 for (;;)
212 va_list va;
213 query = msi_alloc( size*sizeof(WCHAR) );
214 va_start(va, fmt);
215 res = vswprintf(query, size, fmt, va);
216 va_end(va);
217 if (res == -1) size *= 2;
218 else if (res >= size) size = res + 1;
219 else break;
220 msi_free( query );
222 /* perform the query */
223 r = MSI_DatabaseOpenViewW(db, query, &view);
224 msi_free(query);
226 if( r == ERROR_SUCCESS )
228 MSI_ViewExecute( view, NULL );
229 MSI_ViewFetch( view, &rec );
230 MSI_ViewClose( view );
231 msiobj_release( &view->hdr );
233 return rec;
236 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
237 LPCWSTR szQuery, MSIHANDLE *phView)
239 MSIDATABASE *db;
240 MSIQUERY *query = NULL;
241 UINT ret;
243 TRACE("%s %p\n", debugstr_w(szQuery), phView);
245 if (!phView)
246 return ERROR_INVALID_PARAMETER;
248 if (!szQuery)
249 return ERROR_BAD_QUERY_SYNTAX;
251 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
252 if( !db )
254 MSIHANDLE remote, remote_view;
256 if (!(remote = msi_get_remote(hdb)))
257 return ERROR_INVALID_HANDLE;
259 __TRY
261 ret = remote_DatabaseOpenView(remote, szQuery, &remote_view);
263 __EXCEPT(rpc_filter)
265 ret = GetExceptionCode();
267 __ENDTRY
269 if (!ret)
270 *phView = alloc_msi_remote_handle(remote_view);
271 return ret;
274 ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
275 if( ret == ERROR_SUCCESS )
277 *phView = alloc_msihandle( &query->hdr );
278 if (! *phView)
279 ret = ERROR_NOT_ENOUGH_MEMORY;
280 msiobj_release( &query->hdr );
282 msiobj_release( &db->hdr );
284 return ret;
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);
294 if (ret)
295 return ret;
297 if (!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);
303 if (ret)
305 ERR("Error getting column type for %d\n", i);
306 continue;
309 if (MSITYPE_IS_BINARY(type))
311 IStream *stm = NULL;
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);
319 else
320 WARN("failed to get stream\n");
322 continue;
325 ret = view->ops->fetch_int(view, row, i, &ival);
326 if (ret)
328 ERR("Error fetching data for %d\n", i);
329 continue;
332 if (! (type & MSITYPE_VALID))
333 ERR("Invalid type!\n");
335 if (type & MSITYPE_STRING)
337 int len;
338 const WCHAR *sval = msi_string_lookup(db->strings, ival, &len);
339 msi_record_set_string(rec, i, sval, len);
341 else
343 if ((type & MSI_DATASIZEMASK) == 2)
344 MSI_RecordSetInteger(rec, i, ival ? ival - (1<<15) : MSI_NULL_INTEGER);
345 else
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;
356 MSIRECORD *object;
358 TRACE("view %p, row %u, rec %p.\n", view, row, rec);
360 if ((r = view->ops->get_dimensions(view, &row_count, &col_count)))
361 return r;
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 );
371 else
372 *rec = object;
374 return r;
377 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
379 MSIVIEW *view;
380 UINT r;
382 TRACE("%p %p\n", query, prec );
384 view = query->view;
385 if( !view )
386 return ERROR_FUNCTION_FAILED;
388 r = msi_view_get_row(query->db, view, query->row, prec);
389 if (r == ERROR_SUCCESS)
391 query->row ++;
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 */
398 query->row = 0;
401 return r;
404 UINT WINAPI MsiViewFetch( MSIHANDLE hView, MSIHANDLE *record )
406 MSIQUERY *query;
407 MSIRECORD *rec = NULL;
408 UINT ret;
410 TRACE( "%lu, %p\n", hView, record );
412 if( !record )
413 return ERROR_INVALID_PARAMETER;
414 *record = 0;
416 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
417 if (!query)
419 struct wire_record *wire_rec = NULL;
420 MSIHANDLE remote;
422 if (!(remote = msi_get_remote(hView)))
423 return ERROR_INVALID_HANDLE;
425 __TRY
427 ret = remote_ViewFetch(remote, &wire_rec);
429 __EXCEPT(rpc_filter)
431 ret = GetExceptionCode();
433 __ENDTRY
435 if (!ret)
437 ret = unmarshal_record(wire_rec, record);
438 free_remote_record(wire_rec);
440 return ret;
442 ret = MSI_ViewFetch( query, &rec );
443 if( ret == ERROR_SUCCESS )
445 *record = alloc_msihandle( &rec->hdr );
446 if (! *record)
447 ret = ERROR_NOT_ENOUGH_MEMORY;
448 msiobj_release( &rec->hdr );
450 msiobj_release( &query->hdr );
451 return ret;
454 UINT MSI_ViewClose(MSIQUERY *query)
456 MSIVIEW *view;
458 TRACE("%p\n", query );
460 view = query->view;
461 if( !view )
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 )
471 MSIQUERY *query;
472 UINT ret;
474 TRACE( "%lu\n", hView );
476 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
477 if (!query)
479 MSIHANDLE remote;
481 if (!(remote = msi_get_remote(hView)))
482 return ERROR_INVALID_HANDLE;
484 __TRY
486 ret = remote_ViewClose(remote);
488 __EXCEPT(rpc_filter)
490 ret = GetExceptionCode();
492 __ENDTRY
494 return ret;
497 ret = MSI_ViewClose( query );
498 msiobj_release( &query->hdr );
499 return ret;
502 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
504 MSIVIEW *view;
506 TRACE("%p %p\n", query, rec);
508 view = query->view;
509 if( !view )
510 return ERROR_FUNCTION_FAILED;
511 if( !view->ops->execute )
512 return ERROR_FUNCTION_FAILED;
513 query->row = 0;
515 return view->ops->execute( view, rec );
518 UINT WINAPI MsiViewExecute( MSIHANDLE hView, MSIHANDLE hRec )
520 MSIQUERY *query;
521 MSIRECORD *rec = NULL;
522 UINT ret;
524 TRACE( "%lu, %lu\n", hView, hRec );
526 if( hRec )
528 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
529 if( !rec )
530 return ERROR_INVALID_HANDLE;
533 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
534 if( !query )
536 MSIHANDLE remote;
538 if (!(remote = msi_get_remote(hView)))
539 return ERROR_INVALID_HANDLE;
541 __TRY
543 ret = remote_ViewExecute(remote, rec ? (struct wire_record *)&rec->count : NULL);
545 __EXCEPT(rpc_filter)
547 ret = GetExceptionCode();
549 __ENDTRY
551 if (rec)
552 msiobj_release(&rec->hdr);
553 return ret;
556 msiobj_lock( &rec->hdr );
557 ret = MSI_ViewExecute( query, rec );
558 msiobj_unlock( &rec->hdr );
560 msiobj_release( &query->hdr );
561 if( rec )
562 msiobj_release( &rec->hdr );
564 return ret;
567 static UINT msi_set_record_type_string( MSIRECORD *rec, UINT field,
568 UINT type, BOOL temporary )
570 WCHAR szType[0x10];
572 if (MSITYPE_IS_BINARY(type))
573 szType[0] = 'v';
574 else if (type & MSITYPE_LOCALIZABLE)
575 szType[0] = 'l';
576 else if (type & MSITYPE_UNKNOWN)
577 szType[0] = 'f';
578 else if (type & MSITYPE_STRING)
580 if (temporary)
581 szType[0] = 'g';
582 else
583 szType[0] = 's';
585 else
587 if (temporary)
588 szType[0] = 'j';
589 else
590 szType[0] = 'i';
593 if (type & MSITYPE_NULLABLE)
594 szType[0] &= ~0x20;
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;
606 MSIRECORD *rec;
607 MSIVIEW *view = query->view;
608 LPCWSTR name;
609 BOOL temporary;
611 if( !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 )
619 return r;
620 if( !count )
621 return ERROR_INVALID_PARAMETER;
623 rec = MSI_CreateRecord( count );
624 if( !rec )
625 return ERROR_FUNCTION_FAILED;
627 for( i=0; i<count; i++ )
629 name = NULL;
630 r = view->ops->get_column_info( view, i+1, &name, &type, &temporary, NULL );
631 if( r != ERROR_SUCCESS )
632 continue;
633 if (info == MSICOLINFO_NAMES)
634 MSI_RecordSetStringW( rec, i+1, name );
635 else
636 msi_set_record_type_string( rec, i+1, type, temporary );
638 *prec = rec;
639 return ERROR_SUCCESS;
642 UINT WINAPI MsiViewGetColumnInfo( MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec )
644 MSIQUERY *query = NULL;
645 MSIRECORD *rec = NULL;
646 UINT r;
648 TRACE( "%lu, %d, %p\n", hView, info, hRec );
650 if( !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 );
657 if (!query)
659 struct wire_record *wire_rec = NULL;
660 MSIHANDLE remote;
662 if (!(remote = msi_get_remote(hView)))
663 return ERROR_INVALID_HANDLE;
665 __TRY
667 r = remote_ViewGetColumnInfo(remote, info, &wire_rec);
669 __EXCEPT(rpc_filter)
671 r = GetExceptionCode();
673 __ENDTRY
675 if (!r)
677 r = unmarshal_record(wire_rec, hRec);
678 free_remote_record(wire_rec);
681 return r;
684 r = MSI_ViewGetColumnInfo( query, info, &rec );
685 if ( r == ERROR_SUCCESS )
687 *hRec = alloc_msihandle( &rec->hdr );
688 if ( !*hRec )
689 r = ERROR_NOT_ENOUGH_MEMORY;
690 msiobj_release( &rec->hdr );
693 msiobj_release( &query->hdr );
695 return r;
698 UINT MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec )
700 MSIVIEW *view = NULL;
701 UINT r;
703 if ( !query || !rec )
704 return ERROR_INVALID_HANDLE;
706 view = query->view;
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)
715 query->row--;
717 return r;
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 );
730 if (!rec)
731 return ERROR_INVALID_HANDLE;
733 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
734 if (!query)
736 struct wire_record *wire_refreshed = NULL;
737 MSIHANDLE remote;
739 if (!(remote = msi_get_remote(hView)))
740 return ERROR_INVALID_HANDLE;
742 __TRY
744 r = remote_ViewModify(remote, eModifyMode,
745 (struct wire_record *)&rec->count, &wire_refreshed);
747 __EXCEPT(rpc_filter)
749 r = GetExceptionCode();
751 __ENDTRY
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);
760 return r;
763 r = MSI_ViewModify( query, eModifyMode, rec );
765 msiobj_release( &query->hdr );
766 msiobj_release(&rec->hdr);
767 return r;
770 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, WCHAR *buffer, DWORD *buflen )
772 MSIQUERY *query;
773 const WCHAR *column;
774 MSIDBERROR r;
776 TRACE( "%lu, %p, %p\n", handle, buffer, buflen );
778 if (!buflen)
779 return MSIDBERROR_INVALIDARG;
781 if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW)))
783 WCHAR *remote_column = NULL;
784 MSIHANDLE remote;
786 if (!(remote = msi_get_remote(handle)))
787 return MSIDBERROR_INVALIDARG;
789 if (!*buflen)
790 return MSIDBERROR_FUNCTIONERROR;
792 __TRY
794 r = remote_ViewGetError(remote, &remote_column);
796 __EXCEPT(rpc_filter)
798 r = GetExceptionCode();
800 __ENDTRY;
802 if (msi_strncpyW(remote_column ? remote_column : L"", -1, buffer, buflen) == ERROR_MORE_DATA)
803 r = MSIDBERROR_MOREDATA;
805 if (remote_column)
806 midl_user_free(remote_column);
808 return r;
811 if ((r = query->view->error)) column = query->view->error_column;
812 else column = L"";
814 if (msi_strncpyW(column, -1, buffer, buflen) == ERROR_MORE_DATA)
815 r = MSIDBERROR_MOREDATA;
817 msiobj_release( &query->hdr );
818 return r;
821 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, char *buffer, DWORD *buflen )
823 MSIQUERY *query;
824 const WCHAR *column;
825 MSIDBERROR r;
827 TRACE( "%lu, %p, %p\n", handle, buffer, buflen );
829 if (!buflen)
830 return MSIDBERROR_INVALIDARG;
832 if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW)))
834 WCHAR *remote_column = NULL;
835 MSIHANDLE remote;
837 if (!(remote = msi_get_remote(handle)))
838 return MSIDBERROR_INVALIDARG;
840 if (!*buflen)
841 return MSIDBERROR_FUNCTIONERROR;
843 __TRY
845 r = remote_ViewGetError(remote, &remote_column);
847 __EXCEPT(rpc_filter)
849 r = GetExceptionCode();
851 __ENDTRY;
853 if (msi_strncpyWtoA(remote_column ? remote_column : L"", -1, buffer, buflen, FALSE) == ERROR_MORE_DATA)
854 r = MSIDBERROR_MOREDATA;
856 if (remote_column)
857 midl_user_free(remote_column);
859 return r;
862 if ((r = query->view->error)) column = query->view->error_column;
863 else column = L"";
865 if (msi_strncpyWtoA(column, -1, buffer, buflen, FALSE) == ERROR_MORE_DATA)
866 r = MSIDBERROR_MOREDATA;
868 msiobj_release( &query->hdr );
869 return r;
872 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
874 FIXME("\n");
875 return 0;
878 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db, const WCHAR *transform, int error_cond )
880 HRESULT hr;
881 UINT ret = ERROR_FUNCTION_FAILED;
882 IStorage *stg;
883 STATSTG stat;
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 );
890 if (FAILED( hr ))
892 WARN( "failed to open substorage transform %#lx\n", hr );
893 return ERROR_FUNCTION_FAILED;
896 else
898 hr = StgOpenStorage( transform, NULL, STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg );
899 if (FAILED( hr ))
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 );
913 end:
914 IStorage_Release( stg );
915 return ret;
918 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, const WCHAR *transform, int error_cond )
920 MSIDATABASE *db;
921 UINT r;
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 );
930 return r;
933 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, const char *transform, int error_cond )
935 WCHAR *wstr;
936 UINT ret;
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 );
945 msi_free( wstr );
946 return ret;
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 )
965 MSIDATABASE *db;
966 UINT r;
968 TRACE( "%lu\n", hdb );
970 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
971 if( !db )
973 MSIHANDLE remote;
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");
993 else
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;
1009 return r;
1012 struct msi_primary_key_record_info
1014 DWORD n;
1015 MSIRECORD *rec;
1018 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param )
1020 struct msi_primary_key_record_info *info = param;
1021 LPCWSTR name, table;
1022 DWORD type;
1024 type = MSI_RecordGetInteger( rec, 4 );
1025 if( type & MSITYPE_KEY )
1027 info->n++;
1028 if( info->rec )
1030 if ( info->n == 1 )
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;
1049 UINT r;
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 )
1056 return r;
1058 /* count the number of primary key records */
1059 info.n = 0;
1060 info.rec = 0;
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 );
1068 info.n = 0;
1069 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
1070 if( r == ERROR_SUCCESS )
1071 *prec = info.rec;
1072 else
1073 msiobj_release( &info.rec->hdr );
1075 msiobj_release( &query->hdr );
1077 return r;
1080 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb, const WCHAR *table, MSIHANDLE *phRec )
1082 MSIRECORD *rec = NULL;
1083 MSIDATABASE *db;
1084 UINT r;
1086 TRACE( "%lu, %s, %p\n", hdb, debugstr_w(table), phRec );
1088 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
1089 if( !db )
1091 struct wire_record *wire_rec = NULL;
1092 MSIHANDLE remote;
1094 if (!(remote = msi_get_remote(hdb)))
1095 return ERROR_INVALID_HANDLE;
1097 __TRY
1099 r = remote_DatabaseGetPrimaryKeys(remote, table, &wire_rec);
1101 __EXCEPT(rpc_filter)
1103 r = GetExceptionCode();
1105 __ENDTRY
1107 if (!r)
1109 r = unmarshal_record(wire_rec, phRec);
1110 free_remote_record(wire_rec);
1113 return r;
1116 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
1117 if( r == ERROR_SUCCESS )
1119 *phRec = alloc_msihandle( &rec->hdr );
1120 if (! *phRec)
1121 r = ERROR_NOT_ENOUGH_MEMORY;
1122 msiobj_release( &rec->hdr );
1124 msiobj_release( &db->hdr );
1126 return r;
1129 UINT WINAPI MsiDatabaseGetPrimaryKeysA( MSIHANDLE hdb, const char *table, MSIHANDLE *phRec )
1131 WCHAR *szwTable = NULL;
1132 UINT r;
1134 TRACE( "%lu, %s, %p\n", hdb, debugstr_a(table), phRec );
1136 if( table )
1138 szwTable = strdupAtoW( table );
1139 if( !szwTable )
1140 return ERROR_OUTOFMEMORY;
1142 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
1143 msi_free( szwTable );
1145 return r;
1148 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA( MSIHANDLE hDatabase, const char *szTableName )
1150 WCHAR *szwTableName = NULL;
1151 MSICONDITION r;
1153 TRACE( "%lu, %s\n", hDatabase, debugstr_a(szTableName) );
1155 if( szTableName )
1157 szwTableName = strdupAtoW( szTableName );
1158 if( !szwTableName )
1159 return MSICONDITION_ERROR;
1161 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
1162 msi_free( szwTableName );
1164 return r;
1167 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW( MSIHANDLE hDatabase, const WCHAR *szTableName )
1169 MSIDATABASE *db;
1170 MSICONDITION r;
1172 TRACE( "%lu, %s\n", hDatabase, debugstr_w(szTableName) );
1174 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
1175 if( !db )
1177 MSIHANDLE remote;
1179 if (!(remote = msi_get_remote(hDatabase)))
1180 return MSICONDITION_ERROR;
1182 __TRY
1184 r = remote_DatabaseIsTablePersistent(remote, szTableName);
1186 __EXCEPT(rpc_filter)
1188 r = MSICONDITION_ERROR;
1190 __ENDTRY
1192 return r;
1195 r = MSI_DatabaseIsTablePersistent( db, szTableName );
1197 msiobj_release( &db->hdr );
1199 return r;
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)
1209 MSIHANDLE rec = 0;
1210 UINT r;
1212 if ((r = unmarshal_record(remote_rec, &rec)))
1213 return r;
1215 r = MsiViewExecute(view, rec);
1217 MsiCloseHandle(rec);
1218 return r;
1221 UINT __cdecl s_remote_ViewFetch(MSIHANDLE view, struct wire_record **rec)
1223 MSIHANDLE handle;
1224 UINT r = MsiViewFetch(view, &handle);
1225 *rec = NULL;
1226 if (!r)
1227 *rec = marshal_record(handle);
1228 MsiCloseHandle(handle);
1229 return r;
1232 UINT __cdecl s_remote_ViewGetColumnInfo(MSIHANDLE view, MSICOLINFO info, struct wire_record **rec)
1234 MSIHANDLE handle;
1235 UINT r = MsiViewGetColumnInfo(view, info, &handle);
1236 *rec = NULL;
1237 if (!r)
1238 *rec = marshal_record(handle);
1239 MsiCloseHandle(handle);
1240 return r;
1243 MSIDBERROR __cdecl s_remote_ViewGetError(MSIHANDLE view, LPWSTR *column)
1245 WCHAR empty[1];
1246 DWORD size = 1;
1247 UINT r;
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);
1256 return r;
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;
1263 UINT r;
1265 if ((r = unmarshal_record(remote_rec, &handle)))
1266 return r;
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);
1274 return r;