ShellExecuteEx, ExtractIconEx, SHFileOperation, SHGetFileInfo,
[wine] / dlls / msi / msiquery.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2002-2004 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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/unicode.h"
30 #include "msi.h"
31 #include "msiquery.h"
32 #include "objbase.h"
33 #include "objidl.h"
34 #include "msipriv.h"
35 #include "winnls.h"
36
37 #include "query.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
40
41 #if 0
42 typedef struct tagMSIQUERY
43 {
44     MSIOBJECTHDR hdr;
45     MSIVIEW *view;
46     UINT row;
47     MSIDATABASE *db;
48 } MSIQUERY;
49 #endif
50
51 UINT WINAPI MsiDatabaseIsTablePersistentA(
52               MSIHANDLE hDatabase, LPSTR szTableName)
53 {
54     FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName));
55     return ERROR_CALL_NOT_IMPLEMENTED;
56 }
57
58 UINT WINAPI MsiDatabaseIsTablePersistentW(
59               MSIHANDLE hDatabase, LPWSTR szTableName)
60 {
61     FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName));
62     return ERROR_CALL_NOT_IMPLEMENTED;
63 }
64
65 void MSI_CloseView( MSIOBJECTHDR *arg )
66 {
67     MSIQUERY *query = (MSIQUERY*) arg;
68
69     if( query->view && query->view->ops->delete )
70         query->view->ops->delete( query->view );
71     msiobj_release( &query->db->hdr );
72 }
73
74 UINT VIEW_find_column( MSIVIEW *table, LPWSTR name, UINT *n )
75 {
76     LPWSTR col_name;
77     UINT i, count, r;
78
79     r = table->ops->get_dimensions( table, NULL, &count );
80     if( r != ERROR_SUCCESS )
81         return r;
82
83     for( i=1; i<=count; i++ )
84     {
85         INT x;
86
87         col_name = NULL;
88         r = table->ops->get_column_info( table, i, &col_name, NULL );
89         if( r != ERROR_SUCCESS )
90             return r;
91         x = lstrcmpW( name, col_name );
92         HeapFree( GetProcessHeap(), 0, col_name );
93         if( !x )
94         {
95             *n = i;
96             return ERROR_SUCCESS;
97         }
98     }
99
100     return ERROR_INVALID_PARAMETER;
101 }
102
103 UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE hdb,
104               LPCSTR szQuery, MSIHANDLE *phView)
105 {
106     UINT r;
107     LPWSTR szwQuery;
108
109     TRACE("%ld %s %p\n", hdb, debugstr_a(szQuery), phView);
110
111     if( szQuery )
112     {
113         UINT len = MultiByteToWideChar( CP_ACP, 0, szQuery, -1, NULL, 0 );
114         szwQuery = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
115         if( !szwQuery )
116             return ERROR_FUNCTION_FAILED;
117         MultiByteToWideChar( CP_ACP, 0, szQuery, -1, szwQuery, len );
118     }
119     else
120         szwQuery = NULL;
121
122     r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
123
124     HeapFree( GetProcessHeap(), 0, szwQuery );
125     return r;
126 }
127
128 UINT MSI_DatabaseOpenViewW(MSIDATABASE *db,
129               LPCWSTR szQuery, MSIQUERY **pView)
130 {
131     MSIQUERY *query;
132     UINT r;
133
134     TRACE("%s %p\n", debugstr_w(szQuery), pView);
135
136     if( !szQuery)
137         return ERROR_INVALID_PARAMETER;
138
139     /* pre allocate a handle to hold a pointer to the view */
140     query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY),
141                               MSI_CloseView );
142     if( !query )
143         return ERROR_FUNCTION_FAILED;
144
145     msiobj_addref( &db->hdr );
146     query->row = 0;
147     query->db = db;
148     query->view = NULL;
149
150     r = MSI_ParseSQL( db, szQuery, &query->view );
151     if( r == ERROR_SUCCESS )
152     {
153         msiobj_addref( &query->hdr );
154         *pView = query;
155     }
156
157     msiobj_release( &query->hdr );
158     return r;
159 }
160
161 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
162               LPCWSTR szQuery, MSIHANDLE *phView)
163 {
164     MSIDATABASE *db;
165     MSIQUERY *query = NULL;
166     UINT ret;
167
168     TRACE("%s %p\n", debugstr_w(szQuery), phView);
169
170     db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
171     if( !db )
172         return ERROR_INVALID_HANDLE;
173
174     ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
175     if( ret == ERROR_SUCCESS )
176     {
177         *phView = alloc_msihandle( &query->hdr );
178         msiobj_release( &query->hdr );
179     }
180     msiobj_release( &db->hdr );
181
182     return ret;
183 }
184
185 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
186 {
187     MSIVIEW *view;
188     MSIRECORD *rec;
189     UINT row_count = 0, col_count = 0, i, ival, ret, type;
190
191     TRACE("%p %p\n", query, prec );
192
193     view = query->view;
194     if( !view )
195         return ERROR_FUNCTION_FAILED;
196
197     ret = view->ops->get_dimensions( view, &row_count, &col_count );
198     if( ret )
199         return ret;
200     if( !col_count )
201         return ERROR_INVALID_PARAMETER;
202
203     if( query->row >= row_count )
204         return ERROR_NO_MORE_ITEMS;
205
206     rec = MSI_CreateRecord( col_count );
207     if( !rec )
208         return ERROR_FUNCTION_FAILED;
209
210     for( i=1; i<=col_count; i++ )
211     {
212         ret = view->ops->get_column_info( view, i, NULL, &type );
213         if( ret )
214         {
215             ERR("Error getting column type for %d\n", i );
216             continue;
217         }
218         if (( type != MSITYPE_BINARY) && (type != (MSITYPE_BINARY |
219                                                    MSITYPE_NULLABLE)))
220         {
221             ret = view->ops->fetch_int( view, query->row, i, &ival );
222             if( ret )
223             {
224                 ERR("Error fetching data for %d\n", i );
225                 continue;
226             }
227             if( ! (type & MSITYPE_VALID ) )
228                 ERR("Invalid type!\n");
229
230             /* check if it's nul (0) - if so, don't set anything */
231             if( !ival )
232                 continue;
233
234             if( type & MSITYPE_STRING )
235             {
236                 LPWSTR sval;
237
238                 sval = MSI_makestring( query->db, ival );
239                 MSI_RecordSetStringW( rec, i, sval );
240                 HeapFree( GetProcessHeap(), 0, sval );
241             }
242             else
243             {
244                 if( (type & MSI_DATASIZEMASK) == 2 )
245                     MSI_RecordSetInteger( rec, i, ival - (1<<15) );
246                 else
247                     MSI_RecordSetInteger( rec, i, ival - (1<<31) );
248             }
249         }
250         else
251         {
252             IStream *stm = NULL;
253
254             ret = view->ops->fetch_stream( view, query->row, i, &stm );
255             if( ( ret == ERROR_SUCCESS ) && stm )
256             {
257                 MSI_RecordSetIStream( rec, i, stm );
258                 IStream_Release( stm );
259             }
260             else
261                 ERR("failed to get stream\n");
262         }
263     }
264     query->row ++;
265
266     *prec = rec;
267
268     return ERROR_SUCCESS;
269 }
270
271 UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
272 {
273     MSIQUERY *query;
274     MSIRECORD *rec = NULL;
275     UINT ret;
276
277     TRACE("%ld %p\n", hView, record);
278
279     query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
280     if( !query )
281         return ERROR_INVALID_HANDLE;
282     ret = MSI_ViewFetch( query, &rec );
283     if( ret == ERROR_SUCCESS )
284     {
285         *record = alloc_msihandle( &rec->hdr );
286         msiobj_release( &rec->hdr );
287     }
288     msiobj_release( &query->hdr );
289     return ret;
290 }
291
292 UINT MSI_ViewClose(MSIQUERY *query)
293 {
294     MSIVIEW *view;
295
296     TRACE("%p\n", query );
297
298     view = query->view;
299     if( !view )
300         return ERROR_FUNCTION_FAILED;
301     if( !view->ops->close )
302         return ERROR_FUNCTION_FAILED;
303
304     return view->ops->close( view );
305 }
306
307 UINT WINAPI MsiViewClose(MSIHANDLE hView)
308 {
309     MSIQUERY *query;
310     UINT ret;
311
312     TRACE("%ld\n", hView );
313
314     query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
315     if( !query )
316         return ERROR_INVALID_HANDLE;
317
318     ret = MSI_ViewClose( query );
319     msiobj_release( &query->hdr );
320     return ret;
321 }
322
323 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
324 {
325     MSIVIEW *view;
326
327     TRACE("%p %p\n", query, rec);
328
329     view = query->view;
330     if( !view )
331         return ERROR_FUNCTION_FAILED;
332     if( !view->ops->execute )
333         return ERROR_FUNCTION_FAILED;
334     query->row = 0;
335
336     return view->ops->execute( view, rec );
337 }
338
339 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
340 {
341     MSIQUERY *query;
342     MSIRECORD *rec = NULL;
343     UINT ret;
344     
345     TRACE("%ld %ld\n", hView, hRec);
346
347     query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
348     if( !query )
349         return ERROR_INVALID_HANDLE;
350
351     if( hRec )
352     {
353         rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
354         if( !rec )
355         {
356             ret = ERROR_INVALID_HANDLE;
357             goto out;
358         }
359     }
360
361     ret = MSI_ViewExecute( query, rec );
362 out:
363     if( query )
364         msiobj_release( &query->hdr );
365     if( rec )
366         msiobj_release( &rec->hdr );
367
368     return ret;
369 }
370
371 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
372 {
373     MSIVIEW *view;
374     MSIQUERY *query;
375     MSIHANDLE handle;
376     UINT ret, i, count = 0, type;
377     LPWSTR name;
378
379     TRACE("%ld %d %p\n", hView, info, hRec);
380
381     query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
382     if( !query )
383         return ERROR_INVALID_HANDLE;
384
385     view = query->view;
386     if( !view )
387         return ERROR_FUNCTION_FAILED;
388
389     if( !view->ops->get_dimensions )
390         return ERROR_FUNCTION_FAILED;
391
392     ret = view->ops->get_dimensions( view, NULL, &count );
393     if( ret )
394         return ret;
395     if( !count )
396         return ERROR_INVALID_PARAMETER;
397
398     handle = MsiCreateRecord( count );
399     if( !handle )
400         return ERROR_FUNCTION_FAILED;
401
402     for( i=0; i<count; i++ )
403     {
404         name = NULL;
405         ret = view->ops->get_column_info( view, i+1, &name, &type );
406         if( ret != ERROR_SUCCESS )
407             continue;
408         MsiRecordSetStringW( handle, i+1, name );
409         HeapFree( GetProcessHeap(), 0, name );
410     }
411
412     *hRec = handle;
413
414     return ERROR_SUCCESS;
415 }
416
417 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, 
418                  LPCSTR szTransformFile, int iErrorCond)
419 {
420     FIXME("%ld %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
421     return ERROR_CALL_NOT_IMPLEMENTED;
422 }
423
424 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, 
425                  LPCWSTR szTransformFile, int iErrorCond)
426 {
427     FIXME("%ld %s %d\n", hdb, debugstr_w(szTransformFile), iErrorCond);
428     return ERROR_CALL_NOT_IMPLEMENTED;
429 }
430
431 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
432                  LPCSTR szTransformFile, int iReserved1, int iReserved2 )
433 {
434     FIXME("%ld %ld %s %d %d\n", hdb, hdbref, 
435            debugstr_a(szTransformFile), iReserved1, iReserved2);
436     return ERROR_CALL_NOT_IMPLEMENTED;
437 }
438
439 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
440                  LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
441 {
442     FIXME("%ld %ld %s %d %d\n", hdb, hdbref, 
443            debugstr_w(szTransformFile), iReserved1, iReserved2);
444     return ERROR_CALL_NOT_IMPLEMENTED;
445 }
446
447 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
448 {
449     MSIDATABASE *db;
450     UINT r;
451
452     TRACE("%ld\n", hdb);
453
454     db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
455     if( !db )
456         return ERROR_INVALID_HANDLE;
457
458     /* FIXME: lock the database */
459
460     r = MSI_CommitTables( db );
461
462     /* FIXME: unlock the database */
463
464     return r;
465 }
466
467 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb, 
468                     LPCSTR table, MSIHANDLE* rec)
469 {
470     FIXME("%ld %s %p\n", hdb, debugstr_a(table), rec);
471     return ERROR_CALL_NOT_IMPLEMENTED;
472 }
473
474 UINT WINAPI MsiDatabaseGetPrimaryKeysW(MSIHANDLE hdb,
475                     LPCWSTR table, MSIHANDLE* rec)
476 {
477     FIXME("%ld %s %p\n", hdb, debugstr_w(table), rec);
478     return ERROR_CALL_NOT_IMPLEMENTED;
479 }
480
481 UINT WINAPI MsiViewModify(MSIHANDLE hView, MSIMODIFY eModifyMode, MSIHANDLE
482 hRecord)
483 {
484     FIXME("%ld %x %ld\n",hView, eModifyMode, hRecord);
485     return ERROR_CALL_NOT_IMPLEMENTED;
486 }