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