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