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