msi/tests: automation: Add tests for StringList::_NewEnum.
[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 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "wine/debug.h"
29 #include "msi.h"
30 #include "msidefs.h"
31 #include "msipriv.h"
32 #include "wine/unicode.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(msi);
35
36 /***********************************************************************
37  * MsiDoActionA       (MSI.@)
38  */
39 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
40 {
41     LPWSTR szwAction;
42     UINT ret;
43
44     TRACE("%s\n", debugstr_a(szAction));
45
46     szwAction = strdupAtoW(szAction);
47     if (szAction && !szwAction)
48         return ERROR_FUNCTION_FAILED; 
49
50     ret = MsiDoActionW( hInstall, szwAction );
51     msi_free( szwAction );
52     return ret;
53 }
54
55 /***********************************************************************
56  * MsiDoActionW       (MSI.@)
57  */
58 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
59 {
60     MSIPACKAGE *package;
61     UINT ret;
62
63     TRACE("%s\n",debugstr_w(szAction));
64
65     if (!szAction)
66         return ERROR_INVALID_PARAMETER;
67
68     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
69     if (!package)
70         return ERROR_INVALID_HANDLE;
71  
72     ret = ACTION_PerformUIAction( package, szAction );
73     msiobj_release( &package->hdr );
74
75     return ret;
76 }
77
78 /***********************************************************************
79  * MsiSequenceA       (MSI.@)
80  */
81 UINT WINAPI MsiSequenceA( MSIHANDLE hInstall, LPCSTR szTable, INT iSequenceMode )
82 {
83     LPWSTR szwTable;
84     UINT ret;
85
86     TRACE("%s\n", debugstr_a(szTable));
87
88     szwTable = strdupAtoW(szTable);
89     if (szTable && !szwTable)
90         return ERROR_FUNCTION_FAILED; 
91
92     ret = MsiSequenceW( hInstall, szwTable, iSequenceMode );
93     msi_free( szwTable );
94     return ret;
95 }
96
97 /***********************************************************************
98  * MsiSequenceW       (MSI.@)
99  */
100 UINT WINAPI MsiSequenceW( MSIHANDLE hInstall, LPCWSTR szTable, INT iSequenceMode )
101 {
102     MSIPACKAGE *package;
103     UINT ret;
104
105     TRACE("%s\n", debugstr_w(szTable));
106
107     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
108     if (!package)
109         return ERROR_INVALID_HANDLE;
110
111     ret = MSI_Sequence( package, szTable, iSequenceMode );
112     msiobj_release( &package->hdr );
113  
114     return ret;
115 }
116
117 UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz )
118 {
119     UINT len, r = ERROR_SUCCESS;
120
121     if (awbuf->str.w && !sz )
122         return ERROR_INVALID_PARAMETER;
123
124     if (!sz)
125         return r;
126  
127     if (awbuf->unicode)
128     {
129         len = lstrlenW( str );
130         if (awbuf->str.w) 
131             lstrcpynW( awbuf->str.w, str, *sz );
132     }
133     else
134     {
135         len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
136         if (len)
137             len--;
138         WideCharToMultiByte( CP_ACP, 0, str, -1, awbuf->str.a, *sz, NULL, NULL );
139         if ( awbuf->str.a && *sz && (len >= *sz) )
140             awbuf->str.a[*sz - 1] = 0;
141     }
142
143     if (awbuf->str.w && len >= *sz)
144         r = ERROR_MORE_DATA;
145     *sz = len;
146     return r;
147 }
148
149 /***********************************************************************
150  * MsiGetTargetPath   (internal)
151  */
152 static UINT WINAPI MSI_GetTargetPath( MSIHANDLE hInstall, LPCWSTR szFolder,
153                                       awstring *szPathBuf, DWORD* pcchPathBuf )
154 {
155     MSIPACKAGE *package;
156     LPWSTR path;
157     UINT r;
158
159     if (!szFolder)
160         return ERROR_INVALID_PARAMETER;
161
162     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
163     if (!package)
164         return ERROR_INVALID_HANDLE;
165
166     path = resolve_folder( package, szFolder, FALSE, FALSE, TRUE, NULL );
167     msiobj_release( &package->hdr );
168
169     if (!path)
170         return ERROR_DIRECTORY;
171
172     r = msi_strcpy_to_awstring( path, szPathBuf, pcchPathBuf );
173     msi_free( path );
174     return r;
175 }
176
177 /***********************************************************************
178  * MsiGetTargetPathA        (MSI.@)
179  */
180 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, 
181                                LPSTR szPathBuf, DWORD* pcchPathBuf )
182 {
183     LPWSTR szwFolder;
184     awstring path;
185     UINT r;
186
187     TRACE("%s %p %p\n", debugstr_a(szFolder), szPathBuf, pcchPathBuf);
188
189     szwFolder = strdupAtoW(szFolder);
190     if (szFolder && !szwFolder)
191         return ERROR_FUNCTION_FAILED; 
192
193     path.unicode = FALSE;
194     path.str.a = szPathBuf;
195
196     r = MSI_GetTargetPath( hInstall, szwFolder, &path, pcchPathBuf );
197
198     msi_free( szwFolder );
199
200     return r;
201 }
202
203 /***********************************************************************
204  * MsiGetTargetPathW        (MSI.@)
205  */
206 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder,
207                                LPWSTR szPathBuf, DWORD* pcchPathBuf )
208 {
209     awstring path;
210
211     TRACE("%s %p %p\n", debugstr_w(szFolder), szPathBuf, pcchPathBuf);
212
213     path.unicode = TRUE;
214     path.str.w = szPathBuf;
215
216     return MSI_GetTargetPath( hInstall, szFolder, &path, pcchPathBuf );
217 }
218
219 /***********************************************************************
220  * MsiGetSourcePath   (internal)
221  */
222 static UINT MSI_GetSourcePath( MSIHANDLE hInstall, LPCWSTR szFolder,
223                                awstring *szPathBuf, DWORD* pcchPathBuf )
224 {
225     MSIPACKAGE *package;
226     LPWSTR path;
227     UINT r;
228
229     TRACE("%s %p %p\n", debugstr_w(szFolder), szPathBuf, pcchPathBuf );
230
231     if (!szFolder)
232         return ERROR_INVALID_PARAMETER;
233
234     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
235     if (!package)
236         return ERROR_INVALID_HANDLE;
237
238     if (szPathBuf->str.w && !pcchPathBuf )
239     {
240         msiobj_release( &package->hdr );
241         return ERROR_INVALID_PARAMETER;
242     }
243
244     path = resolve_folder(package, szFolder, TRUE, FALSE, TRUE, NULL);
245     msiobj_release( &package->hdr );
246
247     TRACE("path = %s\n",debugstr_w(path));
248     if (!path)
249         return ERROR_DIRECTORY;
250
251     r = msi_strcpy_to_awstring( path, szPathBuf, pcchPathBuf );
252     msi_free( path );
253     return r;
254 }
255
256 /***********************************************************************
257  * MsiGetSourcePathA     (MSI.@)
258  */
259 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, 
260                                LPSTR szPathBuf, DWORD* pcchPathBuf )
261 {
262     LPWSTR folder;
263     awstring str;
264     UINT r;
265
266     TRACE("%s %p %p\n", szFolder, debugstr_a(szPathBuf), pcchPathBuf);
267
268     str.unicode = FALSE;
269     str.str.a = szPathBuf;
270
271     folder = strdupAtoW( szFolder );
272     r = MSI_GetSourcePath( hInstall, folder, &str, pcchPathBuf );
273     msi_free( folder );
274
275     return r;
276 }
277
278 /***********************************************************************
279  * MsiGetSourcePathW     (MSI.@)
280  */
281 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder,
282                                LPWSTR szPathBuf, DWORD* pcchPathBuf )
283 {
284     awstring str;
285
286     TRACE("%s %p %p\n", debugstr_w(szFolder), szPathBuf, pcchPathBuf );
287
288     str.unicode = TRUE;
289     str.str.w = szPathBuf;
290
291     return MSI_GetSourcePath( hInstall, szFolder, &str, pcchPathBuf );
292 }
293
294 /***********************************************************************
295  * MsiSetTargetPathA  (MSI.@)
296  */
297 UINT WINAPI MsiSetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
298                                LPCSTR szFolderPath )
299 {
300     LPWSTR szwFolder = NULL, szwFolderPath = NULL;
301     UINT rc = ERROR_OUTOFMEMORY;
302
303     if ( !szFolder || !szFolderPath )
304         return ERROR_INVALID_PARAMETER;
305
306     szwFolder = strdupAtoW(szFolder);
307     szwFolderPath = strdupAtoW(szFolderPath);
308     if (!szwFolder || !szwFolderPath)
309         goto end;
310
311     rc = MsiSetTargetPathW( hInstall, szwFolder, szwFolderPath );
312
313 end:
314     msi_free(szwFolder);
315     msi_free(szwFolderPath);
316
317     return rc;
318 }
319
320 /*
321  * Ok my original interpretation of this was wrong. And it looks like msdn has
322  * changed a bit also. The given folder path does not have to actually already
323  * exist, it just cannot be read only and must be a legal folder path.
324  */
325 UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, 
326                              LPCWSTR szFolderPath)
327 {
328     DWORD attrib;
329     LPWSTR path = NULL;
330     LPWSTR path2 = NULL;
331     MSIFOLDER *folder;
332     MSIFILE *file;
333
334     TRACE("%p %s %s\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
335
336     attrib = GetFileAttributesW(szFolderPath);
337     /* native MSI tests writeability by making temporary files at each drive */
338     if ( attrib != INVALID_FILE_ATTRIBUTES &&
339           (attrib & FILE_ATTRIBUTE_OFFLINE ||
340            attrib & FILE_ATTRIBUTE_READONLY))
341         return ERROR_FUNCTION_FAILED;
342
343     path = resolve_folder(package,szFolder,FALSE,FALSE,FALSE,&folder);
344     if (!path)
345         return ERROR_DIRECTORY;
346
347     msi_free(folder->Property);
348     folder->Property = build_directory_name(2, szFolderPath, NULL);
349
350     if (lstrcmpiW(path, folder->Property) == 0)
351     {
352         /*
353          *  Resolved Target has not really changed, so just 
354          *  set this folder and do not recalculate everything.
355          */
356         msi_free(folder->ResolvedTarget);
357         folder->ResolvedTarget = NULL;
358         path2 = resolve_folder(package,szFolder,FALSE,TRUE,FALSE,NULL);
359         msi_free(path2);
360     }
361     else
362     {
363         MSIFOLDER *f;
364
365         LIST_FOR_EACH_ENTRY( f, &package->folders, MSIFOLDER, entry )
366         {
367             msi_free(f->ResolvedTarget);
368             f->ResolvedTarget=NULL;
369         }
370
371         LIST_FOR_EACH_ENTRY( f, &package->folders, MSIFOLDER, entry )
372         {
373             path2 = resolve_folder(package, f->Directory, FALSE, TRUE, FALSE, NULL);
374             msi_free(path2);
375         }
376
377         LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
378         {
379             MSICOMPONENT *comp = file->Component;
380             LPWSTR p;
381
382             if (!comp)
383                 continue;
384
385             p = resolve_folder(package, comp->Directory, FALSE, FALSE, FALSE, NULL);
386             msi_free(file->TargetPath);
387
388             file->TargetPath = build_directory_name(2, p, file->FileName);
389             msi_free(p);
390         }
391     }
392     msi_free(path);
393
394     return ERROR_SUCCESS;
395 }
396
397 /***********************************************************************
398  * MsiSetTargetPathW  (MSI.@)
399  */
400 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, 
401                              LPCWSTR szFolderPath)
402 {
403     MSIPACKAGE *package;
404     UINT ret;
405
406     TRACE("%s %s\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
407
408     if ( !szFolder || !szFolderPath )
409         return ERROR_INVALID_PARAMETER;
410
411     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
412     if (!package)
413         return ERROR_INVALID_HANDLE;
414
415     ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
416     msiobj_release( &package->hdr );
417     return ret;
418 }
419
420 /***********************************************************************
421  *           MsiGetMode    (MSI.@)
422  *
423  * Returns an internal installer state (if it is running in a mode iRunMode)
424  *
425  * PARAMS
426  *   hInstall    [I]  Handle to the installation
427  *   hRunMode    [I]  Checking run mode
428  *        MSIRUNMODE_ADMIN             Administrative mode
429  *        MSIRUNMODE_ADVERTISE         Advertisement mode
430  *        MSIRUNMODE_MAINTENANCE       Maintenance mode
431  *        MSIRUNMODE_ROLLBACKENABLED   Rollback is enabled
432  *        MSIRUNMODE_LOGENABLED        Log file is writing
433  *        MSIRUNMODE_OPERATIONS        Operations in progress??
434  *        MSIRUNMODE_REBOOTATEND       We need to reboot after installation completed
435  *        MSIRUNMODE_REBOOTNOW         We need to reboot to continue the installation
436  *        MSIRUNMODE_CABINET           Files from cabinet are installed
437  *        MSIRUNMODE_SOURCESHORTNAMES  Long names in source files is suppressed
438  *        MSIRUNMODE_TARGETSHORTNAMES  Long names in destination files is suppressed
439  *        MSIRUNMODE_RESERVED11        Reserved
440  *        MSIRUNMODE_WINDOWS9X         Running under Windows95/98
441  *        MSIRUNMODE_ZAWENABLED        Demand installation is supported
442  *        MSIRUNMODE_RESERVED14        Reserved
443  *        MSIRUNMODE_RESERVED15        Reserved
444  *        MSIRUNMODE_SCHEDULED         called from install script
445  *        MSIRUNMODE_ROLLBACK          called from rollback script
446  *        MSIRUNMODE_COMMIT            called from commit script
447  *
448  * RETURNS
449  *    In the state: TRUE
450  *    Not in the state: FALSE
451  *
452  */
453 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
454 {
455     BOOL r = FALSE;
456
457     switch (iRunMode)
458     {
459     case MSIRUNMODE_WINDOWS9X:
460         if (GetVersion() & 0x80000000)
461             r = TRUE;
462         break;
463
464     case MSIRUNMODE_RESERVED11:
465     case MSIRUNMODE_RESERVED14:
466     case MSIRUNMODE_RESERVED15:
467         break;
468
469     case MSIRUNMODE_SCHEDULED:
470     case MSIRUNMODE_ROLLBACK:
471     case MSIRUNMODE_COMMIT:
472         break;
473
474     default:
475         FIXME("%ld %d\n", hInstall, iRunMode);
476         r = TRUE;
477     }
478
479     return r;
480 }
481
482 /***********************************************************************
483  *           MsiSetMode    (MSI.@)
484  */
485 BOOL WINAPI MsiSetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode, BOOL fState)
486 {
487     switch (iRunMode)
488     {
489     case MSIRUNMODE_RESERVED11:
490     case MSIRUNMODE_WINDOWS9X:
491     case MSIRUNMODE_RESERVED14:
492     case MSIRUNMODE_RESERVED15:
493         return FALSE;
494     default:
495         FIXME("%ld %d %d\n", hInstall, iRunMode, fState);
496     }
497     return TRUE;
498 }
499
500 /***********************************************************************
501  * MsiSetFeatureStateA (MSI.@)
502  *
503  * According to the docs, when this is called it immediately recalculates
504  * all the component states as well
505  */
506 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
507                                 INSTALLSTATE iState)
508 {
509     LPWSTR szwFeature = NULL;
510     UINT rc;
511
512     szwFeature = strdupAtoW(szFeature);
513
514     if (!szwFeature)
515         return ERROR_FUNCTION_FAILED;
516    
517     rc = MsiSetFeatureStateW(hInstall,szwFeature, iState); 
518
519     msi_free(szwFeature);
520
521     return rc;
522 }
523
524
525
526 UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
527                                 INSTALLSTATE iState)
528 {
529     UINT rc = ERROR_SUCCESS;
530     MSIFEATURE *feature, *child;
531
532     TRACE("%s %i\n", debugstr_w(szFeature), iState);
533
534     feature = get_loaded_feature(package,szFeature);
535     if (!feature)
536         return ERROR_UNKNOWN_FEATURE;
537
538     if (iState == INSTALLSTATE_ADVERTISED && 
539         feature->Attributes & msidbFeatureAttributesDisallowAdvertise)
540         return ERROR_FUNCTION_FAILED;
541
542     msi_feature_set_state( feature, iState );
543
544     ACTION_UpdateComponentStates(package,szFeature);
545
546     /* update all the features that are children of this feature */
547     LIST_FOR_EACH_ENTRY( child, &package->features, MSIFEATURE, entry )
548     {
549         if (lstrcmpW(szFeature, child->Feature_Parent) == 0)
550             MSI_SetFeatureStateW(package, child->Feature, iState);
551     }
552     
553     return rc;
554 }
555
556 /***********************************************************************
557  * MsiSetFeatureStateW (MSI.@)
558  */
559 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
560                                 INSTALLSTATE iState)
561 {
562     MSIPACKAGE* package;
563     UINT rc = ERROR_SUCCESS;
564
565     TRACE("%s %i\n",debugstr_w(szFeature), iState);
566
567     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
568     if (!package)
569         return ERROR_INVALID_HANDLE;
570
571     rc = MSI_SetFeatureStateW(package,szFeature,iState);
572
573     msiobj_release( &package->hdr );
574     return rc;
575 }
576
577 /***********************************************************************
578 * MsiGetFeatureStateA   (MSI.@)
579 */
580 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
581                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
582 {
583     LPWSTR szwFeature = NULL;
584     UINT rc;
585     
586     szwFeature = strdupAtoW(szFeature);
587
588     rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
589
590     msi_free( szwFeature);
591
592     return rc;
593 }
594
595 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPCWSTR szFeature,
596                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
597 {
598     MSIFEATURE *feature;
599
600     feature = get_loaded_feature(package,szFeature);
601     if (!feature)
602         return ERROR_UNKNOWN_FEATURE;
603
604     if (piInstalled)
605         *piInstalled = feature->Installed;
606
607     if (piAction)
608         *piAction = feature->Action;
609
610     TRACE("returning %i %i\n", feature->Installed, feature->Action);
611
612     return ERROR_SUCCESS;
613 }
614
615 /***********************************************************************
616 * MsiGetFeatureStateW   (MSI.@)
617 */
618 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
619                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
620 {
621     MSIPACKAGE* package;
622     UINT ret;
623
624     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled, piAction);
625
626     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
627     if (!package)
628         return ERROR_INVALID_HANDLE;
629     ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
630     msiobj_release( &package->hdr );
631     return ret;
632 }
633
634 /***********************************************************************
635 * MsiGetFeatureCostA   (MSI.@)
636 */
637 UINT WINAPI MsiGetFeatureCostA(MSIHANDLE hInstall, LPCSTR szFeature,
638                   MSICOSTTREE iCostTree, INSTALLSTATE iState, INT *piCost)
639 {
640     FIXME("(%ld %s %i %i %p): stub\n", hInstall, debugstr_a(szFeature),
641           iCostTree, iState, piCost);
642     if (piCost) *piCost = 0;
643     return ERROR_SUCCESS;
644 }
645
646 /***********************************************************************
647 * MsiGetFeatureCostW   (MSI.@)
648 */
649 UINT WINAPI MsiGetFeatureCostW(MSIHANDLE hInstall, LPCWSTR szFeature,
650                   MSICOSTTREE iCostTree, INSTALLSTATE iState, INT *piCost)
651 {
652     FIXME("(%ld %s %i %i %p): stub\n", hInstall, debugstr_w(szFeature),
653           iCostTree, iState, piCost);
654     if (piCost) *piCost = 0;
655     return ERROR_SUCCESS;
656 }
657
658 /***********************************************************************
659  * MsiSetComponentStateA (MSI.@)
660  */
661 UINT WINAPI MsiSetComponentStateA(MSIHANDLE hInstall, LPCSTR szComponent,
662                                   INSTALLSTATE iState)
663 {
664     UINT rc;
665     LPWSTR szwComponent = strdupAtoW(szComponent);
666
667     rc = MsiSetComponentStateW(hInstall, szwComponent, iState);
668
669     msi_free(szwComponent);
670
671     return rc;
672 }
673
674 /***********************************************************************
675  * MsiGetComponentStateA (MSI.@)
676  */
677 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPCSTR szComponent,
678                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
679 {
680     LPWSTR szwComponent= NULL;
681     UINT rc;
682     
683     szwComponent= strdupAtoW(szComponent);
684
685     rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
686
687     msi_free( szwComponent);
688
689     return rc;
690 }
691
692 static UINT MSI_SetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
693                                    INSTALLSTATE iState)
694 {
695     MSICOMPONENT *comp;
696
697     TRACE("%p %s %d\n", package, debugstr_w(szComponent), iState);
698
699     comp = get_loaded_component(package, szComponent);
700     if (!comp)
701         return ERROR_UNKNOWN_COMPONENT;
702
703     comp->Installed = iState;
704
705     return ERROR_SUCCESS;
706 }
707
708 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
709                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
710 {
711     MSICOMPONENT *comp;
712
713     TRACE("%p %s %p %p\n", package, debugstr_w(szComponent),
714            piInstalled, piAction);
715
716     comp = get_loaded_component(package,szComponent);
717     if (!comp)
718         return ERROR_UNKNOWN_COMPONENT;
719
720     if (piInstalled)
721         *piInstalled = comp->Installed;
722
723     if (piAction)
724         *piAction = comp->Action;
725
726     TRACE("states (%i, %i)\n", comp->Installed, comp->Action );
727
728     return ERROR_SUCCESS;
729 }
730
731 /***********************************************************************
732  * MsiSetComponentStateW (MSI.@)
733  */
734 UINT WINAPI MsiSetComponentStateW(MSIHANDLE hInstall, LPCWSTR szComponent,
735                                   INSTALLSTATE iState)
736 {
737     MSIPACKAGE* package;
738     UINT ret;
739
740     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
741     if (!package)
742         return ERROR_INVALID_HANDLE;
743     ret = MSI_SetComponentStateW(package, szComponent, iState);
744     msiobj_release(&package->hdr);
745     return ret;
746 }
747
748 /***********************************************************************
749  * MsiGetComponentStateW (MSI.@)
750  */
751 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPCWSTR szComponent,
752                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
753 {
754     MSIPACKAGE* package;
755     UINT ret;
756
757     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
758            piInstalled, piAction);
759
760     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
761     if (!package)
762         return ERROR_INVALID_HANDLE;
763     ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
764     msiobj_release( &package->hdr );
765     return ret;
766 }
767
768 /***********************************************************************
769  * MsiGetLanguage (MSI.@)
770  */
771 LANGID WINAPI MsiGetLanguage(MSIHANDLE hInstall)
772 {
773     MSIPACKAGE* package;
774     LANGID langid;
775     static const WCHAR szProductLanguage[] =
776         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
777     
778     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
779     if (!package)
780         return ERROR_INVALID_HANDLE;
781
782     langid = msi_get_property_int( package, szProductLanguage, 0 );
783     msiobj_release( &package->hdr );
784     return langid;
785 }
786
787 UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel )
788 {
789     static const WCHAR szInstallLevel[] = {
790         'I','N','S','T','A','L','L','L','E','V','E','L',0 };
791     static const WCHAR fmt[] = { '%','d',0 };
792     WCHAR level[6];
793     UINT r;
794
795     TRACE("%p %i\n", package, iInstallLevel);
796
797     if (iInstallLevel<1 || iInstallLevel>32767)
798         return ERROR_INVALID_PARAMETER;
799
800     sprintfW( level, fmt, iInstallLevel );
801     r = MSI_SetPropertyW( package, szInstallLevel, level );
802     if ( r == ERROR_SUCCESS )
803     {
804         r = MSI_SetFeatureStates( package );
805     }
806
807     return r;
808 }
809
810 /***********************************************************************
811  * MsiSetInstallLevel (MSI.@)
812  */
813 UINT WINAPI MsiSetInstallLevel(MSIHANDLE hInstall, int iInstallLevel)
814 {
815     MSIPACKAGE* package;
816     UINT r;
817
818     TRACE("%ld %i\n", hInstall, iInstallLevel);
819
820     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
821     if ( !package )
822         return ERROR_INVALID_HANDLE;
823
824     r = MSI_SetInstallLevel( package, iInstallLevel );
825
826     msiobj_release( &package->hdr );
827
828     return r;
829 }
830
831 /***********************************************************************
832  * MsiGetFeatureValidStatesW (MSI.@)
833  */
834 UINT WINAPI MsiGetFeatureValidStatesW(MSIHANDLE hInstall, LPCWSTR szFeature,
835                   DWORD* pInstallState)
836 {
837     if(pInstallState) *pInstallState = 1<<INSTALLSTATE_LOCAL;
838     FIXME("%ld %s %p stub returning %d\n",
839         hInstall, debugstr_w(szFeature), pInstallState, pInstallState ? *pInstallState : 0);
840
841     return ERROR_SUCCESS;
842 }
843
844 /***********************************************************************
845  * MsiGetFeatureValidStatesA (MSI.@)
846  */
847 UINT WINAPI MsiGetFeatureValidStatesA(MSIHANDLE hInstall, LPCSTR szFeature,
848                   DWORD* pInstallState)
849 {
850     UINT ret;
851     LPWSTR szwFeature = strdupAtoW(szFeature);
852
853     ret = MsiGetFeatureValidStatesW(hInstall, szwFeature, pInstallState);
854
855     msi_free(szwFeature);
856
857     return ret;
858 }