setupapi: Add stub for CM_Get_Device_Interface_Alias{A,W}.
[wine.git] / dlls / msi / msiquery.c
blob526589c320ced2f375b7b97392b4a07ec32a921b
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,
89 LPCSTR szQuery, MSIHANDLE *phView)
91 UINT r;
92 LPWSTR szwQuery;
94 TRACE("%d %s %p\n", hdb, debugstr_a(szQuery), phView);
96 if( szQuery )
98 szwQuery = strdupAtoW( szQuery );
99 if( !szwQuery )
100 return ERROR_FUNCTION_FAILED;
102 else
103 szwQuery = NULL;
105 r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
107 msi_free( szwQuery );
108 return r;
111 UINT MSI_DatabaseOpenViewW(MSIDATABASE *db,
112 LPCWSTR szQuery, MSIQUERY **pView)
114 MSIQUERY *query;
115 UINT r;
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),
121 MSI_CloseView );
122 if( !query )
123 return ERROR_FUNCTION_FAILED;
125 msiobj_addref( &db->hdr );
126 query->db = db;
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 );
133 *pView = query;
136 msiobj_release( &query->hdr );
137 return r;
140 UINT WINAPIV MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
142 UINT r;
143 int size = 100, res;
144 LPWSTR query;
146 /* construct the string */
147 for (;;)
149 __ms_va_list va;
150 query = msi_alloc( size*sizeof(WCHAR) );
151 __ms_va_start(va, fmt);
152 res = vswprintf(query, size, fmt, va);
153 __ms_va_end(va);
154 if (res == -1) size *= 2;
155 else if (res >= size) size = res + 1;
156 else break;
157 msi_free( query );
159 /* perform the query */
160 r = MSI_DatabaseOpenViewW(db, query, view);
161 msi_free(query);
162 return r;
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 )
173 return r;
175 if( count )
176 max = *count;
178 /* iterate a query */
179 for( n = 0; (max == 0) || (n < max); n++ )
181 r = MSI_ViewFetch( view, &rec );
182 if( r != ERROR_SUCCESS )
183 break;
184 if (func)
185 r = func( rec, param );
186 msiobj_release( &rec->hdr );
187 if( r != ERROR_SUCCESS )
188 break;
191 MSI_ViewClose( view );
193 if( count )
194 *count = n;
196 if( r == ERROR_NO_MORE_ITEMS )
197 r = ERROR_SUCCESS;
199 return r;
202 /* return a single record from a query */
203 MSIRECORD * WINAPIV MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... )
205 MSIRECORD *rec = NULL;
206 MSIQUERY *view = NULL;
207 UINT r;
208 int size = 100, res;
209 LPWSTR query;
211 /* construct the string */
212 for (;;)
214 __ms_va_list va;
215 query = msi_alloc( size*sizeof(WCHAR) );
216 __ms_va_start(va, fmt);
217 res = vswprintf(query, size, fmt, va);
218 __ms_va_end(va);
219 if (res == -1) size *= 2;
220 else if (res >= size) size = res + 1;
221 else break;
222 msi_free( query );
224 /* perform the query */
225 r = MSI_DatabaseOpenViewW(db, query, &view);
226 msi_free(query);
228 if( r == ERROR_SUCCESS )
230 MSI_ViewExecute( view, NULL );
231 MSI_ViewFetch( view, &rec );
232 MSI_ViewClose( view );
233 msiobj_release( &view->hdr );
235 return rec;
238 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
239 LPCWSTR szQuery, MSIHANDLE *phView)
241 MSIDATABASE *db;
242 MSIQUERY *query = NULL;
243 UINT ret;
245 TRACE("%s %p\n", debugstr_w(szQuery), phView);
247 if (!phView)
248 return ERROR_INVALID_PARAMETER;
250 if (!szQuery)
251 return ERROR_BAD_QUERY_SYNTAX;
253 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
254 if( !db )
256 MSIHANDLE remote, remote_view;
258 if (!(remote = msi_get_remote(hdb)))
259 return ERROR_INVALID_HANDLE;
261 __TRY
263 ret = remote_DatabaseOpenView(remote, szQuery, &remote_view);
265 __EXCEPT(rpc_filter)
267 ret = GetExceptionCode();
269 __ENDTRY
271 if (!ret)
272 *phView = alloc_msi_remote_handle(remote_view);
273 return ret;
276 ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
277 if( ret == ERROR_SUCCESS )
279 *phView = alloc_msihandle( &query->hdr );
280 if (! *phView)
281 ret = ERROR_NOT_ENOUGH_MEMORY;
282 msiobj_release( &query->hdr );
284 msiobj_release( &db->hdr );
286 return ret;
289 UINT msi_view_refresh_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD *rec)
291 UINT row_count = 0, col_count = 0, i, ival, ret, type;
293 TRACE("%p %p %d %p\n", db, view, row, rec);
295 ret = view->ops->get_dimensions(view, &row_count, &col_count);
296 if (ret)
297 return ret;
299 if (!col_count)
300 return ERROR_INVALID_PARAMETER;
302 for (i = 1; i <= col_count; i++)
304 ret = view->ops->get_column_info(view, i, NULL, &type, NULL, NULL);
305 if (ret)
307 ERR("Error getting column type for %d\n", i);
308 continue;
311 if (MSITYPE_IS_BINARY(type))
313 IStream *stm = NULL;
315 ret = view->ops->fetch_stream(view, row, i, &stm);
316 if ((ret == ERROR_SUCCESS) && stm)
318 MSI_RecordSetIStream(rec, i, stm);
319 IStream_Release(stm);
321 else
322 WARN("failed to get stream\n");
324 continue;
327 ret = view->ops->fetch_int(view, row, i, &ival);
328 if (ret)
330 ERR("Error fetching data for %d\n", i);
331 continue;
334 if (! (type & MSITYPE_VALID))
335 ERR("Invalid type!\n");
337 if (type & MSITYPE_STRING)
339 int len;
340 const WCHAR *sval = msi_string_lookup(db->strings, ival, &len);
341 msi_record_set_string(rec, i, sval, len);
343 else
345 if ((type & MSI_DATASIZEMASK) == 2)
346 MSI_RecordSetInteger(rec, i, ival ? ival - (1<<15) : MSI_NULL_INTEGER);
347 else
348 MSI_RecordSetInteger(rec, i, ival - (1u<<31));
352 return ERROR_SUCCESS;
355 UINT msi_view_get_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD **rec)
357 UINT row_count = 0, col_count = 0, r;
358 MSIRECORD *object;
360 TRACE("view %p, row %u, rec %p.\n", view, row, rec);
362 if ((r = view->ops->get_dimensions(view, &row_count, &col_count)))
363 return r;
365 if (row >= row_count)
366 return ERROR_NO_MORE_ITEMS;
368 if (!(object = MSI_CreateRecord( col_count )))
369 return ERROR_OUTOFMEMORY;
371 if ((r = msi_view_refresh_row(db, view, row, object)))
372 msiobj_release( &object->hdr );
373 else
374 *rec = object;
376 return r;
379 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
381 MSIVIEW *view;
382 UINT r;
384 TRACE("%p %p\n", query, prec );
386 view = query->view;
387 if( !view )
388 return ERROR_FUNCTION_FAILED;
390 r = msi_view_get_row(query->db, view, query->row, prec);
391 if (r == ERROR_SUCCESS)
393 query->row ++;
394 (*prec)->cookie = (UINT64)(ULONG_PTR)query;
395 MSI_RecordSetInteger(*prec, 0, 1);
398 return r;
401 UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
403 MSIQUERY *query;
404 MSIRECORD *rec = NULL;
405 UINT ret;
407 TRACE("%d %p\n", hView, record);
409 if( !record )
410 return ERROR_INVALID_PARAMETER;
411 *record = 0;
413 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
414 if (!query)
416 struct wire_record *wire_rec = NULL;
417 MSIHANDLE remote;
419 if (!(remote = msi_get_remote(hView)))
420 return ERROR_INVALID_HANDLE;
422 __TRY
424 ret = remote_ViewFetch(remote, &wire_rec);
426 __EXCEPT(rpc_filter)
428 ret = GetExceptionCode();
430 __ENDTRY
432 if (!ret)
434 ret = unmarshal_record(wire_rec, record);
435 free_remote_record(wire_rec);
437 return ret;
439 ret = MSI_ViewFetch( query, &rec );
440 if( ret == ERROR_SUCCESS )
442 *record = alloc_msihandle( &rec->hdr );
443 if (! *record)
444 ret = ERROR_NOT_ENOUGH_MEMORY;
445 msiobj_release( &rec->hdr );
447 msiobj_release( &query->hdr );
448 return ret;
451 UINT MSI_ViewClose(MSIQUERY *query)
453 MSIVIEW *view;
455 TRACE("%p\n", query );
457 view = query->view;
458 if( !view )
459 return ERROR_FUNCTION_FAILED;
460 if( !view->ops->close )
461 return ERROR_FUNCTION_FAILED;
463 return view->ops->close( view );
466 UINT WINAPI MsiViewClose(MSIHANDLE hView)
468 MSIQUERY *query;
469 UINT ret;
471 TRACE("%d\n", hView );
473 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
474 if (!query)
476 MSIHANDLE remote;
478 if (!(remote = msi_get_remote(hView)))
479 return ERROR_INVALID_HANDLE;
481 __TRY
483 ret = remote_ViewClose(remote);
485 __EXCEPT(rpc_filter)
487 ret = GetExceptionCode();
489 __ENDTRY
491 return ret;
494 ret = MSI_ViewClose( query );
495 msiobj_release( &query->hdr );
496 return ret;
499 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
501 MSIVIEW *view;
503 TRACE("%p %p\n", query, rec);
505 view = query->view;
506 if( !view )
507 return ERROR_FUNCTION_FAILED;
508 if( !view->ops->execute )
509 return ERROR_FUNCTION_FAILED;
510 query->row = 0;
512 return view->ops->execute( view, rec );
515 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
517 MSIQUERY *query;
518 MSIRECORD *rec = NULL;
519 UINT ret;
521 TRACE("%d %d\n", hView, hRec);
523 if( hRec )
525 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
526 if( !rec )
527 return ERROR_INVALID_HANDLE;
530 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
531 if( !query )
533 MSIHANDLE remote;
535 if (!(remote = msi_get_remote(hView)))
536 return ERROR_INVALID_HANDLE;
538 __TRY
540 ret = remote_ViewExecute(remote, rec ? (struct wire_record *)&rec->count : NULL);
542 __EXCEPT(rpc_filter)
544 ret = GetExceptionCode();
546 __ENDTRY
548 if (rec)
549 msiobj_release(&rec->hdr);
550 return ret;
553 msiobj_lock( &rec->hdr );
554 ret = MSI_ViewExecute( query, rec );
555 msiobj_unlock( &rec->hdr );
557 msiobj_release( &query->hdr );
558 if( rec )
559 msiobj_release( &rec->hdr );
561 return ret;
564 static UINT msi_set_record_type_string( MSIRECORD *rec, UINT field,
565 UINT type, BOOL temporary )
567 static const WCHAR fmt[] = { '%','d',0 };
568 WCHAR szType[0x10];
570 if (MSITYPE_IS_BINARY(type))
571 szType[0] = 'v';
572 else if (type & MSITYPE_LOCALIZABLE)
573 szType[0] = 'l';
574 else if (type & MSITYPE_UNKNOWN)
575 szType[0] = 'f';
576 else if (type & MSITYPE_STRING)
578 if (temporary)
579 szType[0] = 'g';
580 else
581 szType[0] = 's';
583 else
585 if (temporary)
586 szType[0] = 'j';
587 else
588 szType[0] = 'i';
591 if (type & MSITYPE_NULLABLE)
592 szType[0] &= ~0x20;
594 swprintf( &szType[1], ARRAY_SIZE(szType) - 1, fmt, (type&0xff) );
596 TRACE("type %04x -> %s\n", type, debugstr_w(szType) );
598 return MSI_RecordSetStringW( rec, field, szType );
601 UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec )
603 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
604 MSIRECORD *rec;
605 MSIVIEW *view = query->view;
606 LPCWSTR name;
607 BOOL temporary;
609 if( !view )
610 return ERROR_FUNCTION_FAILED;
612 if( !view->ops->get_dimensions )
613 return ERROR_FUNCTION_FAILED;
615 r = view->ops->get_dimensions( view, NULL, &count );
616 if( r != ERROR_SUCCESS )
617 return r;
618 if( !count )
619 return ERROR_INVALID_PARAMETER;
621 rec = MSI_CreateRecord( count );
622 if( !rec )
623 return ERROR_FUNCTION_FAILED;
625 for( i=0; i<count; i++ )
627 name = NULL;
628 r = view->ops->get_column_info( view, i+1, &name, &type, &temporary, NULL );
629 if( r != ERROR_SUCCESS )
630 continue;
631 if (info == MSICOLINFO_NAMES)
632 MSI_RecordSetStringW( rec, i+1, name );
633 else
634 msi_set_record_type_string( rec, i+1, type, temporary );
636 *prec = rec;
637 return ERROR_SUCCESS;
640 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
642 MSIQUERY *query = NULL;
643 MSIRECORD *rec = NULL;
644 UINT r;
646 TRACE("%d %d %p\n", hView, info, hRec);
648 if( !hRec )
649 return ERROR_INVALID_PARAMETER;
651 if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
652 return ERROR_INVALID_PARAMETER;
654 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
655 if (!query)
657 struct wire_record *wire_rec = NULL;
658 MSIHANDLE remote;
660 if (!(remote = msi_get_remote(hView)))
661 return ERROR_INVALID_HANDLE;
663 __TRY
665 r = remote_ViewGetColumnInfo(remote, info, &wire_rec);
667 __EXCEPT(rpc_filter)
669 r = GetExceptionCode();
671 __ENDTRY
673 if (!r)
675 r = unmarshal_record(wire_rec, hRec);
676 free_remote_record(wire_rec);
679 return r;
682 r = MSI_ViewGetColumnInfo( query, info, &rec );
683 if ( r == ERROR_SUCCESS )
685 *hRec = alloc_msihandle( &rec->hdr );
686 if ( !*hRec )
687 r = ERROR_NOT_ENOUGH_MEMORY;
688 msiobj_release( &rec->hdr );
691 msiobj_release( &query->hdr );
693 return r;
696 UINT MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec )
698 MSIVIEW *view = NULL;
699 UINT r;
701 if ( !query || !rec )
702 return ERROR_INVALID_HANDLE;
704 view = query->view;
705 if ( !view || !view->ops->modify)
706 return ERROR_FUNCTION_FAILED;
708 if ( mode == MSIMODIFY_UPDATE && rec->cookie != (UINT64)(ULONG_PTR)query )
709 return ERROR_FUNCTION_FAILED;
711 r = view->ops->modify( view, mode, rec, query->row - 1 );
712 if (mode == MSIMODIFY_DELETE && r == ERROR_SUCCESS)
713 query->row--;
715 return r;
718 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode,
719 MSIHANDLE hRecord)
721 MSIQUERY *query = NULL;
722 MSIRECORD *rec = NULL;
723 UINT r = ERROR_FUNCTION_FAILED;
725 TRACE("%d %x %d\n", hView, eModifyMode, hRecord);
727 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
729 if (!rec)
730 return ERROR_INVALID_HANDLE;
732 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
733 if (!query)
735 struct wire_record *wire_refreshed = NULL;
736 MSIHANDLE remote;
738 if (!(remote = msi_get_remote(hView)))
739 return ERROR_INVALID_HANDLE;
741 __TRY
743 r = remote_ViewModify(remote, eModifyMode,
744 (struct wire_record *)&rec->count, &wire_refreshed);
746 __EXCEPT(rpc_filter)
748 r = GetExceptionCode();
750 __ENDTRY
752 if (!r && (eModifyMode == MSIMODIFY_REFRESH || eModifyMode == MSIMODIFY_SEEK))
754 r = copy_remote_record(wire_refreshed, hRecord);
755 free_remote_record(wire_refreshed);
758 msiobj_release(&rec->hdr);
759 return r;
762 r = MSI_ViewModify( query, eModifyMode, rec );
764 msiobj_release( &query->hdr );
765 msiobj_release(&rec->hdr);
766 return r;
769 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR buffer, LPDWORD buflen )
771 MSIQUERY *query;
772 const WCHAR *column;
773 MSIDBERROR r;
775 TRACE("%u %p %p\n", handle, buffer, buflen);
777 if (!buflen)
778 return MSIDBERROR_INVALIDARG;
780 if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW)))
782 WCHAR *remote_column = NULL;
783 MSIHANDLE remote;
785 if (!(remote = msi_get_remote(handle)))
786 return MSIDBERROR_INVALIDARG;
788 if (!*buflen)
789 return MSIDBERROR_FUNCTIONERROR;
791 __TRY
793 r = remote_ViewGetError(remote, &remote_column);
795 __EXCEPT(rpc_filter)
797 r = GetExceptionCode();
799 __ENDTRY;
801 if (msi_strncpyW(remote_column ? remote_column : szEmpty, -1, buffer, buflen) == ERROR_MORE_DATA)
802 r = MSIDBERROR_MOREDATA;
804 if (remote_column)
805 midl_user_free(remote_column);
807 return r;
810 if ((r = query->view->error)) column = query->view->error_column;
811 else column = szEmpty;
813 if (msi_strncpyW(column, -1, buffer, buflen) == ERROR_MORE_DATA)
814 r = MSIDBERROR_MOREDATA;
816 msiobj_release( &query->hdr );
817 return r;
820 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR buffer, LPDWORD buflen )
822 MSIQUERY *query;
823 const WCHAR *column;
824 MSIDBERROR r;
826 TRACE("%u %p %p\n", handle, buffer, buflen);
828 if (!buflen)
829 return MSIDBERROR_INVALIDARG;
831 if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW)))
833 WCHAR *remote_column = NULL;
834 MSIHANDLE remote;
836 if (!(remote = msi_get_remote(handle)))
837 return MSIDBERROR_INVALIDARG;
839 if (!*buflen)
840 return MSIDBERROR_FUNCTIONERROR;
842 __TRY
844 r = remote_ViewGetError(remote, &remote_column);
846 __EXCEPT(rpc_filter)
848 r = GetExceptionCode();
850 __ENDTRY;
852 if (msi_strncpyWtoA(remote_column ? remote_column : szEmpty, -1, buffer, buflen, FALSE) == ERROR_MORE_DATA)
853 r = MSIDBERROR_MOREDATA;
855 if (remote_column)
856 midl_user_free(remote_column);
858 return r;
861 if ((r = query->view->error)) column = query->view->error_column;
862 else column = szEmpty;
864 if (msi_strncpyWtoA(column, -1, buffer, buflen, FALSE) == ERROR_MORE_DATA)
865 r = MSIDBERROR_MOREDATA;
867 msiobj_release( &query->hdr );
868 return r;
871 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
873 FIXME("\n");
874 return 0;
877 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db, const WCHAR *transform, int error_cond )
879 HRESULT hr;
880 UINT ret = ERROR_FUNCTION_FAILED;
881 IStorage *stg;
882 STATSTG stat;
884 TRACE( "%p %s %08x\n", db, debugstr_w(transform), error_cond );
886 if (*transform == ':')
888 hr = IStorage_OpenStorage( db->storage, transform + 1, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
889 if (FAILED( hr ))
891 WARN( "failed to open substorage transform 0x%08x\n", hr );
892 return ERROR_FUNCTION_FAILED;
895 else
897 hr = StgOpenStorage( transform, NULL, STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg );
898 if (FAILED( hr ))
900 WARN( "failed to open file transform 0x%08x\n", hr );
901 return ERROR_FUNCTION_FAILED;
905 hr = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
906 if (FAILED( hr )) goto end;
907 if (!IsEqualGUID( &stat.clsid, &CLSID_MsiTransform )) goto end;
908 if (TRACE_ON( msi )) enum_stream_names( stg );
910 ret = msi_table_apply_transform( db, stg );
912 end:
913 IStorage_Release( stg );
914 return ret;
917 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, const WCHAR *transform, int error_cond )
919 MSIDATABASE *db;
920 UINT r;
922 if (error_cond) FIXME( "ignoring error conditions\n" );
924 if (!(db = msihandle2msiinfo(hdb, MSIHANDLETYPE_DATABASE)))
925 return ERROR_INVALID_HANDLE;
927 r = MSI_DatabaseApplyTransformW( db, transform, error_cond );
928 msiobj_release( &db->hdr );
929 return r;
932 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, const char *transform, int error_cond )
934 WCHAR *wstr;
935 UINT ret;
937 TRACE( "%d %s %08x\n", hdb, debugstr_a(transform), error_cond );
939 wstr = strdupAtoW( transform );
940 if (transform && !wstr)
941 return ERROR_NOT_ENOUGH_MEMORY;
943 ret = MsiDatabaseApplyTransformW( hdb, wstr, error_cond );
944 msi_free( wstr );
945 return ret;
948 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
949 LPCSTR szTransformFile, int iReserved1, int iReserved2 )
951 FIXME("%d %d %s %d %d\n", hdb, hdbref,
952 debugstr_a(szTransformFile), iReserved1, iReserved2);
953 return ERROR_CALL_NOT_IMPLEMENTED;
956 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
957 LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
959 FIXME("%d %d %s %d %d\n", hdb, hdbref,
960 debugstr_w(szTransformFile), iReserved1, iReserved2);
961 return ERROR_CALL_NOT_IMPLEMENTED;
964 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
966 MSIDATABASE *db;
967 UINT r;
969 TRACE("%d\n", hdb);
971 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
972 if( !db )
974 MSIHANDLE remote;
976 if (!(remote = msi_get_remote(hdb)))
977 return ERROR_INVALID_HANDLE;
979 WARN("not allowed during a custom action!\n");
981 return ERROR_SUCCESS;
984 if (db->mode == MSI_OPEN_READONLY)
986 msiobj_release( &db->hdr );
987 return ERROR_SUCCESS;
990 /* FIXME: lock the database */
992 r = msi_commit_streams( db );
993 if (r != ERROR_SUCCESS) ERR("Failed to commit streams!\n");
994 else
996 r = MSI_CommitTables( db );
997 if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
1000 /* FIXME: unlock the database */
1002 msiobj_release( &db->hdr );
1004 if (r == ERROR_SUCCESS)
1006 msi_free( db->deletefile );
1007 db->deletefile = NULL;
1010 return r;
1013 struct msi_primary_key_record_info
1015 DWORD n;
1016 MSIRECORD *rec;
1019 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param )
1021 struct msi_primary_key_record_info *info = param;
1022 LPCWSTR name, table;
1023 DWORD type;
1025 type = MSI_RecordGetInteger( rec, 4 );
1026 if( type & MSITYPE_KEY )
1028 info->n++;
1029 if( info->rec )
1031 if ( info->n == 1 )
1033 table = MSI_RecordGetString( rec, 1 );
1034 MSI_RecordSetStringW( info->rec, 0, table);
1037 name = MSI_RecordGetString( rec, 3 );
1038 MSI_RecordSetStringW( info->rec, info->n, name );
1042 return ERROR_SUCCESS;
1045 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db,
1046 LPCWSTR table, MSIRECORD **prec )
1048 static const WCHAR sql[] = {
1049 's','e','l','e','c','t',' ','*',' ',
1050 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
1051 'w','h','e','r','e',' ',
1052 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
1053 struct msi_primary_key_record_info info;
1054 MSIQUERY *query = NULL;
1055 UINT r;
1057 if (!TABLE_Exists( db, table ))
1058 return ERROR_INVALID_TABLE;
1060 r = MSI_OpenQuery( db, &query, sql, table );
1061 if( r != ERROR_SUCCESS )
1062 return r;
1064 /* count the number of primary key records */
1065 info.n = 0;
1066 info.rec = 0;
1067 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
1068 if( r == ERROR_SUCCESS )
1070 TRACE("Found %d primary keys\n", info.n );
1072 /* allocate a record and fill in the names of the tables */
1073 info.rec = MSI_CreateRecord( info.n );
1074 info.n = 0;
1075 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
1076 if( r == ERROR_SUCCESS )
1077 *prec = info.rec;
1078 else
1079 msiobj_release( &info.rec->hdr );
1081 msiobj_release( &query->hdr );
1083 return r;
1086 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb,
1087 LPCWSTR table, MSIHANDLE* phRec )
1089 MSIRECORD *rec = NULL;
1090 MSIDATABASE *db;
1091 UINT r;
1093 TRACE("%d %s %p\n", hdb, debugstr_w(table), phRec);
1095 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
1096 if( !db )
1098 struct wire_record *wire_rec = NULL;
1099 MSIHANDLE remote;
1101 if (!(remote = msi_get_remote(hdb)))
1102 return ERROR_INVALID_HANDLE;
1104 __TRY
1106 r = remote_DatabaseGetPrimaryKeys(remote, table, &wire_rec);
1108 __EXCEPT(rpc_filter)
1110 r = GetExceptionCode();
1112 __ENDTRY
1114 if (!r)
1116 r = unmarshal_record(wire_rec, phRec);
1117 free_remote_record(wire_rec);
1120 return r;
1123 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
1124 if( r == ERROR_SUCCESS )
1126 *phRec = alloc_msihandle( &rec->hdr );
1127 if (! *phRec)
1128 r = ERROR_NOT_ENOUGH_MEMORY;
1129 msiobj_release( &rec->hdr );
1131 msiobj_release( &db->hdr );
1133 return r;
1136 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
1137 LPCSTR table, MSIHANDLE* phRec)
1139 LPWSTR szwTable = NULL;
1140 UINT r;
1142 TRACE("%d %s %p\n", hdb, debugstr_a(table), phRec);
1144 if( table )
1146 szwTable = strdupAtoW( table );
1147 if( !szwTable )
1148 return ERROR_OUTOFMEMORY;
1150 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
1151 msi_free( szwTable );
1153 return r;
1156 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA(
1157 MSIHANDLE hDatabase, LPCSTR szTableName)
1159 LPWSTR szwTableName = NULL;
1160 MSICONDITION r;
1162 TRACE("%x %s\n", hDatabase, debugstr_a(szTableName));
1164 if( szTableName )
1166 szwTableName = strdupAtoW( szTableName );
1167 if( !szwTableName )
1168 return MSICONDITION_ERROR;
1170 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
1171 msi_free( szwTableName );
1173 return r;
1176 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(
1177 MSIHANDLE hDatabase, LPCWSTR szTableName)
1179 MSIDATABASE *db;
1180 MSICONDITION r;
1182 TRACE("%x %s\n", hDatabase, debugstr_w(szTableName));
1184 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
1185 if( !db )
1187 MSIHANDLE remote;
1189 if (!(remote = msi_get_remote(hDatabase)))
1190 return MSICONDITION_ERROR;
1192 __TRY
1194 r = remote_DatabaseIsTablePersistent(remote, szTableName);
1196 __EXCEPT(rpc_filter)
1198 r = MSICONDITION_ERROR;
1200 __ENDTRY
1202 return r;
1205 r = MSI_DatabaseIsTablePersistent( db, szTableName );
1207 msiobj_release( &db->hdr );
1209 return r;
1212 UINT __cdecl s_remote_ViewClose(MSIHANDLE view)
1214 return MsiViewClose(view);
1217 UINT __cdecl s_remote_ViewExecute(MSIHANDLE view, struct wire_record *remote_rec)
1219 MSIHANDLE rec = 0;
1220 UINT r;
1222 if ((r = unmarshal_record(remote_rec, &rec)))
1223 return r;
1225 r = MsiViewExecute(view, rec);
1227 MsiCloseHandle(rec);
1228 return r;
1231 UINT __cdecl s_remote_ViewFetch(MSIHANDLE view, struct wire_record **rec)
1233 MSIHANDLE handle;
1234 UINT r = MsiViewFetch(view, &handle);
1235 *rec = NULL;
1236 if (!r)
1237 *rec = marshal_record(handle);
1238 MsiCloseHandle(handle);
1239 return r;
1242 UINT __cdecl s_remote_ViewGetColumnInfo(MSIHANDLE view, MSICOLINFO info, struct wire_record **rec)
1244 MSIHANDLE handle;
1245 UINT r = MsiViewGetColumnInfo(view, info, &handle);
1246 *rec = NULL;
1247 if (!r)
1248 *rec = marshal_record(handle);
1249 MsiCloseHandle(handle);
1250 return r;
1253 MSIDBERROR __cdecl s_remote_ViewGetError(MSIHANDLE view, LPWSTR *column)
1255 WCHAR empty[1];
1256 DWORD size = 1;
1257 UINT r;
1259 r = MsiViewGetErrorW(view, empty, &size);
1260 if (r == MSIDBERROR_MOREDATA)
1262 if (!(*column = midl_user_allocate(++size * sizeof(WCHAR))))
1263 return MSIDBERROR_FUNCTIONERROR;
1264 r = MsiViewGetErrorW(view, *column, &size);
1266 return r;
1269 UINT __cdecl s_remote_ViewModify(MSIHANDLE view, MSIMODIFY mode,
1270 struct wire_record *remote_rec, struct wire_record **remote_refreshed)
1272 MSIHANDLE handle = 0;
1273 UINT r;
1275 if ((r = unmarshal_record(remote_rec, &handle)))
1276 return r;
1278 r = MsiViewModify(view, mode, handle);
1279 *remote_refreshed = NULL;
1280 if (!r && (mode == MSIMODIFY_REFRESH || mode == MSIMODIFY_SEEK))
1281 *remote_refreshed = marshal_record(handle);
1283 MsiCloseHandle(handle);
1284 return r;