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