msi: Handle remote calls to MsiGetMode.
[wine] / dlls / msi / install.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2005 Aric Stewart for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 /* Msi top level apis directly related to installs */
22
23 #define COBJMACROS
24
25 #include <stdarg.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winerror.h"
30 #include "wine/debug.h"
31 #include "msi.h"
32 #include "msidefs.h"
33
34 #include "msipriv.h"
35 #include "msiserver.h"
36 #include "wine/unicode.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(msi);
39
40 /***********************************************************************
41  * MsiDoActionA       (MSI.@)
42  */
43 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
44 {
45     LPWSTR szwAction;
46     UINT ret;
47
48     TRACE("%s\n", debugstr_a(szAction));
49
50     szwAction = strdupAtoW(szAction);
51     if (szAction && !szwAction)
52         return ERROR_FUNCTION_FAILED; 
53
54     ret = MsiDoActionW( hInstall, szwAction );
55     msi_free( szwAction );
56     return ret;
57 }
58
59 /***********************************************************************
60  * MsiDoActionW       (MSI.@)
61  */
62 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
63 {
64     MSIPACKAGE *package;
65     UINT ret;
66
67     TRACE("%s\n",debugstr_w(szAction));
68
69     if (!szAction)
70         return ERROR_INVALID_PARAMETER;
71
72     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
73     if (!package)
74     {
75         HRESULT hr;
76         IWineMsiRemotePackage *remote_package;
77
78         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
79         if (!remote_package)
80             return ERROR_INVALID_HANDLE;
81
82         hr = IWineMsiRemotePackage_DoAction( remote_package, (BSTR *)szAction );
83
84         IWineMsiRemotePackage_Release( remote_package );
85
86         if (FAILED(hr))
87         {
88             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
89                 return HRESULT_CODE(hr);
90
91             return ERROR_FUNCTION_FAILED;
92         }
93
94         return ERROR_SUCCESS;
95     }
96  
97     ret = ACTION_PerformUIAction( package, szAction, -1 );
98     msiobj_release( &package->hdr );
99
100     return ret;
101 }
102
103 /***********************************************************************
104  * MsiSequenceA       (MSI.@)
105  */
106 UINT WINAPI MsiSequenceA( MSIHANDLE hInstall, LPCSTR szTable, INT iSequenceMode )
107 {
108     LPWSTR szwTable;
109     UINT ret;
110
111     TRACE("%s\n", debugstr_a(szTable));
112
113     szwTable = strdupAtoW(szTable);
114     if (szTable && !szwTable)
115         return ERROR_FUNCTION_FAILED; 
116
117     ret = MsiSequenceW( hInstall, szwTable, iSequenceMode );
118     msi_free( szwTable );
119     return ret;
120 }
121
122 /***********************************************************************
123  * MsiSequenceW       (MSI.@)
124  */
125 UINT WINAPI MsiSequenceW( MSIHANDLE hInstall, LPCWSTR szTable, INT iSequenceMode )
126 {
127     MSIPACKAGE *package;
128     UINT ret;
129
130     TRACE("%s\n", debugstr_w(szTable));
131
132     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
133     if (!package)
134     {
135         HRESULT hr;
136         IWineMsiRemotePackage *remote_package;
137
138         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
139         if (!remote_package)
140             return ERROR_INVALID_HANDLE;
141
142         hr = IWineMsiRemotePackage_Sequence( remote_package, (BSTR *)szTable, iSequenceMode );
143
144         IWineMsiRemotePackage_Release( remote_package );
145
146         if (FAILED(hr))
147         {
148             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
149                 return HRESULT_CODE(hr);
150
151             return ERROR_FUNCTION_FAILED;
152         }
153
154         return ERROR_SUCCESS;
155     }
156
157     ret = MSI_Sequence( package, szTable, iSequenceMode );
158     msiobj_release( &package->hdr );
159  
160     return ret;
161 }
162
163 UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz )
164 {
165     UINT len, r = ERROR_SUCCESS;
166
167     if (awbuf->str.w && !sz )
168         return ERROR_INVALID_PARAMETER;
169
170     if (!sz)
171         return r;
172  
173     if (awbuf->unicode)
174     {
175         len = lstrlenW( str );
176         if (awbuf->str.w) 
177             lstrcpynW( awbuf->str.w, str, *sz );
178     }
179     else
180     {
181         len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
182         if (len)
183             len--;
184         WideCharToMultiByte( CP_ACP, 0, str, -1, awbuf->str.a, *sz, NULL, NULL );
185         if ( awbuf->str.a && *sz && (len >= *sz) )
186             awbuf->str.a[*sz - 1] = 0;
187     }
188
189     if (awbuf->str.w && len >= *sz)
190         r = ERROR_MORE_DATA;
191     *sz = len;
192     return r;
193 }
194
195 /***********************************************************************
196  * MsiGetTargetPath   (internal)
197  */
198 static UINT WINAPI MSI_GetTargetPath( MSIHANDLE hInstall, LPCWSTR szFolder,
199                                       awstring *szPathBuf, DWORD* pcchPathBuf )
200 {
201     MSIPACKAGE *package;
202     LPWSTR path;
203     UINT r = ERROR_FUNCTION_FAILED;
204
205     if (!szFolder)
206         return ERROR_INVALID_PARAMETER;
207
208     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
209     if (!package)
210     {
211         HRESULT hr;
212         IWineMsiRemotePackage *remote_package;
213         LPWSTR value = NULL;
214         DWORD len;
215
216         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
217         if (!remote_package)
218             return ERROR_INVALID_HANDLE;
219
220         len = 0;
221         hr = IWineMsiRemotePackage_GetTargetPath( remote_package, (BSTR *)szFolder,
222                                                   NULL, &len );
223         if (FAILED(hr))
224             goto done;
225
226         len++;
227         value = msi_alloc(len * sizeof(WCHAR));
228         if (!value)
229         {
230             r = ERROR_OUTOFMEMORY;
231             goto done;
232         }
233
234         hr = IWineMsiRemotePackage_GetTargetPath( remote_package, (BSTR *)szFolder,
235                                                   (BSTR *)value, &len);
236         if (FAILED(hr))
237             goto done;
238
239         r = msi_strcpy_to_awstring( value, szPathBuf, pcchPathBuf );
240
241 done:
242         IWineMsiRemotePackage_Release( remote_package );
243         msi_free( value );
244
245         if (FAILED(hr))
246         {
247             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
248                 return HRESULT_CODE(hr);
249
250             return ERROR_FUNCTION_FAILED;
251         }
252
253         return r;
254     }
255
256     path = resolve_folder( package, szFolder, FALSE, FALSE, TRUE, NULL );
257     msiobj_release( &package->hdr );
258
259     if (!path)
260         return ERROR_DIRECTORY;
261
262     r = msi_strcpy_to_awstring( path, szPathBuf, pcchPathBuf );
263     msi_free( path );
264     return r;
265 }
266
267 /***********************************************************************
268  * MsiGetTargetPathA        (MSI.@)
269  */
270 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, 
271                                LPSTR szPathBuf, DWORD* pcchPathBuf )
272 {
273     LPWSTR szwFolder;
274     awstring path;
275     UINT r;
276
277     TRACE("%s %p %p\n", debugstr_a(szFolder), szPathBuf, pcchPathBuf);
278
279     szwFolder = strdupAtoW(szFolder);
280     if (szFolder && !szwFolder)
281         return ERROR_FUNCTION_FAILED; 
282
283     path.unicode = FALSE;
284     path.str.a = szPathBuf;
285
286     r = MSI_GetTargetPath( hInstall, szwFolder, &path, pcchPathBuf );
287
288     msi_free( szwFolder );
289
290     return r;
291 }
292
293 /***********************************************************************
294  * MsiGetTargetPathW        (MSI.@)
295  */
296 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder,
297                                LPWSTR szPathBuf, DWORD* pcchPathBuf )
298 {
299     awstring path;
300
301     TRACE("%s %p %p\n", debugstr_w(szFolder), szPathBuf, pcchPathBuf);
302
303     path.unicode = TRUE;
304     path.str.w = szPathBuf;
305
306     return MSI_GetTargetPath( hInstall, szFolder, &path, pcchPathBuf );
307 }
308
309 /***********************************************************************
310  * MsiGetSourcePath   (internal)
311  */
312 static UINT MSI_GetSourcePath( MSIHANDLE hInstall, LPCWSTR szFolder,
313                                awstring *szPathBuf, DWORD* pcchPathBuf )
314 {
315     MSIPACKAGE *package;
316     LPWSTR path;
317     UINT r = ERROR_FUNCTION_FAILED;
318
319     TRACE("%s %p %p\n", debugstr_w(szFolder), szPathBuf, pcchPathBuf );
320
321     if (!szFolder)
322         return ERROR_INVALID_PARAMETER;
323
324     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
325     if (!package)
326     {
327         HRESULT hr;
328         IWineMsiRemotePackage *remote_package;
329         LPWSTR value = NULL;
330         DWORD len;
331
332         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
333         if (!remote_package)
334             return ERROR_INVALID_HANDLE;
335
336         len = 0;
337         hr = IWineMsiRemotePackage_GetSourcePath( remote_package, (BSTR *)szFolder,
338                                                   NULL, &len );
339         if (FAILED(hr))
340             goto done;
341
342         len++;
343         value = msi_alloc(len * sizeof(WCHAR));
344         if (!value)
345         {
346             r = ERROR_OUTOFMEMORY;
347             goto done;
348         }
349
350         hr = IWineMsiRemotePackage_GetSourcePath( remote_package, (BSTR *)szFolder,
351                                                   (BSTR *)value, &len);
352         if (FAILED(hr))
353             goto done;
354
355         r = msi_strcpy_to_awstring( value, szPathBuf, pcchPathBuf );
356
357 done:
358         IWineMsiRemotePackage_Release( remote_package );
359         msi_free( value );
360
361         if (FAILED(hr))
362         {
363             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
364                 return HRESULT_CODE(hr);
365
366             return ERROR_FUNCTION_FAILED;
367         }
368
369         return r;
370     }
371
372     if (szPathBuf->str.w && !pcchPathBuf )
373     {
374         msiobj_release( &package->hdr );
375         return ERROR_INVALID_PARAMETER;
376     }
377
378     path = resolve_folder(package, szFolder, TRUE, FALSE, TRUE, NULL);
379     msiobj_release( &package->hdr );
380
381     TRACE("path = %s\n",debugstr_w(path));
382     if (!path)
383         return ERROR_DIRECTORY;
384
385     r = msi_strcpy_to_awstring( path, szPathBuf, pcchPathBuf );
386     msi_free( path );
387     return r;
388 }
389
390 /***********************************************************************
391  * MsiGetSourcePathA     (MSI.@)
392  */
393 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, 
394                                LPSTR szPathBuf, DWORD* pcchPathBuf )
395 {
396     LPWSTR folder;
397     awstring str;
398     UINT r;
399
400     TRACE("%s %p %p\n", szFolder, debugstr_a(szPathBuf), pcchPathBuf);
401
402     str.unicode = FALSE;
403     str.str.a = szPathBuf;
404
405     folder = strdupAtoW( szFolder );
406     r = MSI_GetSourcePath( hInstall, folder, &str, pcchPathBuf );
407     msi_free( folder );
408
409     return r;
410 }
411
412 /***********************************************************************
413  * MsiGetSourcePathW     (MSI.@)
414  */
415 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder,
416                                LPWSTR szPathBuf, DWORD* pcchPathBuf )
417 {
418     awstring str;
419
420     TRACE("%s %p %p\n", debugstr_w(szFolder), szPathBuf, pcchPathBuf );
421
422     str.unicode = TRUE;
423     str.str.w = szPathBuf;
424
425     return MSI_GetSourcePath( hInstall, szFolder, &str, pcchPathBuf );
426 }
427
428 /***********************************************************************
429  * MsiSetTargetPathA  (MSI.@)
430  */
431 UINT WINAPI MsiSetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
432                                LPCSTR szFolderPath )
433 {
434     LPWSTR szwFolder = NULL, szwFolderPath = NULL;
435     UINT rc = ERROR_OUTOFMEMORY;
436
437     if ( !szFolder || !szFolderPath )
438         return ERROR_INVALID_PARAMETER;
439
440     szwFolder = strdupAtoW(szFolder);
441     szwFolderPath = strdupAtoW(szFolderPath);
442     if (!szwFolder || !szwFolderPath)
443         goto end;
444
445     rc = MsiSetTargetPathW( hInstall, szwFolder, szwFolderPath );
446
447 end:
448     msi_free(szwFolder);
449     msi_free(szwFolderPath);
450
451     return rc;
452 }
453
454 /*
455  * Ok my original interpretation of this was wrong. And it looks like msdn has
456  * changed a bit also. The given folder path does not have to actually already
457  * exist, it just cannot be read only and must be a legal folder path.
458  */
459 UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, 
460                              LPCWSTR szFolderPath)
461 {
462     DWORD attrib;
463     LPWSTR path = NULL;
464     LPWSTR path2 = NULL;
465     MSIFOLDER *folder;
466     MSIFILE *file;
467
468     TRACE("%p %s %s\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
469
470     attrib = GetFileAttributesW(szFolderPath);
471     /* native MSI tests writeability by making temporary files at each drive */
472     if ( attrib != INVALID_FILE_ATTRIBUTES &&
473           (attrib & FILE_ATTRIBUTE_OFFLINE ||
474            attrib & FILE_ATTRIBUTE_READONLY))
475         return ERROR_FUNCTION_FAILED;
476
477     path = resolve_folder(package,szFolder,FALSE,FALSE,FALSE,&folder);
478     if (!path)
479         return ERROR_DIRECTORY;
480
481     msi_free(folder->Property);
482     folder->Property = build_directory_name(2, szFolderPath, NULL);
483
484     if (lstrcmpiW(path, folder->Property) == 0)
485     {
486         /*
487          *  Resolved Target has not really changed, so just 
488          *  set this folder and do not recalculate everything.
489          */
490         msi_free(folder->ResolvedTarget);
491         folder->ResolvedTarget = NULL;
492         path2 = resolve_folder(package,szFolder,FALSE,TRUE,FALSE,NULL);
493         msi_free(path2);
494     }
495     else
496     {
497         MSIFOLDER *f;
498
499         LIST_FOR_EACH_ENTRY( f, &package->folders, MSIFOLDER, entry )
500         {
501             msi_free(f->ResolvedTarget);
502             f->ResolvedTarget=NULL;
503         }
504
505         LIST_FOR_EACH_ENTRY( f, &package->folders, MSIFOLDER, entry )
506         {
507             path2 = resolve_folder(package, f->Directory, FALSE, TRUE, FALSE, NULL);
508             msi_free(path2);
509         }
510
511         LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
512         {
513             MSICOMPONENT *comp = file->Component;
514             LPWSTR p;
515
516             if (!comp)
517                 continue;
518
519             p = resolve_folder(package, comp->Directory, FALSE, FALSE, FALSE, NULL);
520             msi_free(file->TargetPath);
521
522             file->TargetPath = build_directory_name(2, p, file->FileName);
523             msi_free(p);
524         }
525     }
526     msi_free(path);
527
528     return ERROR_SUCCESS;
529 }
530
531 /***********************************************************************
532  * MsiSetTargetPathW  (MSI.@)
533  */
534 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, 
535                              LPCWSTR szFolderPath)
536 {
537     MSIPACKAGE *package;
538     UINT ret;
539
540     TRACE("%s %s\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
541
542     if ( !szFolder || !szFolderPath )
543         return ERROR_INVALID_PARAMETER;
544
545     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
546     if (!package)
547     {
548         HRESULT hr;
549         IWineMsiRemotePackage *remote_package;
550
551         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
552         if (!remote_package)
553             return ERROR_INVALID_HANDLE;
554
555         hr = IWineMsiRemotePackage_SetTargetPath( remote_package, (BSTR *)szFolder, (BSTR *)szFolderPath );
556
557         IWineMsiRemotePackage_Release( remote_package );
558
559         if (FAILED(hr))
560         {
561             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
562                 return HRESULT_CODE(hr);
563
564             return ERROR_FUNCTION_FAILED;
565         }
566
567         return ERROR_SUCCESS;
568     }
569
570     ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
571     msiobj_release( &package->hdr );
572     return ret;
573 }
574
575 /***********************************************************************
576  *           MsiGetMode    (MSI.@)
577  *
578  * Returns an internal installer state (if it is running in a mode iRunMode)
579  *
580  * PARAMS
581  *   hInstall    [I]  Handle to the installation
582  *   hRunMode    [I]  Checking run mode
583  *        MSIRUNMODE_ADMIN             Administrative mode
584  *        MSIRUNMODE_ADVERTISE         Advertisement mode
585  *        MSIRUNMODE_MAINTENANCE       Maintenance mode
586  *        MSIRUNMODE_ROLLBACKENABLED   Rollback is enabled
587  *        MSIRUNMODE_LOGENABLED        Log file is writing
588  *        MSIRUNMODE_OPERATIONS        Operations in progress??
589  *        MSIRUNMODE_REBOOTATEND       We need to reboot after installation completed
590  *        MSIRUNMODE_REBOOTNOW         We need to reboot to continue the installation
591  *        MSIRUNMODE_CABINET           Files from cabinet are installed
592  *        MSIRUNMODE_SOURCESHORTNAMES  Long names in source files is suppressed
593  *        MSIRUNMODE_TARGETSHORTNAMES  Long names in destination files is suppressed
594  *        MSIRUNMODE_RESERVED11        Reserved
595  *        MSIRUNMODE_WINDOWS9X         Running under Windows95/98
596  *        MSIRUNMODE_ZAWENABLED        Demand installation is supported
597  *        MSIRUNMODE_RESERVED14        Reserved
598  *        MSIRUNMODE_RESERVED15        Reserved
599  *        MSIRUNMODE_SCHEDULED         called from install script
600  *        MSIRUNMODE_ROLLBACK          called from rollback script
601  *        MSIRUNMODE_COMMIT            called from commit script
602  *
603  * RETURNS
604  *    In the state: TRUE
605  *    Not in the state: FALSE
606  *
607  */
608 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
609 {
610     MSIPACKAGE *package;
611     BOOL r = FALSE;
612
613     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
614     if (!package)
615     {
616         BOOL ret;
617         HRESULT hr;
618         IWineMsiRemotePackage *remote_package;
619
620         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
621         if (!remote_package)
622             return FALSE;
623
624         hr = IWineMsiRemotePackage_GetMode(remote_package, iRunMode, &ret);
625         IWineMsiRemotePackage_Release(remote_package);
626
627         if (hr == S_OK)
628             return ret;
629
630         return FALSE;
631     }
632
633     switch (iRunMode)
634     {
635     case MSIRUNMODE_WINDOWS9X:
636         if (GetVersion() & 0x80000000)
637             r = TRUE;
638         break;
639
640     case MSIRUNMODE_RESERVED11:
641     case MSIRUNMODE_RESERVED14:
642     case MSIRUNMODE_RESERVED15:
643         break;
644
645     case MSIRUNMODE_SCHEDULED:
646         r = package->scheduled_action_running;
647         break;
648
649     case MSIRUNMODE_ROLLBACK:
650         r = package->rollback_action_running;
651         break;
652
653     case MSIRUNMODE_COMMIT:
654         r = package->commit_action_running;
655         break;
656
657     default:
658         FIXME("%ld %d\n", hInstall, iRunMode);
659         r = TRUE;
660     }
661
662     return r;
663 }
664
665 /***********************************************************************
666  *           MsiSetMode    (MSI.@)
667  */
668 BOOL WINAPI MsiSetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode, BOOL fState)
669 {
670     switch (iRunMode)
671     {
672     case MSIRUNMODE_RESERVED11:
673     case MSIRUNMODE_WINDOWS9X:
674     case MSIRUNMODE_RESERVED14:
675     case MSIRUNMODE_RESERVED15:
676         return FALSE;
677     default:
678         FIXME("%ld %d %d\n", hInstall, iRunMode, fState);
679     }
680     return TRUE;
681 }
682
683 /***********************************************************************
684  * MsiSetFeatureStateA (MSI.@)
685  *
686  * According to the docs, when this is called it immediately recalculates
687  * all the component states as well
688  */
689 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
690                                 INSTALLSTATE iState)
691 {
692     LPWSTR szwFeature = NULL;
693     UINT rc;
694
695     szwFeature = strdupAtoW(szFeature);
696
697     if (!szwFeature)
698         return ERROR_FUNCTION_FAILED;
699    
700     rc = MsiSetFeatureStateW(hInstall,szwFeature, iState); 
701
702     msi_free(szwFeature);
703
704     return rc;
705 }
706
707
708
709 UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
710                                 INSTALLSTATE iState)
711 {
712     UINT rc = ERROR_SUCCESS;
713     MSIFEATURE *feature, *child;
714
715     TRACE("%s %i\n", debugstr_w(szFeature), iState);
716
717     feature = get_loaded_feature(package,szFeature);
718     if (!feature)
719         return ERROR_UNKNOWN_FEATURE;
720
721     if (iState == INSTALLSTATE_ADVERTISED && 
722         feature->Attributes & msidbFeatureAttributesDisallowAdvertise)
723         return ERROR_FUNCTION_FAILED;
724
725     msi_feature_set_state( feature, iState );
726
727     ACTION_UpdateComponentStates(package,szFeature);
728
729     /* update all the features that are children of this feature */
730     LIST_FOR_EACH_ENTRY( child, &package->features, MSIFEATURE, entry )
731     {
732         if (lstrcmpW(szFeature, child->Feature_Parent) == 0)
733             MSI_SetFeatureStateW(package, child->Feature, iState);
734     }
735     
736     return rc;
737 }
738
739 /***********************************************************************
740  * MsiSetFeatureStateW (MSI.@)
741  */
742 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
743                                 INSTALLSTATE iState)
744 {
745     MSIPACKAGE* package;
746     UINT rc = ERROR_SUCCESS;
747
748     TRACE("%s %i\n",debugstr_w(szFeature), iState);
749
750     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
751     if (!package)
752         return ERROR_INVALID_HANDLE;
753
754     rc = MSI_SetFeatureStateW(package,szFeature,iState);
755
756     msiobj_release( &package->hdr );
757     return rc;
758 }
759
760 /***********************************************************************
761 * MsiGetFeatureStateA   (MSI.@)
762 */
763 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
764                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
765 {
766     LPWSTR szwFeature = NULL;
767     UINT rc;
768     
769     szwFeature = strdupAtoW(szFeature);
770
771     rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
772
773     msi_free( szwFeature);
774
775     return rc;
776 }
777
778 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPCWSTR szFeature,
779                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
780 {
781     MSIFEATURE *feature;
782
783     feature = get_loaded_feature(package,szFeature);
784     if (!feature)
785         return ERROR_UNKNOWN_FEATURE;
786
787     if (piInstalled)
788         *piInstalled = feature->Installed;
789
790     if (piAction)
791         *piAction = feature->Action;
792
793     TRACE("returning %i %i\n", feature->Installed, feature->Action);
794
795     return ERROR_SUCCESS;
796 }
797
798 /***********************************************************************
799 * MsiGetFeatureStateW   (MSI.@)
800 */
801 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
802                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
803 {
804     MSIPACKAGE* package;
805     UINT ret;
806
807     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled, piAction);
808
809     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
810     if (!package)
811         return ERROR_INVALID_HANDLE;
812     ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
813     msiobj_release( &package->hdr );
814     return ret;
815 }
816
817 /***********************************************************************
818 * MsiGetFeatureCostA   (MSI.@)
819 */
820 UINT WINAPI MsiGetFeatureCostA(MSIHANDLE hInstall, LPCSTR szFeature,
821                   MSICOSTTREE iCostTree, INSTALLSTATE iState, INT *piCost)
822 {
823     FIXME("(%ld %s %i %i %p): stub\n", hInstall, debugstr_a(szFeature),
824           iCostTree, iState, piCost);
825     if (piCost) *piCost = 0;
826     return ERROR_SUCCESS;
827 }
828
829 /***********************************************************************
830 * MsiGetFeatureCostW   (MSI.@)
831 */
832 UINT WINAPI MsiGetFeatureCostW(MSIHANDLE hInstall, LPCWSTR szFeature,
833                   MSICOSTTREE iCostTree, INSTALLSTATE iState, INT *piCost)
834 {
835     FIXME("(%ld %s %i %i %p): stub\n", hInstall, debugstr_w(szFeature),
836           iCostTree, iState, piCost);
837     if (piCost) *piCost = 0;
838     return ERROR_SUCCESS;
839 }
840
841 /***********************************************************************
842  * MsiSetComponentStateA (MSI.@)
843  */
844 UINT WINAPI MsiSetComponentStateA(MSIHANDLE hInstall, LPCSTR szComponent,
845                                   INSTALLSTATE iState)
846 {
847     UINT rc;
848     LPWSTR szwComponent = strdupAtoW(szComponent);
849
850     rc = MsiSetComponentStateW(hInstall, szwComponent, iState);
851
852     msi_free(szwComponent);
853
854     return rc;
855 }
856
857 /***********************************************************************
858  * MsiGetComponentStateA (MSI.@)
859  */
860 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPCSTR szComponent,
861                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
862 {
863     LPWSTR szwComponent= NULL;
864     UINT rc;
865     
866     szwComponent= strdupAtoW(szComponent);
867
868     rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
869
870     msi_free( szwComponent);
871
872     return rc;
873 }
874
875 static UINT MSI_SetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
876                                    INSTALLSTATE iState)
877 {
878     MSICOMPONENT *comp;
879
880     TRACE("%p %s %d\n", package, debugstr_w(szComponent), iState);
881
882     comp = get_loaded_component(package, szComponent);
883     if (!comp)
884         return ERROR_UNKNOWN_COMPONENT;
885
886     comp->Installed = iState;
887
888     return ERROR_SUCCESS;
889 }
890
891 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
892                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
893 {
894     MSICOMPONENT *comp;
895
896     TRACE("%p %s %p %p\n", package, debugstr_w(szComponent),
897            piInstalled, piAction);
898
899     comp = get_loaded_component(package,szComponent);
900     if (!comp)
901         return ERROR_UNKNOWN_COMPONENT;
902
903     if (piInstalled)
904         *piInstalled = comp->Installed;
905
906     if (piAction)
907         *piAction = comp->Action;
908
909     TRACE("states (%i, %i)\n", comp->Installed, comp->Action );
910
911     return ERROR_SUCCESS;
912 }
913
914 /***********************************************************************
915  * MsiSetComponentStateW (MSI.@)
916  */
917 UINT WINAPI MsiSetComponentStateW(MSIHANDLE hInstall, LPCWSTR szComponent,
918                                   INSTALLSTATE iState)
919 {
920     MSIPACKAGE* package;
921     UINT ret;
922
923     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
924     if (!package)
925         return ERROR_INVALID_HANDLE;
926     ret = MSI_SetComponentStateW(package, szComponent, iState);
927     msiobj_release(&package->hdr);
928     return ret;
929 }
930
931 /***********************************************************************
932  * MsiGetComponentStateW (MSI.@)
933  */
934 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPCWSTR szComponent,
935                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
936 {
937     MSIPACKAGE* package;
938     UINT ret;
939
940     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
941            piInstalled, piAction);
942
943     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
944     if (!package)
945         return ERROR_INVALID_HANDLE;
946     ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
947     msiobj_release( &package->hdr );
948     return ret;
949 }
950
951 /***********************************************************************
952  * MsiGetLanguage (MSI.@)
953  */
954 LANGID WINAPI MsiGetLanguage(MSIHANDLE hInstall)
955 {
956     MSIPACKAGE* package;
957     LANGID langid;
958     static const WCHAR szProductLanguage[] =
959         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
960     
961     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
962     if (!package)
963         return ERROR_INVALID_HANDLE;
964
965     langid = msi_get_property_int( package, szProductLanguage, 0 );
966     msiobj_release( &package->hdr );
967     return langid;
968 }
969
970 UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel )
971 {
972     static const WCHAR szInstallLevel[] = {
973         'I','N','S','T','A','L','L','L','E','V','E','L',0 };
974     static const WCHAR fmt[] = { '%','d',0 };
975     WCHAR level[6];
976     UINT r;
977
978     TRACE("%p %i\n", package, iInstallLevel);
979
980     if (iInstallLevel<1 || iInstallLevel>32767)
981         return ERROR_INVALID_PARAMETER;
982
983     sprintfW( level, fmt, iInstallLevel );
984     r = MSI_SetPropertyW( package, szInstallLevel, level );
985     if ( r == ERROR_SUCCESS )
986     {
987         r = MSI_SetFeatureStates( package );
988     }
989
990     return r;
991 }
992
993 /***********************************************************************
994  * MsiSetInstallLevel (MSI.@)
995  */
996 UINT WINAPI MsiSetInstallLevel(MSIHANDLE hInstall, int iInstallLevel)
997 {
998     MSIPACKAGE* package;
999     UINT r;
1000
1001     TRACE("%ld %i\n", hInstall, iInstallLevel);
1002
1003     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
1004     if ( !package )
1005         return ERROR_INVALID_HANDLE;
1006
1007     r = MSI_SetInstallLevel( package, iInstallLevel );
1008
1009     msiobj_release( &package->hdr );
1010
1011     return r;
1012 }
1013
1014 /***********************************************************************
1015  * MsiGetFeatureValidStatesW (MSI.@)
1016  */
1017 UINT WINAPI MsiGetFeatureValidStatesW(MSIHANDLE hInstall, LPCWSTR szFeature,
1018                   DWORD* pInstallState)
1019 {
1020     if(pInstallState) *pInstallState = 1<<INSTALLSTATE_LOCAL;
1021     FIXME("%ld %s %p stub returning %d\n",
1022         hInstall, debugstr_w(szFeature), pInstallState, pInstallState ? *pInstallState : 0);
1023
1024     return ERROR_SUCCESS;
1025 }
1026
1027 /***********************************************************************
1028  * MsiGetFeatureValidStatesA (MSI.@)
1029  */
1030 UINT WINAPI MsiGetFeatureValidStatesA(MSIHANDLE hInstall, LPCSTR szFeature,
1031                   DWORD* pInstallState)
1032 {
1033     UINT ret;
1034     LPWSTR szwFeature = strdupAtoW(szFeature);
1035
1036     ret = MsiGetFeatureValidStatesW(hInstall, szwFeature, pInstallState);
1037
1038     msi_free(szwFeature);
1039
1040     return ret;
1041 }