msi: Make sure target paths are normalized.
[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;
765         break;
766
767     case MSIRUNMODE_LOGENABLED:
768         r = (package->log_file != INVALID_HANDLE_VALUE);
769         break;
770
771     default:
772         FIXME("unimplemented run mode: %d\n", iRunMode);
773         r = TRUE;
774     }
775
776     msiobj_release( &package->hdr );
777     return r;
778 }
779
780 /***********************************************************************
781  *           MsiSetMode    (MSI.@)
782  */
783 UINT WINAPI MsiSetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode, BOOL fState)
784 {
785     MSIPACKAGE *package;
786     UINT r;
787
788     TRACE("%d %d %d\n", hInstall, iRunMode, fState);
789
790     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
791     if (!package)
792     {
793         HRESULT hr;
794         IWineMsiRemotePackage *remote_package;
795
796         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
797         if (!remote_package)
798             return FALSE;
799
800         hr = IWineMsiRemotePackage_SetMode( remote_package, iRunMode, fState );
801         IWineMsiRemotePackage_Release( remote_package );
802
803         if (FAILED(hr))
804         {
805             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
806                 return HRESULT_CODE(hr);
807
808             return ERROR_FUNCTION_FAILED;
809         }
810
811         return ERROR_SUCCESS;
812     }
813
814     switch (iRunMode)
815     {
816     case MSIRUNMODE_REBOOTATEND:
817         package->need_reboot = 1;
818         r = ERROR_SUCCESS;
819         break;
820
821     case MSIRUNMODE_REBOOTNOW:
822         FIXME("unimplemented run mode: %d\n", iRunMode);
823         r = ERROR_FUNCTION_FAILED;
824         break;
825
826     default:
827         r = ERROR_ACCESS_DENIED;
828     }
829
830     msiobj_release( &package->hdr );
831     return r;
832 }
833
834 /***********************************************************************
835  * MsiSetFeatureStateA (MSI.@)
836  *
837  * According to the docs, when this is called it immediately recalculates
838  * all the component states as well
839  */
840 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
841                                 INSTALLSTATE iState)
842 {
843     LPWSTR szwFeature = NULL;
844     UINT rc;
845
846     szwFeature = strdupAtoW(szFeature);
847
848     if (!szwFeature)
849         return ERROR_FUNCTION_FAILED;
850    
851     rc = MsiSetFeatureStateW(hInstall,szwFeature, iState); 
852
853     msi_free(szwFeature);
854
855     return rc;
856 }
857
858 /* update component state based on a feature change */
859 void ACTION_UpdateComponentStates( MSIPACKAGE *package, MSIFEATURE *feature )
860 {
861     INSTALLSTATE newstate;
862     ComponentList *cl;
863
864     newstate = feature->ActionRequest;
865     if (newstate == INSTALLSTATE_ABSENT) newstate = INSTALLSTATE_UNKNOWN;
866
867     LIST_FOR_EACH_ENTRY(cl, &feature->Components, ComponentList, entry)
868     {
869         MSICOMPONENT *component = cl->component;
870
871         if (!component->Enabled) continue;
872
873         TRACE("Modifying (%d): Component %s (Installed %d, Action %d, Request %d)\n",
874             newstate, debugstr_w(component->Component), component->Installed,
875             component->Action, component->ActionRequest);
876
877         if (newstate == INSTALLSTATE_LOCAL)
878         {
879             component->Action = INSTALLSTATE_LOCAL;
880             component->ActionRequest = INSTALLSTATE_LOCAL;
881         }
882         else
883         {
884             ComponentList *clist;
885             MSIFEATURE *f;
886
887             component->hasLocalFeature = FALSE;
888
889             component->Action = newstate;
890             component->ActionRequest = newstate;
891             /* if any other feature wants it local we need to set it local */
892             LIST_FOR_EACH_ENTRY(f, &package->features, MSIFEATURE, entry)
893             {
894                 if ( f->ActionRequest != INSTALLSTATE_LOCAL &&
895                      f->ActionRequest != INSTALLSTATE_SOURCE )
896                 {
897                     continue;
898                 }
899                 LIST_FOR_EACH_ENTRY(clist, &f->Components, ComponentList, entry)
900                 {
901                     if (clist->component == component &&
902                         (f->ActionRequest == INSTALLSTATE_LOCAL ||
903                          f->ActionRequest == INSTALLSTATE_SOURCE))
904                     {
905                         TRACE("Saved by %s\n", debugstr_w(f->Feature));
906                         component->hasLocalFeature = TRUE;
907
908                         if (component->Attributes & msidbComponentAttributesOptional)
909                         {
910                             if (f->Attributes & msidbFeatureAttributesFavorSource)
911                             {
912                                 component->Action = INSTALLSTATE_SOURCE;
913                                 component->ActionRequest = INSTALLSTATE_SOURCE;
914                             }
915                             else
916                             {
917                                 component->Action = INSTALLSTATE_LOCAL;
918                                 component->ActionRequest = INSTALLSTATE_LOCAL;
919                             }
920                         }
921                         else if (component->Attributes & msidbComponentAttributesSourceOnly)
922                         {
923                             component->Action = INSTALLSTATE_SOURCE;
924                             component->ActionRequest = INSTALLSTATE_SOURCE;
925                         }
926                         else
927                         {
928                             component->Action = INSTALLSTATE_LOCAL;
929                             component->ActionRequest = INSTALLSTATE_LOCAL;
930                         }
931                     }
932                 }
933             }
934         }
935         TRACE("Result (%d): Component %s (Installed %d, Action %d, Request %d)\n",
936             newstate, debugstr_w(component->Component), component->Installed,
937             component->Action, component->ActionRequest);
938     }
939 }
940
941 UINT MSI_SetFeatureStateW( MSIPACKAGE *package, LPCWSTR szFeature, INSTALLSTATE iState )
942 {
943     UINT rc = ERROR_SUCCESS;
944     MSIFEATURE *feature, *child;
945
946     TRACE("%s %i\n", debugstr_w(szFeature), iState);
947
948     feature = msi_get_loaded_feature( package, szFeature );
949     if (!feature)
950         return ERROR_UNKNOWN_FEATURE;
951
952     if (iState == INSTALLSTATE_ADVERTISED && 
953         feature->Attributes & msidbFeatureAttributesDisallowAdvertise)
954         return ERROR_FUNCTION_FAILED;
955
956     feature->ActionRequest = iState;
957
958     ACTION_UpdateComponentStates( package, feature );
959
960     /* update all the features that are children of this feature */
961     LIST_FOR_EACH_ENTRY( child, &package->features, MSIFEATURE, entry )
962     {
963         if (child->Feature_Parent && !strcmpW( szFeature, child->Feature_Parent ))
964             MSI_SetFeatureStateW(package, child->Feature, iState);
965     }
966     
967     return rc;
968 }
969
970 /***********************************************************************
971  * MsiSetFeatureStateW (MSI.@)
972  */
973 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
974                                 INSTALLSTATE iState)
975 {
976     MSIPACKAGE* package;
977     UINT rc = ERROR_SUCCESS;
978
979     TRACE("%s %i\n",debugstr_w(szFeature), iState);
980
981     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
982     if (!package)
983     {
984         HRESULT hr;
985         BSTR feature;
986         IWineMsiRemotePackage *remote_package;
987
988         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
989         if (!remote_package)
990             return ERROR_INVALID_HANDLE;
991
992         feature = SysAllocString(szFeature);
993         if (!feature)
994         {
995             IWineMsiRemotePackage_Release(remote_package);
996             return ERROR_OUTOFMEMORY;
997         }
998
999         hr = IWineMsiRemotePackage_SetFeatureState(remote_package, feature, iState);
1000
1001         SysFreeString(feature);
1002         IWineMsiRemotePackage_Release(remote_package);
1003
1004         if (FAILED(hr))
1005         {
1006             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1007                 return HRESULT_CODE(hr);
1008
1009             return ERROR_FUNCTION_FAILED;
1010         }
1011
1012         return ERROR_SUCCESS;
1013     }
1014
1015     rc = MSI_SetFeatureStateW(package,szFeature,iState);
1016
1017     msiobj_release( &package->hdr );
1018     return rc;
1019 }
1020
1021 /***********************************************************************
1022 * MsiSetFeatureAttributesA   (MSI.@)
1023 */
1024 UINT WINAPI MsiSetFeatureAttributesA( MSIHANDLE handle, LPCSTR feature, DWORD attrs )
1025 {
1026     UINT r;
1027     WCHAR *featureW = NULL;
1028
1029     TRACE("%u, %s, 0x%08x\n", handle, debugstr_a(feature), attrs);
1030
1031     if (feature && !(featureW = strdupAtoW( feature ))) return ERROR_OUTOFMEMORY;
1032
1033     r = MsiSetFeatureAttributesW( handle, featureW, attrs );
1034     msi_free( featureW );
1035     return r;
1036 }
1037
1038 static DWORD unmap_feature_attributes( DWORD attrs )
1039 {
1040     DWORD ret = 0;
1041
1042     if (attrs & INSTALLFEATUREATTRIBUTE_FAVORLOCAL)             ret = msidbFeatureAttributesFavorLocal;
1043     if (attrs & INSTALLFEATUREATTRIBUTE_FAVORSOURCE)            ret |= msidbFeatureAttributesFavorSource;
1044     if (attrs & INSTALLFEATUREATTRIBUTE_FOLLOWPARENT)           ret |= msidbFeatureAttributesFollowParent;
1045     if (attrs & INSTALLFEATUREATTRIBUTE_FAVORADVERTISE)         ret |= msidbFeatureAttributesFavorAdvertise;
1046     if (attrs & INSTALLFEATUREATTRIBUTE_DISALLOWADVERTISE)      ret |= msidbFeatureAttributesDisallowAdvertise;
1047     if (attrs & INSTALLFEATUREATTRIBUTE_NOUNSUPPORTEDADVERTISE) ret |= msidbFeatureAttributesNoUnsupportedAdvertise;
1048     return ret;
1049 }
1050
1051 /***********************************************************************
1052 * MsiSetFeatureAttributesW   (MSI.@)
1053 */
1054 UINT WINAPI MsiSetFeatureAttributesW( MSIHANDLE handle, LPCWSTR name, DWORD attrs )
1055 {
1056     MSIPACKAGE *package;
1057     MSIFEATURE *feature;
1058     WCHAR *costing;
1059
1060     TRACE("%u, %s, 0x%08x\n", handle, debugstr_w(name), attrs);
1061
1062     if (!name || !name[0]) return ERROR_UNKNOWN_FEATURE;
1063
1064     if (!(package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE )))
1065         return ERROR_INVALID_HANDLE;
1066
1067     costing = msi_dup_property( package->db, szCostingComplete );
1068     if (!costing || !strcmpW( costing, szOne ))
1069     {
1070         msi_free( costing );
1071         msiobj_release( &package->hdr );
1072         return ERROR_FUNCTION_FAILED;
1073     }
1074     msi_free( costing );
1075     if (!(feature = msi_get_loaded_feature( package, name )))
1076     {
1077         msiobj_release( &package->hdr );
1078         return ERROR_UNKNOWN_FEATURE;
1079     }
1080     feature->Attributes = unmap_feature_attributes( attrs );
1081     msiobj_release( &package->hdr );
1082     return ERROR_SUCCESS;
1083 }
1084
1085 /***********************************************************************
1086 * MsiGetFeatureStateA   (MSI.@)
1087 */
1088 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
1089                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
1090 {
1091     LPWSTR szwFeature = NULL;
1092     UINT rc;
1093     
1094     if (szFeature && !(szwFeature = strdupAtoW(szFeature))) return ERROR_OUTOFMEMORY;
1095
1096     rc = MsiGetFeatureStateW(hInstall, szwFeature, piInstalled, piAction);
1097     msi_free( szwFeature);
1098     return rc;
1099 }
1100
1101 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPCWSTR szFeature,
1102                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
1103 {
1104     MSIFEATURE *feature;
1105
1106     feature = msi_get_loaded_feature(package,szFeature);
1107     if (!feature)
1108         return ERROR_UNKNOWN_FEATURE;
1109
1110     if (piInstalled)
1111         *piInstalled = feature->Installed;
1112
1113     if (piAction)
1114         *piAction = feature->ActionRequest;
1115
1116     TRACE("returning %i %i\n", feature->Installed, feature->ActionRequest);
1117
1118     return ERROR_SUCCESS;
1119 }
1120
1121 /***********************************************************************
1122 * MsiGetFeatureStateW   (MSI.@)
1123 */
1124 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
1125                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
1126 {
1127     MSIPACKAGE* package;
1128     UINT ret;
1129
1130     TRACE("%d %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled, piAction);
1131
1132     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1133     if (!package)
1134     {
1135         HRESULT hr;
1136         BSTR feature;
1137         IWineMsiRemotePackage *remote_package;
1138
1139         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1140         if (!remote_package)
1141             return ERROR_INVALID_HANDLE;
1142
1143         feature = SysAllocString(szFeature);
1144         if (!feature)
1145         {
1146             IWineMsiRemotePackage_Release(remote_package);
1147             return ERROR_OUTOFMEMORY;
1148         }
1149
1150         hr = IWineMsiRemotePackage_GetFeatureState(remote_package, feature,
1151                                                    piInstalled, piAction);
1152
1153         SysFreeString(feature);
1154         IWineMsiRemotePackage_Release(remote_package);
1155
1156         if (FAILED(hr))
1157         {
1158             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1159                 return HRESULT_CODE(hr);
1160
1161             return ERROR_FUNCTION_FAILED;
1162         }
1163
1164         return ERROR_SUCCESS;
1165     }
1166
1167     ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
1168     msiobj_release( &package->hdr );
1169     return ret;
1170 }
1171
1172 /***********************************************************************
1173 * MsiGetFeatureCostA   (MSI.@)
1174 */
1175 UINT WINAPI MsiGetFeatureCostA(MSIHANDLE hInstall, LPCSTR szFeature,
1176                   MSICOSTTREE iCostTree, INSTALLSTATE iState, LPINT piCost)
1177 {
1178     LPWSTR szwFeature = NULL;
1179     UINT rc;
1180
1181     szwFeature = strdupAtoW(szFeature);
1182
1183     rc = MsiGetFeatureCostW(hInstall, szwFeature, iCostTree, iState, piCost);
1184
1185     msi_free(szwFeature);
1186
1187     return rc;
1188 }
1189
1190 static INT feature_cost( MSIFEATURE *feature )
1191 {
1192     INT cost = 0;
1193     MSICOMPONENT *comp;
1194
1195     LIST_FOR_EACH_ENTRY( comp, &feature->Components, MSICOMPONENT, entry )
1196     {
1197         cost += comp->Cost;
1198     }
1199     return cost;
1200 }
1201
1202 UINT MSI_GetFeatureCost( MSIPACKAGE *package, MSIFEATURE *feature, MSICOSTTREE tree,
1203                          INSTALLSTATE state, LPINT cost )
1204 {
1205     TRACE("%s, %u, %d, %p\n", debugstr_w(feature->Feature), tree, state, cost);
1206
1207     *cost = 0;
1208     switch (tree)
1209     {
1210     case MSICOSTTREE_CHILDREN:
1211     {
1212         MSIFEATURE *child;
1213
1214         LIST_FOR_EACH_ENTRY( child, &feature->Children, MSIFEATURE, entry )
1215         {
1216             if (child->ActionRequest == state)
1217                 *cost += feature_cost( child );
1218         }
1219         break;
1220     }
1221     case MSICOSTTREE_PARENTS:
1222     {
1223         const WCHAR *feature_parent = feature->Feature_Parent;
1224         for (;;)
1225         {
1226             MSIFEATURE *parent = msi_get_loaded_feature( package, feature_parent );
1227             if (!parent)
1228                 break;
1229
1230             if (parent->ActionRequest == state)
1231                 *cost += feature_cost( parent );
1232
1233             feature_parent = parent->Feature_Parent;
1234         }
1235         break;
1236     }
1237     case MSICOSTTREE_SELFONLY:
1238         if (feature->ActionRequest == state)
1239             *cost = feature_cost( feature );
1240         break;
1241
1242     default:
1243         WARN("unhandled cost tree %u\n", tree);
1244         break;
1245     }
1246
1247     *cost /= 512;
1248     return ERROR_SUCCESS;
1249 }
1250
1251 /***********************************************************************
1252 * MsiGetFeatureCostW   (MSI.@)
1253 */
1254 UINT WINAPI MsiGetFeatureCostW(MSIHANDLE hInstall, LPCWSTR szFeature,
1255                   MSICOSTTREE iCostTree, INSTALLSTATE iState, LPINT piCost)
1256 {
1257     MSIPACKAGE *package;
1258     MSIFEATURE *feature;
1259     UINT ret;
1260
1261     TRACE("(%d %s %i %i %p)\n", hInstall, debugstr_w(szFeature),
1262           iCostTree, iState, piCost);
1263
1264     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1265     if (!package)
1266     {
1267         HRESULT hr;
1268         BSTR feature;
1269         IWineMsiRemotePackage *remote_package;
1270
1271         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1272         if (!remote_package)
1273             return ERROR_INVALID_HANDLE;
1274
1275         feature = SysAllocString(szFeature);
1276         if (!feature)
1277         {
1278             IWineMsiRemotePackage_Release(remote_package);
1279             return ERROR_OUTOFMEMORY;
1280         }
1281
1282         hr = IWineMsiRemotePackage_GetFeatureCost(remote_package, feature,
1283                                                   iCostTree, iState, piCost);
1284
1285         SysFreeString(feature);
1286         IWineMsiRemotePackage_Release(remote_package);
1287
1288         if (FAILED(hr))
1289         {
1290             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1291                 return HRESULT_CODE(hr);
1292
1293             return ERROR_FUNCTION_FAILED;
1294         }
1295
1296         return ERROR_SUCCESS;
1297     }
1298
1299     feature = msi_get_loaded_feature(package, szFeature);
1300
1301     if (feature)
1302         ret = MSI_GetFeatureCost(package, feature, iCostTree, iState, piCost);
1303     else
1304         ret = ERROR_UNKNOWN_FEATURE;
1305
1306     msiobj_release( &package->hdr );
1307     return ret;
1308 }
1309
1310 /***********************************************************************
1311 * MsiGetFeatureInfoA   (MSI.@)
1312 */
1313 UINT WINAPI MsiGetFeatureInfoA( MSIHANDLE handle, LPCSTR feature, LPDWORD attrs,
1314                                 LPSTR title, LPDWORD title_len, LPSTR help, LPDWORD help_len )
1315 {
1316     UINT r;
1317     WCHAR *titleW = NULL, *helpW = NULL, *featureW = NULL;
1318
1319     TRACE("%u, %s, %p, %p, %p, %p, %p\n", handle, debugstr_a(feature), attrs, title,
1320           title_len, help, help_len);
1321
1322     if (feature && !(featureW = strdupAtoW( feature ))) return ERROR_OUTOFMEMORY;
1323
1324     if (title && title_len && !(titleW = msi_alloc( *title_len * sizeof(WCHAR) )))
1325     {
1326         msi_free( featureW );
1327         return ERROR_OUTOFMEMORY;
1328     }
1329     if (help && help_len && !(helpW = msi_alloc( *help_len * sizeof(WCHAR) )))
1330     {
1331         msi_free( featureW );
1332         msi_free( titleW );
1333         return ERROR_OUTOFMEMORY;
1334     }
1335     r = MsiGetFeatureInfoW( handle, featureW, attrs, titleW, title_len, helpW, help_len );
1336     if (r == ERROR_SUCCESS)
1337     {
1338         if (titleW) WideCharToMultiByte( CP_ACP, 0, titleW, -1, title, *title_len + 1, NULL, NULL );
1339         if (helpW) WideCharToMultiByte( CP_ACP, 0, helpW, -1, help, *help_len + 1, NULL, NULL );
1340     }
1341     msi_free( titleW );
1342     msi_free( helpW );
1343     msi_free( featureW );
1344     return r;
1345 }
1346
1347 static DWORD map_feature_attributes( DWORD attrs )
1348 {
1349     DWORD ret = 0;
1350
1351     if (attrs == msidbFeatureAttributesFavorLocal)            ret |= INSTALLFEATUREATTRIBUTE_FAVORLOCAL;
1352     if (attrs & msidbFeatureAttributesFavorSource)            ret |= INSTALLFEATUREATTRIBUTE_FAVORSOURCE;
1353     if (attrs & msidbFeatureAttributesFollowParent)           ret |= INSTALLFEATUREATTRIBUTE_FOLLOWPARENT;
1354     if (attrs & msidbFeatureAttributesFavorAdvertise)         ret |= INSTALLFEATUREATTRIBUTE_FAVORADVERTISE;
1355     if (attrs & msidbFeatureAttributesDisallowAdvertise)      ret |= INSTALLFEATUREATTRIBUTE_DISALLOWADVERTISE;
1356     if (attrs & msidbFeatureAttributesNoUnsupportedAdvertise) ret |= INSTALLFEATUREATTRIBUTE_NOUNSUPPORTEDADVERTISE;
1357     return ret;
1358 }
1359
1360 static UINT MSI_GetFeatureInfo( MSIPACKAGE *package, LPCWSTR name, LPDWORD attrs,
1361                                 LPWSTR title, LPDWORD title_len, LPWSTR help, LPDWORD help_len )
1362 {
1363     UINT r = ERROR_SUCCESS;
1364     MSIFEATURE *feature = msi_get_loaded_feature( package, name );
1365     int len;
1366
1367     if (!feature) return ERROR_UNKNOWN_FEATURE;
1368     if (attrs) *attrs = map_feature_attributes( feature->Attributes );
1369     if (title_len)
1370     {
1371         if (feature->Title) len = strlenW( feature->Title );
1372         else len = 0;
1373         if (*title_len <= len)
1374         {
1375             *title_len = len;
1376             if (title) r = ERROR_MORE_DATA;
1377         }
1378         else if (title)
1379         {
1380             if (feature->Title) strcpyW( title, feature->Title );
1381             else *title = 0;
1382             *title_len = len;
1383         }
1384     }
1385     if (help_len)
1386     {
1387         if (feature->Description) len = strlenW( feature->Description );
1388         else len = 0;
1389         if (*help_len <= len)
1390         {
1391             *help_len = len;
1392             if (help) r = ERROR_MORE_DATA;
1393         }
1394         else if (help)
1395         {
1396             if (feature->Description) strcpyW( help, feature->Description );
1397             else *help = 0;
1398             *help_len = len;
1399         }
1400     }
1401     return r;
1402 }
1403
1404 /***********************************************************************
1405 * MsiGetFeatureInfoW   (MSI.@)
1406 */
1407 UINT WINAPI MsiGetFeatureInfoW( MSIHANDLE handle, LPCWSTR feature, LPDWORD attrs,
1408                                 LPWSTR title, LPDWORD title_len, LPWSTR help, LPDWORD help_len )
1409 {
1410     UINT r;
1411     MSIPACKAGE *package;
1412
1413     TRACE("%u, %s, %p, %p, %p, %p, %p\n", handle, debugstr_w(feature), attrs, title,
1414           title_len, help, help_len);
1415
1416     if (!feature) return ERROR_INVALID_PARAMETER;
1417
1418     if (!(package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE )))
1419         return ERROR_INVALID_HANDLE;
1420
1421     /* features may not have been loaded yet */
1422     msi_load_all_components( package );
1423     msi_load_all_features( package );
1424
1425     r = MSI_GetFeatureInfo( package, feature, attrs, title, title_len, help, help_len );
1426     msiobj_release( &package->hdr );
1427     return r;
1428 }
1429
1430 /***********************************************************************
1431  * MsiSetComponentStateA (MSI.@)
1432  */
1433 UINT WINAPI MsiSetComponentStateA(MSIHANDLE hInstall, LPCSTR szComponent,
1434                                   INSTALLSTATE iState)
1435 {
1436     UINT rc;
1437     LPWSTR szwComponent = strdupAtoW(szComponent);
1438
1439     rc = MsiSetComponentStateW(hInstall, szwComponent, iState);
1440
1441     msi_free(szwComponent);
1442
1443     return rc;
1444 }
1445
1446 /***********************************************************************
1447  * MsiGetComponentStateA (MSI.@)
1448  */
1449 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPCSTR szComponent,
1450                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
1451 {
1452     LPWSTR szwComponent= NULL;
1453     UINT rc;
1454     
1455     szwComponent= strdupAtoW(szComponent);
1456
1457     rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
1458
1459     msi_free( szwComponent);
1460
1461     return rc;
1462 }
1463
1464 static UINT MSI_SetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
1465                                    INSTALLSTATE iState)
1466 {
1467     MSICOMPONENT *comp;
1468
1469     TRACE("%p %s %d\n", package, debugstr_w(szComponent), iState);
1470
1471     comp = msi_get_loaded_component(package, szComponent);
1472     if (!comp)
1473         return ERROR_UNKNOWN_COMPONENT;
1474
1475     if (comp->Enabled)
1476         comp->Action = iState;
1477
1478     return ERROR_SUCCESS;
1479 }
1480
1481 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
1482                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
1483 {
1484     MSICOMPONENT *comp;
1485
1486     TRACE("%p %s %p %p\n", package, debugstr_w(szComponent),
1487            piInstalled, piAction);
1488
1489     comp = msi_get_loaded_component(package,szComponent);
1490     if (!comp)
1491         return ERROR_UNKNOWN_COMPONENT;
1492
1493     if (piInstalled)
1494     {
1495         if (comp->Enabled)
1496             *piInstalled = comp->Installed;
1497         else
1498             *piInstalled = INSTALLSTATE_UNKNOWN;
1499     }
1500
1501     if (piAction)
1502     {
1503         if (comp->Enabled)
1504             *piAction = comp->Action;
1505         else
1506             *piAction = INSTALLSTATE_UNKNOWN;
1507     }
1508
1509     TRACE("states (%i, %i)\n", comp->Installed, comp->Action );
1510     return ERROR_SUCCESS;
1511 }
1512
1513 /***********************************************************************
1514  * MsiSetComponentStateW (MSI.@)
1515  */
1516 UINT WINAPI MsiSetComponentStateW(MSIHANDLE hInstall, LPCWSTR szComponent,
1517                                   INSTALLSTATE iState)
1518 {
1519     MSIPACKAGE* package;
1520     UINT ret;
1521
1522     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1523     if (!package)
1524     {
1525         HRESULT hr;
1526         BSTR component;
1527         IWineMsiRemotePackage *remote_package;
1528
1529         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1530         if (!remote_package)
1531             return ERROR_INVALID_HANDLE;
1532
1533         component = SysAllocString(szComponent);
1534         if (!component)
1535         {
1536             IWineMsiRemotePackage_Release(remote_package);
1537             return ERROR_OUTOFMEMORY;
1538         }
1539
1540         hr = IWineMsiRemotePackage_SetComponentState(remote_package, component, iState);
1541
1542         SysFreeString(component);
1543         IWineMsiRemotePackage_Release(remote_package);
1544
1545         if (FAILED(hr))
1546         {
1547             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1548                 return HRESULT_CODE(hr);
1549
1550             return ERROR_FUNCTION_FAILED;
1551         }
1552
1553         return ERROR_SUCCESS;
1554     }
1555
1556     ret = MSI_SetComponentStateW(package, szComponent, iState);
1557     msiobj_release(&package->hdr);
1558     return ret;
1559 }
1560
1561 /***********************************************************************
1562  * MsiGetComponentStateW (MSI.@)
1563  */
1564 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPCWSTR szComponent,
1565                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
1566 {
1567     MSIPACKAGE* package;
1568     UINT ret;
1569
1570     TRACE("%d %s %p %p\n", hInstall, debugstr_w(szComponent),
1571            piInstalled, piAction);
1572
1573     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1574     if (!package)
1575     {
1576         HRESULT hr;
1577         BSTR component;
1578         IWineMsiRemotePackage *remote_package;
1579
1580         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1581         if (!remote_package)
1582             return ERROR_INVALID_HANDLE;
1583
1584         component = SysAllocString(szComponent);
1585         if (!component)
1586         {
1587             IWineMsiRemotePackage_Release(remote_package);
1588             return ERROR_OUTOFMEMORY;
1589         }
1590
1591         hr = IWineMsiRemotePackage_GetComponentState(remote_package, component,
1592                                                      piInstalled, piAction);
1593
1594         SysFreeString(component);
1595         IWineMsiRemotePackage_Release(remote_package);
1596
1597         if (FAILED(hr))
1598         {
1599             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1600                 return HRESULT_CODE(hr);
1601
1602             return ERROR_FUNCTION_FAILED;
1603         }
1604
1605         return ERROR_SUCCESS;
1606     }
1607
1608     ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
1609     msiobj_release( &package->hdr );
1610     return ret;
1611 }
1612
1613 /***********************************************************************
1614  * MsiGetLanguage (MSI.@)
1615  */
1616 LANGID WINAPI MsiGetLanguage(MSIHANDLE hInstall)
1617 {
1618     MSIPACKAGE* package;
1619     LANGID langid;
1620
1621     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1622     if (!package)
1623     {
1624         HRESULT hr;
1625         LANGID lang;
1626         IWineMsiRemotePackage *remote_package;
1627
1628         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1629         if (!remote_package)
1630             return ERROR_INVALID_HANDLE;
1631
1632         hr = IWineMsiRemotePackage_GetLanguage(remote_package, &lang);
1633
1634         if (SUCCEEDED(hr))
1635             return lang;
1636
1637         return 0;
1638     }
1639
1640     langid = msi_get_property_int( package->db, szProductLanguage, 0 );
1641     msiobj_release( &package->hdr );
1642     return langid;
1643 }
1644
1645 UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel )
1646 {
1647     static const WCHAR fmt[] = { '%','d',0 };
1648     WCHAR level[6];
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     sprintfW( level, fmt, iInstallLevel );
1660     r = msi_set_property( package->db, szInstallLevel, level );
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 }