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