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