msi: Fix a memory leak.
[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, 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, 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,&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,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, 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, 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     feature->ActionRequest = iState;
543     feature->Action = iState;
544
545     ACTION_UpdateComponentStates(package,szFeature);
546
547     /* update all the features that are children of this feature */
548     LIST_FOR_EACH_ENTRY( child, &package->features, MSIFEATURE, entry )
549     {
550         if (lstrcmpW(szFeature, child->Feature_Parent) == 0)
551             MSI_SetFeatureStateW(package, child->Feature, iState);
552     }
553     
554     return rc;
555 }
556
557 /***********************************************************************
558  * MsiSetFeatureStateW (MSI.@)
559  */
560 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
561                                 INSTALLSTATE iState)
562 {
563     MSIPACKAGE* package;
564     UINT rc = ERROR_SUCCESS;
565
566     TRACE("%s %i\n",debugstr_w(szFeature), iState);
567
568     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
569     if (!package)
570         return ERROR_INVALID_HANDLE;
571
572     rc = MSI_SetFeatureStateW(package,szFeature,iState);
573
574     msiobj_release( &package->hdr );
575     return rc;
576 }
577
578 /***********************************************************************
579 * MsiGetFeatureStateA   (MSI.@)
580 */
581 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
582                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
583 {
584     LPWSTR szwFeature = NULL;
585     UINT rc;
586     
587     szwFeature = strdupAtoW(szFeature);
588
589     rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
590
591     msi_free( szwFeature);
592
593     return rc;
594 }
595
596 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPCWSTR szFeature,
597                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
598 {
599     MSIFEATURE *feature;
600
601     feature = get_loaded_feature(package,szFeature);
602     if (!feature)
603         return ERROR_UNKNOWN_FEATURE;
604
605     if (piInstalled)
606         *piInstalled = feature->Installed;
607
608     if (piAction)
609         *piAction = feature->Action;
610
611     TRACE("returning %i %i\n", feature->Installed, feature->Action);
612
613     return ERROR_SUCCESS;
614 }
615
616 /***********************************************************************
617 * MsiGetFeatureStateW   (MSI.@)
618 */
619 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
620                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
621 {
622     MSIPACKAGE* package;
623     UINT ret;
624
625     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled, piAction);
626
627     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
628     if (!package)
629         return ERROR_INVALID_HANDLE;
630     ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
631     msiobj_release( &package->hdr );
632     return ret;
633 }
634
635 /***********************************************************************
636 * MsiGetFeatureCostA   (MSI.@)
637 */
638 UINT WINAPI MsiGetFeatureCostA(MSIHANDLE hInstall, LPCSTR szFeature,
639                   MSICOSTTREE iCostTree, INSTALLSTATE iState, INT *piCost)
640 {
641     FIXME("(%ld %s %i %i %p): stub\n", hInstall, debugstr_a(szFeature),
642           iCostTree, iState, piCost);
643     if (piCost) *piCost = 0;
644     return ERROR_SUCCESS;
645 }
646
647 /***********************************************************************
648 * MsiGetFeatureCostW   (MSI.@)
649 */
650 UINT WINAPI MsiGetFeatureCostW(MSIHANDLE hInstall, LPCWSTR szFeature,
651                   MSICOSTTREE iCostTree, INSTALLSTATE iState, INT *piCost)
652 {
653     FIXME("(%ld %s %i %i %p): stub\n", hInstall, debugstr_w(szFeature),
654           iCostTree, iState, piCost);
655     if (piCost) *piCost = 0;
656     return ERROR_SUCCESS;
657 }
658
659 /***********************************************************************
660  * MsiSetComponentStateA (MSI.@)
661  */
662 UINT WINAPI MsiSetComponentStateA(MSIHANDLE hInstall, LPCSTR szComponent,
663                                   INSTALLSTATE iState)
664 {
665     UINT rc;
666     LPWSTR szwComponent = strdupAtoW(szComponent);
667
668     rc = MsiSetComponentStateW(hInstall, szwComponent, iState);
669
670     msi_free(szwComponent);
671
672     return rc;
673 }
674
675 /***********************************************************************
676  * MsiGetComponentStateA (MSI.@)
677  */
678 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPCSTR szComponent,
679                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
680 {
681     LPWSTR szwComponent= NULL;
682     UINT rc;
683     
684     szwComponent= strdupAtoW(szComponent);
685
686     rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
687
688     msi_free( szwComponent);
689
690     return rc;
691 }
692
693 static UINT MSI_SetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
694                                    INSTALLSTATE iState)
695 {
696     MSICOMPONENT *comp;
697
698     TRACE("%p %s %d\n", package, debugstr_w(szComponent), iState);
699
700     comp = get_loaded_component(package, szComponent);
701     if (!comp)
702         return ERROR_UNKNOWN_COMPONENT;
703
704     comp->Installed = iState;
705
706     return ERROR_SUCCESS;
707 }
708
709 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
710                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
711 {
712     MSICOMPONENT *comp;
713
714     TRACE("%p %s %p %p\n", package, debugstr_w(szComponent),
715            piInstalled, piAction);
716
717     comp = get_loaded_component(package,szComponent);
718     if (!comp)
719         return ERROR_UNKNOWN_COMPONENT;
720
721     if (piInstalled)
722         *piInstalled = comp->Installed;
723
724     if (piAction)
725         *piAction = comp->Action;
726
727     TRACE("states (%i, %i)\n", comp->Installed, comp->Action );
728
729     return ERROR_SUCCESS;
730 }
731
732 /***********************************************************************
733  * MsiSetComponentStateW (MSI.@)
734  */
735 UINT WINAPI MsiSetComponentStateW(MSIHANDLE hInstall, LPCWSTR szComponent,
736                                   INSTALLSTATE iState)
737 {
738     MSIPACKAGE* package;
739     UINT ret;
740
741     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
742     if (!package)
743         return ERROR_INVALID_HANDLE;
744     ret = MSI_SetComponentStateW(package, szComponent, iState);
745     msiobj_release(&package->hdr);
746     return ret;
747 }
748
749 /***********************************************************************
750  * MsiGetComponentStateW (MSI.@)
751  */
752 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPCWSTR szComponent,
753                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
754 {
755     MSIPACKAGE* package;
756     UINT ret;
757
758     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
759            piInstalled, piAction);
760
761     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
762     if (!package)
763         return ERROR_INVALID_HANDLE;
764     ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
765     msiobj_release( &package->hdr );
766     return ret;
767 }
768
769 /***********************************************************************
770  * MsiGetLanguage (MSI.@)
771  */
772 LANGID WINAPI MsiGetLanguage(MSIHANDLE hInstall)
773 {
774     MSIPACKAGE* package;
775     LANGID langid;
776     static const WCHAR szProductLanguage[] =
777         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
778     
779     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
780     if (!package)
781         return ERROR_INVALID_HANDLE;
782
783     langid = msi_get_property_int( package, szProductLanguage, 0 );
784     msiobj_release( &package->hdr );
785     return langid;
786 }
787
788 UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel )
789 {
790     static const WCHAR szInstallLevel[] = {
791         'I','N','S','T','A','L','L','L','E','V','E','L',0 };
792     static const WCHAR fmt[] = { '%','d',0 };
793     WCHAR level[6];
794     UINT r;
795
796     TRACE("%p %i\n", package, iInstallLevel);
797
798     if (iInstallLevel<1 || iInstallLevel>32767)
799         return ERROR_INVALID_PARAMETER;
800
801     sprintfW( level, fmt, iInstallLevel );
802     r = MSI_SetPropertyW( package, szInstallLevel, level );
803     if ( r == ERROR_SUCCESS )
804     {
805         r = MSI_SetFeatureStates( package );
806     }
807
808     return r;
809 }
810
811 /***********************************************************************
812  * MsiSetInstallLevel (MSI.@)
813  */
814 UINT WINAPI MsiSetInstallLevel(MSIHANDLE hInstall, int iInstallLevel)
815 {
816     MSIPACKAGE* package;
817     UINT r;
818
819     TRACE("%ld %i\n", hInstall, iInstallLevel);
820
821     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
822     if ( !package )
823         return ERROR_INVALID_HANDLE;
824
825     r = MSI_SetInstallLevel( package, iInstallLevel );
826
827     msiobj_release( &package->hdr );
828
829     return r;
830 }