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