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