msi: Honor msidbFeatureAttributesFollowParent.
[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 #define COBJMACROS
24
25 #include <stdarg.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winerror.h"
30 #include "wine/debug.h"
31 #include "msi.h"
32 #include "msidefs.h"
33 #include "objbase.h"
34 #include "oleauto.h"
35
36 #include "msipriv.h"
37 #include "msiserver.h"
38 #include "wine/unicode.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(msi);
41
42 /***********************************************************************
43  * MsiDoActionA       (MSI.@)
44  */
45 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
46 {
47     LPWSTR szwAction;
48     UINT ret;
49
50     TRACE("%s\n", debugstr_a(szAction));
51
52     szwAction = strdupAtoW(szAction);
53     if (szAction && !szwAction)
54         return ERROR_FUNCTION_FAILED; 
55
56     ret = MsiDoActionW( hInstall, szwAction );
57     msi_free( szwAction );
58     return ret;
59 }
60
61 /***********************************************************************
62  * MsiDoActionW       (MSI.@)
63  */
64 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
65 {
66     MSIPACKAGE *package;
67     UINT ret;
68
69     TRACE("%s\n",debugstr_w(szAction));
70
71     if (!szAction)
72         return ERROR_INVALID_PARAMETER;
73
74     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
75     if (!package)
76     {
77         HRESULT hr;
78         BSTR action;
79         IWineMsiRemotePackage *remote_package;
80
81         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
82         if (!remote_package)
83             return ERROR_INVALID_HANDLE;
84
85         action = SysAllocString( szAction );
86         if (!action)
87         {
88             IWineMsiRemotePackage_Release( remote_package );
89             return ERROR_OUTOFMEMORY;
90         }
91
92         hr = IWineMsiRemotePackage_DoAction( remote_package, action );
93
94         SysFreeString( action );
95         IWineMsiRemotePackage_Release( remote_package );
96
97         if (FAILED(hr))
98         {
99             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
100                 return HRESULT_CODE(hr);
101
102             return ERROR_FUNCTION_FAILED;
103         }
104
105         return ERROR_SUCCESS;
106     }
107  
108     ret = ACTION_PerformUIAction( package, szAction, -1 );
109     msiobj_release( &package->hdr );
110
111     return ret;
112 }
113
114 /***********************************************************************
115  * MsiSequenceA       (MSI.@)
116  */
117 UINT WINAPI MsiSequenceA( MSIHANDLE hInstall, LPCSTR szTable, INT iSequenceMode )
118 {
119     LPWSTR szwTable;
120     UINT ret;
121
122     TRACE("%s\n", debugstr_a(szTable));
123
124     szwTable = strdupAtoW(szTable);
125     if (szTable && !szwTable)
126         return ERROR_FUNCTION_FAILED; 
127
128     ret = MsiSequenceW( hInstall, szwTable, iSequenceMode );
129     msi_free( szwTable );
130     return ret;
131 }
132
133 /***********************************************************************
134  * MsiSequenceW       (MSI.@)
135  */
136 UINT WINAPI MsiSequenceW( MSIHANDLE hInstall, LPCWSTR szTable, INT iSequenceMode )
137 {
138     MSIPACKAGE *package;
139     UINT ret;
140
141     TRACE("%s\n", debugstr_w(szTable));
142
143     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
144     if (!package)
145     {
146         HRESULT hr;
147         BSTR table;
148         IWineMsiRemotePackage *remote_package;
149
150         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
151         if (!remote_package)
152             return ERROR_INVALID_HANDLE;
153
154         table = SysAllocString( szTable );
155         if (!table)
156         {
157             IWineMsiRemotePackage_Release( remote_package );
158             return ERROR_OUTOFMEMORY;
159         }
160
161         hr = IWineMsiRemotePackage_Sequence( remote_package, table, iSequenceMode );
162
163         SysFreeString( table );
164         IWineMsiRemotePackage_Release( remote_package );
165
166         if (FAILED(hr))
167         {
168             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
169                 return HRESULT_CODE(hr);
170
171             return ERROR_FUNCTION_FAILED;
172         }
173
174         return ERROR_SUCCESS;
175     }
176
177     ret = MSI_Sequence( package, szTable, iSequenceMode );
178     msiobj_release( &package->hdr );
179  
180     return ret;
181 }
182
183 UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz )
184 {
185     UINT len, r = ERROR_SUCCESS;
186
187     if (awbuf->str.w && !sz )
188         return ERROR_INVALID_PARAMETER;
189
190     if (!sz)
191         return r;
192  
193     if (awbuf->unicode)
194     {
195         len = lstrlenW( str );
196         if (awbuf->str.w) 
197             lstrcpynW( awbuf->str.w, str, *sz );
198     }
199     else
200     {
201         len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
202         if (len)
203             len--;
204         WideCharToMultiByte( CP_ACP, 0, str, -1, awbuf->str.a, *sz, NULL, NULL );
205         if ( awbuf->str.a && *sz && (len >= *sz) )
206             awbuf->str.a[*sz - 1] = 0;
207     }
208
209     if (awbuf->str.w && len >= *sz)
210         r = ERROR_MORE_DATA;
211     *sz = len;
212     return r;
213 }
214
215 /***********************************************************************
216  * MsiGetTargetPath   (internal)
217  */
218 static UINT MSI_GetTargetPath( MSIHANDLE hInstall, LPCWSTR szFolder,
219                                awstring *szPathBuf, LPDWORD pcchPathBuf )
220 {
221     MSIPACKAGE *package;
222     LPWSTR path;
223     UINT r = ERROR_FUNCTION_FAILED;
224
225     if (!szFolder)
226         return ERROR_INVALID_PARAMETER;
227
228     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
229     if (!package)
230     {
231         HRESULT hr;
232         IWineMsiRemotePackage *remote_package;
233         LPWSTR value = NULL;
234         BSTR folder;
235         DWORD len;
236
237         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
238         if (!remote_package)
239             return ERROR_INVALID_HANDLE;
240
241         folder = SysAllocString( szFolder );
242         if (!folder)
243         {
244             IWineMsiRemotePackage_Release( remote_package );
245             return ERROR_OUTOFMEMORY;
246         }
247
248         len = 0;
249         hr = IWineMsiRemotePackage_GetTargetPath( remote_package, folder,
250                                                   NULL, &len );
251         if (FAILED(hr))
252             goto done;
253
254         len++;
255         value = msi_alloc(len * sizeof(WCHAR));
256         if (!value)
257         {
258             r = ERROR_OUTOFMEMORY;
259             goto done;
260         }
261
262         hr = IWineMsiRemotePackage_GetTargetPath( remote_package, folder,
263                                                   (BSTR *)value, &len);
264         if (FAILED(hr))
265             goto done;
266
267         r = msi_strcpy_to_awstring( value, szPathBuf, pcchPathBuf );
268
269 done:
270         IWineMsiRemotePackage_Release( remote_package );
271         SysFreeString( folder );
272         msi_free( value );
273
274         if (FAILED(hr))
275         {
276             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
277                 return HRESULT_CODE(hr);
278
279             return ERROR_FUNCTION_FAILED;
280         }
281
282         return r;
283     }
284
285     path = resolve_target_folder( package, szFolder, FALSE, TRUE, NULL );
286     msiobj_release( &package->hdr );
287
288     if (!path)
289         return ERROR_DIRECTORY;
290
291     r = msi_strcpy_to_awstring( path, szPathBuf, pcchPathBuf );
292     msi_free( path );
293     return r;
294 }
295
296 /***********************************************************************
297  * MsiGetTargetPathA        (MSI.@)
298  */
299 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, 
300                                LPSTR szPathBuf, LPDWORD pcchPathBuf )
301 {
302     LPWSTR szwFolder;
303     awstring path;
304     UINT r;
305
306     TRACE("%s %p %p\n", debugstr_a(szFolder), szPathBuf, pcchPathBuf);
307
308     szwFolder = strdupAtoW(szFolder);
309     if (szFolder && !szwFolder)
310         return ERROR_FUNCTION_FAILED; 
311
312     path.unicode = FALSE;
313     path.str.a = szPathBuf;
314
315     r = MSI_GetTargetPath( hInstall, szwFolder, &path, pcchPathBuf );
316
317     msi_free( szwFolder );
318
319     return r;
320 }
321
322 /***********************************************************************
323  * MsiGetTargetPathW        (MSI.@)
324  */
325 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder,
326                                LPWSTR szPathBuf, LPDWORD pcchPathBuf )
327 {
328     awstring path;
329
330     TRACE("%s %p %p\n", debugstr_w(szFolder), szPathBuf, pcchPathBuf);
331
332     path.unicode = TRUE;
333     path.str.w = szPathBuf;
334
335     return MSI_GetTargetPath( hInstall, szFolder, &path, pcchPathBuf );
336 }
337
338 /***********************************************************************
339  * MSI_GetSourcePath   (internal)
340  */
341 static UINT MSI_GetSourcePath( MSIHANDLE hInstall, LPCWSTR szFolder,
342                                awstring *szPathBuf, LPDWORD pcchPathBuf )
343 {
344     MSIPACKAGE *package;
345     LPWSTR path;
346     UINT r = ERROR_FUNCTION_FAILED;
347
348     TRACE("%s %p %p\n", debugstr_w(szFolder), szPathBuf, pcchPathBuf );
349
350     if (!szFolder)
351         return ERROR_INVALID_PARAMETER;
352
353     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
354     if (!package)
355     {
356         HRESULT hr;
357         IWineMsiRemotePackage *remote_package;
358         LPWSTR value = NULL;
359         BSTR folder;
360         DWORD len;
361
362         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
363         if (!remote_package)
364             return ERROR_INVALID_HANDLE;
365
366         folder = SysAllocString( szFolder );
367         if (!folder)
368         {
369             IWineMsiRemotePackage_Release( remote_package );
370             return ERROR_OUTOFMEMORY;
371         }
372
373         len = 0;
374         hr = IWineMsiRemotePackage_GetSourcePath( remote_package, folder,
375                                                   NULL, &len );
376         if (FAILED(hr))
377             goto done;
378
379         len++;
380         value = msi_alloc(len * sizeof(WCHAR));
381         if (!value)
382         {
383             r = ERROR_OUTOFMEMORY;
384             goto done;
385         }
386
387         hr = IWineMsiRemotePackage_GetSourcePath( remote_package, folder,
388                                                   (BSTR *)value, &len);
389         if (FAILED(hr))
390             goto done;
391
392         r = msi_strcpy_to_awstring( value, szPathBuf, pcchPathBuf );
393
394 done:
395         IWineMsiRemotePackage_Release( remote_package );
396         SysFreeString( folder );
397         msi_free( value );
398
399         if (FAILED(hr))
400         {
401             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
402                 return HRESULT_CODE(hr);
403
404             return ERROR_FUNCTION_FAILED;
405         }
406
407         return r;
408     }
409
410     if (szPathBuf->str.w && !pcchPathBuf )
411     {
412         msiobj_release( &package->hdr );
413         return ERROR_INVALID_PARAMETER;
414     }
415
416     path = resolve_source_folder( package, szFolder, NULL );
417     msiobj_release( &package->hdr );
418
419     TRACE("path = %s\n", debugstr_w(path));
420     if (!path)
421         return ERROR_DIRECTORY;
422
423     r = msi_strcpy_to_awstring( path, szPathBuf, pcchPathBuf );
424     msi_free( path );
425     return r;
426 }
427
428 /***********************************************************************
429  * MsiGetSourcePathA     (MSI.@)
430  */
431 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, 
432                                LPSTR szPathBuf, LPDWORD pcchPathBuf )
433 {
434     LPWSTR folder;
435     awstring str;
436     UINT r;
437
438     TRACE("%s %p %p\n", szFolder, debugstr_a(szPathBuf), pcchPathBuf);
439
440     str.unicode = FALSE;
441     str.str.a = szPathBuf;
442
443     folder = strdupAtoW( szFolder );
444     r = MSI_GetSourcePath( hInstall, folder, &str, pcchPathBuf );
445     msi_free( folder );
446
447     return r;
448 }
449
450 /***********************************************************************
451  * MsiGetSourcePathW     (MSI.@)
452  */
453 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder,
454                                LPWSTR szPathBuf, LPDWORD pcchPathBuf )
455 {
456     awstring str;
457
458     TRACE("%s %p %p\n", debugstr_w(szFolder), szPathBuf, pcchPathBuf );
459
460     str.unicode = TRUE;
461     str.str.w = szPathBuf;
462
463     return MSI_GetSourcePath( hInstall, szFolder, &str, pcchPathBuf );
464 }
465
466 /***********************************************************************
467  * MsiSetTargetPathA  (MSI.@)
468  */
469 UINT WINAPI MsiSetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
470                                LPCSTR szFolderPath )
471 {
472     LPWSTR szwFolder = NULL, szwFolderPath = NULL;
473     UINT rc = ERROR_OUTOFMEMORY;
474
475     if ( !szFolder || !szFolderPath )
476         return ERROR_INVALID_PARAMETER;
477
478     szwFolder = strdupAtoW(szFolder);
479     szwFolderPath = strdupAtoW(szFolderPath);
480     if (!szwFolder || !szwFolderPath)
481         goto end;
482
483     rc = MsiSetTargetPathW( hInstall, szwFolder, szwFolderPath );
484
485 end:
486     msi_free(szwFolder);
487     msi_free(szwFolderPath);
488
489     return rc;
490 }
491
492 /*
493  * Ok my original interpretation of this was wrong. And it looks like msdn has
494  * changed a bit also. The given folder path does not have to actually already
495  * exist, it just cannot be read only and must be a legal folder path.
496  */
497 UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, 
498                              LPCWSTR szFolderPath)
499 {
500     DWORD attrib;
501     LPWSTR path = NULL;
502     LPWSTR path2 = NULL;
503     MSIFOLDER *folder;
504     MSIFILE *file;
505
506     TRACE("%p %s %s\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
507
508     attrib = GetFileAttributesW(szFolderPath);
509     /* native MSI tests writeability by making temporary files at each drive */
510     if ( attrib != INVALID_FILE_ATTRIBUTES &&
511           (attrib & FILE_ATTRIBUTE_OFFLINE ||
512            attrib & FILE_ATTRIBUTE_READONLY))
513         return ERROR_FUNCTION_FAILED;
514
515     path = resolve_target_folder( package, szFolder, FALSE, FALSE, &folder );
516     if (!path)
517         return ERROR_DIRECTORY;
518
519     msi_free(folder->Property);
520     folder->Property = build_directory_name(2, szFolderPath, NULL);
521
522     if (!strcmpiW( path, folder->Property ))
523     {
524         /*
525          *  Resolved Target has not really changed, so just 
526          *  set this folder and do not recalculate everything.
527          */
528         msi_free(folder->ResolvedTarget);
529         folder->ResolvedTarget = NULL;
530         path2 = resolve_target_folder( package, szFolder, TRUE, FALSE, NULL );
531         msi_free(path2);
532     }
533     else
534     {
535         MSIFOLDER *f;
536
537         LIST_FOR_EACH_ENTRY( f, &package->folders, MSIFOLDER, entry )
538         {
539             msi_free(f->ResolvedTarget);
540             f->ResolvedTarget=NULL;
541         }
542
543         LIST_FOR_EACH_ENTRY( f, &package->folders, MSIFOLDER, entry )
544         {
545             path2 = resolve_target_folder( package, f->Directory, TRUE, FALSE, NULL );
546             msi_free(path2);
547         }
548
549         LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
550         {
551             MSICOMPONENT *comp = file->Component;
552             LPWSTR dir;
553
554             if (!comp->Enabled || (comp->assembly && !comp->assembly->application))
555                 continue;
556
557             dir = resolve_target_folder( package, comp->Directory, FALSE, FALSE, NULL );
558             msi_free(file->TargetPath);
559
560             file->TargetPath = build_directory_name(2, dir, file->FileName);
561             msi_free(dir);
562         }
563     }
564     msi_free(path);
565
566     return ERROR_SUCCESS;
567 }
568
569 /***********************************************************************
570  * MsiSetTargetPathW  (MSI.@)
571  */
572 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, 
573                              LPCWSTR szFolderPath)
574 {
575     MSIPACKAGE *package;
576     UINT ret;
577
578     TRACE("%s %s\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
579
580     if ( !szFolder || !szFolderPath )
581         return ERROR_INVALID_PARAMETER;
582
583     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
584     if (!package)
585     {
586         HRESULT hr;
587         BSTR folder, path;
588         IWineMsiRemotePackage *remote_package;
589
590         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
591         if (!remote_package)
592             return ERROR_INVALID_HANDLE;
593
594         folder = SysAllocString( szFolder );
595         path = SysAllocString( szFolderPath );
596         if (!folder || !path)
597         {
598             SysFreeString(folder);
599             SysFreeString(path);
600             IWineMsiRemotePackage_Release( remote_package );
601             return ERROR_OUTOFMEMORY;
602         }
603
604         hr = IWineMsiRemotePackage_SetTargetPath( remote_package, folder, path );
605
606         SysFreeString(folder);
607         SysFreeString(path);
608         IWineMsiRemotePackage_Release( remote_package );
609
610         if (FAILED(hr))
611         {
612             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
613                 return HRESULT_CODE(hr);
614
615             return ERROR_FUNCTION_FAILED;
616         }
617
618         return ERROR_SUCCESS;
619     }
620
621     ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
622     msiobj_release( &package->hdr );
623     return ret;
624 }
625
626 /***********************************************************************
627  *           MsiGetMode    (MSI.@)
628  *
629  * Returns an internal installer state (if it is running in a mode iRunMode)
630  *
631  * PARAMS
632  *   hInstall    [I]  Handle to the installation
633  *   hRunMode    [I]  Checking run mode
634  *        MSIRUNMODE_ADMIN             Administrative mode
635  *        MSIRUNMODE_ADVERTISE         Advertisement mode
636  *        MSIRUNMODE_MAINTENANCE       Maintenance mode
637  *        MSIRUNMODE_ROLLBACKENABLED   Rollback is enabled
638  *        MSIRUNMODE_LOGENABLED        Log file is writing
639  *        MSIRUNMODE_OPERATIONS        Operations in progress??
640  *        MSIRUNMODE_REBOOTATEND       We need to reboot after installation completed
641  *        MSIRUNMODE_REBOOTNOW         We need to reboot to continue the installation
642  *        MSIRUNMODE_CABINET           Files from cabinet are installed
643  *        MSIRUNMODE_SOURCESHORTNAMES  Long names in source files is suppressed
644  *        MSIRUNMODE_TARGETSHORTNAMES  Long names in destination files is suppressed
645  *        MSIRUNMODE_RESERVED11        Reserved
646  *        MSIRUNMODE_WINDOWS9X         Running under Windows95/98
647  *        MSIRUNMODE_ZAWENABLED        Demand installation is supported
648  *        MSIRUNMODE_RESERVED14        Reserved
649  *        MSIRUNMODE_RESERVED15        Reserved
650  *        MSIRUNMODE_SCHEDULED         called from install script
651  *        MSIRUNMODE_ROLLBACK          called from rollback script
652  *        MSIRUNMODE_COMMIT            called from commit script
653  *
654  * RETURNS
655  *    In the state: TRUE
656  *    Not in the state: FALSE
657  *
658  */
659 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
660 {
661     MSIPACKAGE *package;
662     BOOL r = FALSE;
663
664     TRACE("%d %d\n", hInstall, iRunMode);
665
666     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
667     if (!package)
668     {
669         BOOL ret;
670         HRESULT hr;
671         IWineMsiRemotePackage *remote_package;
672
673         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
674         if (!remote_package)
675             return FALSE;
676
677         hr = IWineMsiRemotePackage_GetMode(remote_package, iRunMode, &ret);
678         IWineMsiRemotePackage_Release(remote_package);
679
680         if (hr == S_OK)
681             return ret;
682
683         return FALSE;
684     }
685
686     switch (iRunMode)
687     {
688     case MSIRUNMODE_WINDOWS9X:
689         if (GetVersion() & 0x80000000)
690             r = TRUE;
691         break;
692
693     case MSIRUNMODE_OPERATIONS:
694     case MSIRUNMODE_RESERVED11:
695     case MSIRUNMODE_RESERVED14:
696     case MSIRUNMODE_RESERVED15:
697         break;
698
699     case MSIRUNMODE_SCHEDULED:
700         r = package->scheduled_action_running;
701         break;
702
703     case MSIRUNMODE_ROLLBACK:
704         r = package->rollback_action_running;
705         break;
706
707     case MSIRUNMODE_COMMIT:
708         r = package->commit_action_running;
709         break;
710
711     case MSIRUNMODE_MAINTENANCE:
712         r = msi_get_property_int( package->db, szInstalled, 0 ) != 0;
713         break;
714
715     case MSIRUNMODE_REBOOTATEND:
716         r = package->need_reboot;
717         break;
718
719     case MSIRUNMODE_LOGENABLED:
720         r = (package->log_file != INVALID_HANDLE_VALUE);
721         break;
722
723     default:
724         FIXME("unimplemented run mode: %d\n", iRunMode);
725         r = TRUE;
726     }
727
728     msiobj_release( &package->hdr );
729     return r;
730 }
731
732 /***********************************************************************
733  *           MsiSetMode    (MSI.@)
734  */
735 UINT WINAPI MsiSetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode, BOOL fState)
736 {
737     MSIPACKAGE *package;
738     UINT r;
739
740     TRACE("%d %d %d\n", hInstall, iRunMode, fState);
741
742     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
743     if (!package)
744     {
745         HRESULT hr;
746         IWineMsiRemotePackage *remote_package;
747
748         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
749         if (!remote_package)
750             return FALSE;
751
752         hr = IWineMsiRemotePackage_SetMode( remote_package, iRunMode, fState );
753         IWineMsiRemotePackage_Release( remote_package );
754
755         if (FAILED(hr))
756         {
757             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
758                 return HRESULT_CODE(hr);
759
760             return ERROR_FUNCTION_FAILED;
761         }
762
763         return ERROR_SUCCESS;
764     }
765
766     switch (iRunMode)
767     {
768     case MSIRUNMODE_REBOOTATEND:
769         package->need_reboot = 1;
770         r = ERROR_SUCCESS;
771         break;
772
773     case MSIRUNMODE_REBOOTNOW:
774         FIXME("unimplemented run mode: %d\n", iRunMode);
775         r = ERROR_FUNCTION_FAILED;
776         break;
777
778     default:
779         r = ERROR_ACCESS_DENIED;
780     }
781
782     msiobj_release( &package->hdr );
783     return r;
784 }
785
786 /***********************************************************************
787  * MsiSetFeatureStateA (MSI.@)
788  *
789  * According to the docs, when this is called it immediately recalculates
790  * all the component states as well
791  */
792 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
793                                 INSTALLSTATE iState)
794 {
795     LPWSTR szwFeature = NULL;
796     UINT rc;
797
798     szwFeature = strdupAtoW(szFeature);
799
800     if (!szwFeature)
801         return ERROR_FUNCTION_FAILED;
802    
803     rc = MsiSetFeatureStateW(hInstall,szwFeature, iState); 
804
805     msi_free(szwFeature);
806
807     return rc;
808 }
809
810
811
812 UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
813                                 INSTALLSTATE iState)
814 {
815     UINT rc = ERROR_SUCCESS;
816     MSIFEATURE *feature, *child;
817
818     TRACE("%s %i\n", debugstr_w(szFeature), iState);
819
820     feature = get_loaded_feature(package,szFeature);
821     if (!feature)
822         return ERROR_UNKNOWN_FEATURE;
823
824     if (iState == INSTALLSTATE_ADVERTISED && 
825         feature->Attributes & msidbFeatureAttributesDisallowAdvertise)
826         return ERROR_FUNCTION_FAILED;
827
828     feature->ActionRequest = iState;
829
830     ACTION_UpdateComponentStates( package, feature );
831
832     /* update all the features that are children of this feature */
833     LIST_FOR_EACH_ENTRY( child, &package->features, MSIFEATURE, entry )
834     {
835         if (child->Feature_Parent && !strcmpW( szFeature, child->Feature_Parent ))
836             MSI_SetFeatureStateW(package, child->Feature, iState);
837     }
838     
839     return rc;
840 }
841
842 /***********************************************************************
843  * MsiSetFeatureStateW (MSI.@)
844  */
845 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
846                                 INSTALLSTATE iState)
847 {
848     MSIPACKAGE* package;
849     UINT rc = ERROR_SUCCESS;
850
851     TRACE("%s %i\n",debugstr_w(szFeature), iState);
852
853     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
854     if (!package)
855     {
856         HRESULT hr;
857         BSTR feature;
858         IWineMsiRemotePackage *remote_package;
859
860         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
861         if (!remote_package)
862             return ERROR_INVALID_HANDLE;
863
864         feature = SysAllocString(szFeature);
865         if (!feature)
866         {
867             IWineMsiRemotePackage_Release(remote_package);
868             return ERROR_OUTOFMEMORY;
869         }
870
871         hr = IWineMsiRemotePackage_SetFeatureState(remote_package, feature, iState);
872
873         SysFreeString(feature);
874         IWineMsiRemotePackage_Release(remote_package);
875
876         if (FAILED(hr))
877         {
878             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
879                 return HRESULT_CODE(hr);
880
881             return ERROR_FUNCTION_FAILED;
882         }
883
884         return ERROR_SUCCESS;
885     }
886
887     rc = MSI_SetFeatureStateW(package,szFeature,iState);
888
889     msiobj_release( &package->hdr );
890     return rc;
891 }
892
893 /***********************************************************************
894 * MsiGetFeatureStateA   (MSI.@)
895 */
896 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
897                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
898 {
899     LPWSTR szwFeature = NULL;
900     UINT rc;
901     
902     szwFeature = strdupAtoW(szFeature);
903
904     rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
905
906     msi_free( szwFeature);
907
908     return rc;
909 }
910
911 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPCWSTR szFeature,
912                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
913 {
914     MSIFEATURE *feature;
915
916     feature = get_loaded_feature(package,szFeature);
917     if (!feature)
918         return ERROR_UNKNOWN_FEATURE;
919
920     if (piInstalled)
921         *piInstalled = feature->Installed;
922
923     if (piAction)
924         *piAction = feature->ActionRequest;
925
926     TRACE("returning %i %i\n", feature->Installed, feature->ActionRequest);
927
928     return ERROR_SUCCESS;
929 }
930
931 /***********************************************************************
932 * MsiGetFeatureStateW   (MSI.@)
933 */
934 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
935                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
936 {
937     MSIPACKAGE* package;
938     UINT ret;
939
940     TRACE("%d %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled, piAction);
941
942     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
943     if (!package)
944     {
945         HRESULT hr;
946         BSTR feature;
947         IWineMsiRemotePackage *remote_package;
948
949         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
950         if (!remote_package)
951             return ERROR_INVALID_HANDLE;
952
953         feature = SysAllocString(szFeature);
954         if (!feature)
955         {
956             IWineMsiRemotePackage_Release(remote_package);
957             return ERROR_OUTOFMEMORY;
958         }
959
960         hr = IWineMsiRemotePackage_GetFeatureState(remote_package, feature,
961                                                    piInstalled, piAction);
962
963         SysFreeString(feature);
964         IWineMsiRemotePackage_Release(remote_package);
965
966         if (FAILED(hr))
967         {
968             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
969                 return HRESULT_CODE(hr);
970
971             return ERROR_FUNCTION_FAILED;
972         }
973
974         return ERROR_SUCCESS;
975     }
976
977     ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
978     msiobj_release( &package->hdr );
979     return ret;
980 }
981
982 /***********************************************************************
983 * MsiGetFeatureCostA   (MSI.@)
984 */
985 UINT WINAPI MsiGetFeatureCostA(MSIHANDLE hInstall, LPCSTR szFeature,
986                   MSICOSTTREE iCostTree, INSTALLSTATE iState, LPINT piCost)
987 {
988     LPWSTR szwFeature = NULL;
989     UINT rc;
990
991     szwFeature = strdupAtoW(szFeature);
992
993     rc = MsiGetFeatureCostW(hInstall, szwFeature, iCostTree, iState, piCost);
994
995     msi_free(szwFeature);
996
997     return rc;
998 }
999
1000 static INT feature_cost( MSIFEATURE *feature )
1001 {
1002     INT cost = 0;
1003     MSICOMPONENT *comp;
1004
1005     LIST_FOR_EACH_ENTRY( comp, &feature->Components, MSICOMPONENT, entry )
1006     {
1007         cost += comp->Cost;
1008     }
1009     return cost;
1010 }
1011
1012 UINT MSI_GetFeatureCost( MSIPACKAGE *package, MSIFEATURE *feature, MSICOSTTREE tree,
1013                          INSTALLSTATE state, LPINT cost )
1014 {
1015     TRACE("%s, %u, %d, %p\n", debugstr_w(feature->Feature), tree, state, cost);
1016
1017     *cost = 0;
1018     switch (tree)
1019     {
1020     case MSICOSTTREE_CHILDREN:
1021     {
1022         MSIFEATURE *child;
1023
1024         LIST_FOR_EACH_ENTRY( child, &feature->Children, MSIFEATURE, entry )
1025         {
1026             if (child->ActionRequest == state)
1027                 *cost += feature_cost( child );
1028         }
1029         break;
1030     }
1031     case MSICOSTTREE_PARENTS:
1032     {
1033         const WCHAR *feature_parent = feature->Feature_Parent;
1034         for (;;)
1035         {
1036             MSIFEATURE *parent = get_loaded_feature( package, feature_parent );
1037             if (!parent)
1038                 break;
1039
1040             if (parent->ActionRequest == state)
1041                 *cost += feature_cost( parent );
1042
1043             feature_parent = parent->Feature_Parent;
1044         }
1045         break;
1046     }
1047     case MSICOSTTREE_SELFONLY:
1048         if (feature->ActionRequest == state)
1049             *cost = feature_cost( feature );
1050         break;
1051
1052     default:
1053         WARN("unhandled cost tree %u\n", tree);
1054         break;
1055     }
1056
1057     *cost /= 512;
1058     return ERROR_SUCCESS;
1059 }
1060
1061 /***********************************************************************
1062 * MsiGetFeatureCostW   (MSI.@)
1063 */
1064 UINT WINAPI MsiGetFeatureCostW(MSIHANDLE hInstall, LPCWSTR szFeature,
1065                   MSICOSTTREE iCostTree, INSTALLSTATE iState, LPINT piCost)
1066 {
1067     MSIPACKAGE *package;
1068     MSIFEATURE *feature;
1069     UINT ret;
1070
1071     TRACE("(%d %s %i %i %p)\n", hInstall, debugstr_w(szFeature),
1072           iCostTree, iState, piCost);
1073
1074     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1075     if (!package)
1076     {
1077         HRESULT hr;
1078         BSTR feature;
1079         IWineMsiRemotePackage *remote_package;
1080
1081         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1082         if (!remote_package)
1083             return ERROR_INVALID_HANDLE;
1084
1085         feature = SysAllocString(szFeature);
1086         if (!feature)
1087         {
1088             IWineMsiRemotePackage_Release(remote_package);
1089             return ERROR_OUTOFMEMORY;
1090         }
1091
1092         hr = IWineMsiRemotePackage_GetFeatureCost(remote_package, feature,
1093                                                   iCostTree, iState, piCost);
1094
1095         SysFreeString(feature);
1096         IWineMsiRemotePackage_Release(remote_package);
1097
1098         if (FAILED(hr))
1099         {
1100             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1101                 return HRESULT_CODE(hr);
1102
1103             return ERROR_FUNCTION_FAILED;
1104         }
1105
1106         return ERROR_SUCCESS;
1107     }
1108
1109     feature = get_loaded_feature(package, szFeature);
1110
1111     if (feature)
1112         ret = MSI_GetFeatureCost(package, feature, iCostTree, iState, piCost);
1113     else
1114         ret = ERROR_UNKNOWN_FEATURE;
1115
1116     msiobj_release( &package->hdr );
1117     return ret;
1118 }
1119
1120 /***********************************************************************
1121  * MsiSetComponentStateA (MSI.@)
1122  */
1123 UINT WINAPI MsiSetComponentStateA(MSIHANDLE hInstall, LPCSTR szComponent,
1124                                   INSTALLSTATE iState)
1125 {
1126     UINT rc;
1127     LPWSTR szwComponent = strdupAtoW(szComponent);
1128
1129     rc = MsiSetComponentStateW(hInstall, szwComponent, iState);
1130
1131     msi_free(szwComponent);
1132
1133     return rc;
1134 }
1135
1136 /***********************************************************************
1137  * MsiGetComponentStateA (MSI.@)
1138  */
1139 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPCSTR szComponent,
1140                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
1141 {
1142     LPWSTR szwComponent= NULL;
1143     UINT rc;
1144     
1145     szwComponent= strdupAtoW(szComponent);
1146
1147     rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
1148
1149     msi_free( szwComponent);
1150
1151     return rc;
1152 }
1153
1154 static UINT MSI_SetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
1155                                    INSTALLSTATE iState)
1156 {
1157     MSICOMPONENT *comp;
1158
1159     TRACE("%p %s %d\n", package, debugstr_w(szComponent), iState);
1160
1161     comp = get_loaded_component(package, szComponent);
1162     if (!comp)
1163         return ERROR_UNKNOWN_COMPONENT;
1164
1165     if (comp->Enabled)
1166         comp->Action = iState;
1167
1168     return ERROR_SUCCESS;
1169 }
1170
1171 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
1172                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
1173 {
1174     MSICOMPONENT *comp;
1175
1176     TRACE("%p %s %p %p\n", package, debugstr_w(szComponent),
1177            piInstalled, piAction);
1178
1179     comp = get_loaded_component(package,szComponent);
1180     if (!comp)
1181         return ERROR_UNKNOWN_COMPONENT;
1182
1183     if (piInstalled)
1184     {
1185         if (comp->Enabled)
1186             *piInstalled = comp->Installed;
1187         else
1188             *piInstalled = INSTALLSTATE_UNKNOWN;
1189     }
1190
1191     if (piAction)
1192     {
1193         if (comp->Enabled)
1194             *piAction = comp->Action;
1195         else
1196             *piAction = INSTALLSTATE_UNKNOWN;
1197     }
1198
1199     TRACE("states (%i, %i)\n", comp->Installed, comp->Action );
1200     return ERROR_SUCCESS;
1201 }
1202
1203 /***********************************************************************
1204  * MsiSetComponentStateW (MSI.@)
1205  */
1206 UINT WINAPI MsiSetComponentStateW(MSIHANDLE hInstall, LPCWSTR szComponent,
1207                                   INSTALLSTATE iState)
1208 {
1209     MSIPACKAGE* package;
1210     UINT ret;
1211
1212     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1213     if (!package)
1214     {
1215         HRESULT hr;
1216         BSTR component;
1217         IWineMsiRemotePackage *remote_package;
1218
1219         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1220         if (!remote_package)
1221             return ERROR_INVALID_HANDLE;
1222
1223         component = SysAllocString(szComponent);
1224         if (!component)
1225         {
1226             IWineMsiRemotePackage_Release(remote_package);
1227             return ERROR_OUTOFMEMORY;
1228         }
1229
1230         hr = IWineMsiRemotePackage_SetComponentState(remote_package, component, iState);
1231
1232         SysFreeString(component);
1233         IWineMsiRemotePackage_Release(remote_package);
1234
1235         if (FAILED(hr))
1236         {
1237             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1238                 return HRESULT_CODE(hr);
1239
1240             return ERROR_FUNCTION_FAILED;
1241         }
1242
1243         return ERROR_SUCCESS;
1244     }
1245
1246     ret = MSI_SetComponentStateW(package, szComponent, iState);
1247     msiobj_release(&package->hdr);
1248     return ret;
1249 }
1250
1251 /***********************************************************************
1252  * MsiGetComponentStateW (MSI.@)
1253  */
1254 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPCWSTR szComponent,
1255                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
1256 {
1257     MSIPACKAGE* package;
1258     UINT ret;
1259
1260     TRACE("%d %s %p %p\n", hInstall, debugstr_w(szComponent),
1261            piInstalled, piAction);
1262
1263     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1264     if (!package)
1265     {
1266         HRESULT hr;
1267         BSTR component;
1268         IWineMsiRemotePackage *remote_package;
1269
1270         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1271         if (!remote_package)
1272             return ERROR_INVALID_HANDLE;
1273
1274         component = SysAllocString(szComponent);
1275         if (!component)
1276         {
1277             IWineMsiRemotePackage_Release(remote_package);
1278             return ERROR_OUTOFMEMORY;
1279         }
1280
1281         hr = IWineMsiRemotePackage_GetComponentState(remote_package, component,
1282                                                      piInstalled, piAction);
1283
1284         SysFreeString(component);
1285         IWineMsiRemotePackage_Release(remote_package);
1286
1287         if (FAILED(hr))
1288         {
1289             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1290                 return HRESULT_CODE(hr);
1291
1292             return ERROR_FUNCTION_FAILED;
1293         }
1294
1295         return ERROR_SUCCESS;
1296     }
1297
1298     ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
1299     msiobj_release( &package->hdr );
1300     return ret;
1301 }
1302
1303 /***********************************************************************
1304  * MsiGetLanguage (MSI.@)
1305  */
1306 LANGID WINAPI MsiGetLanguage(MSIHANDLE hInstall)
1307 {
1308     MSIPACKAGE* package;
1309     LANGID langid;
1310     static const WCHAR szProductLanguage[] =
1311         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
1312     
1313     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1314     if (!package)
1315     {
1316         HRESULT hr;
1317         LANGID lang;
1318         IWineMsiRemotePackage *remote_package;
1319
1320         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1321         if (!remote_package)
1322             return ERROR_INVALID_HANDLE;
1323
1324         hr = IWineMsiRemotePackage_GetLanguage(remote_package, &lang);
1325
1326         if (SUCCEEDED(hr))
1327             return lang;
1328
1329         return 0;
1330     }
1331
1332     langid = msi_get_property_int( package->db, szProductLanguage, 0 );
1333     msiobj_release( &package->hdr );
1334     return langid;
1335 }
1336
1337 UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel )
1338 {
1339     static const WCHAR szInstallLevel[] = {
1340         'I','N','S','T','A','L','L','L','E','V','E','L',0 };
1341     static const WCHAR fmt[] = { '%','d',0 };
1342     WCHAR level[6];
1343     UINT r;
1344
1345     TRACE("%p %i\n", package, iInstallLevel);
1346
1347     if (iInstallLevel > 32767)
1348         return ERROR_INVALID_PARAMETER;
1349
1350     if (iInstallLevel < 1)
1351         return MSI_SetFeatureStates( package );
1352
1353     sprintfW( level, fmt, iInstallLevel );
1354     r = msi_set_property( package->db, szInstallLevel, level );
1355     if ( r == ERROR_SUCCESS )
1356         r = MSI_SetFeatureStates( package );
1357
1358     return r;
1359 }
1360
1361 /***********************************************************************
1362  * MsiSetInstallLevel (MSI.@)
1363  */
1364 UINT WINAPI MsiSetInstallLevel(MSIHANDLE hInstall, int iInstallLevel)
1365 {
1366     MSIPACKAGE* package;
1367     UINT r;
1368
1369     TRACE("%d %i\n", hInstall, iInstallLevel);
1370
1371     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
1372     if (!package)
1373     {
1374         HRESULT hr;
1375         IWineMsiRemotePackage *remote_package;
1376
1377         remote_package = (IWineMsiRemotePackage *)msi_get_remote(hInstall);
1378         if (!remote_package)
1379             return ERROR_INVALID_HANDLE;
1380
1381         hr = IWineMsiRemotePackage_SetInstallLevel(remote_package, iInstallLevel);
1382
1383         IWineMsiRemotePackage_Release(remote_package);
1384
1385         if (FAILED(hr))
1386         {
1387             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1388                 return HRESULT_CODE(hr);
1389
1390             return ERROR_FUNCTION_FAILED;
1391         }
1392
1393         return ERROR_SUCCESS;
1394     }
1395
1396     r = MSI_SetInstallLevel( package, iInstallLevel );
1397
1398     msiobj_release( &package->hdr );
1399
1400     return r;
1401 }
1402
1403 /***********************************************************************
1404  * MsiGetFeatureValidStatesW (MSI.@)
1405  */
1406 UINT WINAPI MsiGetFeatureValidStatesW(MSIHANDLE hInstall, LPCWSTR szFeature,
1407                   LPDWORD pInstallState)
1408 {
1409     if(pInstallState) *pInstallState = 1<<INSTALLSTATE_LOCAL;
1410     FIXME("%d %s %p stub returning %d\n",
1411         hInstall, debugstr_w(szFeature), pInstallState, pInstallState ? *pInstallState : 0);
1412
1413     return ERROR_SUCCESS;
1414 }
1415
1416 /***********************************************************************
1417  * MsiGetFeatureValidStatesA (MSI.@)
1418  */
1419 UINT WINAPI MsiGetFeatureValidStatesA(MSIHANDLE hInstall, LPCSTR szFeature,
1420                   LPDWORD pInstallState)
1421 {
1422     UINT ret;
1423     LPWSTR szwFeature = strdupAtoW(szFeature);
1424
1425     ret = MsiGetFeatureValidStatesW(hInstall, szwFeature, pInstallState);
1426
1427     msi_free(szwFeature);
1428
1429     return ret;
1430 }