msi: Fix printing NULL strings.
[wine] / dlls / msi / install.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2005 Aric Stewart 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 /* Msi top level apis directly related to installs */
22
23 #define COBJMACROS
24
25 #include <stdarg.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winerror.h"
30 #include "wine/debug.h"
31 #include "msi.h"
32 #include "msidefs.h"
33 #include "objbase.h"
34 #include "oleauto.h"
35
36 #include "msipriv.h"
37 #include "msiserver.h"
38 #include "wine/unicode.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(msi);
41
42 /***********************************************************************
43  * MsiDoActionA       (MSI.@)
44  */
45 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
46 {
47     LPWSTR szwAction;
48     UINT ret;
49
50     TRACE("%s\n", debugstr_a(szAction));
51
52     szwAction = strdupAtoW(szAction);
53     if (szAction && !szwAction)
54         return ERROR_FUNCTION_FAILED; 
55
56     ret = MsiDoActionW( hInstall, szwAction );
57     msi_free( szwAction );
58     return ret;
59 }
60
61 /***********************************************************************
62  * MsiDoActionW       (MSI.@)
63  */
64 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
65 {
66     MSIPACKAGE *package;
67     UINT ret;
68
69     TRACE("%s\n",debugstr_w(szAction));
70
71     if (!szAction)
72         return ERROR_INVALID_PARAMETER;
73
74     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
75     if (!package)
76     {
77         HRESULT hr;
78         BSTR action;
79         IWineMsiRemotePackage *remote_package;
80
81         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
82         if (!remote_package)
83             return ERROR_INVALID_HANDLE;
84
85         action = SysAllocString( szAction );
86         if (!action)
87         {
88             IWineMsiRemotePackage_Release( remote_package );
89             return ERROR_OUTOFMEMORY;
90         }
91
92         hr = IWineMsiRemotePackage_DoAction( remote_package, action );
93
94         SysFreeString( action );
95         IWineMsiRemotePackage_Release( remote_package );
96
97         if (FAILED(hr))
98         {
99             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
100                 return HRESULT_CODE(hr);
101
102             return ERROR_FUNCTION_FAILED;
103         }
104
105         return ERROR_SUCCESS;
106     }
107  
108     ret = ACTION_PerformUIAction( package, szAction, -1 );
109     msiobj_release( &package->hdr );
110
111     return ret;
112 }
113
114 /***********************************************************************
115  * MsiSequenceA       (MSI.@)
116  */
117 UINT WINAPI MsiSequenceA( MSIHANDLE hInstall, LPCSTR szTable, INT iSequenceMode )
118 {
119     LPWSTR szwTable;
120     UINT ret;
121
122     TRACE("%s, %d\n", debugstr_a(szTable), iSequenceMode);
123
124     szwTable = strdupAtoW(szTable);
125     if (szTable && !szwTable)
126         return ERROR_FUNCTION_FAILED; 
127
128     ret = MsiSequenceW( hInstall, szwTable, iSequenceMode );
129     msi_free( szwTable );
130     return ret;
131 }
132
133 /***********************************************************************
134  * MsiSequenceW       (MSI.@)
135  */
136 UINT WINAPI MsiSequenceW( MSIHANDLE hInstall, LPCWSTR szTable, INT iSequenceMode )
137 {
138     MSIPACKAGE *package;
139     UINT ret;
140
141     TRACE("%s, %d\n", debugstr_w(szTable), iSequenceMode);
142
143     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
144     if (!package)
145     {
146         HRESULT hr;
147         BSTR table;
148         IWineMsiRemotePackage *remote_package;
149
150         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
151         if (!remote_package)
152             return ERROR_INVALID_HANDLE;
153
154         table = SysAllocString( szTable );
155         if (!table)
156         {
157             IWineMsiRemotePackage_Release( remote_package );
158             return ERROR_OUTOFMEMORY;
159         }
160
161         hr = IWineMsiRemotePackage_Sequence( remote_package, table, iSequenceMode );
162
163         SysFreeString( table );
164         IWineMsiRemotePackage_Release( remote_package );
165
166         if (FAILED(hr))
167         {
168             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
169                 return HRESULT_CODE(hr);
170
171             return ERROR_FUNCTION_FAILED;
172         }
173
174         return ERROR_SUCCESS;
175     }
176     ret = MSI_Sequence( package, szTable );
177     msiobj_release( &package->hdr );
178     return ret;
179 }
180
181 UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz )
182 {
183     UINT len, r = ERROR_SUCCESS;
184
185     if (awbuf->str.w && !sz )
186         return ERROR_INVALID_PARAMETER;
187
188     if (!sz)
189         return r;
190  
191     if (awbuf->unicode)
192     {
193         len = lstrlenW( str );
194         if (awbuf->str.w) 
195             lstrcpynW( awbuf->str.w, str, *sz );
196     }
197     else
198     {
199         len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
200         if (len)
201             len--;
202         WideCharToMultiByte( CP_ACP, 0, str, -1, awbuf->str.a, *sz, NULL, NULL );
203         if ( awbuf->str.a && *sz && (len >= *sz) )
204             awbuf->str.a[*sz - 1] = 0;
205     }
206
207     if (awbuf->str.w && len >= *sz)
208         r = ERROR_MORE_DATA;
209     *sz = len;
210     return r;
211 }
212
213 const WCHAR *msi_get_target_folder( MSIPACKAGE *package, const WCHAR *name )
214 {
215     MSIFOLDER *folder = msi_get_loaded_folder( package, name );
216     if (folder) return folder->ResolvedTarget;
217     return NULL;
218 }
219
220 /***********************************************************************
221  * MsiGetTargetPath   (internal)
222  */
223 static UINT MSI_GetTargetPath( MSIHANDLE hInstall, LPCWSTR szFolder,
224                                awstring *szPathBuf, LPDWORD pcchPathBuf )
225 {
226     MSIPACKAGE *package;
227     const WCHAR *path;
228     UINT r = ERROR_FUNCTION_FAILED;
229
230     if (!szFolder)
231         return ERROR_INVALID_PARAMETER;
232
233     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
234     if (!package)
235     {
236         HRESULT hr;
237         IWineMsiRemotePackage *remote_package;
238         LPWSTR value = NULL;
239         BSTR folder;
240         DWORD len;
241
242         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
243         if (!remote_package)
244             return ERROR_INVALID_HANDLE;
245
246         folder = SysAllocString( szFolder );
247         if (!folder)
248         {
249             IWineMsiRemotePackage_Release( remote_package );
250             return ERROR_OUTOFMEMORY;
251         }
252
253         len = 0;
254         hr = IWineMsiRemotePackage_GetTargetPath( remote_package, folder, NULL, &len );
255         if (FAILED(hr))
256             goto done;
257
258         len++;
259         value = msi_alloc(len * sizeof(WCHAR));
260         if (!value)
261         {
262             r = ERROR_OUTOFMEMORY;
263             goto done;
264         }
265
266         hr = IWineMsiRemotePackage_GetTargetPath( remote_package, folder, value, &len );
267         if (FAILED(hr))
268             goto done;
269
270         r = msi_strcpy_to_awstring( value, szPathBuf, pcchPathBuf );
271
272 done:
273         IWineMsiRemotePackage_Release( remote_package );
274         SysFreeString( folder );
275         msi_free( value );
276
277         if (FAILED(hr))
278         {
279             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
280                 return HRESULT_CODE(hr);
281
282             return ERROR_FUNCTION_FAILED;
283         }
284
285         return r;
286     }
287
288     path = msi_get_target_folder( package, szFolder );
289     msiobj_release( &package->hdr );
290
291     if (!path)
292         return ERROR_DIRECTORY;
293
294     r = msi_strcpy_to_awstring( path, szPathBuf, pcchPathBuf );
295     return r;
296 }
297
298 /***********************************************************************
299  * MsiGetTargetPathA        (MSI.@)
300  */
301 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, 
302                                LPSTR szPathBuf, LPDWORD pcchPathBuf )
303 {
304     LPWSTR szwFolder;
305     awstring path;
306     UINT r;
307
308     TRACE("%s %p %p\n", debugstr_a(szFolder), szPathBuf, pcchPathBuf);
309
310     szwFolder = strdupAtoW(szFolder);
311     if (szFolder && !szwFolder)
312         return ERROR_FUNCTION_FAILED; 
313
314     path.unicode = FALSE;
315     path.str.a = szPathBuf;
316
317     r = MSI_GetTargetPath( hInstall, szwFolder, &path, pcchPathBuf );
318
319     msi_free( szwFolder );
320
321     return r;
322 }
323
324 /***********************************************************************
325  * MsiGetTargetPathW        (MSI.@)
326  */
327 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder,
328                                LPWSTR szPathBuf, LPDWORD pcchPathBuf )
329 {
330     awstring path;
331
332     TRACE("%s %p %p\n", debugstr_w(szFolder), szPathBuf, pcchPathBuf);
333
334     path.unicode = TRUE;
335     path.str.w = szPathBuf;
336
337     return MSI_GetTargetPath( hInstall, szFolder, &path, pcchPathBuf );
338 }
339
340 static WCHAR *get_source_root( MSIDATABASE *db )
341 {
342     WCHAR *path, *p;
343
344     if ((path = msi_dup_property( db, szSourceDir ))) return path;
345     if ((path = msi_dup_property( db, szDatabase )))
346     {
347         if ((p = strrchrW( path, '\\' ))) p[1] = 0;
348     }
349     return path;
350 }
351
352 WCHAR *msi_resolve_source_folder( MSIPACKAGE *package, const WCHAR *name, MSIFOLDER **folder )
353 {
354     MSIFOLDER *f;
355     LPWSTR p, path = NULL, parent;
356
357     TRACE("working to resolve %s\n", debugstr_w(name));
358
359     if (!strcmpW( name, szSourceDir )) name = szTargetDir;
360     if (!(f = msi_get_loaded_folder( package, name ))) return NULL;
361
362     /* special resolving for root dir */
363     if (!strcmpW( name, szTargetDir ) && !f->ResolvedSource)
364     {
365         f->ResolvedSource = get_source_root( package->db );
366     }
367     if (folder) *folder = f;
368     if (f->ResolvedSource)
369     {
370         path = strdupW( f->ResolvedSource );
371         TRACE("   already resolved to %s\n", debugstr_w(path));
372         return path;
373     }
374     if (!f->Parent) return path;
375     parent = f->Parent;
376     TRACE(" ! parent is %s\n", debugstr_w(parent));
377
378     p = msi_resolve_source_folder( package, parent, NULL );
379
380     if (package->WordCount & msidbSumInfoSourceTypeCompressed)
381         path = get_source_root( package->db );
382     else if (package->WordCount & msidbSumInfoSourceTypeSFN)
383         path = msi_build_directory_name( 3, p, f->SourceShortPath, NULL );
384     else
385         path = msi_build_directory_name( 3, p, f->SourceLongPath, NULL );
386
387     TRACE("-> %s\n", debugstr_w(path));
388     f->ResolvedSource = strdupW( path );
389     msi_free( p );
390
391     return path;
392 }
393
394 /***********************************************************************
395  * MSI_GetSourcePath   (internal)
396  */
397 static UINT MSI_GetSourcePath( MSIHANDLE hInstall, LPCWSTR szFolder,
398                                awstring *szPathBuf, LPDWORD pcchPathBuf )
399 {
400     MSIPACKAGE *package;
401     LPWSTR path;
402     UINT r = ERROR_FUNCTION_FAILED;
403
404     TRACE("%s %p %p\n", debugstr_w(szFolder), szPathBuf, pcchPathBuf );
405
406     if (!szFolder)
407         return ERROR_INVALID_PARAMETER;
408
409     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
410     if (!package)
411     {
412         HRESULT hr;
413         IWineMsiRemotePackage *remote_package;
414         LPWSTR value = NULL;
415         BSTR folder;
416         DWORD len;
417
418         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
419         if (!remote_package)
420             return ERROR_INVALID_HANDLE;
421
422         folder = SysAllocString( szFolder );
423         if (!folder)
424         {
425             IWineMsiRemotePackage_Release( remote_package );
426             return ERROR_OUTOFMEMORY;
427         }
428
429         len = 0;
430         hr = IWineMsiRemotePackage_GetSourcePath( remote_package, folder, NULL, &len );
431         if (FAILED(hr))
432             goto done;
433
434         len++;
435         value = msi_alloc(len * sizeof(WCHAR));
436         if (!value)
437         {
438             r = ERROR_OUTOFMEMORY;
439             goto done;
440         }
441
442         hr = IWineMsiRemotePackage_GetSourcePath( remote_package, folder, value, &len );
443         if (FAILED(hr))
444             goto done;
445
446         r = msi_strcpy_to_awstring( value, szPathBuf, pcchPathBuf );
447
448 done:
449         IWineMsiRemotePackage_Release( remote_package );
450         SysFreeString( folder );
451         msi_free( value );
452
453         if (FAILED(hr))
454         {
455             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
456                 return HRESULT_CODE(hr);
457
458             return ERROR_FUNCTION_FAILED;
459         }
460
461         return r;
462     }
463
464     if (szPathBuf->str.w && !pcchPathBuf )
465     {
466         msiobj_release( &package->hdr );
467         return ERROR_INVALID_PARAMETER;
468     }
469
470     path = msi_resolve_source_folder( package, szFolder, NULL );
471     msiobj_release( &package->hdr );
472
473     TRACE("path = %s\n", debugstr_w(path));
474     if (!path)
475         return ERROR_DIRECTORY;
476
477     r = msi_strcpy_to_awstring( path, szPathBuf, pcchPathBuf );
478     msi_free( path );
479     return r;
480 }
481
482 /***********************************************************************
483  * MsiGetSourcePathA     (MSI.@)
484  */
485 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, 
486                                LPSTR szPathBuf, LPDWORD pcchPathBuf )
487 {
488     LPWSTR folder;
489     awstring str;
490     UINT r;
491
492     TRACE("%s %p %p\n", debugstr_a(szFolder), debugstr_a(szPathBuf), pcchPathBuf);
493
494     str.unicode = FALSE;
495     str.str.a = szPathBuf;
496
497     folder = strdupAtoW( szFolder );
498     r = MSI_GetSourcePath( hInstall, folder, &str, pcchPathBuf );
499     msi_free( folder );
500
501     return r;
502 }
503
504 /***********************************************************************
505  * MsiGetSourcePathW     (MSI.@)
506  */
507 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder,
508                                LPWSTR szPathBuf, LPDWORD pcchPathBuf )
509 {
510     awstring str;
511
512     TRACE("%s %p %p\n", debugstr_w(szFolder), szPathBuf, pcchPathBuf );
513
514     str.unicode = TRUE;
515     str.str.w = szPathBuf;
516
517     return MSI_GetSourcePath( hInstall, szFolder, &str, pcchPathBuf );
518 }
519
520 /***********************************************************************
521  * MsiSetTargetPathA  (MSI.@)
522  */
523 UINT WINAPI MsiSetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
524                                LPCSTR szFolderPath )
525 {
526     LPWSTR szwFolder = NULL, szwFolderPath = NULL;
527     UINT rc = ERROR_OUTOFMEMORY;
528
529     if ( !szFolder || !szFolderPath )
530         return ERROR_INVALID_PARAMETER;
531
532     szwFolder = strdupAtoW(szFolder);
533     szwFolderPath = strdupAtoW(szFolderPath);
534     if (!szwFolder || !szwFolderPath)
535         goto end;
536
537     rc = MsiSetTargetPathW( hInstall, szwFolder, szwFolderPath );
538
539 end:
540     msi_free(szwFolder);
541     msi_free(szwFolderPath);
542
543     return rc;
544 }
545
546 static void set_target_path( MSIPACKAGE *package, MSIFOLDER *folder, const WCHAR *path )
547 {
548     FolderList *fl;
549     MSIFOLDER *child;
550     WCHAR *target_path;
551
552     if (!(target_path = strdupW( path ))) return;
553     msi_clean_path( target_path );
554     if (strcmpW( target_path, folder->ResolvedTarget ))
555     {
556         msi_free( folder->ResolvedTarget );
557         folder->ResolvedTarget = target_path;
558         msi_set_property( package->db, folder->Directory, folder->ResolvedTarget );
559
560         LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
561         {
562             child = fl->folder;
563             msi_resolve_target_folder( package, child->Directory, FALSE );
564         }
565     }
566     else msi_free( target_path );
567 }
568
569 UINT MSI_SetTargetPathW( MSIPACKAGE *package, LPCWSTR szFolder, LPCWSTR szFolderPath )
570 {
571     DWORD attrib, len;
572     MSIFOLDER *folder;
573     MSIFILE *file;
574
575     TRACE("%p %s %s\n", package, debugstr_w(szFolder), debugstr_w(szFolderPath));
576
577     attrib = GetFileAttributesW(szFolderPath);
578     /* native MSI tests writeability by making temporary files at each drive */
579     if (attrib != INVALID_FILE_ATTRIBUTES &&
580         (attrib & FILE_ATTRIBUTE_OFFLINE || attrib & FILE_ATTRIBUTE_READONLY))
581     {
582         return ERROR_FUNCTION_FAILED;
583     }
584     if (!(folder = msi_get_loaded_folder( package, szFolder ))) return ERROR_DIRECTORY;
585
586     len = strlenW( szFolderPath );
587     if (len && szFolderPath[len - 1] != '\\')
588     {
589         WCHAR *path = msi_alloc( (len + 2) * sizeof(WCHAR) );
590         memcpy( path, szFolderPath, len * sizeof(WCHAR) );
591         path[len] = '\\';
592         path[len + 1] = 0;
593         set_target_path( package, folder, path );
594         msi_free( path );
595     }
596     else set_target_path( package, folder, szFolderPath );
597
598     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
599     {
600         const WCHAR *dir;
601         MSICOMPONENT *comp = file->Component;
602
603         if (!comp->Enabled || (comp->assembly && !comp->assembly->application)) continue;
604
605         dir = msi_get_target_folder( package, comp->Directory );
606         msi_free( file->TargetPath );
607         file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
608     }
609     return ERROR_SUCCESS;
610 }
611
612 /***********************************************************************
613  * MsiSetTargetPathW  (MSI.@)
614  */
615 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, 
616                              LPCWSTR szFolderPath)
617 {
618     MSIPACKAGE *package;
619     UINT ret;
620
621     TRACE("%s %s\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
622
623     if ( !szFolder || !szFolderPath )
624         return ERROR_INVALID_PARAMETER;
625
626     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
627     if (!package)
628     {
629         HRESULT hr;
630         BSTR folder, path;
631         IWineMsiRemotePackage *remote_package;
632
633         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
634         if (!remote_package)
635             return ERROR_INVALID_HANDLE;
636
637         folder = SysAllocString( szFolder );
638         path = SysAllocString( szFolderPath );
639         if (!folder || !path)
640         {
641             SysFreeString(folder);
642             SysFreeString(path);
643             IWineMsiRemotePackage_Release( remote_package );
644             return ERROR_OUTOFMEMORY;
645         }
646
647         hr = IWineMsiRemotePackage_SetTargetPath( remote_package, folder, path );
648
649         SysFreeString(folder);
650         SysFreeString(path);
651         IWineMsiRemotePackage_Release( remote_package );
652
653         if (FAILED(hr))
654         {
655             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
656                 return HRESULT_CODE(hr);
657
658             return ERROR_FUNCTION_FAILED;
659         }
660
661         return ERROR_SUCCESS;
662     }
663
664     ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
665     msiobj_release( &package->hdr );
666     return ret;
667 }
668
669 /***********************************************************************
670  *           MsiGetMode    (MSI.@)
671  *
672  * Returns an internal installer state (if it is running in a mode iRunMode)
673  *
674  * PARAMS
675  *   hInstall    [I]  Handle to the installation
676  *   hRunMode    [I]  Checking run mode
677  *        MSIRUNMODE_ADMIN             Administrative mode
678  *        MSIRUNMODE_ADVERTISE         Advertisement mode
679  *        MSIRUNMODE_MAINTENANCE       Maintenance mode
680  *        MSIRUNMODE_ROLLBACKENABLED   Rollback is enabled
681  *        MSIRUNMODE_LOGENABLED        Log file is writing
682  *        MSIRUNMODE_OPERATIONS        Operations in progress??
683  *        MSIRUNMODE_REBOOTATEND       We need to reboot after installation completed
684  *        MSIRUNMODE_REBOOTNOW         We need to reboot to continue the installation
685  *        MSIRUNMODE_CABINET           Files from cabinet are installed
686  *        MSIRUNMODE_SOURCESHORTNAMES  Long names in source files is suppressed
687  *        MSIRUNMODE_TARGETSHORTNAMES  Long names in destination files is suppressed
688  *        MSIRUNMODE_RESERVED11        Reserved
689  *        MSIRUNMODE_WINDOWS9X         Running under Windows95/98
690  *        MSIRUNMODE_ZAWENABLED        Demand installation is supported
691  *        MSIRUNMODE_RESERVED14        Reserved
692  *        MSIRUNMODE_RESERVED15        Reserved
693  *        MSIRUNMODE_SCHEDULED         called from install script
694  *        MSIRUNMODE_ROLLBACK          called from rollback script
695  *        MSIRUNMODE_COMMIT            called from commit script
696  *
697  * RETURNS
698  *    In the state: TRUE
699  *    Not in the state: FALSE
700  *
701  */
702 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
703 {
704     MSIPACKAGE *package;
705     BOOL r = FALSE;
706
707     TRACE("%d %d\n", hInstall, iRunMode);
708
709     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
710     if (!package)
711     {
712         BOOL ret;
713         HRESULT hr;
714         IWineMsiRemotePackage *remote_package;
715
716         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
717         if (!remote_package)
718             return FALSE;
719
720         hr = IWineMsiRemotePackage_GetMode(remote_package, iRunMode, &ret);
721         IWineMsiRemotePackage_Release(remote_package);
722
723         if (hr == S_OK)
724             return ret;
725
726         return FALSE;
727     }
728
729     switch (iRunMode)
730     {
731     case MSIRUNMODE_ADMIN:
732         FIXME("no support for administrative installs\n");
733         break;
734
735     case MSIRUNMODE_ADVERTISE:
736         FIXME("no support for advertised installs\n");
737         break;
738
739     case MSIRUNMODE_WINDOWS9X:
740         if (GetVersion() & 0x80000000)
741             r = TRUE;
742         break;
743
744     case MSIRUNMODE_OPERATIONS:
745     case MSIRUNMODE_RESERVED11:
746     case MSIRUNMODE_RESERVED14:
747     case MSIRUNMODE_RESERVED15:
748         break;
749
750     case MSIRUNMODE_SCHEDULED:
751         r = package->scheduled_action_running;
752         break;
753
754     case MSIRUNMODE_ROLLBACK:
755         r = package->rollback_action_running;
756         break;
757
758     case MSIRUNMODE_COMMIT:
759         r = package->commit_action_running;
760         break;
761
762     case MSIRUNMODE_MAINTENANCE:
763         r = msi_get_property_int( package->db, szInstalled, 0 ) != 0;
764         break;
765
766     case MSIRUNMODE_ROLLBACKENABLED:
767         r = msi_get_property_int( package->db, szRollbackDisabled, 0 ) == 0;
768         break;
769
770     case MSIRUNMODE_REBOOTATEND:
771         r = package->need_reboot;
772         break;
773
774     case MSIRUNMODE_LOGENABLED:
775         r = (package->log_file != INVALID_HANDLE_VALUE);
776         break;
777
778     default:
779         FIXME("unimplemented run mode: %d\n", iRunMode);
780         r = TRUE;
781     }
782
783     msiobj_release( &package->hdr );
784     return r;
785 }
786
787 /***********************************************************************
788  *           MsiSetMode    (MSI.@)
789  */
790 UINT WINAPI MsiSetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode, BOOL fState)
791 {
792     MSIPACKAGE *package;
793     UINT r;
794
795     TRACE("%d %d %d\n", hInstall, iRunMode, fState);
796
797     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
798     if (!package)
799     {
800         HRESULT hr;
801         IWineMsiRemotePackage *remote_package;
802
803         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
804         if (!remote_package)
805             return FALSE;
806
807         hr = IWineMsiRemotePackage_SetMode( remote_package, iRunMode, fState );
808         IWineMsiRemotePackage_Release( remote_package );
809
810         if (FAILED(hr))
811         {
812             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
813                 return HRESULT_CODE(hr);
814
815             return ERROR_FUNCTION_FAILED;
816         }
817
818         return ERROR_SUCCESS;
819     }
820
821     switch (iRunMode)
822     {
823     case MSIRUNMODE_REBOOTATEND:
824         package->need_reboot = 1;
825         r = ERROR_SUCCESS;
826         break;
827
828     case MSIRUNMODE_REBOOTNOW:
829         FIXME("unimplemented run mode: %d\n", iRunMode);
830         r = ERROR_FUNCTION_FAILED;
831         break;
832
833     default:
834         r = ERROR_ACCESS_DENIED;
835     }
836
837     msiobj_release( &package->hdr );
838     return r;
839 }
840
841 /***********************************************************************
842  * MsiSetFeatureStateA (MSI.@)
843  *
844  * According to the docs, when this is called it immediately recalculates
845  * all the component states as well
846  */
847 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
848                                 INSTALLSTATE iState)
849 {
850     LPWSTR szwFeature = NULL;
851     UINT rc;
852
853     szwFeature = strdupAtoW(szFeature);
854
855     if (!szwFeature)
856         return ERROR_FUNCTION_FAILED;
857    
858     rc = MsiSetFeatureStateW(hInstall,szwFeature, iState); 
859
860     msi_free(szwFeature);
861
862     return rc;
863 }
864
865 /* update component state based on a feature change */
866 void ACTION_UpdateComponentStates( MSIPACKAGE *package, MSIFEATURE *feature )
867 {
868     INSTALLSTATE newstate;
869     ComponentList *cl;
870
871     newstate = feature->ActionRequest;
872     if (newstate == INSTALLSTATE_ABSENT) newstate = INSTALLSTATE_UNKNOWN;
873
874     LIST_FOR_EACH_ENTRY(cl, &feature->Components, ComponentList, entry)
875     {
876         MSICOMPONENT *component = cl->component;
877
878         if (!component->Enabled) continue;
879
880         TRACE("Modifying (%d): Component %s (Installed %d, Action %d, Request %d)\n",
881             newstate, debugstr_w(component->Component), component->Installed,
882             component->Action, component->ActionRequest);
883
884         if (newstate == INSTALLSTATE_LOCAL)
885         {
886             component->Action = INSTALLSTATE_LOCAL;
887             component->ActionRequest = INSTALLSTATE_LOCAL;
888         }
889         else
890         {
891             ComponentList *clist;
892             MSIFEATURE *f;
893
894             component->hasLocalFeature = FALSE;
895
896             component->Action = newstate;
897             component->ActionRequest = newstate;
898             /* if any other feature wants it local we need to set it local */
899             LIST_FOR_EACH_ENTRY(f, &package->features, MSIFEATURE, entry)
900             {
901                 if ( f->ActionRequest != INSTALLSTATE_LOCAL &&
902                      f->ActionRequest != INSTALLSTATE_SOURCE )
903                 {
904                     continue;
905                 }
906                 LIST_FOR_EACH_ENTRY(clist, &f->Components, ComponentList, entry)
907                 {
908                     if (clist->component == component &&
909                         (f->ActionRequest == INSTALLSTATE_LOCAL ||
910                          f->ActionRequest == INSTALLSTATE_SOURCE))
911                     {
912                         TRACE("Saved by %s\n", debugstr_w(f->Feature));
913                         component->hasLocalFeature = TRUE;
914
915                         if (component->Attributes & msidbComponentAttributesOptional)
916                         {
917                             if (f->Attributes & msidbFeatureAttributesFavorSource)
918                             {
919                                 component->Action = INSTALLSTATE_SOURCE;
920                                 component->ActionRequest = INSTALLSTATE_SOURCE;
921                             }
922                             else
923                             {
924                                 component->Action = INSTALLSTATE_LOCAL;
925                                 component->ActionRequest = INSTALLSTATE_LOCAL;
926                             }
927                         }
928                         else if (component->Attributes & msidbComponentAttributesSourceOnly)
929                         {
930                             component->Action = INSTALLSTATE_SOURCE;
931                             component->ActionRequest = INSTALLSTATE_SOURCE;
932                         }
933                         else
934                         {
935                             component->Action = INSTALLSTATE_LOCAL;
936                             component->ActionRequest = INSTALLSTATE_LOCAL;
937                         }
938                     }
939                 }
940             }
941         }
942         TRACE("Result (%d): Component %s (Installed %d, Action %d, Request %d)\n",
943             newstate, debugstr_w(component->Component), component->Installed,
944             component->Action, component->ActionRequest);
945     }
946 }
947
948 UINT WINAPI MSI_SetFeatureStateW( MSIPACKAGE *package, LPCWSTR szFeature, INSTALLSTATE iState )
949 {
950     UINT rc = ERROR_SUCCESS;
951     MSIFEATURE *feature, *child;
952
953     TRACE("%s %i\n", debugstr_w(szFeature), iState);
954
955     feature = msi_get_loaded_feature( package, szFeature );
956     if (!feature)
957         return ERROR_UNKNOWN_FEATURE;
958
959     if (iState == INSTALLSTATE_ADVERTISED && 
960         feature->Attributes & msidbFeatureAttributesDisallowAdvertise)
961         return ERROR_FUNCTION_FAILED;
962
963     feature->ActionRequest = iState;
964
965     ACTION_UpdateComponentStates( package, feature );
966
967     /* update all the features that are children of this feature */
968     LIST_FOR_EACH_ENTRY( child, &package->features, MSIFEATURE, entry )
969     {
970         if (child->Feature_Parent && !strcmpW( szFeature, child->Feature_Parent ))
971             MSI_SetFeatureStateW(package, child->Feature, iState);
972     }
973     
974     return rc;
975 }
976
977 /***********************************************************************
978  * MsiSetFeatureStateW (MSI.@)
979  */
980 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
981                                 INSTALLSTATE iState)
982 {
983     MSIPACKAGE* package;
984     UINT rc = ERROR_SUCCESS;
985
986     TRACE("%s %i\n",debugstr_w(szFeature), iState);
987
988     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
989     if (!package)
990     {
991         HRESULT hr;
992         BSTR feature;
993         IWineMsiRemotePackage *remote_package;
994
995         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
996         if (!remote_package)
997             return ERROR_INVALID_HANDLE;
998
999         feature = SysAllocString(szFeature);
1000         if (!feature)
1001         {
1002             IWineMsiRemotePackage_Release(remote_package);
1003             return ERROR_OUTOFMEMORY;
1004         }
1005
1006         hr = IWineMsiRemotePackage_SetFeatureState(remote_package, feature, iState);
1007
1008         SysFreeString(feature);
1009         IWineMsiRemotePackage_Release(remote_package);
1010
1011         if (FAILED(hr))
1012         {
1013             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1014                 return HRESULT_CODE(hr);
1015
1016             return ERROR_FUNCTION_FAILED;
1017         }
1018
1019         return ERROR_SUCCESS;
1020     }
1021
1022     rc = MSI_SetFeatureStateW(package,szFeature,iState);
1023
1024     msiobj_release( &package->hdr );
1025     return rc;
1026 }
1027
1028 /***********************************************************************
1029 * MsiSetFeatureAttributesA   (MSI.@)
1030 */
1031 UINT WINAPI MsiSetFeatureAttributesA( MSIHANDLE handle, LPCSTR feature, DWORD attrs )
1032 {
1033     UINT r;
1034     WCHAR *featureW = NULL;
1035
1036     TRACE("%u, %s, 0x%08x\n", handle, debugstr_a(feature), attrs);
1037
1038     if (feature && !(featureW = strdupAtoW( feature ))) return ERROR_OUTOFMEMORY;
1039
1040     r = MsiSetFeatureAttributesW( handle, featureW, attrs );
1041     msi_free( featureW );
1042     return r;
1043 }
1044
1045 static DWORD unmap_feature_attributes( DWORD attrs )
1046 {
1047     DWORD ret = 0;
1048
1049     if (attrs & INSTALLFEATUREATTRIBUTE_FAVORLOCAL)             ret = msidbFeatureAttributesFavorLocal;
1050     if (attrs & INSTALLFEATUREATTRIBUTE_FAVORSOURCE)            ret |= msidbFeatureAttributesFavorSource;
1051     if (attrs & INSTALLFEATUREATTRIBUTE_FOLLOWPARENT)           ret |= msidbFeatureAttributesFollowParent;
1052     if (attrs & INSTALLFEATUREATTRIBUTE_FAVORADVERTISE)         ret |= msidbFeatureAttributesFavorAdvertise;
1053     if (attrs & INSTALLFEATUREATTRIBUTE_DISALLOWADVERTISE)      ret |= msidbFeatureAttributesDisallowAdvertise;
1054     if (attrs & INSTALLFEATUREATTRIBUTE_NOUNSUPPORTEDADVERTISE) ret |= msidbFeatureAttributesNoUnsupportedAdvertise;
1055     return ret;
1056 }
1057
1058 /***********************************************************************
1059 * MsiSetFeatureAttributesW   (MSI.@)
1060 */
1061 UINT WINAPI MsiSetFeatureAttributesW( MSIHANDLE handle, LPCWSTR name, DWORD attrs )
1062 {
1063     MSIPACKAGE *package;
1064     MSIFEATURE *feature;
1065     WCHAR *costing;
1066
1067     TRACE("%u, %s, 0x%08x\n", handle, debugstr_w(name), attrs);
1068
1069     if (!name || !name[0]) return ERROR_UNKNOWN_FEATURE;
1070
1071     if (!(package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE )))
1072         return ERROR_INVALID_HANDLE;
1073
1074     costing = msi_dup_property( package->db, szCostingComplete );
1075     if (!costing || !strcmpW( costing, szOne ))
1076     {
1077         msi_free( costing );
1078         msiobj_release( &package->hdr );
1079         return ERROR_FUNCTION_FAILED;
1080     }
1081     msi_free( costing );
1082     if (!(feature = msi_get_loaded_feature( package, name )))
1083     {
1084         msiobj_release( &package->hdr );
1085         return ERROR_UNKNOWN_FEATURE;
1086     }
1087     feature->Attributes = unmap_feature_attributes( attrs );
1088     msiobj_release( &package->hdr );
1089     return ERROR_SUCCESS;
1090 }
1091
1092 /***********************************************************************
1093 * MsiGetFeatureStateA   (MSI.@)
1094 */
1095 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
1096                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
1097 {
1098     LPWSTR szwFeature = NULL;
1099     UINT rc;
1100     
1101     if (szFeature && !(szwFeature = strdupAtoW(szFeature))) return ERROR_OUTOFMEMORY;
1102
1103     rc = MsiGetFeatureStateW(hInstall, szwFeature, piInstalled, piAction);
1104     msi_free( szwFeature);
1105     return rc;
1106 }
1107
1108 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPCWSTR szFeature,
1109                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
1110 {
1111     MSIFEATURE *feature;
1112
1113     feature = msi_get_loaded_feature(package,szFeature);
1114     if (!feature)
1115         return ERROR_UNKNOWN_FEATURE;
1116
1117     if (piInstalled)
1118         *piInstalled = feature->Installed;
1119
1120     if (piAction)
1121         *piAction = feature->ActionRequest;
1122
1123     TRACE("returning %i %i\n", feature->Installed, feature->ActionRequest);
1124
1125     return ERROR_SUCCESS;
1126 }
1127
1128 /***********************************************************************
1129 * MsiGetFeatureStateW   (MSI.@)
1130 */
1131 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
1132                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
1133 {
1134     MSIPACKAGE* package;
1135     UINT ret;
1136
1137     TRACE("%d %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled, piAction);
1138
1139     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1140     if (!package)
1141     {
1142         HRESULT hr;
1143         BSTR feature;
1144         IWineMsiRemotePackage *remote_package;
1145
1146         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1147         if (!remote_package)
1148             return ERROR_INVALID_HANDLE;
1149
1150         feature = SysAllocString(szFeature);
1151         if (!feature)
1152         {
1153             IWineMsiRemotePackage_Release(remote_package);
1154             return ERROR_OUTOFMEMORY;
1155         }
1156
1157         hr = IWineMsiRemotePackage_GetFeatureState(remote_package, feature,
1158                                                    piInstalled, piAction);
1159
1160         SysFreeString(feature);
1161         IWineMsiRemotePackage_Release(remote_package);
1162
1163         if (FAILED(hr))
1164         {
1165             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1166                 return HRESULT_CODE(hr);
1167
1168             return ERROR_FUNCTION_FAILED;
1169         }
1170
1171         return ERROR_SUCCESS;
1172     }
1173
1174     ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
1175     msiobj_release( &package->hdr );
1176     return ret;
1177 }
1178
1179 /***********************************************************************
1180 * MsiGetFeatureCostA   (MSI.@)
1181 */
1182 UINT WINAPI MsiGetFeatureCostA(MSIHANDLE hInstall, LPCSTR szFeature,
1183                   MSICOSTTREE iCostTree, INSTALLSTATE iState, LPINT piCost)
1184 {
1185     LPWSTR szwFeature = NULL;
1186     UINT rc;
1187
1188     szwFeature = strdupAtoW(szFeature);
1189
1190     rc = MsiGetFeatureCostW(hInstall, szwFeature, iCostTree, iState, piCost);
1191
1192     msi_free(szwFeature);
1193
1194     return rc;
1195 }
1196
1197 static INT feature_cost( MSIFEATURE *feature )
1198 {
1199     INT cost = 0;
1200     MSICOMPONENT *comp;
1201
1202     LIST_FOR_EACH_ENTRY( comp, &feature->Components, MSICOMPONENT, entry )
1203     {
1204         cost += comp->Cost;
1205     }
1206     return cost;
1207 }
1208
1209 UINT MSI_GetFeatureCost( MSIPACKAGE *package, MSIFEATURE *feature, MSICOSTTREE tree,
1210                          INSTALLSTATE state, LPINT cost )
1211 {
1212     TRACE("%s, %u, %d, %p\n", debugstr_w(feature->Feature), tree, state, cost);
1213
1214     *cost = 0;
1215     switch (tree)
1216     {
1217     case MSICOSTTREE_CHILDREN:
1218     {
1219         MSIFEATURE *child;
1220
1221         LIST_FOR_EACH_ENTRY( child, &feature->Children, MSIFEATURE, entry )
1222         {
1223             if (child->ActionRequest == state)
1224                 *cost += feature_cost( child );
1225         }
1226         break;
1227     }
1228     case MSICOSTTREE_PARENTS:
1229     {
1230         const WCHAR *feature_parent = feature->Feature_Parent;
1231         for (;;)
1232         {
1233             MSIFEATURE *parent = msi_get_loaded_feature( package, feature_parent );
1234             if (!parent)
1235                 break;
1236
1237             if (parent->ActionRequest == state)
1238                 *cost += feature_cost( parent );
1239
1240             feature_parent = parent->Feature_Parent;
1241         }
1242         break;
1243     }
1244     case MSICOSTTREE_SELFONLY:
1245         if (feature->ActionRequest == state)
1246             *cost = feature_cost( feature );
1247         break;
1248
1249     default:
1250         WARN("unhandled cost tree %u\n", tree);
1251         break;
1252     }
1253
1254     *cost /= 512;
1255     return ERROR_SUCCESS;
1256 }
1257
1258 /***********************************************************************
1259 * MsiGetFeatureCostW   (MSI.@)
1260 */
1261 UINT WINAPI MsiGetFeatureCostW(MSIHANDLE hInstall, LPCWSTR szFeature,
1262                   MSICOSTTREE iCostTree, INSTALLSTATE iState, LPINT piCost)
1263 {
1264     MSIPACKAGE *package;
1265     MSIFEATURE *feature;
1266     UINT ret;
1267
1268     TRACE("(%d %s %i %i %p)\n", hInstall, debugstr_w(szFeature),
1269           iCostTree, iState, piCost);
1270
1271     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1272     if (!package)
1273     {
1274         HRESULT hr;
1275         BSTR feature;
1276         IWineMsiRemotePackage *remote_package;
1277
1278         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1279         if (!remote_package)
1280             return ERROR_INVALID_HANDLE;
1281
1282         feature = SysAllocString(szFeature);
1283         if (!feature)
1284         {
1285             IWineMsiRemotePackage_Release(remote_package);
1286             return ERROR_OUTOFMEMORY;
1287         }
1288
1289         hr = IWineMsiRemotePackage_GetFeatureCost(remote_package, feature,
1290                                                   iCostTree, iState, piCost);
1291
1292         SysFreeString(feature);
1293         IWineMsiRemotePackage_Release(remote_package);
1294
1295         if (FAILED(hr))
1296         {
1297             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1298                 return HRESULT_CODE(hr);
1299
1300             return ERROR_FUNCTION_FAILED;
1301         }
1302
1303         return ERROR_SUCCESS;
1304     }
1305
1306     feature = msi_get_loaded_feature(package, szFeature);
1307
1308     if (feature)
1309         ret = MSI_GetFeatureCost(package, feature, iCostTree, iState, piCost);
1310     else
1311         ret = ERROR_UNKNOWN_FEATURE;
1312
1313     msiobj_release( &package->hdr );
1314     return ret;
1315 }
1316
1317 /***********************************************************************
1318 * MsiGetFeatureInfoA   (MSI.@)
1319 */
1320 UINT WINAPI MsiGetFeatureInfoA( MSIHANDLE handle, LPCSTR feature, LPDWORD attrs,
1321                                 LPSTR title, LPDWORD title_len, LPSTR help, LPDWORD help_len )
1322 {
1323     UINT r;
1324     WCHAR *titleW = NULL, *helpW = NULL, *featureW = NULL;
1325
1326     TRACE("%u, %s, %p, %p, %p, %p, %p\n", handle, debugstr_a(feature), attrs, title,
1327           title_len, help, help_len);
1328
1329     if (feature && !(featureW = strdupAtoW( feature ))) return ERROR_OUTOFMEMORY;
1330
1331     if (title && title_len && !(titleW = msi_alloc( *title_len * sizeof(WCHAR) )))
1332     {
1333         msi_free( featureW );
1334         return ERROR_OUTOFMEMORY;
1335     }
1336     if (help && help_len && !(helpW = msi_alloc( *help_len * sizeof(WCHAR) )))
1337     {
1338         msi_free( featureW );
1339         msi_free( titleW );
1340         return ERROR_OUTOFMEMORY;
1341     }
1342     r = MsiGetFeatureInfoW( handle, featureW, attrs, titleW, title_len, helpW, help_len );
1343     if (r == ERROR_SUCCESS)
1344     {
1345         if (titleW) WideCharToMultiByte( CP_ACP, 0, titleW, -1, title, *title_len + 1, NULL, NULL );
1346         if (helpW) WideCharToMultiByte( CP_ACP, 0, helpW, -1, help, *help_len + 1, NULL, NULL );
1347     }
1348     msi_free( titleW );
1349     msi_free( helpW );
1350     msi_free( featureW );
1351     return r;
1352 }
1353
1354 static DWORD map_feature_attributes( DWORD attrs )
1355 {
1356     DWORD ret = 0;
1357
1358     if (attrs == msidbFeatureAttributesFavorLocal)            ret |= INSTALLFEATUREATTRIBUTE_FAVORLOCAL;
1359     if (attrs & msidbFeatureAttributesFavorSource)            ret |= INSTALLFEATUREATTRIBUTE_FAVORSOURCE;
1360     if (attrs & msidbFeatureAttributesFollowParent)           ret |= INSTALLFEATUREATTRIBUTE_FOLLOWPARENT;
1361     if (attrs & msidbFeatureAttributesFavorAdvertise)         ret |= INSTALLFEATUREATTRIBUTE_FAVORADVERTISE;
1362     if (attrs & msidbFeatureAttributesDisallowAdvertise)      ret |= INSTALLFEATUREATTRIBUTE_DISALLOWADVERTISE;
1363     if (attrs & msidbFeatureAttributesNoUnsupportedAdvertise) ret |= INSTALLFEATUREATTRIBUTE_NOUNSUPPORTEDADVERTISE;
1364     return ret;
1365 }
1366
1367 static UINT MSI_GetFeatureInfo( MSIPACKAGE *package, LPCWSTR name, LPDWORD attrs,
1368                                 LPWSTR title, LPDWORD title_len, LPWSTR help, LPDWORD help_len )
1369 {
1370     UINT r = ERROR_SUCCESS;
1371     MSIFEATURE *feature = msi_get_loaded_feature( package, name );
1372     int len;
1373
1374     if (!feature) return ERROR_UNKNOWN_FEATURE;
1375     if (attrs) *attrs = map_feature_attributes( feature->Attributes );
1376     if (title_len)
1377     {
1378         if (feature->Title) len = strlenW( feature->Title );
1379         else len = 0;
1380         if (*title_len <= len)
1381         {
1382             *title_len = len;
1383             if (title) r = ERROR_MORE_DATA;
1384         }
1385         else if (title)
1386         {
1387             if (feature->Title) strcpyW( title, feature->Title );
1388             else *title = 0;
1389             *title_len = len;
1390         }
1391     }
1392     if (help_len)
1393     {
1394         if (feature->Description) len = strlenW( feature->Description );
1395         else len = 0;
1396         if (*help_len <= len)
1397         {
1398             *help_len = len;
1399             if (help) r = ERROR_MORE_DATA;
1400         }
1401         else if (help)
1402         {
1403             if (feature->Description) strcpyW( help, feature->Description );
1404             else *help = 0;
1405             *help_len = len;
1406         }
1407     }
1408     return r;
1409 }
1410
1411 /***********************************************************************
1412 * MsiGetFeatureInfoW   (MSI.@)
1413 */
1414 UINT WINAPI MsiGetFeatureInfoW( MSIHANDLE handle, LPCWSTR feature, LPDWORD attrs,
1415                                 LPWSTR title, LPDWORD title_len, LPWSTR help, LPDWORD help_len )
1416 {
1417     UINT r;
1418     MSIPACKAGE *package;
1419
1420     TRACE("%u, %s, %p, %p, %p, %p, %p\n", handle, debugstr_w(feature), attrs, title,
1421           title_len, help, help_len);
1422
1423     if (!feature) return ERROR_INVALID_PARAMETER;
1424
1425     if (!(package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE )))
1426         return ERROR_INVALID_HANDLE;
1427
1428     /* features may not have been loaded yet */
1429     msi_load_all_components( package );
1430     msi_load_all_features( package );
1431
1432     r = MSI_GetFeatureInfo( package, feature, attrs, title, title_len, help, help_len );
1433     msiobj_release( &package->hdr );
1434     return r;
1435 }
1436
1437 /***********************************************************************
1438  * MsiSetComponentStateA (MSI.@)
1439  */
1440 UINT WINAPI MsiSetComponentStateA(MSIHANDLE hInstall, LPCSTR szComponent,
1441                                   INSTALLSTATE iState)
1442 {
1443     UINT rc;
1444     LPWSTR szwComponent = strdupAtoW(szComponent);
1445
1446     rc = MsiSetComponentStateW(hInstall, szwComponent, iState);
1447
1448     msi_free(szwComponent);
1449
1450     return rc;
1451 }
1452
1453 /***********************************************************************
1454  * MsiGetComponentStateA (MSI.@)
1455  */
1456 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPCSTR szComponent,
1457                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
1458 {
1459     LPWSTR szwComponent= NULL;
1460     UINT rc;
1461     
1462     szwComponent= strdupAtoW(szComponent);
1463
1464     rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
1465
1466     msi_free( szwComponent);
1467
1468     return rc;
1469 }
1470
1471 static UINT MSI_SetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
1472                                    INSTALLSTATE iState)
1473 {
1474     MSICOMPONENT *comp;
1475
1476     TRACE("%p %s %d\n", package, debugstr_w(szComponent), iState);
1477
1478     comp = msi_get_loaded_component(package, szComponent);
1479     if (!comp)
1480         return ERROR_UNKNOWN_COMPONENT;
1481
1482     if (comp->Enabled)
1483         comp->Action = iState;
1484
1485     return ERROR_SUCCESS;
1486 }
1487
1488 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
1489                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
1490 {
1491     MSICOMPONENT *comp;
1492
1493     TRACE("%p %s %p %p\n", package, debugstr_w(szComponent),
1494            piInstalled, piAction);
1495
1496     comp = msi_get_loaded_component(package,szComponent);
1497     if (!comp)
1498         return ERROR_UNKNOWN_COMPONENT;
1499
1500     if (piInstalled)
1501     {
1502         if (comp->Enabled)
1503             *piInstalled = comp->Installed;
1504         else
1505             *piInstalled = INSTALLSTATE_UNKNOWN;
1506     }
1507
1508     if (piAction)
1509     {
1510         if (comp->Enabled)
1511             *piAction = comp->Action;
1512         else
1513             *piAction = INSTALLSTATE_UNKNOWN;
1514     }
1515
1516     TRACE("states (%i, %i)\n", comp->Installed, comp->Action );
1517     return ERROR_SUCCESS;
1518 }
1519
1520 /***********************************************************************
1521  * MsiSetComponentStateW (MSI.@)
1522  */
1523 UINT WINAPI MsiSetComponentStateW(MSIHANDLE hInstall, LPCWSTR szComponent,
1524                                   INSTALLSTATE iState)
1525 {
1526     MSIPACKAGE* package;
1527     UINT ret;
1528
1529     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1530     if (!package)
1531     {
1532         HRESULT hr;
1533         BSTR component;
1534         IWineMsiRemotePackage *remote_package;
1535
1536         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1537         if (!remote_package)
1538             return ERROR_INVALID_HANDLE;
1539
1540         component = SysAllocString(szComponent);
1541         if (!component)
1542         {
1543             IWineMsiRemotePackage_Release(remote_package);
1544             return ERROR_OUTOFMEMORY;
1545         }
1546
1547         hr = IWineMsiRemotePackage_SetComponentState(remote_package, component, iState);
1548
1549         SysFreeString(component);
1550         IWineMsiRemotePackage_Release(remote_package);
1551
1552         if (FAILED(hr))
1553         {
1554             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1555                 return HRESULT_CODE(hr);
1556
1557             return ERROR_FUNCTION_FAILED;
1558         }
1559
1560         return ERROR_SUCCESS;
1561     }
1562
1563     ret = MSI_SetComponentStateW(package, szComponent, iState);
1564     msiobj_release(&package->hdr);
1565     return ret;
1566 }
1567
1568 /***********************************************************************
1569  * MsiGetComponentStateW (MSI.@)
1570  */
1571 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPCWSTR szComponent,
1572                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
1573 {
1574     MSIPACKAGE* package;
1575     UINT ret;
1576
1577     TRACE("%d %s %p %p\n", hInstall, debugstr_w(szComponent),
1578            piInstalled, piAction);
1579
1580     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1581     if (!package)
1582     {
1583         HRESULT hr;
1584         BSTR component;
1585         IWineMsiRemotePackage *remote_package;
1586
1587         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1588         if (!remote_package)
1589             return ERROR_INVALID_HANDLE;
1590
1591         component = SysAllocString(szComponent);
1592         if (!component)
1593         {
1594             IWineMsiRemotePackage_Release(remote_package);
1595             return ERROR_OUTOFMEMORY;
1596         }
1597
1598         hr = IWineMsiRemotePackage_GetComponentState(remote_package, component,
1599                                                      piInstalled, piAction);
1600
1601         SysFreeString(component);
1602         IWineMsiRemotePackage_Release(remote_package);
1603
1604         if (FAILED(hr))
1605         {
1606             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1607                 return HRESULT_CODE(hr);
1608
1609             return ERROR_FUNCTION_FAILED;
1610         }
1611
1612         return ERROR_SUCCESS;
1613     }
1614
1615     ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
1616     msiobj_release( &package->hdr );
1617     return ret;
1618 }
1619
1620 /***********************************************************************
1621  * MsiGetLanguage (MSI.@)
1622  */
1623 LANGID WINAPI MsiGetLanguage(MSIHANDLE hInstall)
1624 {
1625     MSIPACKAGE* package;
1626     LANGID langid;
1627
1628     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1629     if (!package)
1630     {
1631         HRESULT hr;
1632         LANGID lang;
1633         IWineMsiRemotePackage *remote_package;
1634
1635         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1636         if (!remote_package)
1637             return ERROR_INVALID_HANDLE;
1638
1639         hr = IWineMsiRemotePackage_GetLanguage(remote_package, &lang);
1640
1641         if (SUCCEEDED(hr))
1642             return lang;
1643
1644         return 0;
1645     }
1646
1647     langid = msi_get_property_int( package->db, szProductLanguage, 0 );
1648     msiobj_release( &package->hdr );
1649     return langid;
1650 }
1651
1652 UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel )
1653 {
1654     static const WCHAR fmt[] = { '%','d',0 };
1655     WCHAR level[6];
1656     UINT r;
1657
1658     TRACE("%p %i\n", package, iInstallLevel);
1659
1660     if (iInstallLevel > 32767)
1661         return ERROR_INVALID_PARAMETER;
1662
1663     if (iInstallLevel < 1)
1664         return MSI_SetFeatureStates( package );
1665
1666     sprintfW( level, fmt, iInstallLevel );
1667     r = msi_set_property( package->db, szInstallLevel, level );
1668     if ( r == ERROR_SUCCESS )
1669         r = MSI_SetFeatureStates( package );
1670
1671     return r;
1672 }
1673
1674 /***********************************************************************
1675  * MsiSetInstallLevel (MSI.@)
1676  */
1677 UINT WINAPI MsiSetInstallLevel(MSIHANDLE hInstall, int iInstallLevel)
1678 {
1679     MSIPACKAGE* package;
1680     UINT r;
1681
1682     TRACE("%d %i\n", hInstall, iInstallLevel);
1683
1684     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1685     if (!package)
1686     {
1687         HRESULT hr;
1688         IWineMsiRemotePackage *remote_package;
1689
1690         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1691         if (!remote_package)
1692             return ERROR_INVALID_HANDLE;
1693
1694         hr = IWineMsiRemotePackage_SetInstallLevel(remote_package, iInstallLevel);
1695
1696         IWineMsiRemotePackage_Release(remote_package);
1697
1698         if (FAILED(hr))
1699         {
1700             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1701                 return HRESULT_CODE(hr);
1702
1703             return ERROR_FUNCTION_FAILED;
1704         }
1705
1706         return ERROR_SUCCESS;
1707     }
1708
1709     r = MSI_SetInstallLevel( package, iInstallLevel );
1710
1711     msiobj_release( &package->hdr );
1712
1713     return r;
1714 }
1715
1716 /***********************************************************************
1717  * MsiGetFeatureValidStatesW (MSI.@)
1718  */
1719 UINT WINAPI MsiGetFeatureValidStatesW(MSIHANDLE hInstall, LPCWSTR szFeature,
1720                   LPDWORD pInstallState)
1721 {
1722     if(pInstallState) *pInstallState = 1<<INSTALLSTATE_LOCAL;
1723     FIXME("%d %s %p stub returning %d\n",
1724         hInstall, debugstr_w(szFeature), pInstallState, pInstallState ? *pInstallState : 0);
1725
1726     return ERROR_SUCCESS;
1727 }
1728
1729 /***********************************************************************
1730  * MsiGetFeatureValidStatesA (MSI.@)
1731  */
1732 UINT WINAPI MsiGetFeatureValidStatesA(MSIHANDLE hInstall, LPCSTR szFeature,
1733                   LPDWORD pInstallState)
1734 {
1735     UINT ret;
1736     LPWSTR szwFeature = strdupAtoW(szFeature);
1737
1738     ret = MsiGetFeatureValidStatesW(hInstall, szwFeature, pInstallState);
1739
1740     msi_free(szwFeature);
1741
1742     return ret;
1743 }