1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
4 * Copyright 2002-2005 Mike McCormack for CodeWeavers
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
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"
35
36 #include "msipriv.h"
37 #include "query.h"
38 #include "winemsi_s.h"
39
40 #include "initguid.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(msi);
43
MSI_CloseView(MSIOBJECTHDR * arg)44 static void MSI_CloseView( MSIOBJECTHDR *arg )
45 {
46 MSIQUERY *query = (MSIQUERY*) arg;
47 struct list *ptr, *t;
48
49 if( query->view && query->view->ops->delete )
50 query->view->ops->delete( query->view );
51 msiobj_release( &query->db->hdr );
52
53 LIST_FOR_EACH_SAFE( ptr, t, &query->mem )
54 {
55 free( ptr );
56 }
57 }
58
VIEW_find_column(MSIVIEW * table,LPCWSTR name,LPCWSTR table_name,UINT * n)59 UINT VIEW_find_column( MSIVIEW *table, LPCWSTR name, LPCWSTR table_name, UINT *n )
60 {
61 LPCWSTR col_name, haystack_table_name;
62 UINT i, count, r;
63
64 r = table->ops->get_dimensions( table, NULL, &count );
65 if( r != ERROR_SUCCESS )
66 return r;
67
68 for( i=1; i<=count; i++ )
69 {
70 INT x;
71
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 )
80 {
81 *n = i;
82 return ERROR_SUCCESS;
83 }
84 }
85 return ERROR_INVALID_PARAMETER;
86 }
87
MsiDatabaseOpenViewA(MSIHANDLE hdb,const char * szQuery,MSIHANDLE * phView)88 UINT WINAPI MsiDatabaseOpenViewA( MSIHANDLE hdb, const char *szQuery, MSIHANDLE *phView )
89 {
90 UINT r;
91 WCHAR *szwQuery;
92
93 TRACE( "%lu, %s, %p\n", hdb, debugstr_a(szQuery), phView );
94
95 if( szQuery )
96 {
97 szwQuery = strdupAtoW( szQuery );
98 if( !szwQuery )
99 return ERROR_FUNCTION_FAILED;
100 }
101 else
102 szwQuery = NULL;
103
104 r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
105
106 free( szwQuery );
107 return r;
108 }
109
MSI_DatabaseOpenViewW(MSIDATABASE * db,const WCHAR * szQuery,MSIQUERY ** pView)110 UINT MSI_DatabaseOpenViewW( MSIDATABASE *db, const WCHAR *szQuery, MSIQUERY **pView )
111 {
112 MSIQUERY *query;
113 UINT r;
114
115 TRACE( "%s, %p\n", debugstr_w(szQuery), pView );
116
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;
122
123 msiobj_addref( &db->hdr );
124 query->db = db;
125 list_init( &query->mem );
126
127 r = MSI_ParseSQL( db, szQuery, &query->view, &query->mem );
128 if( r == ERROR_SUCCESS )
129 {
130 msiobj_addref( &query->hdr );
131 *pView = query;
132 }
133
134 msiobj_release( &query->hdr );
135 return r;
136 }
137
MSI_OpenQuery(MSIDATABASE * db,MSIQUERY ** view,LPCWSTR fmt,...)138 UINT WINAPIV MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
139 {
140 UINT r;
141 int size = 100, res;
142 LPWSTR query;
143
144 /* construct the string */
145 for (;;)
146 {
147 va_list va;
148 query = malloc(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 free(query);
156 }
157 /* perform the query */
158 r = MSI_DatabaseOpenViewW(db, query, view);
159 free(query);
160 return r;
161 }
162
MSI_IterateRecords(MSIQUERY * view,LPDWORD count,record_func func,LPVOID param)163 UINT MSI_IterateRecords( MSIQUERY *view, LPDWORD count,
164 record_func func, LPVOID param )
165 {
166 MSIRECORD *rec = NULL;
167 UINT r, n = 0, max = 0;
168
169 r = MSI_ViewExecute( view, NULL );
170 if( r != ERROR_SUCCESS )
171 return r;
172
173 if( count )
174 max = *count;
175
176 /* iterate a query */
177 for( n = 0; (max == 0) || (n < max); n++ )
178 {
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;
187 }
188
189 MSI_ViewClose( view );
190
191 if( count )
192 *count = n;
193
194 if( r == ERROR_NO_MORE_ITEMS )
195 r = ERROR_SUCCESS;
196
197 return r;
198 }
199
200 /* return a single record from a query */
MSI_QueryGetRecord(MSIDATABASE * db,LPCWSTR fmt,...)201 MSIRECORD * WINAPIV MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... )
202 {
203 MSIRECORD *rec = NULL;
204 MSIQUERY *view = NULL;
205 UINT r;
206 int size = 100, res;
207 LPWSTR query;
208
209 /* construct the string */
210 for (;;)
211 {
212 va_list va;
213 query = malloc(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 free(query);
221 }
222 /* perform the query */
223 r = MSI_DatabaseOpenViewW(db, query, &view);
224 free(query);
225
226 if( r == ERROR_SUCCESS )
227 {
228 MSI_ViewExecute( view, NULL );
229 MSI_ViewFetch( view, &rec );
230 MSI_ViewClose( view );
231 msiobj_release( &view->hdr );
232 }
233 return rec;
234 }
235
MsiDatabaseOpenViewW(MSIHANDLE hdb,LPCWSTR szQuery,MSIHANDLE * phView)236 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
237 LPCWSTR szQuery, MSIHANDLE *phView)
238 {
239 MSIDATABASE *db;
240 MSIQUERY *query = NULL;
241 UINT ret;
242
243 TRACE("%s %p\n", debugstr_w(szQuery), phView);
244
245 if (!phView)
246 return ERROR_INVALID_PARAMETER;
247
248 if (!szQuery)
249 return ERROR_BAD_QUERY_SYNTAX;
250
251 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
252 if( !db )
253 {
254 MSIHANDLE remote, remote_view;
255
256 if (!(remote = msi_get_remote(hdb)))
257 return ERROR_INVALID_HANDLE;
258
259 __TRY
260 {
261 ret = remote_DatabaseOpenView(remote, szQuery, &remote_view);
262 }
263 __EXCEPT(rpc_filter)
264 {
265 ret = GetExceptionCode();
266 }
267 __ENDTRY
268
269 if (!ret)
270 *phView = alloc_msi_remote_handle(remote_view);
271 return ret;
272 }
273
274 ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
275 if( ret == ERROR_SUCCESS )
276 {
277 *phView = alloc_msihandle( &query->hdr );
278 if (! *phView)
279 ret = ERROR_NOT_ENOUGH_MEMORY;
280 msiobj_release( &query->hdr );
281 }
282 msiobj_release( &db->hdr );
283
284 return ret;
285 }
286
msi_view_refresh_row(MSIDATABASE * db,MSIVIEW * view,UINT row,MSIRECORD * rec)287 UINT msi_view_refresh_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD *rec)
288 {
289 UINT row_count = 0, col_count = 0, i, ival, ret, type;
290
291 TRACE("%p %p %d %p\n", db, view, row, rec);
292
293 ret = view->ops->get_dimensions(view, &row_count, &col_count);
294 if (ret)
295 return ret;
296
297 if (!col_count)
298 return ERROR_INVALID_PARAMETER;
299
300 for (i = 1; i <= col_count; i++)
301 {
302 ret = view->ops->get_column_info(view, i, NULL, &type, NULL, NULL);
303 if (ret)
304 {
305 ERR("Error getting column type for %d\n", i);
306 continue;
307 }
308
309 if (MSITYPE_IS_BINARY(type))
310 {
311 IStream *stm = NULL;
312
313 ret = view->ops->fetch_stream(view, row, i, &stm);
314 if ((ret == ERROR_SUCCESS) && stm)
315 {
316 MSI_RecordSetIStream(rec, i, stm);
317 IStream_Release(stm);
318 }
319 else
320 WARN("failed to get stream\n");
321
322 continue;
323 }
324
325 ret = view->ops->fetch_int(view, row, i, &ival);
326 if (ret)
327 {
328 ERR("Error fetching data for %d\n", i);
329 continue;
330 }
331
332 if (! (type & MSITYPE_VALID))
333 ERR("Invalid type!\n");
334
335 if (type & MSITYPE_STRING)
336 {
337 int len;
338 const WCHAR *sval = msi_string_lookup(db->strings, ival, &len);
339 msi_record_set_string(rec, i, sval, len);
340 }
341 else
342 {
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));
347 }
348 }
349
350 return ERROR_SUCCESS;
351 }
352
msi_view_get_row(MSIDATABASE * db,MSIVIEW * view,UINT row,MSIRECORD ** rec)353 UINT msi_view_get_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD **rec)
354 {
355 UINT row_count = 0, col_count = 0, r;
356 MSIRECORD *object;
357
358 TRACE("view %p, row %u, rec %p.\n", view, row, rec);
359
360 if ((r = view->ops->get_dimensions(view, &row_count, &col_count)))
361 return r;
362
363 if (row >= row_count)
364 return ERROR_NO_MORE_ITEMS;
365
366 if (!(object = MSI_CreateRecord( col_count )))
367 return ERROR_OUTOFMEMORY;
368
369 if ((r = msi_view_refresh_row(db, view, row, object)))
370 msiobj_release( &object->hdr );
371 else
372 *rec = object;
373
374 return r;
375 }
376
MSI_ViewFetch(MSIQUERY * query,MSIRECORD ** prec)377 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
378 {
379 MSIVIEW *view;
380 UINT r;
381
382 TRACE("%p %p\n", query, prec );
383
384 view = query->view;
385 if( !view )
386 return ERROR_FUNCTION_FAILED;
387
388 r = msi_view_get_row(query->db, view, query->row, prec);
389 if (r == ERROR_SUCCESS)
390 {
391 query->row ++;
392 (*prec)->cookie = (UINT64)(ULONG_PTR)query;
393 MSI_RecordSetInteger(*prec, 0, 1);
394 }
395 else if (r == ERROR_NO_MORE_ITEMS)
396 {
397 /* end of view; reset cursor to first row */
398 query->row = 0;
399 }
400
401 return r;
402 }
403
MsiViewFetch(MSIHANDLE hView,MSIHANDLE * record)404 UINT WINAPI MsiViewFetch( MSIHANDLE hView, MSIHANDLE *record )
405 {
406 MSIQUERY *query;
407 MSIRECORD *rec = NULL;
408 UINT ret;
409
410 TRACE( "%lu, %p\n", hView, record );
411
412 if( !record )
413 return ERROR_INVALID_PARAMETER;
414 *record = 0;
415
416 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
417 if (!query)
418 {
419 struct wire_record *wire_rec = NULL;
420 MSIHANDLE remote;
421
422 if (!(remote = msi_get_remote(hView)))
423 return ERROR_INVALID_HANDLE;
424
425 __TRY
426 {
427 ret = remote_ViewFetch(remote, &wire_rec);
428 }
429 __EXCEPT(rpc_filter)
430 {
431 ret = GetExceptionCode();
432 }
433 __ENDTRY
434
435 if (!ret)
436 {
437 ret = unmarshal_record(wire_rec, record);
438 free_remote_record(wire_rec);
439 }
440 return ret;
441 }
442 ret = MSI_ViewFetch( query, &rec );
443 if( ret == ERROR_SUCCESS )
444 {
445 *record = alloc_msihandle( &rec->hdr );
446 if (! *record)
447 ret = ERROR_NOT_ENOUGH_MEMORY;
448 msiobj_release( &rec->hdr );
449 }
450 msiobj_release( &query->hdr );
451 return ret;
452 }
453
MSI_ViewClose(MSIQUERY * query)454 UINT MSI_ViewClose(MSIQUERY *query)
455 {
456 MSIVIEW *view;
457
458 TRACE("%p\n", query );
459
460 view = query->view;
461 if( !view )
462 return ERROR_FUNCTION_FAILED;
463 if( !view->ops->close )
464 return ERROR_FUNCTION_FAILED;
465
466 return view->ops->close( view );
467 }
468
MsiViewClose(MSIHANDLE hView)469 UINT WINAPI MsiViewClose( MSIHANDLE hView )
470 {
471 MSIQUERY *query;
472 UINT ret;
473
474 TRACE( "%lu\n", hView );
475
476 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
477 if (!query)
478 {
479 MSIHANDLE remote;
480
481 if (!(remote = msi_get_remote(hView)))
482 return ERROR_INVALID_HANDLE;
483
484 __TRY
485 {
486 ret = remote_ViewClose(remote);
487 }
488 __EXCEPT(rpc_filter)
489 {
490 ret = GetExceptionCode();
491 }
492 __ENDTRY
493
494 return ret;
495 }
496
497 ret = MSI_ViewClose( query );
498 msiobj_release( &query->hdr );
499 return ret;
500 }
501
MSI_ViewExecute(MSIQUERY * query,MSIRECORD * rec)502 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
503 {
504 MSIVIEW *view;
505
506 TRACE("%p %p\n", query, rec);
507
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;
514
515 return view->ops->execute( view, rec );
516 }
517
MsiViewExecute(MSIHANDLE hView,MSIHANDLE hRec)518 UINT WINAPI MsiViewExecute( MSIHANDLE hView, MSIHANDLE hRec )
519 {
520 MSIQUERY *query;
521 MSIRECORD *rec = NULL;
522 UINT ret;
523
524 TRACE( "%lu, %lu\n", hView, hRec );
525
526 if( hRec )
527 {
528 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
529 if( !rec )
530 return ERROR_INVALID_HANDLE;
531 }
532
533 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
534 if( !query )
535 {
536 MSIHANDLE remote;
537
538 if (!(remote = msi_get_remote(hView)))
539 return ERROR_INVALID_HANDLE;
540
541 __TRY
542 {
543 ret = remote_ViewExecute(remote, rec ? (struct wire_record *)&rec->count : NULL);
544 }
545 __EXCEPT(rpc_filter)
546 {
547 ret = GetExceptionCode();
548 }
549 __ENDTRY
550
551 if (rec)
552 msiobj_release(&rec->hdr);
553 return ret;
554 }
555
556 msiobj_lock( &rec->hdr );
557 ret = MSI_ViewExecute( query, rec );
558 msiobj_unlock( &rec->hdr );
559
560 msiobj_release( &query->hdr );
561 if( rec )
562 msiobj_release( &rec->hdr );
563
564 return ret;
565 }
566
set_record_type_string(MSIRECORD * rec,UINT field,UINT type,BOOL temporary)567 static UINT set_record_type_string( MSIRECORD *rec, UINT field, UINT type, BOOL temporary )
568 {
569 WCHAR szType[0x10];
570
571 if (MSITYPE_IS_BINARY(type))
572 szType[0] = 'v';
573 else if (type & MSITYPE_LOCALIZABLE)
574 szType[0] = 'l';
575 else if (type & MSITYPE_UNKNOWN)
576 szType[0] = 'f';
577 else if (type & MSITYPE_STRING)
578 {
579 if (temporary)
580 szType[0] = 'g';
581 else
582 szType[0] = 's';
583 }
584 else
585 {
586 if (temporary)
587 szType[0] = 'j';
588 else
589 szType[0] = 'i';
590 }
591
592 if (type & MSITYPE_NULLABLE)
593 szType[0] &= ~0x20;
594
595 swprintf( &szType[1], ARRAY_SIZE(szType) - 1, L"%d", (type&0xff) );
596
597 TRACE("type %04x -> %s\n", type, debugstr_w(szType) );
598
599 return MSI_RecordSetStringW( rec, field, szType );
600 }
601
MSI_ViewGetColumnInfo(MSIQUERY * query,MSICOLINFO info,MSIRECORD ** prec)602 UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec )
603 {
604 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
605 MSIRECORD *rec;
606 MSIVIEW *view = query->view;
607 LPCWSTR name;
608 BOOL temporary;
609
610 if( !view )
611 return ERROR_FUNCTION_FAILED;
612
613 if( !view->ops->get_dimensions )
614 return ERROR_FUNCTION_FAILED;
615
616 r = view->ops->get_dimensions( view, NULL, &count );
617 if( r != ERROR_SUCCESS )
618 return r;
619 if( !count )
620 return ERROR_INVALID_PARAMETER;
621
622 rec = MSI_CreateRecord( count );
623 if( !rec )
624 return ERROR_FUNCTION_FAILED;
625
626 for( i=0; i<count; i++ )
627 {
628 name = NULL;
629 r = view->ops->get_column_info( view, i+1, &name, &type, &temporary, NULL );
630 if( r != ERROR_SUCCESS )
631 continue;
632 if (info == MSICOLINFO_NAMES)
633 MSI_RecordSetStringW( rec, i+1, name );
634 else
635 set_record_type_string( rec, i+1, type, temporary );
636 }
637 *prec = rec;
638 return ERROR_SUCCESS;
639 }
640
MsiViewGetColumnInfo(MSIHANDLE hView,MSICOLINFO info,MSIHANDLE * hRec)641 UINT WINAPI MsiViewGetColumnInfo( MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec )
642 {
643 MSIQUERY *query = NULL;
644 MSIRECORD *rec = NULL;
645 UINT r;
646
647 TRACE( "%lu, %d, %p\n", hView, info, hRec );
648
649 if( !hRec )
650 return ERROR_INVALID_PARAMETER;
651
652 if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
653 return ERROR_INVALID_PARAMETER;
654
655 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
656 if (!query)
657 {
658 struct wire_record *wire_rec = NULL;
659 MSIHANDLE remote;
660
661 if (!(remote = msi_get_remote(hView)))
662 return ERROR_INVALID_HANDLE;
663
664 __TRY
665 {
666 r = remote_ViewGetColumnInfo(remote, info, &wire_rec);
667 }
668 __EXCEPT(rpc_filter)
669 {
670 r = GetExceptionCode();
671 }
672 __ENDTRY
673
674 if (!r)
675 {
676 r = unmarshal_record(wire_rec, hRec);
677 free_remote_record(wire_rec);
678 }
679
680 return r;
681 }
682
683 r = MSI_ViewGetColumnInfo( query, info, &rec );
684 if ( r == ERROR_SUCCESS )
685 {
686 *hRec = alloc_msihandle( &rec->hdr );
687 if ( !*hRec )
688 r = ERROR_NOT_ENOUGH_MEMORY;
689 msiobj_release( &rec->hdr );
690 }
691
692 msiobj_release( &query->hdr );
693
694 return r;
695 }
696
MSI_ViewModify(MSIQUERY * query,MSIMODIFY mode,MSIRECORD * rec)697 UINT MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec )
698 {
699 MSIVIEW *view = NULL;
700 UINT r;
701
702 if ( !query || !rec )
703 return ERROR_INVALID_HANDLE;
704
705 view = query->view;
706 if ( !view || !view->ops->modify)
707 return ERROR_FUNCTION_FAILED;
708
709 if ( mode == MSIMODIFY_UPDATE && rec->cookie != (UINT64)(ULONG_PTR)query )
710 return ERROR_FUNCTION_FAILED;
711
712 r = view->ops->modify( view, mode, rec, query->row - 1 );
713 if (mode == MSIMODIFY_DELETE && r == ERROR_SUCCESS)
714 query->row--;
715
716 return r;
717 }
718
MsiViewModify(MSIHANDLE hView,MSIMODIFY eModifyMode,MSIHANDLE hRecord)719 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode, MSIHANDLE hRecord )
720 {
721 MSIQUERY *query = NULL;
722 MSIRECORD *rec = NULL;
723 UINT r = ERROR_FUNCTION_FAILED;
724
725 TRACE( "%lu, %#x, %lu\n", hView, eModifyMode, hRecord );
726
727 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
728
729 if (!rec)
730 return ERROR_INVALID_HANDLE;
731
732 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
733 if (!query)
734 {
735 struct wire_record *wire_refreshed = NULL;
736 MSIHANDLE remote;
737
738 if (!(remote = msi_get_remote(hView)))
739 return ERROR_INVALID_HANDLE;
740
741 __TRY
742 {
743 r = remote_ViewModify(remote, eModifyMode,
744 (struct wire_record *)&rec->count, &wire_refreshed);
745 }
746 __EXCEPT(rpc_filter)
747 {
748 r = GetExceptionCode();
749 }
750 __ENDTRY
751
752 if (!r && (eModifyMode == MSIMODIFY_REFRESH || eModifyMode == MSIMODIFY_SEEK))
753 {
754 r = copy_remote_record(wire_refreshed, hRecord);
755 free_remote_record(wire_refreshed);
756 }
757
758 msiobj_release(&rec->hdr);
759 return r;
760 }
761
762 r = MSI_ViewModify( query, eModifyMode, rec );
763
764 msiobj_release( &query->hdr );
765 msiobj_release(&rec->hdr);
766 return r;
767 }
768
MsiViewGetErrorW(MSIHANDLE handle,WCHAR * buffer,DWORD * buflen)769 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, WCHAR *buffer, DWORD *buflen )
770 {
771 MSIQUERY *query;
772 const WCHAR *column;
773 MSIDBERROR r;
774
775 TRACE( "%lu, %p, %p\n", handle, buffer, buflen );
776
777 if (!buflen)
778 return MSIDBERROR_INVALIDARG;
779
780 if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW)))
781 {
782 WCHAR *remote_column = NULL;
783 MSIHANDLE remote;
784
785 if (!(remote = msi_get_remote(handle)))
786 return MSIDBERROR_INVALIDARG;
787
788 if (!*buflen)
789 return MSIDBERROR_FUNCTIONERROR;
790
791 __TRY
792 {
793 r = remote_ViewGetError(remote, &remote_column);
794 }
795 __EXCEPT(rpc_filter)
796 {
797 r = GetExceptionCode();
798 }
799 __ENDTRY;
800
801 if (msi_strncpyW(remote_column ? remote_column : L"", -1, buffer, buflen) == ERROR_MORE_DATA)
802 r = MSIDBERROR_MOREDATA;
803
804 if (remote_column)
805 midl_user_free(remote_column);
806
807 return r;
808 }
809
810 if ((r = query->view->error)) column = query->view->error_column;
811 else column = L"";
812
813 if (msi_strncpyW(column, -1, buffer, buflen) == ERROR_MORE_DATA)
814 r = MSIDBERROR_MOREDATA;
815
816 msiobj_release( &query->hdr );
817 return r;
818 }
819
MsiViewGetErrorA(MSIHANDLE handle,char * buffer,DWORD * buflen)820 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, char *buffer, DWORD *buflen )
821 {
822 MSIQUERY *query;
823 const WCHAR *column;
824 MSIDBERROR r;
825
826 TRACE( "%lu, %p, %p\n", handle, buffer, buflen );
827
828 if (!buflen)
829 return MSIDBERROR_INVALIDARG;
830
831 if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW)))
832 {
833 WCHAR *remote_column = NULL;
834 MSIHANDLE remote;
835
836 if (!(remote = msi_get_remote(handle)))
837 return MSIDBERROR_INVALIDARG;
838
839 if (!*buflen)
840 return MSIDBERROR_FUNCTIONERROR;
841
842 __TRY
843 {
844 r = remote_ViewGetError(remote, &remote_column);
845 }
846 __EXCEPT(rpc_filter)
847 {
848 r = GetExceptionCode();
849 }
850 __ENDTRY;
851
852 if (msi_strncpyWtoA(remote_column ? remote_column : L"", -1, buffer, buflen, FALSE) == ERROR_MORE_DATA)
853 r = MSIDBERROR_MOREDATA;
854
855 if (remote_column)
856 midl_user_free(remote_column);
857
858 return r;
859 }
860
861 if ((r = query->view->error)) column = query->view->error_column;
862 else column = L"";
863
864 if (msi_strncpyWtoA(column, -1, buffer, buflen, FALSE) == ERROR_MORE_DATA)
865 r = MSIDBERROR_MOREDATA;
866
867 msiobj_release( &query->hdr );
868 return r;
869 }
870
MsiGetLastErrorRecord(void)871 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
872 {
873 FIXME("\n");
874 return 0;
875 }
876
MSI_DatabaseApplyTransformW(MSIDATABASE * db,const WCHAR * transform,int error_cond)877 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db, const WCHAR *transform, int error_cond )
878 {
879 HRESULT hr;
880 UINT ret = ERROR_FUNCTION_FAILED;
881 IStorage *stg;
882 STATSTG stat;
883
884 TRACE( "%p %s %08x\n", db, debugstr_w(transform), error_cond );
885
886 if (*transform == ':')
887 {
888 hr = IStorage_OpenStorage( db->storage, transform + 1, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
889 if (FAILED( hr ))
890 {
891 WARN( "failed to open substorage transform %#lx\n", hr );
892 return ERROR_FUNCTION_FAILED;
893 }
894 }
895 else
896 {
897 hr = StgOpenStorage( transform, NULL, STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg );
898 if (FAILED( hr ))
899 {
900 WARN( "failed to open file transform %#lx\n", hr );
901 return ERROR_FUNCTION_FAILED;
902 }
903 }
904
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 );
909
910 ret = msi_table_apply_transform( db, stg, error_cond );
911
912 end:
913 IStorage_Release( stg );
914 return ret;
915 }
916
MsiDatabaseApplyTransformW(MSIHANDLE hdb,const WCHAR * transform,int error_cond)917 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, const WCHAR *transform, int error_cond )
918 {
919 MSIDATABASE *db;
920 UINT r;
921
922 if (error_cond & ~MSITRANSFORM_ERROR_VIEWTRANSFORM) FIXME( "ignoring error conditions\n" );
923
924 if (!(db = msihandle2msiinfo(hdb, MSIHANDLETYPE_DATABASE)))
925 return ERROR_INVALID_HANDLE;
926
927 r = MSI_DatabaseApplyTransformW( db, transform, error_cond );
928 msiobj_release( &db->hdr );
929 return r;
930 }
931
MsiDatabaseApplyTransformA(MSIHANDLE hdb,const char * transform,int error_cond)932 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, const char *transform, int error_cond )
933 {
934 WCHAR *wstr;
935 UINT ret;
936
937 TRACE( "%lu, %s, %#x\n", hdb, debugstr_a(transform), error_cond );
938
939 wstr = strdupAtoW( transform );
940 if (transform && !wstr)
941 return ERROR_NOT_ENOUGH_MEMORY;
942
943 ret = MsiDatabaseApplyTransformW( hdb, wstr, error_cond );
944 free( wstr );
945 return ret;
946 }
947
MsiDatabaseGenerateTransformA(MSIHANDLE hdb,MSIHANDLE hdbref,const char * szTransformFile,int iReserved1,int iReserved2)948 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref, const char *szTransformFile,
949 int iReserved1, int iReserved2 )
950 {
951 FIXME( "%lu, %lu, %s, %d, %d\n", hdb, hdbref, debugstr_a(szTransformFile), iReserved1, iReserved2 );
952 return ERROR_CALL_NOT_IMPLEMENTED;
953 }
954
MsiDatabaseGenerateTransformW(MSIHANDLE hdb,MSIHANDLE hdbref,const WCHAR * szTransformFile,int iReserved1,int iReserved2)955 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref, const WCHAR *szTransformFile,
956 int iReserved1, int iReserved2 )
957 {
958 FIXME( "%lu, %lu, %s, %d, %d\n", hdb, hdbref, debugstr_w(szTransformFile), iReserved1, iReserved2 );
959 return ERROR_CALL_NOT_IMPLEMENTED;
960 }
961
MsiDatabaseCommit(MSIHANDLE hdb)962 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
963 {
964 MSIDATABASE *db;
965 UINT r;
966
967 TRACE( "%lu\n", hdb );
968
969 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
970 if( !db )
971 {
972 MSIHANDLE remote;
973
974 if (!(remote = msi_get_remote(hdb)))
975 return ERROR_INVALID_HANDLE;
976
977 WARN("not allowed during a custom action!\n");
978
979 return ERROR_SUCCESS;
980 }
981
982 if (db->mode == MSI_OPEN_READONLY)
983 {
984 msiobj_release( &db->hdr );
985 return ERROR_SUCCESS;
986 }
987
988 /* FIXME: lock the database */
989
990 r = msi_commit_streams( db );
991 if (r != ERROR_SUCCESS) ERR("Failed to commit streams!\n");
992 else
993 {
994 r = MSI_CommitTables( db );
995 if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
996 }
997
998 /* FIXME: unlock the database */
999
1000 msiobj_release( &db->hdr );
1001
1002 if (r == ERROR_SUCCESS)
1003 {
1004 free( db->deletefile );
1005 db->deletefile = NULL;
1006 }
1007
1008 return r;
1009 }
1010
1011 struct primary_key_record_info
1012 {
1013 DWORD n;
1014 MSIRECORD *rec;
1015 };
1016
primary_key_iterator(MSIRECORD * rec,void * param)1017 static UINT primary_key_iterator( MSIRECORD *rec, void *param )
1018 {
1019 struct primary_key_record_info *info = param;
1020 LPCWSTR name, table;
1021 DWORD type;
1022
1023 type = MSI_RecordGetInteger( rec, 4 );
1024 if( type & MSITYPE_KEY )
1025 {
1026 info->n++;
1027 if( info->rec )
1028 {
1029 if ( info->n == 1 )
1030 {
1031 table = MSI_RecordGetString( rec, 1 );
1032 MSI_RecordSetStringW( info->rec, 0, table);
1033 }
1034
1035 name = MSI_RecordGetString( rec, 3 );
1036 MSI_RecordSetStringW( info->rec, info->n, name );
1037 }
1038 }
1039
1040 return ERROR_SUCCESS;
1041 }
1042
MSI_DatabaseGetPrimaryKeys(MSIDATABASE * db,const WCHAR * table,MSIRECORD ** prec)1043 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db, const WCHAR *table, MSIRECORD **prec )
1044 {
1045 struct primary_key_record_info info;
1046 MSIQUERY *query = NULL;
1047 UINT r;
1048
1049 if (!TABLE_Exists( db, table ))
1050 return ERROR_INVALID_TABLE;
1051
1052 r = MSI_OpenQuery( db, &query, L"SELECT * FROM `_Columns` WHERE `Table` = '%s'", table );
1053 if( r != ERROR_SUCCESS )
1054 return r;
1055
1056 /* count the number of primary key records */
1057 info.n = 0;
1058 info.rec = 0;
1059 r = MSI_IterateRecords( query, 0, primary_key_iterator, &info );
1060 if( r == ERROR_SUCCESS )
1061 {
1062 TRACE( "found %lu primary keys\n", info.n );
1063
1064 /* allocate a record and fill in the names of the tables */
1065 info.rec = MSI_CreateRecord( info.n );
1066 info.n = 0;
1067 r = MSI_IterateRecords( query, 0, primary_key_iterator, &info );
1068 if( r == ERROR_SUCCESS )
1069 *prec = info.rec;
1070 else
1071 msiobj_release( &info.rec->hdr );
1072 }
1073 msiobj_release( &query->hdr );
1074
1075 return r;
1076 }
1077
MsiDatabaseGetPrimaryKeysW(MSIHANDLE hdb,const WCHAR * table,MSIHANDLE * phRec)1078 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb, const WCHAR *table, MSIHANDLE *phRec )
1079 {
1080 MSIRECORD *rec = NULL;
1081 MSIDATABASE *db;
1082 UINT r;
1083
1084 TRACE( "%lu, %s, %p\n", hdb, debugstr_w(table), phRec );
1085
1086 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
1087 if( !db )
1088 {
1089 struct wire_record *wire_rec = NULL;
1090 MSIHANDLE remote;
1091
1092 if (!(remote = msi_get_remote(hdb)))
1093 return ERROR_INVALID_HANDLE;
1094
1095 __TRY
1096 {
1097 r = remote_DatabaseGetPrimaryKeys(remote, table, &wire_rec);
1098 }
1099 __EXCEPT(rpc_filter)
1100 {
1101 r = GetExceptionCode();
1102 }
1103 __ENDTRY
1104
1105 if (!r)
1106 {
1107 r = unmarshal_record(wire_rec, phRec);
1108 free_remote_record(wire_rec);
1109 }
1110
1111 return r;
1112 }
1113
1114 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
1115 if( r == ERROR_SUCCESS )
1116 {
1117 *phRec = alloc_msihandle( &rec->hdr );
1118 if (! *phRec)
1119 r = ERROR_NOT_ENOUGH_MEMORY;
1120 msiobj_release( &rec->hdr );
1121 }
1122 msiobj_release( &db->hdr );
1123
1124 return r;
1125 }
1126
MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,const char * table,MSIHANDLE * phRec)1127 UINT WINAPI MsiDatabaseGetPrimaryKeysA( MSIHANDLE hdb, const char *table, MSIHANDLE *phRec )
1128 {
1129 WCHAR *szwTable = NULL;
1130 UINT r;
1131
1132 TRACE( "%lu, %s, %p\n", hdb, debugstr_a(table), phRec );
1133
1134 if( table )
1135 {
1136 szwTable = strdupAtoW( table );
1137 if( !szwTable )
1138 return ERROR_OUTOFMEMORY;
1139 }
1140 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
1141 free( szwTable );
1142
1143 return r;
1144 }
1145
MsiDatabaseIsTablePersistentA(MSIHANDLE hDatabase,const char * szTableName)1146 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA( MSIHANDLE hDatabase, const char *szTableName )
1147 {
1148 WCHAR *szwTableName = NULL;
1149 MSICONDITION r;
1150
1151 TRACE( "%lu, %s\n", hDatabase, debugstr_a(szTableName) );
1152
1153 if( szTableName )
1154 {
1155 szwTableName = strdupAtoW( szTableName );
1156 if( !szwTableName )
1157 return MSICONDITION_ERROR;
1158 }
1159 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
1160 free( szwTableName );
1161
1162 return r;
1163 }
1164
MsiDatabaseIsTablePersistentW(MSIHANDLE hDatabase,const WCHAR * szTableName)1165 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW( MSIHANDLE hDatabase, const WCHAR *szTableName )
1166 {
1167 MSIDATABASE *db;
1168 MSICONDITION r;
1169
1170 TRACE( "%lu, %s\n", hDatabase, debugstr_w(szTableName) );
1171
1172 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
1173 if( !db )
1174 {
1175 MSIHANDLE remote;
1176
1177 if (!(remote = msi_get_remote(hDatabase)))
1178 return MSICONDITION_ERROR;
1179
1180 __TRY
1181 {
1182 r = remote_DatabaseIsTablePersistent(remote, szTableName);
1183 }
1184 __EXCEPT(rpc_filter)
1185 {
1186 r = MSICONDITION_ERROR;
1187 }
1188 __ENDTRY
1189
1190 return r;
1191 }
1192
1193 r = MSI_DatabaseIsTablePersistent( db, szTableName );
1194
1195 msiobj_release( &db->hdr );
1196
1197 return r;
1198 }
1199
s_remote_ViewClose(MSIHANDLE view)1200 UINT __cdecl s_remote_ViewClose(MSIHANDLE view)
1201 {
1202 return MsiViewClose(view);
1203 }
1204
s_remote_ViewExecute(MSIHANDLE view,struct wire_record * remote_rec)1205 UINT __cdecl s_remote_ViewExecute(MSIHANDLE view, struct wire_record *remote_rec)
1206 {
1207 MSIHANDLE rec = 0;
1208 UINT r;
1209
1210 if ((r = unmarshal_record(remote_rec, &rec)))
1211 return r;
1212
1213 r = MsiViewExecute(view, rec);
1214
1215 MsiCloseHandle(rec);
1216 return r;
1217 }
1218
s_remote_ViewFetch(MSIHANDLE view,struct wire_record ** rec)1219 UINT __cdecl s_remote_ViewFetch(MSIHANDLE view, struct wire_record **rec)
1220 {
1221 MSIHANDLE handle;
1222 UINT r = MsiViewFetch(view, &handle);
1223 *rec = NULL;
1224 if (!r)
1225 *rec = marshal_record(handle);
1226 MsiCloseHandle(handle);
1227 return r;
1228 }
1229
s_remote_ViewGetColumnInfo(MSIHANDLE view,MSICOLINFO info,struct wire_record ** rec)1230 UINT __cdecl s_remote_ViewGetColumnInfo(MSIHANDLE view, MSICOLINFO info, struct wire_record **rec)
1231 {
1232 MSIHANDLE handle;
1233 UINT r = MsiViewGetColumnInfo(view, info, &handle);
1234 *rec = NULL;
1235 if (!r)
1236 *rec = marshal_record(handle);
1237 MsiCloseHandle(handle);
1238 return r;
1239 }
1240
s_remote_ViewGetError(MSIHANDLE view,LPWSTR * column)1241 MSIDBERROR __cdecl s_remote_ViewGetError(MSIHANDLE view, LPWSTR *column)
1242 {
1243 WCHAR empty[1];
1244 DWORD size = 1;
1245 UINT r;
1246
1247 r = MsiViewGetErrorW(view, empty, &size);
1248 if (r == MSIDBERROR_MOREDATA)
1249 {
1250 if (!(*column = midl_user_allocate(++size * sizeof(WCHAR))))
1251 return MSIDBERROR_FUNCTIONERROR;
1252 r = MsiViewGetErrorW(view, *column, &size);
1253 }
1254 return r;
1255 }
1256
s_remote_ViewModify(MSIHANDLE view,MSIMODIFY mode,struct wire_record * remote_rec,struct wire_record ** remote_refreshed)1257 UINT __cdecl s_remote_ViewModify(MSIHANDLE view, MSIMODIFY mode,
1258 struct wire_record *remote_rec, struct wire_record **remote_refreshed)
1259 {
1260 MSIHANDLE handle = 0;
1261 UINT r;
1262
1263 if ((r = unmarshal_record(remote_rec, &handle)))
1264 return r;
1265
1266 r = MsiViewModify(view, mode, handle);
1267 *remote_refreshed = NULL;
1268 if (!r && (mode == MSIMODIFY_REFRESH || mode == MSIMODIFY_SEEK))
1269 *remote_refreshed = marshal_record(handle);
1270
1271 MsiCloseHandle(handle);
1272 return r;
1273 }
1274