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