2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004 Aric Stewart for CodeWeavers
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.
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.
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
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
38 #include "wine/debug.h"
42 #include "msvcrt/fcntl.h"
49 #include "wine/unicode.h"
52 #define CUSTOM_ACTION_TYPE_MASK 0x3F
54 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
56 typedef struct tagMSIFEATURE
59 WCHAR Feature_Parent
[96];
61 WCHAR Description
[0x100];
67 INSTALLSTATE Installed
;
68 INSTALLSTATE ActionRequest
;
72 INT Components
[1024]; /* yes hardcoded limit.... I am bad */
76 typedef struct tagMSICOMPONENT
79 WCHAR ComponentId
[96];
82 WCHAR Condition
[0x100];
85 INSTALLSTATE Installed
;
86 INSTALLSTATE ActionRequest
;
93 typedef struct tagMSIFOLDER
99 LPWSTR ResolvedTarget
;
100 LPWSTR ResolvedSource
;
101 LPWSTR Property
; /* initially set property */
104 /* 0 = uninitialized */
106 /* 2 = created remove if empty */
107 /* 3 = created persist if empty */
112 typedef struct tagMSIFILE
124 /* 0 = uninitialize */
125 /* 1 = not present */
126 /* 2 = present but replace */
127 /* 3 = present do not replace */
137 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
);
138 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
);
140 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
);
141 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
);
143 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
);
144 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
);
145 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
);
146 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
);
147 static UINT
ACTION_FileCost(MSIPACKAGE
*package
);
148 static UINT
ACTION_InstallFiles(MSIPACKAGE
*package
);
149 static UINT
ACTION_DuplicateFiles(MSIPACKAGE
*package
);
150 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
);
151 static UINT
ACTION_CustomAction(MSIPACKAGE
*package
,const WCHAR
*action
);
152 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
);
153 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
);
154 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
);
155 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
);
156 static UINT
ACTION_RegisterClassInfo(MSIPACKAGE
*package
);
157 static UINT
ACTION_RegisterProgIdInfo(MSIPACKAGE
*package
);
158 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
);
159 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
);
161 static UINT
HANDLE_CustomType1(MSIPACKAGE
*package
, const LPWSTR source
,
162 const LPWSTR target
, const INT type
);
163 static UINT
HANDLE_CustomType2(MSIPACKAGE
*package
, const LPWSTR source
,
164 const LPWSTR target
, const INT type
);
165 static UINT
HANDLE_CustomType18(MSIPACKAGE
*package
, const LPWSTR source
,
166 const LPWSTR target
, const INT type
);
167 static UINT
HANDLE_CustomType50(MSIPACKAGE
*package
, const LPWSTR source
,
168 const LPWSTR target
, const INT type
);
169 static UINT
HANDLE_CustomType34(MSIPACKAGE
*package
, const LPWSTR source
,
170 const LPWSTR target
, const INT type
);
172 static DWORD
deformat_string(MSIPACKAGE
*package
, WCHAR
* ptr
,WCHAR
** data
);
173 static LPWSTR
resolve_folder(MSIPACKAGE
*package
, LPCWSTR name
,
174 BOOL source
, BOOL set_prop
, MSIFOLDER
**folder
);
176 static int track_tempfile(MSIPACKAGE
*package
, LPCWSTR name
, LPCWSTR path
);
179 * consts and values used
181 static const WCHAR cszSourceDir
[] = {'S','o','u','r','c','e','D','i','r',0};
182 static const WCHAR cszRootDrive
[] = {'R','O','O','T','D','R','I','V','E',0};
183 static const WCHAR cszTargetDir
[] = {'T','A','R','G','E','T','D','I','R',0};
184 static const WCHAR cszTempFolder
[]= {'T','e','m','p','F','o','l','d','e','r',0};
185 static const WCHAR cszDatabase
[]={'D','A','T','A','B','A','S','E',0};
186 static const WCHAR c_collen
[] = {'C',':','\\',0};
188 static const WCHAR cszlsb
[]={'[',0};
189 static const WCHAR cszrsb
[]={']',0};
190 static const WCHAR cszbs
[]={'\\',0};
192 const static WCHAR szCreateFolders
[] =
193 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
194 const static WCHAR szCostFinalize
[] =
195 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
196 const static WCHAR szInstallFiles
[] =
197 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
198 const static WCHAR szDuplicateFiles
[] =
199 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
200 const static WCHAR szWriteRegistryValues
[] =
201 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
202 const static WCHAR szCostInitialize
[] =
203 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
204 const static WCHAR szFileCost
[] = {'F','i','l','e','C','o','s','t',0};
205 const static WCHAR szInstallInitialize
[] =
206 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
207 const static WCHAR szInstallValidate
[] =
208 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
209 const static WCHAR szLaunchConditions
[] =
210 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
211 const static WCHAR szProcessComponents
[] =
212 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
213 const static WCHAR szRegisterTypeLibraries
[] =
214 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r',
216 const static WCHAR szRegisterClassInfo
[] =
217 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
218 const static WCHAR szRegisterProgIdInfo
[] =
219 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
220 const static WCHAR szCreateShortcuts
[] =
221 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
222 const static WCHAR szPublishProduct
[] =
223 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
225 /********************************************************
226 * helper functions to get around current HACKS and such
227 ********************************************************/
228 inline static void reduce_to_longfilename(WCHAR
* filename
)
230 LPWSTR p
= strchrW(filename
,'|');
232 memmove(filename
, p
+1, (strlenW(p
+1)+1)*sizeof(WCHAR
));
235 inline static char *strdupWtoA( const WCHAR
*str
)
240 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
242 if ((ret
= HeapAlloc( GetProcessHeap(), 0, len
)))
243 WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
248 inline static WCHAR
*strdupAtoW( const char *str
)
253 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
254 if ((ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
255 MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
260 static LPWSTR
dupstrW(LPCWSTR src
)
263 if (!src
) return NULL
;
264 dest
= HeapAlloc(GetProcessHeap(), 0, (strlenW(src
)+1)*sizeof(WCHAR
));
269 inline static WCHAR
*load_dynamic_stringW(MSIRECORD
*row
, INT index
)
276 if (MSI_RecordIsNull(row
,index
))
279 rc
= MSI_RecordGetStringW(row
,index
,NULL
,&sz
);
281 /* having an empty string is different than NULL */
284 ret
= HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR
));
290 ret
= HeapAlloc(GetProcessHeap(),0,sz
* sizeof (WCHAR
));
291 rc
= MSI_RecordGetStringW(row
,index
,ret
,&sz
);
292 if (rc
!=ERROR_SUCCESS
)
294 ERR("Unable to load dynamic string\n");
295 HeapFree(GetProcessHeap(), 0, ret
);
301 inline static LPWSTR
load_dynamic_property(MSIPACKAGE
*package
, LPCWSTR prop
,
308 r
= MSI_GetPropertyW(package
, prop
, NULL
, &sz
);
309 if (r
!= ERROR_SUCCESS
&& r
!= ERROR_MORE_DATA
)
316 str
= HeapAlloc(GetProcessHeap(),0,sz
*sizeof(WCHAR
));
317 r
= MSI_GetPropertyW(package
, prop
, str
, &sz
);
318 if (r
!= ERROR_SUCCESS
)
320 HeapFree(GetProcessHeap(),0,str
);
328 inline static int get_loaded_component(MSIPACKAGE
* package
, LPCWSTR Component
)
333 for (i
= 0; i
< package
->loaded_components
; i
++)
335 if (strcmpW(Component
,package
->components
[i
].Component
)==0)
344 inline static int get_loaded_feature(MSIPACKAGE
* package
, LPCWSTR Feature
)
349 for (i
= 0; i
< package
->loaded_features
; i
++)
351 if (strcmpW(Feature
,package
->features
[i
].Feature
)==0)
360 inline static int get_loaded_file(MSIPACKAGE
* package
, LPCWSTR file
)
365 for (i
= 0; i
< package
->loaded_files
; i
++)
367 if (strcmpW(file
,package
->files
[i
].File
)==0)
377 static int track_tempfile(MSIPACKAGE
*package
, LPCWSTR name
, LPCWSTR path
)
385 for (i
=0; i
< package
->loaded_files
; i
++)
386 if (strcmpW(package
->files
[i
].File
,name
)==0)
389 index
= package
->loaded_files
;
390 package
->loaded_files
++;
391 if (package
->loaded_files
== 1)
392 package
->files
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE
));
394 package
->files
= HeapReAlloc(GetProcessHeap(),0,
395 package
->files
, package
->loaded_files
* sizeof(MSIFILE
));
397 memset(&package
->files
[index
],0,sizeof(MSIFILE
));
399 package
->files
[index
].File
= dupstrW(name
);
400 package
->files
[index
].TargetPath
= dupstrW(path
);
401 package
->files
[index
].Temporary
= TRUE
;
403 TRACE("Tracking tempfile (%s)\n",debugstr_w(package
->files
[index
].File
));
408 void ACTION_remove_tracked_tempfiles(MSIPACKAGE
* package
)
415 for (i
= 0; i
< package
->loaded_files
; i
++)
417 if (package
->files
[i
].Temporary
)
419 TRACE("Cleaning up %s\n",debugstr_w(package
->files
[i
].TargetPath
));
420 DeleteFileW(package
->files
[i
].TargetPath
);
426 /* Called when the package is being closed */
427 extern void ACTION_free_package_structures( MSIPACKAGE
* package
)
431 TRACE("Freeing package action data\n");
433 /* No dynamic buffers in features */
434 if (package
->features
&& package
->loaded_features
> 0)
435 HeapFree(GetProcessHeap(),0,package
->features
);
437 for (i
= 0; i
< package
->loaded_folders
; i
++)
439 HeapFree(GetProcessHeap(),0,package
->folders
[i
].Directory
);
440 HeapFree(GetProcessHeap(),0,package
->folders
[i
].TargetDefault
);
441 HeapFree(GetProcessHeap(),0,package
->folders
[i
].SourceDefault
);
442 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedTarget
);
443 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedSource
);
444 HeapFree(GetProcessHeap(),0,package
->folders
[i
].Property
);
446 if (package
->folders
&& package
->loaded_folders
> 0)
447 HeapFree(GetProcessHeap(),0,package
->folders
);
449 /* no dynamic buffers in components */
450 if (package
->components
&& package
->loaded_components
> 0)
451 HeapFree(GetProcessHeap(),0,package
->components
);
453 for (i
= 0; i
< package
->loaded_files
; i
++)
455 HeapFree(GetProcessHeap(),0,package
->files
[i
].File
);
456 HeapFree(GetProcessHeap(),0,package
->files
[i
].FileName
);
457 HeapFree(GetProcessHeap(),0,package
->files
[i
].Version
);
458 HeapFree(GetProcessHeap(),0,package
->files
[i
].Language
);
459 HeapFree(GetProcessHeap(),0,package
->files
[i
].SourcePath
);
460 HeapFree(GetProcessHeap(),0,package
->files
[i
].TargetPath
);
463 if (package
->files
&& package
->loaded_files
> 0)
464 HeapFree(GetProcessHeap(),0,package
->files
);
467 static UINT
ACTION_OpenQuery( MSIDATABASE
*db
, MSIQUERY
**view
, LPCWSTR fmt
, ... )
474 /* figure out how much space we need to allocate */
476 sz
= strlenW(fmt
) + 1;
486 case 's': /* a string */
487 sz
+= strlenW(va_arg(va
,LPCWSTR
));
490 case 'i': /* an integer -2147483648 seems to be longest */
492 (void)va_arg(va
,int);
494 case '%': /* a single % - leave it alone */
497 FIXME("Unhandled character type %c\n",*p
);
503 /* construct the string */
504 szQuery
= HeapAlloc(GetProcessHeap(), 0, sz
*sizeof(WCHAR
));
506 vsnprintfW(szQuery
, sz
, fmt
, va
);
509 /* perform the query */
510 rc
= MSI_DatabaseOpenViewW(db
, szQuery
, view
);
511 HeapFree(GetProcessHeap(), 0, szQuery
);
515 static void ui_progress(MSIPACKAGE
*package
, int a
, int b
, int c
, int d
)
519 row
= MSI_CreateRecord(4);
520 MSI_RecordSetInteger(row
,1,a
);
521 MSI_RecordSetInteger(row
,2,b
);
522 MSI_RecordSetInteger(row
,3,c
);
523 MSI_RecordSetInteger(row
,4,d
);
524 MSI_ProcessMessage(package
, INSTALLMESSAGE_PROGRESS
, row
);
525 msiobj_release(&row
->hdr
);
528 static void ui_actiondata(MSIPACKAGE
*package
, LPCWSTR action
, MSIRECORD
* record
)
530 static const WCHAR Query_t
[] =
531 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
532 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
533 ' ','\'','%','s','\'',0};
540 if (!package
->LastAction
|| strcmpW(package
->LastAction
,action
))
542 rc
= ACTION_OpenQuery(package
->db
, &view
, Query_t
, action
);
543 if (rc
!= ERROR_SUCCESS
)
546 rc
= MSI_ViewExecute(view
, 0);
547 if (rc
!= ERROR_SUCCESS
)
552 rc
= MSI_ViewFetch(view
,&row
);
553 if (rc
!= ERROR_SUCCESS
)
559 if (MSI_RecordIsNull(row
,3))
561 msiobj_release(&row
->hdr
);
563 msiobj_release(&view
->hdr
);
567 /* update the cached actionformat */
568 if (package
->ActionFormat
)
569 HeapFree(GetProcessHeap(),0,package
->ActionFormat
);
570 package
->ActionFormat
= load_dynamic_stringW(row
,3);
572 if (package
->LastAction
)
573 HeapFree(GetProcessHeap(),0,package
->LastAction
);
574 package
->LastAction
= dupstrW(action
);
576 msiobj_release(&row
->hdr
);
578 msiobj_release(&view
->hdr
);
582 ptr
= package
->ActionFormat
;
590 ptr2
= strchrW(ptr
,'[');
593 strncpyW(tmp
,ptr
,ptr2
-ptr
);
595 strcatW(message
,tmp
);
598 data
= load_dynamic_stringW(record
,field
);
601 strcatW(message
,data
);
602 HeapFree(GetProcessHeap(),0,data
);
604 ptr
=strchrW(ptr2
,']');
609 strcatW(message
,ptr
);
614 row
= MSI_CreateRecord(1);
615 MSI_RecordSetStringW(row
,1,message
);
617 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONDATA
, row
);
618 msiobj_release(&row
->hdr
);
622 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
624 static const WCHAR template_s
[]=
625 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ','%','s','.',0};
626 static const WCHAR format
[] =
627 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
628 static const WCHAR Query_t
[] =
629 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
630 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
631 ' ','\'','%','s','\'',0};
637 WCHAR
*ActionText
=NULL
;
639 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
641 rc
= ACTION_OpenQuery(package
->db
, &view
, Query_t
, action
);
642 if (rc
!= ERROR_SUCCESS
)
644 rc
= MSI_ViewExecute(view
, 0);
645 if (rc
!= ERROR_SUCCESS
)
648 msiobj_release(&view
->hdr
);
651 rc
= MSI_ViewFetch(view
,&row
);
652 if (rc
!= ERROR_SUCCESS
)
655 msiobj_release(&view
->hdr
);
659 ActionText
= load_dynamic_stringW(row
,2);
660 msiobj_release(&row
->hdr
);
662 msiobj_release(&view
->hdr
);
664 sprintfW(message
,template_s
,timet
,action
,ActionText
);
666 row
= MSI_CreateRecord(1);
667 MSI_RecordSetStringW(row
,1,message
);
669 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
670 msiobj_release(&row
->hdr
);
671 HeapFree(GetProcessHeap(),0,ActionText
);
674 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
678 static const WCHAR template_s
[]=
679 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ','%','s',
681 static const WCHAR template_e
[]=
682 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ','%','s',
683 '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ','%','i','.',0};
684 static const WCHAR format
[] =
685 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
689 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
691 sprintfW(message
,template_s
,timet
,action
);
693 sprintfW(message
,template_e
,timet
,action
,rc
);
695 row
= MSI_CreateRecord(1);
696 MSI_RecordSetStringW(row
,1,message
);
698 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
699 msiobj_release(&row
->hdr
);
703 * build_directory_name()
705 * This function is to save messing round with directory names
706 * It handles adding backslashes between path segments,
707 * and can add \ at the end of the directory name if told to.
709 * It takes a variable number of arguments.
710 * It always allocates a new string for the result, so make sure
711 * to free the return value when finished with it.
713 * The first arg is the number of path segments that follow.
714 * The arguments following count are a list of path segments.
715 * A path segment may be NULL.
717 * Path segments will be added with a \ seperating them.
718 * A \ will not be added after the last segment, however if the
719 * last segment is NULL, then the last character will be a \
722 static LPWSTR
build_directory_name(DWORD count
, ...)
729 for(i
=0; i
<count
; i
++)
731 LPCWSTR str
= va_arg(va
,LPCWSTR
);
733 sz
+= strlenW(str
) + 1;
737 dir
= HeapAlloc(GetProcessHeap(), 0, sz
*sizeof(WCHAR
));
741 for(i
=0; i
<count
; i
++)
743 LPCWSTR str
= va_arg(va
,LPCWSTR
);
747 if( ((i
+1)!=count
) && dir
[strlenW(dir
)-1]!='\\')
754 /****************************************************
755 * TOP level entry points
756 *****************************************************/
758 UINT
ACTION_DoTopLevelINSTALL(MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
759 LPCWSTR szCommandLine
)
764 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
768 LPWSTR p
, check
, path
;
770 path
= dupstrW(szPackagePath
);
771 p
= strrchrW(path
,'\\');
778 check
= load_dynamic_property(package
, cszSourceDir
,NULL
);
780 MSI_SetPropertyW(package
, cszSourceDir
, path
);
782 HeapFree(GetProcessHeap(), 0, check
);
784 HeapFree(GetProcessHeap(), 0, path
);
790 ptr
= (LPWSTR
)szCommandLine
;
797 TRACE("Looking at %s\n",debugstr_w(ptr
));
799 ptr2
= strchrW(ptr
,'=');
805 while (*ptr
== ' ') ptr
++;
807 prop
= HeapAlloc(GetProcessHeap(),0,(len
+1)*sizeof(WCHAR
));
808 strncpyW(prop
,ptr
,len
);
814 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
827 val
= HeapAlloc(GetProcessHeap(),0,(len
+1)*sizeof(WCHAR
));
828 strncpyW(val
,ptr2
,len
);
831 if (strlenW(prop
) > 0)
833 TRACE("Found commandline property (%s) = (%s)\n",
834 debugstr_w(prop
), debugstr_w(val
));
835 MSI_SetPropertyW(package
,prop
,val
);
837 HeapFree(GetProcessHeap(),0,val
);
838 HeapFree(GetProcessHeap(),0,prop
);
845 if (MSI_GetPropertyW(package
,szUILevel
,buffer
,&sz
) == ERROR_SUCCESS
)
847 if (atoiW(buffer
) >= INSTALLUILEVEL_REDUCED
)
849 rc
= ACTION_ProcessUISequence(package
);
850 if (rc
== ERROR_SUCCESS
)
851 rc
= ACTION_ProcessExecSequence(package
,TRUE
);
854 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
857 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
859 /* process the ending type action */
860 if (rc
== ERROR_SUCCESS
)
861 rc
= ACTION_PerformActionSequence(package
,-1);
862 else if (rc
== ERROR_FUNCTION_FAILED
)
863 rc
= ACTION_PerformActionSequence(package
,-3);
868 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
)
875 static const WCHAR ExecSeqQuery
[] = {
876 's','e','l','e','c','t',' ','*',' ',
878 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
879 'S','e','q','u','e','n','c','e',' ',
880 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
883 rc
= ACTION_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
885 if (rc
== ERROR_SUCCESS
)
887 rc
= MSI_ViewExecute(view
, 0);
889 if (rc
!= ERROR_SUCCESS
)
892 msiobj_release(&view
->hdr
);
896 TRACE("Running the actions\n");
898 rc
= MSI_ViewFetch(view
,&row
);
899 if (rc
!= ERROR_SUCCESS
)
905 /* check conditions */
906 if (!MSI_RecordIsNull(row
,2))
909 cond
= load_dynamic_stringW(row
,2);
913 /* this is a hack to skip errors in the condition code */
914 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
916 HeapFree(GetProcessHeap(),0,cond
);
917 msiobj_release(&row
->hdr
);
921 HeapFree(GetProcessHeap(),0,cond
);
926 rc
= MSI_RecordGetStringW(row
,1,buffer
,&sz
);
927 if (rc
!= ERROR_SUCCESS
)
929 ERR("Error is %x\n",rc
);
930 msiobj_release(&row
->hdr
);
934 rc
= ACTION_PerformAction(package
,buffer
);
935 msiobj_release(&row
->hdr
);
938 msiobj_release(&view
->hdr
);
946 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
950 static const WCHAR ExecSeqQuery
[] = {
951 's','e','l','e','c','t',' ','*',' ',
953 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
954 'S','e','q','u','e','n','c','e',' ',
955 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
956 '>',' ','%','i',' ','o','r','d','e','r',' ',
957 'b','y',' ','S','e','q','u','e','n','c','e',0 };
959 static const WCHAR IVQuery
[] = {
960 's','e','l','e','c','t',' ','S','e','q','u','e','n','c','e',' ',
961 'f','r','o','m',' ','I','n','s','t','a','l','l',
962 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e',' ',
963 'w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',' ',
964 '`','I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`',
968 /* get the sequence number */
971 rc
= MSI_DatabaseOpenViewW(package
->db
, IVQuery
, &view
);
972 if (rc
!= ERROR_SUCCESS
)
974 rc
= MSI_ViewExecute(view
, 0);
975 if (rc
!= ERROR_SUCCESS
)
978 msiobj_release(&view
->hdr
);
981 rc
= MSI_ViewFetch(view
,&row
);
982 if (rc
!= ERROR_SUCCESS
)
985 msiobj_release(&view
->hdr
);
988 seq
= MSI_RecordGetInteger(row
,1);
989 msiobj_release(&row
->hdr
);
991 msiobj_release(&view
->hdr
);
994 rc
= ACTION_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
995 if (rc
== ERROR_SUCCESS
)
997 rc
= MSI_ViewExecute(view
, 0);
999 if (rc
!= ERROR_SUCCESS
)
1001 MSI_ViewClose(view
);
1002 msiobj_release(&view
->hdr
);
1006 TRACE("Running the actions\n");
1010 WCHAR buffer
[0x100];
1013 rc
= MSI_ViewFetch(view
,&row
);
1014 if (rc
!= ERROR_SUCCESS
)
1020 /* check conditions */
1021 if (!MSI_RecordIsNull(row
,2))
1024 cond
= load_dynamic_stringW(row
,2);
1028 /* this is a hack to skip errors in the condition code */
1029 if (MSI_EvaluateConditionW(package
, cond
) ==
1032 HeapFree(GetProcessHeap(),0,cond
);
1033 msiobj_release(&row
->hdr
);
1037 HeapFree(GetProcessHeap(),0,cond
);
1042 rc
= MSI_RecordGetStringW(row
,1,buffer
,&sz
);
1043 if (rc
!= ERROR_SUCCESS
)
1045 ERR("Error is %x\n",rc
);
1046 msiobj_release(&row
->hdr
);
1050 rc
= ACTION_PerformAction(package
,buffer
);
1052 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
1055 if (rc
!= ERROR_SUCCESS
)
1057 ERR("Execution halted due to error (%i)\n",rc
);
1058 msiobj_release(&row
->hdr
);
1062 msiobj_release(&row
->hdr
);
1065 MSI_ViewClose(view
);
1066 msiobj_release(&view
->hdr
);
1074 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
1078 static const WCHAR ExecSeqQuery
[] = {
1079 's','e','l','e','c','t',' ','*',' ',
1080 'f','r','o','m',' ','I','n','s','t','a','l','l',
1081 'U','I','S','e','q','u','e','n','c','e',' ',
1082 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', '>',' ','0',' ',
1083 'o','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e',0};
1085 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1087 if (rc
== ERROR_SUCCESS
)
1089 rc
= MSI_ViewExecute(view
, 0);
1091 if (rc
!= ERROR_SUCCESS
)
1093 MSI_ViewClose(view
);
1094 msiobj_release(&view
->hdr
);
1098 TRACE("Running the actions \n");
1102 WCHAR buffer
[0x100];
1104 MSIRECORD
* row
= 0;
1106 rc
= MSI_ViewFetch(view
,&row
);
1107 if (rc
!= ERROR_SUCCESS
)
1113 /* check conditions */
1114 if (!MSI_RecordIsNull(row
,2))
1117 cond
= load_dynamic_stringW(row
,2);
1121 /* this is a hack to skip errors in the condition code */
1122 if (MSI_EvaluateConditionW(package
, cond
) ==
1125 HeapFree(GetProcessHeap(),0,cond
);
1126 msiobj_release(&row
->hdr
);
1130 HeapFree(GetProcessHeap(),0,cond
);
1135 rc
= MSI_RecordGetStringW(row
,1,buffer
,&sz
);
1136 if (rc
!= ERROR_SUCCESS
)
1138 ERR("Error is %x\n",rc
);
1139 msiobj_release(&row
->hdr
);
1143 rc
= ACTION_PerformAction(package
,buffer
);
1145 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
1148 if (rc
!= ERROR_SUCCESS
)
1150 ERR("Execution halted due to error (%i)\n",rc
);
1151 msiobj_release(&row
->hdr
);
1155 msiobj_release(&row
->hdr
);
1158 MSI_ViewClose(view
);
1159 msiobj_release(&view
->hdr
);
1166 /********************************************************
1167 * ACTION helper functions and functions that perform the actions
1168 *******************************************************/
1171 * Alot of actions are really important even if they don't do anything
1172 * explicit.. Lots of properties are set at the beginning of the installation
1173 * CostFinalize does a bunch of work to translated the directories and such
1175 * But until I get write access to the database that is hard, so I am going to
1176 * hack it to see if I can get something to run.
1178 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
)
1180 UINT rc
= ERROR_SUCCESS
;
1182 TRACE("Performing action (%s)\n",debugstr_w(action
));
1183 ui_actioninfo(package
, action
, TRUE
, 0);
1184 ui_actionstart(package
, action
);
1185 ui_progress(package
,2,1,0,0);
1187 /* pre install, setup and configuration block */
1188 if (strcmpW(action
,szLaunchConditions
)==0)
1189 rc
= ACTION_LaunchConditions(package
);
1190 else if (strcmpW(action
,szCostInitialize
)==0)
1191 rc
= ACTION_CostInitialize(package
);
1192 else if (strcmpW(action
,szFileCost
)==0)
1193 rc
= ACTION_FileCost(package
);
1194 else if (strcmpW(action
,szCostFinalize
)==0)
1195 rc
= ACTION_CostFinalize(package
);
1196 else if (strcmpW(action
,szInstallValidate
)==0)
1197 rc
= ACTION_InstallValidate(package
);
1200 else if (strcmpW(action
,szProcessComponents
)==0)
1201 rc
= ACTION_ProcessComponents(package
);
1202 else if (strcmpW(action
,szInstallInitialize
)==0)
1203 rc
= ACTION_InstallInitialize(package
);
1204 else if (strcmpW(action
,szCreateFolders
)==0)
1205 rc
= ACTION_CreateFolders(package
);
1206 else if (strcmpW(action
,szInstallFiles
)==0)
1207 rc
= ACTION_InstallFiles(package
);
1208 else if (strcmpW(action
,szDuplicateFiles
)==0)
1209 rc
= ACTION_DuplicateFiles(package
);
1210 else if (strcmpW(action
,szWriteRegistryValues
)==0)
1211 rc
= ACTION_WriteRegistryValues(package
);
1212 else if (strcmpW(action
,szRegisterTypeLibraries
)==0)
1213 rc
= ACTION_RegisterTypeLibraries(package
);
1214 else if (strcmpW(action
,szRegisterClassInfo
)==0)
1215 rc
= ACTION_RegisterClassInfo(package
);
1216 else if (strcmpW(action
,szRegisterProgIdInfo
)==0)
1217 rc
= ACTION_RegisterProgIdInfo(package
);
1218 else if (strcmpW(action
,szCreateShortcuts
)==0)
1219 rc
= ACTION_CreateShortcuts(package
);
1220 else if (strcmpW(action
,szPublishProduct
)==0)
1221 rc
= ACTION_PublishProduct(package
);
1224 Called during iTunes but unimplemented and seem important
1226 ResolveSource (sets SourceDir)
1230 else if ((rc
= ACTION_CustomAction(package
,action
)) != ERROR_SUCCESS
)
1232 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action
));
1233 rc
= ERROR_FUNCTION_NOT_CALLED
;
1236 ui_actioninfo(package
, action
, FALSE
, rc
);
1241 static UINT
ACTION_CustomAction(MSIPACKAGE
*package
,const WCHAR
*action
)
1243 UINT rc
= ERROR_SUCCESS
;
1245 MSIRECORD
* row
= 0;
1246 static const WCHAR ExecSeqQuery
[] =
1247 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','C','u','s','t','o'
1248 ,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i'
1249 ,'o','n','`',' ','=',' ','`','%','s','`',0};
1253 WCHAR
*deformated
=NULL
;
1255 rc
= ACTION_OpenQuery(package
->db
, &view
, ExecSeqQuery
, action
);
1256 if (rc
!= ERROR_SUCCESS
)
1259 rc
= MSI_ViewExecute(view
, 0);
1260 if (rc
!= ERROR_SUCCESS
)
1262 MSI_ViewClose(view
);
1263 msiobj_release(&view
->hdr
);
1267 rc
= MSI_ViewFetch(view
,&row
);
1268 if (rc
!= ERROR_SUCCESS
)
1270 MSI_ViewClose(view
);
1271 msiobj_release(&view
->hdr
);
1275 type
= MSI_RecordGetInteger(row
,2);
1277 source
= load_dynamic_stringW(row
,3);
1278 target
= load_dynamic_stringW(row
,4);
1280 TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action
),type
,
1281 debugstr_w(source
), debugstr_w(target
));
1283 /* we are ignoring ALOT of flags and important synchronization stuff */
1284 switch (type
& CUSTOM_ACTION_TYPE_MASK
)
1286 case 1: /* DLL file stored in a Binary table stream */
1287 rc
= HANDLE_CustomType1(package
,source
,target
,type
);
1289 case 2: /* EXE file stored in a Binary table strem */
1290 rc
= HANDLE_CustomType2(package
,source
,target
,type
);
1292 case 18: /*EXE file installed with package */
1293 rc
= HANDLE_CustomType18(package
,source
,target
,type
);
1295 case 50: /*EXE file specified by a property value */
1296 rc
= HANDLE_CustomType50(package
,source
,target
,type
);
1298 case 34: /*EXE to be run in specified directory */
1299 rc
= HANDLE_CustomType34(package
,source
,target
,type
);
1301 case 35: /* Directory set with formatted text. */
1302 case 51: /* Property set with formatted text. */
1303 deformat_string(package
,target
,&deformated
);
1304 rc
= MSI_SetPropertyW(package
,source
,deformated
);
1305 HeapFree(GetProcessHeap(),0,deformated
);
1308 FIXME("UNHANDLED ACTION TYPE %i (%s %s)\n",
1309 type
& CUSTOM_ACTION_TYPE_MASK
, debugstr_w(source
),
1310 debugstr_w(target
));
1313 HeapFree(GetProcessHeap(),0,source
);
1314 HeapFree(GetProcessHeap(),0,target
);
1315 msiobj_release(&row
->hdr
);
1316 MSI_ViewClose(view
);
1317 msiobj_release(&view
->hdr
);
1321 static UINT
store_binary_to_temp(MSIPACKAGE
*package
, const LPWSTR source
,
1326 if (MSI_GetPropertyW(package
, cszTempFolder
, tmp_file
, &sz
)
1328 GetTempPathW(MAX_PATH
,tmp_file
);
1330 strcatW(tmp_file
,source
);
1332 if (GetFileAttributesW(tmp_file
) != INVALID_FILE_ATTRIBUTES
)
1334 TRACE("File already exists\n");
1335 return ERROR_SUCCESS
;
1339 /* write out the file */
1342 MSIRECORD
* row
= 0;
1343 static const WCHAR fmt
[] =
1344 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','B','i'
1345 ,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`','%','s','`',0};
1349 if (track_tempfile(package
, source
, tmp_file
)!=0)
1350 FIXME("File Name in temp tracking collision\n");
1352 the_file
= CreateFileW(tmp_file
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
1353 FILE_ATTRIBUTE_NORMAL
, NULL
);
1355 if (the_file
== INVALID_HANDLE_VALUE
)
1356 return ERROR_FUNCTION_FAILED
;
1358 rc
= ACTION_OpenQuery(package
->db
, &view
, fmt
, source
);
1359 if (rc
!= ERROR_SUCCESS
)
1362 rc
= MSI_ViewExecute(view
, 0);
1363 if (rc
!= ERROR_SUCCESS
)
1365 MSI_ViewClose(view
);
1366 msiobj_release(&view
->hdr
);
1370 rc
= MSI_ViewFetch(view
,&row
);
1371 if (rc
!= ERROR_SUCCESS
)
1373 MSI_ViewClose(view
);
1374 msiobj_release(&view
->hdr
);
1382 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
1383 if (rc
!= ERROR_SUCCESS
)
1385 ERR("Failed to get stream\n");
1386 CloseHandle(the_file
);
1387 DeleteFileW(tmp_file
);
1390 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
1391 } while (sz
== 1024);
1393 CloseHandle(the_file
);
1395 msiobj_release(&row
->hdr
);
1396 MSI_ViewClose(view
);
1397 msiobj_release(&view
->hdr
);
1400 return ERROR_SUCCESS
;
1403 typedef UINT __stdcall
CustomEntry(MSIHANDLE
);
1406 MSIPACKAGE
*package
;
1411 static DWORD WINAPI
DllThread(LPVOID info
)
1415 thread_struct
*stuff
;
1418 stuff
= (thread_struct
*)info
;
1420 TRACE("Asynchronous start (%s, %s) \n", debugstr_w(stuff
->source
),
1421 debugstr_w(stuff
->target
));
1423 DLL
= LoadLibraryW(stuff
->source
);
1426 proc
= strdupWtoA( stuff
->target
);
1427 fn
= (CustomEntry
*)GetProcAddress(DLL
,proc
);
1431 MSIPACKAGE
*package
= stuff
->package
;
1433 TRACE("Calling function\n");
1434 hPackage
= msiobj_findhandle( &package
->hdr
);
1436 ERR("Handle for object %p not found\n", package
);
1438 msiobj_release( &package
->hdr
);
1441 ERR("Cannot load functon\n");
1443 HeapFree(GetProcessHeap(),0,proc
);
1447 ERR("Unable to load library\n");
1448 msiobj_release( &stuff
->package
->hdr
);
1449 HeapFree(GetProcessHeap(),0,stuff
->source
);
1450 HeapFree(GetProcessHeap(),0,stuff
->target
);
1451 HeapFree(GetProcessHeap(), 0, stuff
);
1455 static UINT
HANDLE_CustomType1(MSIPACKAGE
*package
, const LPWSTR source
,
1456 const LPWSTR target
, const INT type
)
1458 WCHAR tmp_file
[MAX_PATH
];
1463 store_binary_to_temp(package
, source
, tmp_file
);
1465 TRACE("Calling function %s from %s\n",debugstr_w(target
),
1466 debugstr_w(tmp_file
));
1468 if (!strchrW(tmp_file
,'.'))
1470 static const WCHAR dot
[]={'.',0};
1471 strcatW(tmp_file
,dot
);
1477 HANDLE ThreadHandle
;
1478 thread_struct
*info
= HeapAlloc( GetProcessHeap(), 0, sizeof(*info
) );
1480 msiobj_addref( &package
->hdr
);
1481 info
->package
= package
;
1482 info
->target
= dupstrW(target
);
1483 info
->source
= dupstrW(tmp_file
);
1484 TRACE("Start Asynchronous execution of dll\n");
1485 ThreadHandle
= CreateThread(NULL
,0,DllThread
,(LPVOID
)info
,0,&ThreadId
);
1486 CloseHandle(ThreadHandle
);
1487 /* FIXME: release the package if the CreateThread fails */
1488 return ERROR_SUCCESS
;
1491 DLL
= LoadLibraryW(tmp_file
);
1494 proc
= strdupWtoA( target
);
1495 fn
= (CustomEntry
*)GetProcAddress(DLL
,proc
);
1500 TRACE("Calling function\n");
1501 hPackage
= msiobj_findhandle( &package
->hdr
);
1503 ERR("Handle for object %p not found\n", package
);
1505 msiobj_release( &package
->hdr
);
1508 ERR("Cannot load functon\n");
1510 HeapFree(GetProcessHeap(),0,proc
);
1514 ERR("Unable to load library\n");
1516 return ERROR_SUCCESS
;
1519 static UINT
HANDLE_CustomType2(MSIPACKAGE
*package
, const LPWSTR source
,
1520 const LPWSTR target
, const INT type
)
1522 WCHAR tmp_file
[MAX_PATH
];
1524 PROCESS_INFORMATION info
;
1529 static const WCHAR spc
[] = {' ',0};
1531 memset(&si
,0,sizeof(STARTUPINFOW
));
1533 store_binary_to_temp(package
, source
, tmp_file
);
1535 deformat_string(package
,target
,&deformated
);
1537 len
= strlenW(tmp_file
) + strlenW(deformated
) + 2;
1539 cmd
= (WCHAR
*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR
)*len
);
1541 strcpyW(cmd
,tmp_file
);
1543 strcatW(cmd
,deformated
);
1545 HeapFree(GetProcessHeap(),0,deformated
);
1547 TRACE("executing exe %s \n",debugstr_w(cmd
));
1549 rc
= CreateProcessW(NULL
, cmd
, NULL
, NULL
, FALSE
, 0, NULL
,
1550 c_collen
, &si
, &info
);
1552 HeapFree(GetProcessHeap(),0,cmd
);
1556 ERR("Unable to execute command\n");
1557 return ERROR_SUCCESS
;
1561 WaitForSingleObject(info
.hProcess
,INFINITE
);
1563 CloseHandle( info
.hProcess
);
1564 CloseHandle( info
.hThread
);
1565 return ERROR_SUCCESS
;
1568 static UINT
HANDLE_CustomType18(MSIPACKAGE
*package
, const LPWSTR source
,
1569 const LPWSTR target
, const INT type
)
1572 PROCESS_INFORMATION info
;
1577 static const WCHAR spc
[] = {' ',0};
1580 memset(&si
,0,sizeof(STARTUPINFOW
));
1582 index
= get_loaded_file(package
,source
);
1584 len
= strlenW(package
->files
[index
].TargetPath
);
1586 deformat_string(package
,target
,&deformated
);
1587 len
+= strlenW(deformated
);
1590 cmd
= (WCHAR
*)HeapAlloc(GetProcessHeap(),0,len
* sizeof(WCHAR
));
1592 strcpyW(cmd
, package
->files
[index
].TargetPath
);
1594 strcatW(cmd
, deformated
);
1596 HeapFree(GetProcessHeap(),0,deformated
);
1598 TRACE("executing exe %s \n",debugstr_w(cmd
));
1600 rc
= CreateProcessW(NULL
, cmd
, NULL
, NULL
, FALSE
, 0, NULL
,
1601 c_collen
, &si
, &info
);
1603 HeapFree(GetProcessHeap(),0,cmd
);
1607 ERR("Unable to execute command\n");
1608 return ERROR_SUCCESS
;
1612 WaitForSingleObject(info
.hProcess
,INFINITE
);
1614 CloseHandle( info
.hProcess
);
1615 CloseHandle( info
.hThread
);
1616 return ERROR_SUCCESS
;
1619 static UINT
HANDLE_CustomType50(MSIPACKAGE
*package
, const LPWSTR source
,
1620 const LPWSTR target
, const INT type
)
1623 PROCESS_INFORMATION info
;
1630 static const WCHAR spc
[] = {' ',0};
1632 memset(&si
,0,sizeof(STARTUPINFOW
));
1633 memset(&info
,0,sizeof(PROCESS_INFORMATION
));
1635 prop
= load_dynamic_property(package
,source
,&prc
);
1639 deformat_string(package
,target
,&deformated
);
1640 len
= strlenW(prop
) + strlenW(deformated
) + 2;
1641 cmd
= (WCHAR
*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR
)*len
);
1645 strcatW(cmd
,deformated
);
1647 HeapFree(GetProcessHeap(),0,deformated
);
1649 TRACE("executing exe %s \n",debugstr_w(cmd
));
1651 rc
= CreateProcessW(NULL
, cmd
, NULL
, NULL
, FALSE
, 0, NULL
,
1652 c_collen
, &si
, &info
);
1654 HeapFree(GetProcessHeap(),0,cmd
);
1658 ERR("Unable to execute command\n");
1659 return ERROR_SUCCESS
;
1663 WaitForSingleObject(info
.hProcess
,INFINITE
);
1665 CloseHandle( info
.hProcess
);
1666 CloseHandle( info
.hThread
);
1667 return ERROR_SUCCESS
;
1670 static UINT
HANDLE_CustomType34(MSIPACKAGE
*package
, const LPWSTR source
,
1671 const LPWSTR target
, const INT type
)
1673 LPWSTR filename
, deformated
;
1675 PROCESS_INFORMATION info
;
1678 memset(&si
,0,sizeof(STARTUPINFOW
));
1680 filename
= resolve_folder(package
, source
, FALSE
, FALSE
, NULL
);
1683 return ERROR_FUNCTION_FAILED
;
1685 SetCurrentDirectoryW(filename
);
1686 HeapFree(GetProcessHeap(),0,filename
);
1688 deformat_string(package
,target
,&deformated
);
1690 TRACE("executing exe %s \n",debugstr_w(deformated
));
1692 rc
= CreateProcessW(NULL
, deformated
, NULL
, NULL
, FALSE
, 0, NULL
,
1693 c_collen
, &si
, &info
);
1694 HeapFree(GetProcessHeap(),0,deformated
);
1698 ERR("Unable to execute command\n");
1699 return ERROR_SUCCESS
;
1703 WaitForSingleObject(info
.hProcess
,INFINITE
);
1705 CloseHandle( info
.hProcess
);
1706 CloseHandle( info
.hThread
);
1707 return ERROR_SUCCESS
;
1710 /***********************************************************************
1713 * Recursively create all directories in the path.
1715 * shamelessly stolen from setupapi/queue.c
1717 static BOOL
create_full_pathW(const WCHAR
*path
)
1723 new_path
= HeapAlloc(GetProcessHeap(), 0, (strlenW(path
) + 1) *
1726 strcpyW(new_path
, path
);
1728 while((len
= strlenW(new_path
)) && new_path
[len
- 1] == '\\')
1729 new_path
[len
- 1] = 0;
1731 while(!CreateDirectoryW(new_path
, NULL
))
1734 DWORD last_error
= GetLastError();
1735 if(last_error
== ERROR_ALREADY_EXISTS
)
1738 if(last_error
!= ERROR_PATH_NOT_FOUND
)
1744 if(!(slash
= strrchrW(new_path
, '\\')))
1750 len
= slash
- new_path
;
1752 if(!create_full_pathW(new_path
))
1757 new_path
[len
] = '\\';
1760 HeapFree(GetProcessHeap(), 0, new_path
);
1765 * Also we cannot enable/disable components either, so for now I am just going
1766 * to do all the directories for all the components.
1768 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1770 static const WCHAR ExecSeqQuery
[] = {
1771 's','e','l','e','c','t',' ','D','i','r','e','c','t','o','r','y','_',' ',
1772 'f','r','o','m',' ','C','r','e','a','t','e','F','o','l','d','e','r',0 };
1777 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1778 if (rc
!= ERROR_SUCCESS
)
1779 return ERROR_SUCCESS
;
1781 rc
= MSI_ViewExecute(view
, 0);
1782 if (rc
!= ERROR_SUCCESS
)
1784 MSI_ViewClose(view
);
1785 msiobj_release(&view
->hdr
);
1794 MSIRECORD
*row
= NULL
, *uirow
;
1796 rc
= MSI_ViewFetch(view
,&row
);
1797 if (rc
!= ERROR_SUCCESS
)
1804 rc
= MSI_RecordGetStringW(row
,1,dir
,&sz
);
1806 if (rc
!= ERROR_SUCCESS
)
1808 ERR("Unable to get folder id \n");
1809 msiobj_release(&row
->hdr
);
1814 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,&folder
);
1817 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
1818 msiobj_release(&row
->hdr
);
1822 TRACE("Folder is %s\n",debugstr_w(full_path
));
1825 uirow
= MSI_CreateRecord(1);
1826 MSI_RecordSetStringW(uirow
,1,full_path
);
1827 ui_actiondata(package
,szCreateFolders
,uirow
);
1828 msiobj_release( &uirow
->hdr
);
1830 if (folder
->State
== 0)
1831 create_full_pathW(full_path
);
1835 msiobj_release(&row
->hdr
);
1836 HeapFree(GetProcessHeap(),0,full_path
);
1838 MSI_ViewClose(view
);
1839 msiobj_release(&view
->hdr
);
1844 static int load_component(MSIPACKAGE
* package
, MSIRECORD
* row
)
1846 int index
= package
->loaded_components
;
1849 /* fill in the data */
1851 package
->loaded_components
++;
1852 if (package
->loaded_components
== 1)
1853 package
->components
= HeapAlloc(GetProcessHeap(),0,
1854 sizeof(MSICOMPONENT
));
1856 package
->components
= HeapReAlloc(GetProcessHeap(),0,
1857 package
->components
, package
->loaded_components
*
1858 sizeof(MSICOMPONENT
));
1860 memset(&package
->components
[index
],0,sizeof(MSICOMPONENT
));
1863 MSI_RecordGetStringW(row
,1,package
->components
[index
].Component
,&sz
);
1865 TRACE("Loading Component %s\n",
1866 debugstr_w(package
->components
[index
].Component
));
1869 if (!MSI_RecordIsNull(row
,2))
1870 MSI_RecordGetStringW(row
,2,package
->components
[index
].ComponentId
,&sz
);
1873 MSI_RecordGetStringW(row
,3,package
->components
[index
].Directory
,&sz
);
1875 package
->components
[index
].Attributes
= MSI_RecordGetInteger(row
,4);
1878 MSI_RecordGetStringW(row
,5,package
->components
[index
].Condition
,&sz
);
1881 MSI_RecordGetStringW(row
,6,package
->components
[index
].KeyPath
,&sz
);
1883 package
->components
[index
].Installed
= INSTALLSTATE_ABSENT
;
1884 package
->components
[index
].Action
= INSTALLSTATE_UNKNOWN
;
1885 package
->components
[index
].ActionRequest
= INSTALLSTATE_UNKNOWN
;
1887 package
->components
[index
].Enabled
= TRUE
;
1892 static void load_feature(MSIPACKAGE
* package
, MSIRECORD
* row
)
1894 int index
= package
->loaded_features
;
1896 static const WCHAR Query1
[] = {'S','E','L','E','C','T',' ','C','o','m','p',
1897 'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',
1898 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',
1899 'a','t','u','r','e','_','=','\'','%','s','\'',0};
1900 static const WCHAR Query2
[] = {'S','E','L','E','C','T',' ','*',' ','F','R',
1901 'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',
1902 'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};
1909 /* fill in the data */
1911 package
->loaded_features
++;
1912 if (package
->loaded_features
== 1)
1913 package
->features
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE
));
1915 package
->features
= HeapReAlloc(GetProcessHeap(),0,package
->features
,
1916 package
->loaded_features
* sizeof(MSIFEATURE
));
1918 memset(&package
->features
[index
],0,sizeof(MSIFEATURE
));
1921 MSI_RecordGetStringW(row
,1,package
->features
[index
].Feature
,&sz
);
1923 TRACE("Loading feature %s\n",debugstr_w(package
->features
[index
].Feature
));
1926 if (!MSI_RecordIsNull(row
,2))
1927 MSI_RecordGetStringW(row
,2,package
->features
[index
].Feature_Parent
,&sz
);
1930 if (!MSI_RecordIsNull(row
,3))
1931 MSI_RecordGetStringW(row
,3,package
->features
[index
].Title
,&sz
);
1934 if (!MSI_RecordIsNull(row
,4))
1935 MSI_RecordGetStringW(row
,4,package
->features
[index
].Description
,&sz
);
1937 if (!MSI_RecordIsNull(row
,5))
1938 package
->features
[index
].Display
= MSI_RecordGetInteger(row
,5);
1940 package
->features
[index
].Level
= MSI_RecordGetInteger(row
,6);
1943 if (!MSI_RecordIsNull(row
,7))
1944 MSI_RecordGetStringW(row
,7,package
->features
[index
].Directory
,&sz
);
1946 package
->features
[index
].Attributes
= MSI_RecordGetInteger(row
,8);
1948 package
->features
[index
].Installed
= INSTALLSTATE_ABSENT
;
1949 package
->features
[index
].Action
= INSTALLSTATE_UNKNOWN
;
1950 package
->features
[index
].ActionRequest
= INSTALLSTATE_UNKNOWN
;
1952 /* load feature components */
1954 rc
= ACTION_OpenQuery(package
->db
, &view
, Query1
, package
->features
[index
].Feature
);
1955 if (rc
!= ERROR_SUCCESS
)
1957 rc
= MSI_ViewExecute(view
,0);
1958 if (rc
!= ERROR_SUCCESS
)
1960 MSI_ViewClose(view
);
1961 msiobj_release(&view
->hdr
);
1967 WCHAR buffer
[0x100];
1970 INT cnt
= package
->features
[index
].ComponentCount
;
1972 rc
= MSI_ViewFetch(view
,&row2
);
1973 if (rc
!= ERROR_SUCCESS
)
1977 MSI_RecordGetStringW(row2
,1,buffer
,&sz
);
1979 /* check to see if the component is already loaded */
1980 c_indx
= get_loaded_component(package
,buffer
);
1983 TRACE("Component %s already loaded at %i\n", debugstr_w(buffer
),
1985 package
->features
[index
].Components
[cnt
] = c_indx
;
1986 package
->features
[index
].ComponentCount
++;
1990 rc
= ACTION_OpenQuery(package
->db
, &view2
, Query2
, buffer
);
1991 if (rc
!= ERROR_SUCCESS
)
1993 msiobj_release( &row2
->hdr
);
1996 rc
= MSI_ViewExecute(view2
,0);
1997 if (rc
!= ERROR_SUCCESS
)
1999 msiobj_release( &row2
->hdr
);
2000 MSI_ViewClose(view2
);
2001 msiobj_release( &view2
->hdr
);
2008 rc
= MSI_ViewFetch(view2
,&row3
);
2009 if (rc
!= ERROR_SUCCESS
)
2011 c_indx
= load_component(package
,row3
);
2012 msiobj_release( &row3
->hdr
);
2014 package
->features
[index
].Components
[cnt
] = c_indx
;
2015 package
->features
[index
].ComponentCount
++;
2016 TRACE("Loaded new component to index %i\n",c_indx
);
2018 MSI_ViewClose(view2
);
2019 msiobj_release( &view2
->hdr
);
2020 msiobj_release( &row2
->hdr
);
2022 MSI_ViewClose(view
);
2023 msiobj_release(&view
->hdr
);
2027 * I am not doing any of the costing functionality yet.
2028 * Mostly looking at doing the Component and Feature loading
2030 * The native MSI does ALOT of modification to tables here. Mostly adding alot
2031 * of temporary columns to the Feature and Component tables.
2033 * note: native msi also tracks the short filename. but I am only going to
2034 * track the long ones. Also looking at this directory table
2035 * it appears that the directory table does not get the parents
2036 * resolved base on property only based on their entrys in the
2039 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
2044 static const WCHAR Query_all
[] = {
2045 'S','E','L','E','C','T',' ','*',' ',
2046 'F','R','O','M',' ','F','e','a','t','u','r','e',0};
2047 static const WCHAR szCosting
[] = {
2048 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2049 static const WCHAR szZero
[] = { '0', 0 };
2051 MSI_SetPropertyW(package
, szCosting
, szZero
);
2052 MSI_SetPropertyW(package
, cszRootDrive
, c_collen
);
2054 rc
= MSI_DatabaseOpenViewW(package
->db
,Query_all
,&view
);
2055 if (rc
!= ERROR_SUCCESS
)
2057 rc
= MSI_ViewExecute(view
,0);
2058 if (rc
!= ERROR_SUCCESS
)
2060 MSI_ViewClose(view
);
2061 msiobj_release(&view
->hdr
);
2068 rc
= MSI_ViewFetch(view
,&row
);
2069 if (rc
!= ERROR_SUCCESS
)
2072 load_feature(package
,row
);
2073 msiobj_release(&row
->hdr
);
2075 MSI_ViewClose(view
);
2076 msiobj_release(&view
->hdr
);
2078 return ERROR_SUCCESS
;
2081 static UINT
load_file(MSIPACKAGE
* package
, MSIRECORD
* row
)
2083 DWORD index
= package
->loaded_files
;
2087 /* fill in the data */
2089 package
->loaded_files
++;
2090 if (package
->loaded_files
== 1)
2091 package
->files
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE
));
2093 package
->files
= HeapReAlloc(GetProcessHeap(),0,
2094 package
->files
, package
->loaded_files
* sizeof(MSIFILE
));
2096 memset(&package
->files
[index
],0,sizeof(MSIFILE
));
2098 package
->files
[index
].File
= load_dynamic_stringW(row
, 1);
2099 buffer
= load_dynamic_stringW(row
, 2);
2101 package
->files
[index
].ComponentIndex
= -1;
2102 for (i
= 0; i
< package
->loaded_components
; i
++)
2103 if (strcmpW(package
->components
[i
].Component
,buffer
)==0)
2105 package
->files
[index
].ComponentIndex
= i
;
2108 if (package
->files
[index
].ComponentIndex
== -1)
2109 ERR("Unfound Component %s\n",debugstr_w(buffer
));
2110 HeapFree(GetProcessHeap(), 0, buffer
);
2112 package
->files
[index
].FileName
= load_dynamic_stringW(row
,3);
2114 reduce_to_longfilename(package
->files
[index
].FileName
);
2116 package
->files
[index
].FileSize
= MSI_RecordGetInteger(row
,4);
2117 package
->files
[index
].Version
= load_dynamic_stringW(row
, 5);
2118 package
->files
[index
].Language
= load_dynamic_stringW(row
, 6);
2119 package
->files
[index
].Attributes
= MSI_RecordGetInteger(row
,7);
2120 package
->files
[index
].Sequence
= MSI_RecordGetInteger(row
,8);
2122 package
->files
[index
].Temporary
= FALSE
;
2123 package
->files
[index
].State
= 0;
2125 TRACE("File Loaded (%s)\n",debugstr_w(package
->files
[index
].File
));
2127 return ERROR_SUCCESS
;
2130 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
2135 static const WCHAR Query
[] = {
2136 'S','E','L','E','C','T',' ','*',' ',
2137 'F','R','O','M',' ','F','i','l','e',' ',
2138 'O','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e', 0};
2141 return ERROR_INVALID_HANDLE
;
2143 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2144 if (rc
!= ERROR_SUCCESS
)
2145 return ERROR_SUCCESS
;
2147 rc
= MSI_ViewExecute(view
, 0);
2148 if (rc
!= ERROR_SUCCESS
)
2150 MSI_ViewClose(view
);
2151 msiobj_release(&view
->hdr
);
2152 return ERROR_SUCCESS
;
2157 rc
= MSI_ViewFetch(view
,&row
);
2158 if (rc
!= ERROR_SUCCESS
)
2163 load_file(package
,row
);
2164 msiobj_release(&row
->hdr
);
2166 MSI_ViewClose(view
);
2167 msiobj_release(&view
->hdr
);
2169 return ERROR_SUCCESS
;
2172 static INT
load_folder(MSIPACKAGE
*package
, const WCHAR
* dir
)
2175 static const WCHAR Query
[] =
2176 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',
2177 't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',
2178 'o','r','y','`',' ','=',' ','`','%','s','`',0};
2181 LPWSTR targetdir
, parent
, srcdir
;
2182 MSIRECORD
* row
= 0;
2186 TRACE("Looking for dir %s\n",debugstr_w(dir
));
2188 for (i
= 0; i
< package
->loaded_folders
; i
++)
2190 if (strcmpW(package
->folders
[i
].Directory
,dir
)==0)
2192 TRACE(" %s retuning on index %lu\n",debugstr_w(dir
),i
);
2197 TRACE("Working to load %s\n",debugstr_w(dir
));
2199 index
= package
->loaded_folders
++;
2200 if (package
->loaded_folders
==1)
2201 package
->folders
= HeapAlloc(GetProcessHeap(),0,
2204 package
->folders
= HeapReAlloc(GetProcessHeap(),0,
2205 package
->folders
, package
->loaded_folders
*
2208 memset(&package
->folders
[index
],0,sizeof(MSIFOLDER
));
2210 package
->folders
[index
].Directory
= dupstrW(dir
);
2212 rc
= ACTION_OpenQuery(package
->db
, &view
, Query
, dir
);
2213 if (rc
!= ERROR_SUCCESS
)
2216 rc
= MSI_ViewExecute(view
, 0);
2217 if (rc
!= ERROR_SUCCESS
)
2219 MSI_ViewClose(view
);
2220 msiobj_release(&view
->hdr
);
2224 rc
= MSI_ViewFetch(view
,&row
);
2225 if (rc
!= ERROR_SUCCESS
)
2227 MSI_ViewClose(view
);
2228 msiobj_release(&view
->hdr
);
2232 targetdir
= load_dynamic_stringW(row
,3);
2234 /* split src and target dir */
2235 if (strchrW(targetdir
,':'))
2237 srcdir
=strchrW(targetdir
,':');
2244 /* for now only pick long filename versions */
2245 if (strchrW(targetdir
,'|'))
2247 targetdir
= strchrW(targetdir
,'|');
2251 if (srcdir
&& strchrW(srcdir
,'|'))
2253 srcdir
= strchrW(srcdir
,'|');
2258 /* now check for root dirs */
2259 if (targetdir
[0] == '.' && targetdir
[1] == 0)
2262 if (srcdir
&& srcdir
[0] == '.' && srcdir
[1] == 0)
2267 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir
));
2268 if (package
->folders
[index
].TargetDefault
)
2269 HeapFree(GetProcessHeap(),0, package
->folders
[index
].TargetDefault
);
2270 package
->folders
[index
].TargetDefault
= dupstrW(targetdir
);
2274 package
->folders
[index
].SourceDefault
= dupstrW(srcdir
);
2276 package
->folders
[index
].SourceDefault
= dupstrW(targetdir
);
2277 HeapFree(GetProcessHeap(), 0, targetdir
);
2279 parent
= load_dynamic_stringW(row
,2);
2282 i
= load_folder(package
,parent
);
2283 package
->folders
[index
].ParentIndex
= i
;
2284 TRACE("Parent is index %i... %s %s\n",
2285 package
->folders
[index
].ParentIndex
,
2286 debugstr_w(package
->folders
[package
->folders
[index
].ParentIndex
].Directory
),
2287 debugstr_w(parent
));
2290 package
->folders
[index
].ParentIndex
= -2;
2291 HeapFree(GetProcessHeap(), 0, parent
);
2293 package
->folders
[index
].Property
= load_dynamic_property(package
, dir
,NULL
);
2295 msiobj_release(&row
->hdr
);
2296 MSI_ViewClose(view
);
2297 msiobj_release(&view
->hdr
);
2298 TRACE(" %s retuning on index %i\n",debugstr_w(dir
),index
);
2303 static LPWSTR
resolve_folder(MSIPACKAGE
*package
, LPCWSTR name
,
2304 BOOL source
, BOOL set_prop
, MSIFOLDER
**folder
)
2307 LPWSTR p
, path
= NULL
;
2309 TRACE("Working to resolve %s\n",debugstr_w(name
));
2311 /* special resolving for Target and Source root dir */
2312 if (strcmpW(name
,cszTargetDir
)==0 || strcmpW(name
,cszSourceDir
)==0)
2316 path
= load_dynamic_property(package
,cszTargetDir
,NULL
);
2319 path
= load_dynamic_property(package
,cszRootDrive
,NULL
);
2321 MSI_SetPropertyW(package
,cszTargetDir
,path
);
2324 *folder
= &(package
->folders
[0]);
2329 path
= load_dynamic_property(package
,cszSourceDir
,NULL
);
2332 path
= load_dynamic_property(package
,cszDatabase
,NULL
);
2335 p
= strrchrW(path
,'\\');
2341 *folder
= &(package
->folders
[0]);
2346 for (i
= 0; i
< package
->loaded_folders
; i
++)
2348 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
2352 if (i
>= package
->loaded_folders
)
2356 *folder
= &(package
->folders
[i
]);
2358 if (!source
&& package
->folders
[i
].ResolvedTarget
)
2360 path
= dupstrW(package
->folders
[i
].ResolvedTarget
);
2361 TRACE(" already resolved to %s\n",debugstr_w(path
));
2364 else if (source
&& package
->folders
[i
].ResolvedSource
)
2366 path
= dupstrW(package
->folders
[i
].ResolvedSource
);
2369 else if (!source
&& package
->folders
[i
].Property
)
2371 path
= dupstrW(package
->folders
[i
].Property
);
2372 TRACE(" internally set to %s\n",debugstr_w(path
));
2374 MSI_SetPropertyW(package
,name
,path
);
2378 if (package
->folders
[i
].ParentIndex
>= 0)
2380 LPWSTR parent
= package
->folders
[package
->folders
[i
].ParentIndex
].Directory
;
2382 TRACE(" ! Parent is %s\n", debugstr_w(parent
));
2384 p
= resolve_folder(package
, parent
, source
, set_prop
, NULL
);
2387 TRACE(" TargetDefault = %s\n",debugstr_w(package
->folders
[i
].TargetDefault
));
2388 path
= build_directory_name(3, p
, package
->folders
[i
].TargetDefault
, NULL
);
2389 package
->folders
[i
].ResolvedTarget
= dupstrW(path
);
2390 TRACE(" resolved into %s\n",debugstr_w(path
));
2392 MSI_SetPropertyW(package
,name
,path
);
2396 path
= build_directory_name(3, p
, package
->folders
[i
].SourceDefault
, NULL
);
2397 package
->folders
[i
].ResolvedSource
= dupstrW(path
);
2399 HeapFree(GetProcessHeap(),0,p
);
2404 static UINT
SetFeatureStates(MSIPACKAGE
*package
)
2410 LPWSTR override
= NULL
;
2411 static const WCHAR all
[]={'A','L','L',0};
2412 static const WCHAR szlevel
[] = {
2413 'I','N','S','T','A','L','L','L','E','V','E','L',0};
2414 static const WCHAR szAddLocal
[] = {
2415 'A','D','D','L','O','C','A','L',0};
2417 /* I do not know if this is where it should happen.. but */
2419 TRACE("Checking Install Level\n");
2421 level
= load_dynamic_property(package
,szlevel
,NULL
);
2424 install_level
= atoiW(level
);
2425 HeapFree(GetProcessHeap(), 0, level
);
2430 /* ok hereis the rub
2431 * ADDLOCAL and its friend OVERRIDE INSTALLLEVLE
2432 * I have confirmed this if ADDLOCALis stated then the INSTALLLEVEL is
2433 * itnored for all the features. seems strange, epsecially since it is not
2434 * documented anywhere, but it is how it works.
2437 override
= load_dynamic_property(package
,szAddLocal
,NULL
);
2441 for(i
= 0; i
< package
->loaded_features
; i
++)
2443 if (strcmpiW(override
,all
)==0)
2445 package
->features
[i
].ActionRequest
= INSTALLSTATE_LOCAL
;
2446 package
->features
[i
].Action
= INSTALLSTATE_LOCAL
;
2450 LPWSTR ptr
= override
;
2451 LPWSTR ptr2
= strchrW(override
,',');
2456 strncmpW(ptr
,package
->features
[i
].Feature
, ptr2
-ptr
)==0)
2458 strcmpW(ptr
,package
->features
[i
].Feature
)==0))
2460 package
->features
[i
].ActionRequest
= INSTALLSTATE_LOCAL
;
2461 package
->features
[i
].Action
= INSTALLSTATE_LOCAL
;
2467 ptr2
= strchrW(ptr
,',');
2474 HeapFree(GetProcessHeap(),0,override
);
2478 for(i
= 0; i
< package
->loaded_features
; i
++)
2480 BOOL feature_state
= ((package
->features
[i
].Level
> 0) &&
2481 (package
->features
[i
].Level
<= install_level
));
2485 package
->features
[i
].ActionRequest
= INSTALLSTATE_LOCAL
;
2486 package
->features
[i
].Action
= INSTALLSTATE_LOCAL
;
2492 * now we want to enable or disable components base on feature
2495 for(i
= 0; i
< package
->loaded_features
; i
++)
2497 MSIFEATURE
* feature
= &package
->features
[i
];
2498 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
2499 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2500 feature
->ActionRequest
);
2502 for( j
= 0; j
< feature
->ComponentCount
; j
++)
2504 MSICOMPONENT
* component
= &package
->components
[
2505 feature
->Components
[j
]];
2507 if (!component
->Enabled
)
2509 component
->Action
= INSTALLSTATE_ABSENT
;
2510 component
->ActionRequest
= INSTALLSTATE_ABSENT
;
2514 if (feature
->Action
== INSTALLSTATE_LOCAL
)
2515 component
->Action
= INSTALLSTATE_LOCAL
;
2516 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
2517 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
2522 for(i
= 0; i
< package
->loaded_components
; i
++)
2524 MSICOMPONENT
* component
= &package
->components
[i
];
2526 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
2527 debugstr_w(component
->Component
), component
->Installed
,
2528 component
->Action
, component
->ActionRequest
);
2532 return ERROR_SUCCESS
;
2536 * Alot is done in this function aside from just the costing.
2537 * The costing needs to be implemented at some point but for now I am going
2538 * to focus on the directory building
2541 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2543 static const WCHAR ExecSeqQuery
[] = {
2544 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2545 'D','i','r','e','c','t','o','r','y',0};
2546 static const WCHAR ConditionQuery
[] = {
2547 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2548 'C','o','n','d','i','t','i','o','n',0};
2549 static const WCHAR szCosting
[] = {
2550 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2551 static const WCHAR szlevel
[] = {
2552 'I','N','S','T','A','L','L','L','E','V','E','L',0};
2553 static const WCHAR szOne
[] = { '1', 0 };
2559 TRACE("Building Directory properties\n");
2561 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2562 if (rc
== ERROR_SUCCESS
)
2564 rc
= MSI_ViewExecute(view
, 0);
2565 if (rc
!= ERROR_SUCCESS
)
2567 MSI_ViewClose(view
);
2568 msiobj_release(&view
->hdr
);
2576 MSIRECORD
* row
= 0;
2579 rc
= MSI_ViewFetch(view
,&row
);
2580 if (rc
!= ERROR_SUCCESS
)
2587 MSI_RecordGetStringW(row
,1,name
,&sz
);
2589 /* This helper function now does ALL the work */
2590 TRACE("Dir %s ...\n",debugstr_w(name
));
2591 load_folder(package
,name
);
2592 path
= resolve_folder(package
,name
,FALSE
,TRUE
,NULL
);
2593 TRACE("resolves to %s\n",debugstr_w(path
));
2594 HeapFree( GetProcessHeap(), 0, path
);
2596 msiobj_release(&row
->hdr
);
2598 MSI_ViewClose(view
);
2599 msiobj_release(&view
->hdr
);
2602 TRACE("File calculations %i files\n",package
->loaded_files
);
2604 for (i
= 0; i
< package
->loaded_files
; i
++)
2606 MSICOMPONENT
* comp
= NULL
;
2607 MSIFILE
* file
= NULL
;
2609 file
= &package
->files
[i
];
2610 if (file
->ComponentIndex
>= 0)
2611 comp
= &package
->components
[file
->ComponentIndex
];
2613 if (file
->Temporary
== TRUE
)
2620 /* calculate target */
2621 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, NULL
);
2623 if (file
->TargetPath
)
2624 HeapFree(GetProcessHeap(),0,file
->TargetPath
);
2626 TRACE("file %s is named %s\n",
2627 debugstr_w(file
->File
),debugstr_w(file
->FileName
));
2629 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
2631 HeapFree(GetProcessHeap(),0,p
);
2633 TRACE("file %s resolves to %s\n",
2634 debugstr_w(file
->File
),debugstr_w(file
->TargetPath
));
2636 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
2639 comp
->Cost
+= file
->FileSize
;
2649 static const WCHAR name
[] =
2651 static const WCHAR name_fmt
[] =
2652 {'%','u','.','%','u','.','%','u','.','%','u',0};
2653 WCHAR filever
[0x100];
2654 VS_FIXEDFILEINFO
*lpVer
;
2656 FIXME("Version comparison.. \n");
2657 versize
= GetFileVersionInfoSizeW(file
->TargetPath
,&handle
);
2658 version
= HeapAlloc(GetProcessHeap(),0,versize
);
2659 GetFileVersionInfoW(file
->TargetPath
, 0, versize
, version
);
2661 VerQueryValueW(version
, name
, (LPVOID
*)&lpVer
, &sz
);
2663 sprintfW(filever
,name_fmt
,
2664 HIWORD(lpVer
->dwFileVersionMS
),
2665 LOWORD(lpVer
->dwFileVersionMS
),
2666 HIWORD(lpVer
->dwFileVersionLS
),
2667 LOWORD(lpVer
->dwFileVersionLS
));
2669 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
2670 debugstr_w(filever
));
2671 if (strcmpiW(filever
,file
->Version
)<0)
2674 FIXME("cost should be diff in size\n");
2675 comp
->Cost
+= file
->FileSize
;
2679 HeapFree(GetProcessHeap(),0,version
);
2687 TRACE("Evaluating Condition Table\n");
2689 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
2690 if (rc
== ERROR_SUCCESS
)
2692 rc
= MSI_ViewExecute(view
, 0);
2693 if (rc
!= ERROR_SUCCESS
)
2695 MSI_ViewClose(view
);
2696 msiobj_release(&view
->hdr
);
2702 WCHAR Feature
[0x100];
2703 MSIRECORD
* row
= 0;
2707 rc
= MSI_ViewFetch(view
,&row
);
2709 if (rc
!= ERROR_SUCCESS
)
2716 MSI_RecordGetStringW(row
,1,Feature
,&sz
);
2718 feature_index
= get_loaded_feature(package
,Feature
);
2719 if (feature_index
< 0)
2720 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature
));
2724 Condition
= load_dynamic_stringW(row
,3);
2726 if (MSI_EvaluateConditionW(package
,Condition
) ==
2729 int level
= MSI_RecordGetInteger(row
,2);
2730 TRACE("Reseting feature %s to level %i\n",
2731 debugstr_w(Feature
), level
);
2732 package
->features
[feature_index
].Level
= level
;
2734 HeapFree(GetProcessHeap(),0,Condition
);
2737 msiobj_release(&row
->hdr
);
2739 MSI_ViewClose(view
);
2740 msiobj_release(&view
->hdr
);
2743 TRACE("Enabling or Disabling Components\n");
2744 for (i
= 0; i
< package
->loaded_components
; i
++)
2746 if (package
->components
[i
].Condition
[0])
2748 if (MSI_EvaluateConditionW(package
,
2749 package
->components
[i
].Condition
) == MSICONDITION_FALSE
)
2751 TRACE("Disabling component %s\n",
2752 debugstr_w(package
->components
[i
].Component
));
2753 package
->components
[i
].Enabled
= FALSE
;
2758 MSI_SetPropertyW(package
,szCosting
,szOne
);
2759 /* set default run level if not set */
2760 level
= load_dynamic_property(package
,szlevel
,NULL
);
2762 MSI_SetPropertyW(package
,szlevel
, szOne
);
2764 HeapFree(GetProcessHeap(),0,level
);
2766 return SetFeatureStates(package
);
2771 * This is a helper function for handling embedded cabinet media
2773 static UINT
writeout_cabinet_stream(MSIPACKAGE
*package
, WCHAR
* stream_name
,
2781 WCHAR tmp
[MAX_PATH
];
2783 rc
= read_raw_stream_data(package
->db
,stream_name
,&data
,&size
);
2784 if (rc
!= ERROR_SUCCESS
)
2788 if (MSI_GetPropertyW(package
, cszTempFolder
, tmp
, &write
))
2789 GetTempPathW(MAX_PATH
,tmp
);
2791 GetTempFileNameW(tmp
,stream_name
,0,source
);
2793 track_tempfile(package
,strrchrW(source
,'\\'), source
);
2794 the_file
= CreateFileW(source
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
2795 FILE_ATTRIBUTE_NORMAL
, NULL
);
2797 if (the_file
== INVALID_HANDLE_VALUE
)
2799 rc
= ERROR_FUNCTION_FAILED
;
2803 WriteFile(the_file
,data
,size
,&write
,NULL
);
2804 CloseHandle(the_file
);
2805 TRACE("wrote %li bytes to %s\n",write
,debugstr_w(source
));
2807 HeapFree(GetProcessHeap(),0,data
);
2812 /* Support functions for FDI functions */
2815 MSIPACKAGE
* package
;
2819 static void * cabinet_alloc(ULONG cb
)
2821 return HeapAlloc(GetProcessHeap(), 0, cb
);
2824 static void cabinet_free(void *pv
)
2826 HeapFree(GetProcessHeap(), 0, pv
);
2829 static INT_PTR
cabinet_open(char *pszFile
, int oflag
, int pmode
)
2832 DWORD dwShareMode
= 0;
2833 DWORD dwCreateDisposition
= OPEN_EXISTING
;
2834 switch (oflag
& _O_ACCMODE
)
2837 dwAccess
= GENERIC_READ
;
2838 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_DELETE
;
2841 dwAccess
= GENERIC_WRITE
;
2842 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
2845 dwAccess
= GENERIC_READ
| GENERIC_WRITE
;
2846 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
2849 if ((oflag
& (_O_CREAT
| _O_EXCL
)) == (_O_CREAT
| _O_EXCL
))
2850 dwCreateDisposition
= CREATE_NEW
;
2851 else if (oflag
& _O_CREAT
)
2852 dwCreateDisposition
= CREATE_ALWAYS
;
2853 return (INT_PTR
)CreateFileA(pszFile
, dwAccess
, dwShareMode
, NULL
, dwCreateDisposition
, 0, NULL
);
2856 static UINT
cabinet_read(INT_PTR hf
, void *pv
, UINT cb
)
2859 if (ReadFile((HANDLE
)hf
, pv
, cb
, &dwRead
, NULL
))
2864 static UINT
cabinet_write(INT_PTR hf
, void *pv
, UINT cb
)
2867 if (WriteFile((HANDLE
)hf
, pv
, cb
, &dwWritten
, NULL
))
2872 static int cabinet_close(INT_PTR hf
)
2874 return CloseHandle((HANDLE
)hf
) ? 0 : -1;
2877 static long cabinet_seek(INT_PTR hf
, long dist
, int seektype
)
2879 /* flags are compatible and so are passed straight through */
2880 return SetFilePointer((HANDLE
)hf
, dist
, NULL
, seektype
);
2883 static INT_PTR
cabinet_notify(FDINOTIFICATIONTYPE fdint
, PFDINOTIFICATION pfdin
)
2885 /* FIXME: try to do more processing in this function */
2888 case fdintCOPY_FILE
:
2890 CabData
*data
= (CabData
*) pfdin
->pv
;
2891 ULONG len
= strlen(data
->cab_path
) + strlen(pfdin
->psz1
);
2892 char *file
= cabinet_alloc((len
+1)*sizeof(char));
2896 LPWSTR tracknametmp
;
2897 static const WCHAR tmpprefix
[] = {'C','A','B','T','M','P','_',0};
2899 strcpy(file
, data
->cab_path
);
2900 strcat(file
, pfdin
->psz1
);
2902 TRACE("file: %s\n", debugstr_a(file
));
2904 /* track this file so it can be deleted if not installed */
2905 trackpath
=strdupAtoW(file
);
2906 tracknametmp
=strdupAtoW(strrchr(file
,'\\')+1);
2907 trackname
= HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp
) +
2908 strlenW(tmpprefix
)+1) * sizeof(WCHAR
));
2910 strcpyW(trackname
,tmpprefix
);
2911 strcatW(trackname
,tracknametmp
);
2913 track_tempfile(data
->package
, trackname
, trackpath
);
2915 HeapFree(GetProcessHeap(),0,trackpath
);
2916 HeapFree(GetProcessHeap(),0,trackname
);
2917 HeapFree(GetProcessHeap(),0,tracknametmp
);
2919 return cabinet_open(file
, _O_WRONLY
| _O_CREAT
, 0);
2921 case fdintCLOSE_FILE_INFO
:
2925 if (!DosDateTimeToFileTime(pfdin
->date
, pfdin
->time
, &ft
))
2927 if (!LocalFileTimeToFileTime(&ft
, &ftLocal
))
2929 if (!SetFileTime((HANDLE
)pfdin
->hf
, &ftLocal
, 0, &ftLocal
))
2932 cabinet_close(pfdin
->hf
);
2940 /***********************************************************************
2941 * extract_cabinet_file
2943 * Extract files from a cab file.
2945 static BOOL
extract_cabinet_file(MSIPACKAGE
* package
, const WCHAR
* source
,
2955 TRACE("Extracting %s to %s\n",debugstr_w(source
), debugstr_w(path
));
2957 hfdi
= FDICreate(cabinet_alloc
,
2968 ERR("FDICreate failed\n");
2972 if (!(cabinet
= strdupWtoA( source
)))
2977 if (!(cab_path
= strdupWtoA( path
)))
2980 HeapFree(GetProcessHeap(), 0, cabinet
);
2984 data
.package
= package
;
2985 data
.cab_path
= cab_path
;
2987 ret
= FDICopy(hfdi
, cabinet
, "", 0, cabinet_notify
, NULL
, &data
);
2990 ERR("FDICopy failed\n");
2994 HeapFree(GetProcessHeap(), 0, cabinet
);
2995 HeapFree(GetProcessHeap(), 0, cab_path
);
3000 static UINT
ready_media_for_file(MSIPACKAGE
*package
, UINT sequence
,
3005 MSIRECORD
* row
= 0;
3006 WCHAR source
[MAX_PATH
];
3007 static const WCHAR ExecSeqQuery
[] = {
3008 's','e','l','e','c','t',' ','*',' ',
3009 'f','r','o','m',' ','M','e','d','i','a',' ',
3010 'w','h','e','r','e',' ','L','a','s','t','S','e','q','u','e','n','c','e',' ','>','=',' ','%','i',' ',
3011 'o','r','d','e','r',' ','b','y',' ','L','a','s','t','S','e','q','u','e','n','c','e',0};
3016 static UINT last_sequence
= 0;
3018 if (sequence
<= last_sequence
)
3020 TRACE("Media already ready (%u, %u)\n",sequence
,last_sequence
);
3021 return ERROR_SUCCESS
;
3024 sprintfW(Query
,ExecSeqQuery
,sequence
);
3026 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3027 if (rc
!= ERROR_SUCCESS
)
3030 rc
= MSI_ViewExecute(view
, 0);
3031 if (rc
!= ERROR_SUCCESS
)
3033 MSI_ViewClose(view
);
3034 msiobj_release(&view
->hdr
);
3038 rc
= MSI_ViewFetch(view
,&row
);
3039 if (rc
!= ERROR_SUCCESS
)
3041 MSI_ViewClose(view
);
3042 msiobj_release(&view
->hdr
);
3045 seq
= MSI_RecordGetInteger(row
,2);
3046 last_sequence
= seq
;
3048 if (!MSI_RecordIsNull(row
,4))
3051 MSI_RecordGetStringW(row
,4,cab
,&sz
);
3052 TRACE("Source is CAB %s\n",debugstr_w(cab
));
3053 /* the stream does not contain the # character */
3056 writeout_cabinet_stream(package
,&cab
[1],source
);
3057 strcpyW(path
,source
);
3058 *(strrchrW(path
,'\\')+1)=0;
3063 if (MSI_GetPropertyW(package
, cszSourceDir
, source
, &sz
))
3065 ERR("No Source dir defined \n");
3066 rc
= ERROR_FUNCTION_FAILED
;
3070 strcpyW(path
,source
);
3071 strcatW(source
,cab
);
3072 /* extract the cab file into a folder in the temp folder */
3074 if (MSI_GetPropertyW(package
, cszTempFolder
,path
, &sz
)
3076 GetTempPathW(MAX_PATH
,path
);
3079 rc
= !extract_cabinet_file(package
, source
,path
);
3081 msiobj_release(&row
->hdr
);
3082 MSI_ViewClose(view
);
3083 msiobj_release(&view
->hdr
);
3087 inline static UINT
create_component_directory ( MSIPACKAGE
* package
, INT component
)
3091 LPWSTR install_path
;
3093 install_path
= resolve_folder(package
, package
->components
[component
].Directory
,
3094 FALSE
, FALSE
, &folder
);
3096 return ERROR_FUNCTION_FAILED
;
3098 /* create the path */
3099 if (folder
->State
== 0)
3101 create_full_pathW(install_path
);
3104 HeapFree(GetProcessHeap(), 0, install_path
);
3109 static UINT
ACTION_InstallFiles(MSIPACKAGE
*package
)
3111 UINT rc
= ERROR_SUCCESS
;
3114 WCHAR uipath
[MAX_PATH
];
3117 return ERROR_INVALID_HANDLE
;
3119 /* increment progress bar each time action data is sent */
3120 ui_progress(package
,1,1,1,0);
3122 for (index
= 0; index
< package
->loaded_files
; index
++)
3124 WCHAR path_to_source
[MAX_PATH
];
3127 file
= &package
->files
[index
];
3129 if (file
->Temporary
)
3132 if (package
->components
[file
->ComponentIndex
].ActionRequest
!=
3135 TRACE("File %s is not scheduled for install\n",
3136 debugstr_w(file
->File
));
3141 if ((file
->State
== 1) || (file
->State
== 2))
3143 TRACE("Installing %s\n",debugstr_w(file
->File
));
3144 rc
= ready_media_for_file(package
,file
->Sequence
,path_to_source
);
3147 * our file table could change here because a new temp file
3148 * may have been created
3150 file
= &package
->files
[index
];
3151 if (rc
!= ERROR_SUCCESS
)
3153 ERR("Unable to ready media\n");
3154 rc
= ERROR_FUNCTION_FAILED
;
3158 create_component_directory( package
, file
->ComponentIndex
);
3160 strcpyW(file
->SourcePath
, path_to_source
);
3161 strcatW(file
->SourcePath
, file
->File
);
3163 TRACE("file paths %s to %s\n",debugstr_w(file
->SourcePath
),
3164 debugstr_w(file
->TargetPath
));
3167 uirow
=MSI_CreateRecord(9);
3168 MSI_RecordSetStringW(uirow
,1,file
->File
);
3169 strcpyW(uipath
,file
->TargetPath
);
3170 *(strrchrW(uipath
,'\\')+1)=0;
3171 MSI_RecordSetStringW(uirow
,9,uipath
);
3172 MSI_RecordSetInteger(uirow
,6,file
->FileSize
);
3173 ui_actiondata(package
,szInstallFiles
,uirow
);
3174 msiobj_release( &uirow
->hdr
);
3176 if (!MoveFileW(file
->SourcePath
,file
->TargetPath
))
3178 rc
= GetLastError();
3179 ERR("Unable to move file (%s -> %s) (error %d)\n",
3180 debugstr_w(file
->SourcePath
), debugstr_w(file
->TargetPath
),
3182 if (rc
== ERROR_ALREADY_EXISTS
&& file
->State
== 2)
3184 CopyFileW(file
->SourcePath
,file
->TargetPath
,FALSE
);
3185 DeleteFileW(file
->SourcePath
);
3188 else if (rc
== ERROR_FILE_NOT_FOUND
)
3190 ERR("Source File Not Found! Continueing\n");
3195 ERR("Ignoring Error and continuing...\n");
3202 ui_progress(package
,2,0,0,0);
3209 inline static UINT
get_file_target(MSIPACKAGE
*package
, LPCWSTR file_key
,
3210 LPWSTR
* file_source
)
3215 return ERROR_INVALID_HANDLE
;
3217 for (index
= 0; index
< package
->loaded_files
; index
++)
3219 if (strcmpW(file_key
,package
->files
[index
].File
)==0)
3221 if (package
->files
[index
].State
>= 3)
3223 *file_source
= dupstrW(package
->files
[index
].TargetPath
);
3224 return ERROR_SUCCESS
;
3227 return ERROR_FILE_NOT_FOUND
;
3231 return ERROR_FUNCTION_FAILED
;
3234 static UINT
ACTION_DuplicateFiles(MSIPACKAGE
*package
)
3238 MSIRECORD
* row
= 0;
3239 static const WCHAR ExecSeqQuery
[] = {
3240 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
3241 'D','u','p','l','i','c','a','t','e','F','i','l','e',0};
3244 return ERROR_INVALID_HANDLE
;
3246 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3247 if (rc
!= ERROR_SUCCESS
)
3248 return ERROR_SUCCESS
;
3250 rc
= MSI_ViewExecute(view
, 0);
3251 if (rc
!= ERROR_SUCCESS
)
3253 MSI_ViewClose(view
);
3254 msiobj_release(&view
->hdr
);
3260 WCHAR file_key
[0x100];
3261 WCHAR
*file_source
= NULL
;
3262 WCHAR dest_name
[0x100];
3263 LPWSTR dest_path
, dest
;
3264 WCHAR component
[0x100];
3265 INT component_index
;
3269 rc
= MSI_ViewFetch(view
,&row
);
3270 if (rc
!= ERROR_SUCCESS
)
3277 rc
= MSI_RecordGetStringW(row
,2,component
,&sz
);
3278 if (rc
!= ERROR_SUCCESS
)
3280 ERR("Unable to get component\n");
3281 msiobj_release(&row
->hdr
);
3285 component_index
= get_loaded_component(package
,component
);
3286 if (package
->components
[component_index
].ActionRequest
!=
3289 TRACE("Skipping copy due to disabled component\n");
3290 msiobj_release(&row
->hdr
);
3295 rc
= MSI_RecordGetStringW(row
,3,file_key
,&sz
);
3296 if (rc
!= ERROR_SUCCESS
)
3298 ERR("Unable to get file key\n");
3299 msiobj_release(&row
->hdr
);
3303 rc
= get_file_target(package
,file_key
,&file_source
);
3305 if (rc
!= ERROR_SUCCESS
)
3307 ERR("Original file unknown %s\n",debugstr_w(file_key
));
3308 msiobj_release(&row
->hdr
);
3310 HeapFree(GetProcessHeap(),0,file_source
);
3314 if (MSI_RecordIsNull(row
,4))
3316 strcpyW(dest_name
,strrchrW(file_source
,'\\')+1);
3321 MSI_RecordGetStringW(row
,4,dest_name
,&sz
);
3322 reduce_to_longfilename(dest_name
);
3325 if (MSI_RecordIsNull(row
,5))
3328 dest_path
= dupstrW(file_source
);
3329 p
= strrchrW(dest_path
,'\\');
3335 WCHAR destkey
[0x100];
3337 MSI_RecordGetStringW(row
,5,destkey
,&sz
);
3339 dest_path
= resolve_folder(package
, destkey
, FALSE
,FALSE
,NULL
);
3342 ERR("Unable to get destination folder\n");
3343 msiobj_release(&row
->hdr
);
3345 HeapFree(GetProcessHeap(),0,file_source
);
3350 dest
= build_directory_name(2, dest_path
, dest_name
);
3351 HeapFree(GetProcessHeap(), 0, dest_path
);
3353 TRACE("Duplicating file %s to %s\n",debugstr_w(file_source
),
3356 if (strcmpW(file_source
,dest
))
3357 rc
= !CopyFileW(file_source
,dest
,TRUE
);
3361 if (rc
!= ERROR_SUCCESS
)
3362 ERR("Failed to copy file\n");
3364 FIXME("We should track these duplicate files as well\n");
3366 msiobj_release(&row
->hdr
);
3367 HeapFree(GetProcessHeap(),0,dest
);
3368 HeapFree(GetProcessHeap(),0,file_source
);
3370 MSI_ViewClose(view
);
3371 msiobj_release(&view
->hdr
);
3376 /* OK this value is "interpretted" and then formatted based on the
3377 first few characters */
3378 static LPSTR
parse_value(MSIPACKAGE
*package
, WCHAR
*value
, DWORD
*type
,
3382 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
3391 deformat_string(package
, &value
[2], &deformated
);
3393 /* binary value type */
3396 *size
= strlenW(ptr
)/2;
3397 data
= HeapAlloc(GetProcessHeap(),0,*size
);
3409 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
3412 HeapFree(GetProcessHeap(),0,deformated
);
3414 TRACE("Data %li bytes(%i)\n",*size
,count
);
3419 deformat_string(package
, &value
[1], &deformated
);
3422 *size
= sizeof(DWORD
);
3423 data
= HeapAlloc(GetProcessHeap(),0,*size
);
3424 *(LPDWORD
)data
= atoiW(deformated
);
3425 TRACE("DWORD %i\n",*data
);
3427 HeapFree(GetProcessHeap(),0,deformated
);
3440 *type
=REG_EXPAND_SZ
;
3448 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
3453 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
3457 MSIRECORD
* row
= 0;
3458 static const WCHAR ExecSeqQuery
[] = {
3459 's','e','l','e','c','t',' ','*',' ',
3460 'f','r','o','m',' ','R','e','g','i','s','t','r','y',0 };
3463 return ERROR_INVALID_HANDLE
;
3465 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3466 if (rc
!= ERROR_SUCCESS
)
3467 return ERROR_SUCCESS
;
3469 rc
= MSI_ViewExecute(view
, 0);
3470 if (rc
!= ERROR_SUCCESS
)
3472 MSI_ViewClose(view
);
3473 msiobj_release(&view
->hdr
);
3477 /* increment progress bar each time action data is sent */
3478 ui_progress(package
,1,1,1,0);
3482 static const WCHAR szHCR
[] =
3483 {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T','\\',0};
3484 static const WCHAR szHCU
[] =
3485 {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',0};
3486 static const WCHAR szHLM
[] =
3487 {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',
3489 static const WCHAR szHU
[] =
3490 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
3492 LPSTR value_data
= NULL
;
3493 HKEY root_key
, hkey
;
3495 LPWSTR value
, key
, name
, component
;
3497 INT component_index
;
3502 rc
= MSI_ViewFetch(view
,&row
);
3503 if (rc
!= ERROR_SUCCESS
)
3514 component
= load_dynamic_stringW(row
, 6);
3515 component_index
= get_loaded_component(package
,component
);
3517 if (package
->components
[component_index
].ActionRequest
!=
3520 TRACE("Skipping write due to disabled component\n");
3521 msiobj_release(&row
->hdr
);
3525 /* null values have special meanings during uninstalls and such */
3527 if(MSI_RecordIsNull(row
,5))
3529 msiobj_release(&row
->hdr
);
3533 root
= MSI_RecordGetInteger(row
,2);
3534 key
= load_dynamic_stringW(row
, 3);
3536 name
= load_dynamic_stringW(row
, 4);
3538 /* get the root key */
3541 case 0: root_key
= HKEY_CLASSES_ROOT
;
3544 case 1: root_key
= HKEY_CURRENT_USER
;
3547 case 2: root_key
= HKEY_LOCAL_MACHINE
;
3550 case 3: root_key
= HKEY_USERS
;
3554 ERR("Unknown root %i\n",root
);
3561 msiobj_release(&row
->hdr
);
3565 size
= strlenW(key
) + strlenW(szRoot
) + 1;
3566 uikey
= HeapAlloc(GetProcessHeap(), 0, size
*sizeof(WCHAR
));
3567 strcpyW(uikey
,szRoot
);
3569 if (RegCreateKeyW( root_key
, key
, &hkey
))
3571 ERR("Could not create key %s\n",debugstr_w(key
));
3572 msiobj_release(&row
->hdr
);
3576 value
= load_dynamic_stringW(row
,5);
3577 value_data
= parse_value(package
, value
, &type
, &size
);
3581 TRACE("Setting value %s\n",debugstr_w(name
));
3582 RegSetValueExW(hkey
, name
, 0, type
, value_data
, size
);
3584 uirow
= MSI_CreateRecord(3);
3585 MSI_RecordSetStringW(uirow
,2,name
);
3586 MSI_RecordSetStringW(uirow
,1,uikey
);
3589 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
3591 MSI_RecordSetStringW(uirow
,3,value
);
3593 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
3594 ui_progress(package
,2,0,0,0);
3595 msiobj_release( &uirow
->hdr
);
3597 HeapFree(GetProcessHeap(),0,value_data
);
3599 HeapFree(GetProcessHeap(),0,value
);
3601 msiobj_release(&row
->hdr
);
3605 HeapFree(GetProcessHeap(),0,uikey
);
3607 HeapFree(GetProcessHeap(),0,key
);
3609 HeapFree(GetProcessHeap(),0,name
);
3611 HeapFree(GetProcessHeap(),0,component
);
3613 MSI_ViewClose(view
);
3614 msiobj_release(&view
->hdr
);
3619 * This helper function should probably go alot of places
3621 * Thinking about this, maybe this should become yet another Bison file
3623 static DWORD
deformat_string(MSIPACKAGE
*package
, WCHAR
* ptr
,WCHAR
** data
)
3635 TRACE("Deformatting NULL string\n");
3639 /* scan for special characters */
3640 if (!strchrW(ptr
,'[') || (strchrW(ptr
,'[') && !strchrW(ptr
,']')))
3643 size
= (strlenW(ptr
)+1) * sizeof(WCHAR
);
3644 *data
= HeapAlloc(GetProcessHeap(),0,size
);
3649 /* formatted string located */
3650 mark
= strchrW(ptr
,'[');
3653 INT cnt
= (mark
- ptr
);
3654 TRACE("%i (%i) characters before marker\n",cnt
,(mark
-ptr
));
3655 size
= cnt
* sizeof(WCHAR
);
3656 size
+= sizeof(WCHAR
);
3657 *data
= HeapAlloc(GetProcessHeap(),0,size
);
3658 strncpyW(*data
,ptr
,cnt
);
3663 size
= sizeof(WCHAR
);
3664 *data
= HeapAlloc(GetProcessHeap(),0,size
);
3669 *strchrW(key
,']')=0;
3670 mark
= strchrW(mark
,']');
3672 TRACE("Current %s .. %s\n",debugstr_w(*data
),debugstr_w(mark
));
3674 rc
= MSI_GetPropertyW(package
, key
, NULL
, &sz
);
3675 if ((rc
== ERROR_SUCCESS
) || (rc
== ERROR_MORE_DATA
))
3680 value
= HeapAlloc(GetProcessHeap(),0,sz
* sizeof(WCHAR
));
3681 MSI_GetPropertyW(package
, key
, value
, &sz
);
3683 chunk
= (strlenW(value
)+1) * sizeof(WCHAR
);
3685 newdata
= HeapReAlloc(GetProcessHeap(),0,*data
,size
);
3687 strcatW(*data
,value
);
3689 TRACE("Current %s .. %s\n",debugstr_w(*data
),debugstr_w(mark
));
3693 chunk
= (strlenW(mark
)+1) * sizeof(WCHAR
);
3695 newdata
= HeapReAlloc(GetProcessHeap(),0,*data
,size
);
3697 strcatW(*data
,mark
);
3699 (*data
)[strlenW(*data
)]=0;
3700 TRACE("Current %s .. %s\n",debugstr_w(*data
),debugstr_w(mark
));
3702 /* recursively do this to clean up */
3703 mark
= HeapAlloc(GetProcessHeap(),0,size
);
3704 strcpyW(mark
,*data
);
3705 TRACE("String at this point %s\n",debugstr_w(mark
));
3706 size
= deformat_string(package
,mark
,data
);
3707 HeapFree(GetProcessHeap(),0,mark
);
3711 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
3713 return ERROR_SUCCESS
;
3717 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
3720 static const WCHAR q1
[]={
3721 'S','E','L','E','C','T',' ','*',' ',
3722 'F','R','O','M',' ','R','e','g','i','s','t','r','y',0};
3725 MSIRECORD
* row
= 0;
3727 TRACE(" InstallValidate \n");
3729 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
3730 if (rc
!= ERROR_SUCCESS
)
3731 return ERROR_SUCCESS
;
3733 rc
= MSI_ViewExecute(view
, 0);
3734 if (rc
!= ERROR_SUCCESS
)
3736 MSI_ViewClose(view
);
3737 msiobj_release(&view
->hdr
);
3742 rc
= MSI_ViewFetch(view
,&row
);
3743 if (rc
!= ERROR_SUCCESS
)
3750 msiobj_release(&row
->hdr
);
3752 MSI_ViewClose(view
);
3753 msiobj_release(&view
->hdr
);
3755 ui_progress(package
,0,progress
+package
->loaded_files
,0,0);
3757 return ERROR_SUCCESS
;
3760 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
3763 MSIQUERY
* view
= NULL
;
3764 MSIRECORD
* row
= 0;
3765 static const WCHAR ExecSeqQuery
[] = {
3766 'S','E','L','E','C','T',' ','*',' ',
3767 'f','r','o','m',' ','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n',0};
3768 static const WCHAR title
[]=
3769 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3771 TRACE("Checking launch conditions\n");
3773 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3774 if (rc
!= ERROR_SUCCESS
)
3775 return ERROR_SUCCESS
;
3777 rc
= MSI_ViewExecute(view
, 0);
3778 if (rc
!= ERROR_SUCCESS
)
3780 MSI_ViewClose(view
);
3781 msiobj_release(&view
->hdr
);
3786 while (rc
== ERROR_SUCCESS
)
3789 LPWSTR message
= NULL
;
3791 rc
= MSI_ViewFetch(view
,&row
);
3792 if (rc
!= ERROR_SUCCESS
)
3798 cond
= load_dynamic_stringW(row
,1);
3800 if (MSI_EvaluateConditionW(package
,cond
) != MSICONDITION_TRUE
)
3802 message
= load_dynamic_stringW(row
,2);
3803 MessageBoxW(NULL
,message
,title
,MB_OK
);
3804 HeapFree(GetProcessHeap(),0,message
);
3805 rc
= ERROR_FUNCTION_FAILED
;
3807 HeapFree(GetProcessHeap(),0,cond
);
3808 msiobj_release(&row
->hdr
);
3810 MSI_ViewClose(view
);
3811 msiobj_release(&view
->hdr
);
3815 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, INT
3818 MSICOMPONENT
* cmp
= &package
->components
[component_index
];
3820 if (cmp
->KeyPath
[0]==0)
3822 LPWSTR p
= resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,NULL
);
3825 if ((cmp
->Attributes
& 0x4) || (cmp
->Attributes
& 0x20))
3827 FIXME("UNIMPLEMENTED keypath as Registry or ODBC Source\n");
3833 j
= get_loaded_file(package
,cmp
->KeyPath
);
3837 LPWSTR p
= dupstrW(package
->files
[j
].TargetPath
);
3845 * Ok further analysis makes me think that this work is
3846 * actually done in the PublishComponents and PublishFeatures
3847 * step, and not here. It appears like the keypath and all that is
3848 * resolved in this step, however actually written in the Publish steps.
3849 * But we will leave it here for now because it is unclear
3851 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
3854 WCHAR squished_pc
[0x100];
3855 WCHAR squished_cc
[0x100];
3858 HKEY hkey
=0,hkey2
=0,hkey3
=0;
3859 static const WCHAR szProductCode
[]=
3860 {'P','r','o','d','u','c','t','C','o','d','e',0};
3861 static const WCHAR szInstaller
[] = {
3862 'S','o','f','t','w','a','r','e','\\',
3863 'M','i','c','r','o','s','o','f','t','\\',
3864 'W','i','n','d','o','w','s','\\',
3865 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3866 'I','n','s','t','a','l','l','e','r',0 };
3867 static const WCHAR szFeatures
[] = {
3868 'F','e','a','t','u','r','e','s',0 };
3869 static const WCHAR szComponents
[] = {
3870 'C','o','m','p','o','n','e','n','t','s',0 };
3873 return ERROR_INVALID_HANDLE
;
3875 /* writes the Component and Features values to the registry */
3876 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
3880 squash_guid(productcode
,squished_pc
);
3881 rc
= RegCreateKeyW(HKEY_LOCAL_MACHINE
,szInstaller
,&hkey
);
3882 if (rc
!= ERROR_SUCCESS
)
3885 rc
= RegCreateKeyW(hkey
,szFeatures
,&hkey2
);
3886 if (rc
!= ERROR_SUCCESS
)
3889 rc
= RegCreateKeyW(hkey2
,squished_pc
,&hkey3
);
3890 if (rc
!= ERROR_SUCCESS
)
3893 /* here the guids are base 85 encoded */
3894 for (i
= 0; i
< package
->loaded_features
; i
++)
3901 size
= package
->features
[i
].ComponentCount
*21*sizeof(WCHAR
);
3902 data
= HeapAlloc(GetProcessHeap(), 0, size
);
3905 for (j
= 0; j
< package
->features
[i
].ComponentCount
; j
++)
3908 TRACE("From %s\n",debugstr_w(package
->components
3909 [package
->features
[i
].Components
[j
]].ComponentId
));
3910 CLSIDFromString(package
->components
3911 [package
->features
[i
].Components
[j
]].ComponentId
,
3913 encode_base85_guid(&clsid
,buf
);
3914 TRACE("to %s\n",debugstr_w(buf
));
3918 size
= strlenW(data
)*sizeof(WCHAR
);
3919 RegSetValueExW(hkey3
,package
->features
[i
].Feature
,0,REG_SZ
,
3921 HeapFree(GetProcessHeap(),0,data
);
3927 rc
= RegCreateKeyW(hkey
,szComponents
,&hkey2
);
3928 if (rc
!= ERROR_SUCCESS
)
3931 for (i
= 0; i
< package
->loaded_components
; i
++)
3933 if (package
->components
[i
].ComponentId
[0]!=0)
3935 WCHAR
*keypath
= NULL
;
3938 squash_guid(package
->components
[i
].ComponentId
,squished_cc
);
3939 rc
= RegCreateKeyW(hkey2
,squished_cc
,&hkey3
);
3940 if (rc
!= ERROR_SUCCESS
)
3943 keypath
= resolve_keypath(package
,i
);
3946 RegSetValueExW(hkey3
,squished_pc
,0,REG_SZ
,(LPVOID
)keypath
,
3947 (strlenW(keypath
)+1)*sizeof(WCHAR
));
3951 uirow
= MSI_CreateRecord(3);
3952 MSI_RecordSetStringW(uirow
,1,productcode
);
3953 MSI_RecordSetStringW(uirow
,2,package
->components
[i
].
3955 MSI_RecordSetStringW(uirow
,3,keypath
);
3956 ui_actiondata(package
,szProcessComponents
,uirow
);
3957 msiobj_release( &uirow
->hdr
);
3958 HeapFree(GetProcessHeap(),0,keypath
);
3963 HeapFree(GetProcessHeap(), 0, productcode
);
3969 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
3972 * OK this is a bit confusing.. I am given a _Component key and I believe
3973 * that the file that is being registered as a type library is the "key file
3974 * of that component" which I interpret to mean "The file in the KeyPath of
3979 MSIRECORD
* row
= 0;
3980 static const WCHAR Query
[] = {
3981 'S','E','L','E','C','T',' ','*',' ',
3982 'f','r','o','m',' ','T','y','p','e','L','i','b',0};
3987 return ERROR_INVALID_HANDLE
;
3989 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3990 if (rc
!= ERROR_SUCCESS
)
3991 return ERROR_SUCCESS
;
3993 rc
= MSI_ViewExecute(view
, 0);
3994 if (rc
!= ERROR_SUCCESS
)
3996 MSI_ViewClose(view
);
3997 msiobj_release(&view
->hdr
);
4003 WCHAR component
[0x100];
4007 rc
= MSI_ViewFetch(view
,&row
);
4008 if (rc
!= ERROR_SUCCESS
)
4015 MSI_RecordGetStringW(row
,3,component
,&sz
);
4017 index
= get_loaded_component(package
,component
);
4020 msiobj_release(&row
->hdr
);
4024 if (package
->components
[index
].ActionRequest
!= INSTALLSTATE_LOCAL
)
4026 TRACE("Skipping typelib reg due to disabled component\n");
4027 msiobj_release(&row
->hdr
);
4031 index
= get_loaded_file(package
,package
->components
[index
].KeyPath
);
4035 msiobj_release(&row
->hdr
);
4039 res
= LoadTypeLib(package
->files
[index
].TargetPath
,&ptLib
);
4043 WCHAR helpid
[0x100];
4046 MSI_RecordGetStringW(row
,6,helpid
,&sz
);
4048 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,NULL
);
4049 res
= RegisterTypeLib(ptLib
,package
->files
[index
].TargetPath
,help
);
4050 HeapFree(GetProcessHeap(),0,help
);
4052 if (!SUCCEEDED(res
))
4053 ERR("Failed to register type library %s\n",
4054 debugstr_w(package
->files
[index
].TargetPath
));
4057 /* Yes the row has more fields than I need, but #1 is
4058 correct and the only one I need. Why make a new row? */
4060 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
4062 TRACE("Registered %s\n",
4063 debugstr_w(package
->files
[index
].TargetPath
));
4067 ITypeLib_Release(ptLib
);
4070 ERR("Failed to load type library %s\n",
4071 debugstr_w(package
->files
[index
].TargetPath
));
4073 msiobj_release(&row
->hdr
);
4075 MSI_ViewClose(view
);
4076 msiobj_release(&view
->hdr
);
4081 static UINT
register_appid(MSIPACKAGE
*package
, LPCWSTR clsid
, LPCWSTR app
)
4083 static const WCHAR szAppID
[] = { 'A','p','p','I','D',0 };
4086 MSIRECORD
* row
= 0;
4087 static const WCHAR ExecSeqQuery
[] =
4088 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'
4089 ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};
4094 return ERROR_INVALID_HANDLE
;
4096 rc
= ACTION_OpenQuery(package
->db
, &view
, ExecSeqQuery
, clsid
);
4097 if (rc
!= ERROR_SUCCESS
)
4100 rc
= MSI_ViewExecute(view
, 0);
4101 if (rc
!= ERROR_SUCCESS
)
4103 MSI_ViewClose(view
);
4104 msiobj_release(&view
->hdr
);
4108 RegCreateKeyW(HKEY_CLASSES_ROOT
,szAppID
,&hkey2
);
4109 RegCreateKeyW(hkey2
,clsid
,&hkey3
);
4110 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,(LPVOID
)app
,
4111 (strlenW(app
)+1)*sizeof(WCHAR
));
4113 rc
= MSI_ViewFetch(view
,&row
);
4114 if (rc
!= ERROR_SUCCESS
)
4116 MSI_ViewClose(view
);
4117 msiobj_release(&view
->hdr
);
4121 if (!MSI_RecordIsNull(row
,2))
4123 LPWSTR deformated
=0;
4125 static const WCHAR szRemoteServerName
[] =
4126 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
4127 buffer
= load_dynamic_stringW(row
,2);
4128 size
= deformat_string(package
,buffer
,&deformated
);
4129 RegSetValueExW(hkey3
,szRemoteServerName
,0,REG_SZ
,(LPVOID
)deformated
,
4131 HeapFree(GetProcessHeap(),0,deformated
);
4132 HeapFree(GetProcessHeap(),0,buffer
);
4135 if (!MSI_RecordIsNull(row
,3))
4137 static const WCHAR szLocalService
[] =
4138 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
4140 buffer
= load_dynamic_stringW(row
,3);
4141 size
= (strlenW(buffer
)+1) * sizeof(WCHAR
);
4142 RegSetValueExW(hkey3
,szLocalService
,0,REG_SZ
,(LPVOID
)buffer
,size
);
4143 HeapFree(GetProcessHeap(),0,buffer
);
4146 if (!MSI_RecordIsNull(row
,4))
4148 static const WCHAR szService
[] =
4149 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
4151 buffer
= load_dynamic_stringW(row
,4);
4152 size
= (strlenW(buffer
)+1) * sizeof(WCHAR
);
4153 RegSetValueExW(hkey3
,szService
,0,REG_SZ
,(LPVOID
)buffer
,size
);
4154 HeapFree(GetProcessHeap(),0,buffer
);
4157 if (!MSI_RecordIsNull(row
,5))
4159 static const WCHAR szDLL
[] =
4160 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
4162 buffer
= load_dynamic_stringW(row
,5);
4163 size
= (strlenW(buffer
)+1) * sizeof(WCHAR
);
4164 RegSetValueExW(hkey3
,szDLL
,0,REG_SZ
,(LPVOID
)buffer
,size
);
4165 HeapFree(GetProcessHeap(),0,buffer
);
4168 if (!MSI_RecordIsNull(row
,6))
4170 static const WCHAR szActivate
[] =
4171 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
4172 static const WCHAR szY
[] = {'Y',0};
4174 if (MSI_RecordGetInteger(row
,6))
4175 RegSetValueExW(hkey3
,szActivate
,0,REG_SZ
,(LPVOID
)szY
,4);
4178 if (!MSI_RecordIsNull(row
,7))
4180 static const WCHAR szRunAs
[] = {'R','u','n','A','s',0};
4181 static const WCHAR szUser
[] =
4182 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
4184 if (MSI_RecordGetInteger(row
,7))
4185 RegSetValueExW(hkey3
,szRunAs
,0,REG_SZ
,(LPVOID
)szUser
,34);
4188 msiobj_release(&row
->hdr
);
4189 MSI_ViewClose(view
);
4190 msiobj_release(&view
->hdr
);
4196 static UINT
ACTION_RegisterClassInfo(MSIPACKAGE
*package
)
4199 * Again I am assuming the words, "Whose key file represents" when referring
4200 * to a Component as to meaning that Components KeyPath file
4202 * Also there is a very strong connection between ClassInfo and ProgID
4203 * that I am mostly glossing over.
4204 * What would be more propper is to load the ClassInfo and the ProgID info
4205 * into memory data structures and then be able to enable and disable them
4206 * based on component.
4211 MSIRECORD
* row
= 0;
4212 static const WCHAR ExecSeqQuery
[] = {
4213 'S','E','L','E','C','T',' ','*',' ',
4214 'f','r','o','m',' ','C','l','a','s','s',0};
4215 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
4216 static const WCHAR szProgID
[] = { 'P','r','o','g','I','D',0 };
4217 static const WCHAR szAppID
[] = { 'A','p','p','I','D',0 };
4218 HKEY hkey
,hkey2
,hkey3
;
4221 return ERROR_INVALID_HANDLE
;
4223 rc
= RegCreateKeyW(HKEY_CLASSES_ROOT
,szCLSID
,&hkey
);
4224 if (rc
!= ERROR_SUCCESS
)
4225 return ERROR_FUNCTION_FAILED
;
4227 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4228 if (rc
!= ERROR_SUCCESS
)
4234 rc
= MSI_ViewExecute(view
, 0);
4235 if (rc
!= ERROR_SUCCESS
)
4237 MSI_ViewClose(view
);
4238 msiobj_release(&view
->hdr
);
4245 WCHAR buffer
[0x100];
4250 rc
= MSI_ViewFetch(view
,&row
);
4251 if (rc
!= ERROR_SUCCESS
)
4258 MSI_RecordGetStringW(row
,3,buffer
,&sz
);
4260 index
= get_loaded_component(package
,buffer
);
4264 msiobj_release(&row
->hdr
);
4268 if (package
->components
[index
].ActionRequest
!= INSTALLSTATE_LOCAL
)
4270 TRACE("Skipping class reg due to disabled component\n");
4271 msiobj_release(&row
->hdr
);
4276 MSI_RecordGetStringW(row
,1,clsid
,&sz
);
4277 RegCreateKeyW(hkey
,clsid
,&hkey2
);
4279 if (!MSI_RecordIsNull(row
,5))
4282 MSI_RecordGetStringW(row
,5,desc
,&sz
);
4284 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)desc
,
4285 (strlenW(desc
)+1)*sizeof(WCHAR
));
4291 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
4293 RegCreateKeyW(hkey2
,buffer
,&hkey3
);
4295 index
= get_loaded_file(package
,package
->components
[index
].KeyPath
);
4296 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,
4297 (LPVOID
)package
->files
[index
].TargetPath
,
4298 (strlenW(package
->files
[index
].TargetPath
)+1)
4303 if (!MSI_RecordIsNull(row
,4))
4306 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
4308 RegCreateKeyW(hkey2
,szProgID
,&hkey3
);
4310 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,(LPVOID
)buffer
,
4311 (strlenW(buffer
)+1)*sizeof(WCHAR
));
4316 if (!MSI_RecordIsNull(row
,6))
4319 MSI_RecordGetStringW(row
,6,buffer
,&sz
);
4321 RegSetValueExW(hkey2
,szAppID
,0,REG_SZ
,(LPVOID
)buffer
,
4322 (strlenW(buffer
)+1)*sizeof(WCHAR
));
4324 register_appid(package
,buffer
,desc
);
4329 FIXME("Process the rest of the fields >7\n");
4331 ui_actiondata(package
,szRegisterClassInfo
,row
);
4333 msiobj_release(&row
->hdr
);
4335 MSI_ViewClose(view
);
4336 msiobj_release(&view
->hdr
);
4343 static UINT
register_progid_base(MSIRECORD
* row
, LPWSTR clsid
)
4345 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
4347 WCHAR buffer
[0x100];
4352 MSI_RecordGetStringW(row
,1,buffer
,&sz
);
4353 RegCreateKeyW(HKEY_CLASSES_ROOT
,buffer
,&hkey
);
4355 if (!MSI_RecordIsNull(row
,4))
4358 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
4359 RegSetValueExW(hkey
,NULL
,0,REG_SZ
,(LPVOID
)buffer
, (strlenW(buffer
)+1) *
4363 if (!MSI_RecordIsNull(row
,3))
4367 MSI_RecordGetStringW(row
,3,buffer
,&sz
);
4368 RegCreateKeyW(hkey
,szCLSID
,&hkey2
);
4369 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)buffer
, (strlenW(buffer
)+1) *
4373 strcpyW(clsid
,buffer
);
4379 FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
4380 return ERROR_FUNCTION_FAILED
;
4382 if (!MSI_RecordIsNull(row
,5))
4383 FIXME ("UNHANDLED icon in Progid\n");
4384 return ERROR_SUCCESS
;
4387 static UINT
register_progid(MSIPACKAGE
*package
, MSIRECORD
* row
, LPWSTR clsid
);
4389 static UINT
register_parent_progid(MSIPACKAGE
*package
, LPCWSTR parent
,
4394 MSIRECORD
* row
= 0;
4395 static const WCHAR Query_t
[] =
4396 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'
4397 ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'
4401 return ERROR_INVALID_HANDLE
;
4403 rc
= ACTION_OpenQuery(package
->db
, &view
, Query_t
, parent
);
4404 if (rc
!= ERROR_SUCCESS
)
4407 rc
= MSI_ViewExecute(view
, 0);
4408 if (rc
!= ERROR_SUCCESS
)
4410 MSI_ViewClose(view
);
4411 msiobj_release(&view
->hdr
);
4415 rc
= MSI_ViewFetch(view
,&row
);
4416 if (rc
!= ERROR_SUCCESS
)
4418 MSI_ViewClose(view
);
4419 msiobj_release(&view
->hdr
);
4423 register_progid(package
,row
,clsid
);
4425 msiobj_release(&row
->hdr
);
4426 MSI_ViewClose(view
);
4427 msiobj_release(&view
->hdr
);
4431 static UINT
register_progid(MSIPACKAGE
*package
, MSIRECORD
* row
, LPWSTR clsid
)
4433 UINT rc
= ERROR_SUCCESS
;
4435 if (MSI_RecordIsNull(row
,2))
4436 rc
= register_progid_base(row
,clsid
);
4439 WCHAR buffer
[0x1000];
4442 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
4444 /* check if already registered */
4446 MSI_RecordGetStringW(row
,1,buffer
,&sz
);
4447 RegCreateKeyExW(HKEY_CLASSES_ROOT
, buffer
, 0, NULL
, 0,
4448 KEY_ALL_ACCESS
, NULL
, &hkey
, &disp
);
4449 if (disp
== REG_OPENED_EXISTING_KEY
)
4451 TRACE("Key already registered\n");
4455 /* clsid is same as parent */
4456 RegCreateKeyW(hkey
,szCLSID
,&hkey2
);
4457 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)clsid
, (strlenW(clsid
)+1) *
4463 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
4464 rc
= register_parent_progid(package
,buffer
,clsid
);
4466 if (!MSI_RecordIsNull(row
,4))
4469 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
4470 RegSetValueExW(hkey
,NULL
,0,REG_SZ
,(LPVOID
)buffer
,
4471 (strlenW(buffer
)+1) * sizeof(WCHAR
));
4474 if (!MSI_RecordIsNull(row
,5))
4475 FIXME ("UNHANDLED icon in Progid\n");
4482 static UINT
ACTION_RegisterProgIdInfo(MSIPACKAGE
*package
)
4485 * Sigh, here I am just brute force registering all progids
4486 * this needs to be linked to the Classes that have been registered
4487 * but the easiest way to do that is to load all these stuff into
4488 * memory for easy checking.
4490 * Gives me something to continue to work toward.
4494 MSIRECORD
* row
= 0;
4495 static const WCHAR Query
[] = {
4496 'S','E','L','E','C','T',' ','*',' ',
4497 'F','R','O','M',' ','P','r','o','g','I','d',0};
4500 return ERROR_INVALID_HANDLE
;
4502 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
4503 if (rc
!= ERROR_SUCCESS
)
4504 return ERROR_SUCCESS
;
4506 rc
= MSI_ViewExecute(view
, 0);
4507 if (rc
!= ERROR_SUCCESS
)
4509 MSI_ViewClose(view
);
4510 msiobj_release(&view
->hdr
);
4516 WCHAR clsid
[0x1000];
4518 rc
= MSI_ViewFetch(view
,&row
);
4519 if (rc
!= ERROR_SUCCESS
)
4525 register_progid(package
,row
,clsid
);
4526 ui_actiondata(package
,szRegisterProgIdInfo
,row
);
4528 msiobj_release(&row
->hdr
);
4530 MSI_ViewClose(view
);
4531 msiobj_release(&view
->hdr
);
4535 static UINT
build_icon_path(MSIPACKAGE
*package
, LPCWSTR icon_name
,
4539 LPWSTR SystemFolder
;
4543 static const WCHAR szInstaller
[] =
4544 {'I','n','s','t','a','l','l','e','r','\\',0};
4545 static const WCHAR szProductCode
[] =
4546 {'P','r','o','d','u','c','t','C','o','d','e',0};
4547 static const WCHAR szFolder
[] =
4548 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
4550 ProductCode
= load_dynamic_property(package
,szProductCode
,&rc
);
4554 SystemFolder
= load_dynamic_property(package
,szFolder
,NULL
);
4556 dest
= build_directory_name(3, SystemFolder
, szInstaller
, ProductCode
);
4558 create_full_pathW(dest
);
4560 *FilePath
= build_directory_name(2, dest
, icon_name
);
4562 HeapFree(GetProcessHeap(),0,SystemFolder
);
4563 HeapFree(GetProcessHeap(),0,ProductCode
);
4564 HeapFree(GetProcessHeap(),0,dest
);
4565 return ERROR_SUCCESS
;
4568 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
4572 MSIRECORD
* row
= 0;
4573 static const WCHAR Query
[] = {
4574 'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ',
4575 'S','h','o','r','t','c','u','t',0};
4581 return ERROR_INVALID_HANDLE
;
4583 res
= CoInitialize( NULL
);
4586 ERR("CoInitialize failed\n");
4587 return ERROR_FUNCTION_FAILED
;
4590 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
4591 if (rc
!= ERROR_SUCCESS
)
4592 return ERROR_SUCCESS
;
4594 rc
= MSI_ViewExecute(view
, 0);
4595 if (rc
!= ERROR_SUCCESS
)
4597 MSI_ViewClose(view
);
4598 msiobj_release(&view
->hdr
);
4604 LPWSTR target_file
, target_folder
;
4605 WCHAR buffer
[0x100];
4608 static const WCHAR szlnk
[]={'.','l','n','k',0};
4610 rc
= MSI_ViewFetch(view
,&row
);
4611 if (rc
!= ERROR_SUCCESS
)
4618 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
4620 index
= get_loaded_component(package
,buffer
);
4624 msiobj_release(&row
->hdr
);
4628 if (package
->components
[index
].ActionRequest
!= INSTALLSTATE_LOCAL
)
4630 TRACE("Skipping shortcut creation due to disabled component\n");
4631 msiobj_release(&row
->hdr
);
4635 ui_actiondata(package
,szCreateShortcuts
,row
);
4637 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
4638 &IID_IShellLinkW
, (LPVOID
*) &sl
);
4642 ERR("Is IID_IShellLink\n");
4643 msiobj_release(&row
->hdr
);
4647 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
4650 ERR("Is IID_IPersistFile\n");
4651 msiobj_release(&row
->hdr
);
4656 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
4657 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,NULL
);
4659 /* may be needed because of a bug somehwere else */
4660 create_full_pathW(target_folder
);
4663 MSI_RecordGetStringW(row
,3,buffer
,&sz
);
4664 reduce_to_longfilename(buffer
);
4665 if (!strchrW(buffer
,'.'))
4666 strcatW(buffer
,szlnk
);
4667 target_file
= build_directory_name(2, target_folder
, buffer
);
4668 HeapFree(GetProcessHeap(),0,target_folder
);
4671 MSI_RecordGetStringW(row
,5,buffer
,&sz
);
4672 if (strchrW(buffer
,'['))
4675 deformat_string(package
,buffer
,&deformated
);
4676 IShellLinkW_SetPath(sl
,deformated
);
4677 HeapFree(GetProcessHeap(),0,deformated
);
4681 FIXME("UNHANDLED shortcut format, advertised shortcut\n");
4682 IPersistFile_Release( pf
);
4683 IShellLinkW_Release( sl
);
4684 msiobj_release(&row
->hdr
);
4688 if (!MSI_RecordIsNull(row
,6))
4692 MSI_RecordGetStringW(row
,6,buffer
,&sz
);
4693 deformat_string(package
,buffer
,&deformated
);
4694 IShellLinkW_SetArguments(sl
,deformated
);
4695 HeapFree(GetProcessHeap(),0,deformated
);
4698 if (!MSI_RecordIsNull(row
,7))
4701 deformated
= load_dynamic_stringW(row
,7);
4702 IShellLinkW_SetDescription(sl
,deformated
);
4703 HeapFree(GetProcessHeap(),0,deformated
);
4706 if (!MSI_RecordIsNull(row
,8))
4707 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
4709 if (!MSI_RecordIsNull(row
,9))
4715 MSI_RecordGetStringW(row
,9,buffer
,&sz
);
4717 build_icon_path(package
,buffer
,&Path
);
4718 index
= MSI_RecordGetInteger(row
,10);
4720 IShellLinkW_SetIconLocation(sl
,Path
,index
);
4721 HeapFree(GetProcessHeap(),0,Path
);
4724 if (!MSI_RecordIsNull(row
,11))
4725 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
4727 if (!MSI_RecordIsNull(row
,12))
4731 MSI_RecordGetStringW(row
,12,buffer
,&sz
);
4732 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, NULL
);
4733 IShellLinkW_SetWorkingDirectory(sl
,Path
);
4734 HeapFree(GetProcessHeap(), 0, Path
);
4737 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
4738 IPersistFile_Save(pf
,target_file
,FALSE
);
4740 HeapFree(GetProcessHeap(),0,target_file
);
4742 IPersistFile_Release( pf
);
4743 IShellLinkW_Release( sl
);
4745 msiobj_release(&row
->hdr
);
4747 MSI_ViewClose(view
);
4748 msiobj_release(&view
->hdr
);
4758 * 99% of the work done here is only done for
4759 * advertised installs. However this is where the
4760 * Icon table is processed and written out
4761 * so that is what I am going to do here.
4763 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
4767 MSIRECORD
* row
= 0;
4768 static const WCHAR Query
[]={
4769 'S','E','L','E','C','T',' ','*',' ',
4770 'f','r','o','m',' ','I','c','o','n',0};
4774 return ERROR_INVALID_HANDLE
;
4776 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
4777 if (rc
!= ERROR_SUCCESS
)
4778 return ERROR_SUCCESS
;
4780 rc
= MSI_ViewExecute(view
, 0);
4781 if (rc
!= ERROR_SUCCESS
)
4783 MSI_ViewClose(view
);
4784 msiobj_release(&view
->hdr
);
4791 WCHAR
*FilePath
=NULL
;
4792 WCHAR
*FileName
=NULL
;
4795 rc
= MSI_ViewFetch(view
,&row
);
4796 if (rc
!= ERROR_SUCCESS
)
4802 FileName
= load_dynamic_stringW(row
,1);
4805 ERR("Unable to get FileName\n");
4806 msiobj_release(&row
->hdr
);
4810 build_icon_path(package
,FileName
,&FilePath
);
4812 HeapFree(GetProcessHeap(),0,FileName
);
4814 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
4816 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
4817 FILE_ATTRIBUTE_NORMAL
, NULL
);
4819 if (the_file
== INVALID_HANDLE_VALUE
)
4821 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
4822 msiobj_release(&row
->hdr
);
4823 HeapFree(GetProcessHeap(),0,FilePath
);
4831 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
4832 if (rc
!= ERROR_SUCCESS
)
4834 ERR("Failed to get stream\n");
4835 CloseHandle(the_file
);
4836 DeleteFileW(FilePath
);
4839 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
4840 } while (sz
== 1024);
4842 HeapFree(GetProcessHeap(),0,FilePath
);
4844 CloseHandle(the_file
);
4845 msiobj_release(&row
->hdr
);
4847 MSI_ViewClose(view
);
4848 msiobj_release(&view
->hdr
);
4853 /* Msi functions that seem appropriate here */
4854 UINT WINAPI
MsiDoActionA( MSIHANDLE hInstall
, LPCSTR szAction
)
4859 TRACE(" exteral attempt at action %s\n",szAction
);
4862 return ERROR_FUNCTION_FAILED
;
4864 return ERROR_FUNCTION_FAILED
;
4866 szwAction
= strdupAtoW(szAction
);
4869 return ERROR_FUNCTION_FAILED
;
4872 rc
= MsiDoActionW(hInstall
, szwAction
);
4873 HeapFree(GetProcessHeap(),0,szwAction
);
4877 UINT WINAPI
MsiDoActionW( MSIHANDLE hInstall
, LPCWSTR szAction
)
4879 MSIPACKAGE
*package
;
4880 UINT ret
= ERROR_INVALID_HANDLE
;
4882 TRACE(" external attempt at action %s \n",debugstr_w(szAction
));
4884 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
4887 ret
= ACTION_PerformAction(package
,szAction
);
4888 msiobj_release( &package
->hdr
);
4893 UINT WINAPI
MsiGetTargetPathA( MSIHANDLE hInstall
, LPCSTR szFolder
,
4894 LPSTR szPathBuf
, DWORD
* pcchPathBuf
)
4900 TRACE("getting folder %s %p %li\n",szFolder
,szPathBuf
, *pcchPathBuf
);
4903 return ERROR_FUNCTION_FAILED
;
4905 return ERROR_FUNCTION_FAILED
;
4907 szwFolder
= strdupAtoW(szFolder
);
4910 return ERROR_FUNCTION_FAILED
;
4912 szwPathBuf
= HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf
* sizeof(WCHAR
));
4914 rc
= MsiGetTargetPathW(hInstall
, szwFolder
, szwPathBuf
,pcchPathBuf
);
4916 WideCharToMultiByte( CP_ACP
, 0, szwPathBuf
, *pcchPathBuf
, szPathBuf
,
4917 *pcchPathBuf
, NULL
, NULL
);
4919 HeapFree(GetProcessHeap(),0,szwFolder
);
4920 HeapFree(GetProcessHeap(),0,szwPathBuf
);
4925 UINT WINAPI
MsiGetTargetPathW( MSIHANDLE hInstall
, LPCWSTR szFolder
, LPWSTR
4926 szPathBuf
, DWORD
* pcchPathBuf
)
4929 UINT rc
= ERROR_FUNCTION_FAILED
;
4930 MSIPACKAGE
*package
;
4932 TRACE("(%s %p %li)\n",debugstr_w(szFolder
),szPathBuf
,*pcchPathBuf
);
4934 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
4936 return ERROR_INVALID_HANDLE
;
4937 path
= resolve_folder(package
, szFolder
, FALSE
, FALSE
, NULL
);
4938 msiobj_release( &package
->hdr
);
4940 if (path
&& (strlenW(path
) > *pcchPathBuf
))
4942 *pcchPathBuf
= strlenW(path
)+1;
4943 rc
= ERROR_MORE_DATA
;
4947 *pcchPathBuf
= strlenW(path
)+1;
4948 strcpyW(szPathBuf
,path
);
4949 TRACE("Returning Path %s\n",debugstr_w(path
));
4952 HeapFree(GetProcessHeap(),0,path
);
4958 UINT WINAPI
MsiGetSourcePathA( MSIHANDLE hInstall
, LPCSTR szFolder
,
4959 LPSTR szPathBuf
, DWORD
* pcchPathBuf
)
4965 TRACE("getting source %s %p %li\n",szFolder
,szPathBuf
, *pcchPathBuf
);
4968 return ERROR_FUNCTION_FAILED
;
4970 return ERROR_FUNCTION_FAILED
;
4972 szwFolder
= strdupAtoW(szFolder
);
4974 return ERROR_FUNCTION_FAILED
;
4976 szwPathBuf
= HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf
* sizeof(WCHAR
));
4978 rc
= MsiGetSourcePathW(hInstall
, szwFolder
, szwPathBuf
,pcchPathBuf
);
4980 WideCharToMultiByte( CP_ACP
, 0, szwPathBuf
, *pcchPathBuf
, szPathBuf
,
4981 *pcchPathBuf
, NULL
, NULL
);
4983 HeapFree(GetProcessHeap(),0,szwFolder
);
4984 HeapFree(GetProcessHeap(),0,szwPathBuf
);
4989 UINT WINAPI
MsiGetSourcePathW( MSIHANDLE hInstall
, LPCWSTR szFolder
, LPWSTR
4990 szPathBuf
, DWORD
* pcchPathBuf
)
4993 UINT rc
= ERROR_FUNCTION_FAILED
;
4994 MSIPACKAGE
*package
;
4996 TRACE("(%s %p %li)\n",debugstr_w(szFolder
),szPathBuf
,*pcchPathBuf
);
4998 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5000 return ERROR_INVALID_HANDLE
;
5001 path
= resolve_folder(package
, szFolder
, TRUE
, FALSE
, NULL
);
5002 msiobj_release( &package
->hdr
);
5004 if (path
&& strlenW(path
) > *pcchPathBuf
)
5006 *pcchPathBuf
= strlenW(path
)+1;
5007 rc
= ERROR_MORE_DATA
;
5011 *pcchPathBuf
= strlenW(path
)+1;
5012 strcpyW(szPathBuf
,path
);
5013 TRACE("Returning Path %s\n",debugstr_w(path
));
5016 HeapFree(GetProcessHeap(),0,path
);
5022 UINT WINAPI
MsiSetTargetPathA(MSIHANDLE hInstall
, LPCSTR szFolder
,
5023 LPCSTR szFolderPath
)
5026 LPWSTR szwFolderPath
;
5030 return ERROR_FUNCTION_FAILED
;
5032 return ERROR_FUNCTION_FAILED
;
5034 szwFolder
= strdupAtoW(szFolder
);
5036 return ERROR_FUNCTION_FAILED
;
5038 szwFolderPath
= strdupAtoW(szFolderPath
);
5041 HeapFree(GetProcessHeap(),0,szwFolder
);
5042 return ERROR_FUNCTION_FAILED
;
5045 rc
= MsiSetTargetPathW(hInstall
, szwFolder
, szwFolderPath
);
5047 HeapFree(GetProcessHeap(),0,szwFolder
);
5048 HeapFree(GetProcessHeap(),0,szwFolderPath
);
5053 UINT
MSI_SetTargetPathW(MSIPACKAGE
*package
, LPCWSTR szFolder
,
5054 LPCWSTR szFolderPath
)
5061 TRACE("(%p %s %s)\n",package
, debugstr_w(szFolder
),debugstr_w(szFolderPath
));
5064 return ERROR_INVALID_HANDLE
;
5066 if (szFolderPath
[0]==0)
5067 return ERROR_FUNCTION_FAILED
;
5069 if (GetFileAttributesW(szFolderPath
) == INVALID_FILE_ATTRIBUTES
)
5070 return ERROR_FUNCTION_FAILED
;
5072 path
= resolve_folder(package
,szFolder
,FALSE
,FALSE
,&folder
);
5074 return ERROR_INVALID_PARAMETER
;
5075 HeapFree(GetProcessHeap(),0,path
);
5077 len
= strlenW(szFolderPath
);
5079 if (szFolderPath
[len
-1]!='\\')
5082 folder
->Property
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
5083 strcpyW(folder
->Property
,szFolderPath
);
5084 strcatW(folder
->Property
,cszbs
);
5087 folder
->Property
= dupstrW(szFolderPath
);
5089 for (i
= 0; i
< package
->loaded_folders
; i
++)
5090 package
->folders
[i
].ResolvedTarget
=NULL
;
5092 for (i
= 0; i
< package
->loaded_folders
; i
++)
5094 path
= resolve_folder(package
, package
->folders
[i
].Directory
, FALSE
,
5096 HeapFree(GetProcessHeap(),0,path
);
5099 return ERROR_SUCCESS
;
5102 UINT WINAPI
MsiSetTargetPathW(MSIHANDLE hInstall
, LPCWSTR szFolder
,
5103 LPCWSTR szFolderPath
)
5105 MSIPACKAGE
*package
;
5108 TRACE("(%s %s)\n",debugstr_w(szFolder
),debugstr_w(szFolderPath
));
5110 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5111 ret
= MSI_SetTargetPathW( package
, szFolder
, szFolderPath
);
5112 msiobj_release( &package
->hdr
);
5116 /***********************************************************************
5117 * MsiGetMode (MSI.@)
5119 * Returns an internal installer state (if it is running in a mode iRunMode)
5122 * hInstall [I] Handle to the installation
5123 * hRunMode [I] Checking run mode
5124 * MSIRUNMODE_ADMIN Administrative mode
5125 * MSIRUNMODE_ADVERTISE Advertisement mode
5126 * MSIRUNMODE_MAINTENANCE Maintenance mode
5127 * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled
5128 * MSIRUNMODE_LOGENABLED Log file is writing
5129 * MSIRUNMODE_OPERATIONS Operations in progress??
5130 * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed
5131 * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation
5132 * MSIRUNMODE_CABINET Files from cabinet are installed
5133 * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is supressed
5134 * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is supressed
5135 * MSIRUNMODE_RESERVED11 Reserved
5136 * MSIRUNMODE_WINDOWS9X Running under Windows95/98
5137 * MSIRUNMODE_ZAWENABLED Demand installation is supported
5138 * MSIRUNMODE_RESERVED14 Reserved
5139 * MSIRUNMODE_RESERVED15 Reserved
5140 * MSIRUNMODE_SCHEDULED called from install script
5141 * MSIRUNMODE_ROLLBACK called from rollback script
5142 * MSIRUNMODE_COMMIT called from commit script
5145 * In the state: TRUE
5146 * Not in the state: FALSE
5150 BOOL WINAPI
MsiGetMode(MSIHANDLE hInstall
, MSIRUNMODE iRunMode
)
5152 FIXME("STUB (iRunMode=%i)\n",iRunMode
);
5157 * According to the docs, when this is called it immediately recalculates
5158 * all the component states as well
5160 UINT WINAPI
MsiSetFeatureStateA(MSIHANDLE hInstall
, LPCSTR szFeature
,
5161 INSTALLSTATE iState
)
5163 LPWSTR szwFeature
= NULL
;
5166 szwFeature
= strdupAtoW(szFeature
);
5169 return ERROR_FUNCTION_FAILED
;
5171 rc
= MsiSetFeatureStateW(hInstall
,szwFeature
, iState
);
5173 HeapFree(GetProcessHeap(),0,szwFeature
);
5178 UINT WINAPI
MsiSetFeatureStateW(MSIHANDLE hInstall
, LPCWSTR szFeature
,
5179 INSTALLSTATE iState
)
5181 MSIPACKAGE
* package
;
5184 TRACE(" %s to %i\n",debugstr_w(szFeature
), iState
);
5186 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5188 return ERROR_INVALID_HANDLE
;
5190 index
= get_loaded_feature(package
,szFeature
);
5192 return ERROR_UNKNOWN_FEATURE
;
5194 package
->features
[index
].ActionRequest
= iState
;
5196 return ERROR_SUCCESS
;
5199 UINT WINAPI
MsiGetFeatureStateA(MSIHANDLE hInstall
, LPSTR szFeature
,
5200 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5202 LPWSTR szwFeature
= NULL
;
5205 szwFeature
= strdupAtoW(szFeature
);
5207 rc
= MsiGetFeatureStateW(hInstall
,szwFeature
,piInstalled
, piAction
);
5209 HeapFree( GetProcessHeap(), 0 , szwFeature
);
5214 UINT
MSI_GetFeatureStateW(MSIPACKAGE
*package
, LPWSTR szFeature
,
5215 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5219 index
= get_loaded_feature(package
,szFeature
);
5221 return ERROR_UNKNOWN_FEATURE
;
5224 *piInstalled
= package
->features
[index
].Installed
;
5227 *piAction
= package
->features
[index
].Action
;
5229 TRACE("returning %i %i\n",*piInstalled
,*piAction
);
5231 return ERROR_SUCCESS
;
5234 UINT WINAPI
MsiGetFeatureStateW(MSIHANDLE hInstall
, LPWSTR szFeature
,
5235 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5237 MSIPACKAGE
* package
;
5240 TRACE("%ld %s %p %p\n", hInstall
, debugstr_w(szFeature
), piInstalled
,
5243 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5245 return ERROR_INVALID_HANDLE
;
5246 ret
= MSI_GetFeatureStateW(package
, szFeature
, piInstalled
, piAction
);
5247 msiobj_release( &package
->hdr
);
5251 UINT WINAPI
MsiGetComponentStateA(MSIHANDLE hInstall
, LPSTR szComponent
,
5252 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5254 LPWSTR szwComponent
= NULL
;
5257 szwComponent
= strdupAtoW(szComponent
);
5259 rc
= MsiGetComponentStateW(hInstall
,szwComponent
,piInstalled
, piAction
);
5261 HeapFree( GetProcessHeap(), 0 , szwComponent
);
5266 UINT
MSI_GetComponentStateW(MSIPACKAGE
*package
, LPWSTR szComponent
,
5267 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5271 TRACE("%p %s %p %p\n", package
, debugstr_w(szComponent
), piInstalled
,
5274 index
= get_loaded_component(package
,szComponent
);
5276 return ERROR_UNKNOWN_COMPONENT
;
5279 *piInstalled
= package
->components
[index
].Installed
;
5282 *piInstalled
= package
->components
[index
].Action
;
5284 return ERROR_SUCCESS
;
5287 UINT WINAPI
MsiGetComponentStateW(MSIHANDLE hInstall
, LPWSTR szComponent
,
5288 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5290 MSIPACKAGE
* package
;
5293 TRACE("%ld %s %p %p\n", hInstall
, debugstr_w(szComponent
),
5294 piInstalled
, piAction
);
5296 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5298 return ERROR_INVALID_HANDLE
;
5299 ret
= MSI_GetComponentStateW( package
, szComponent
, piInstalled
, piAction
);
5300 msiobj_release( &package
->hdr
);
5305 static UINT
ACTION_Template(MSIPACKAGE
*package
)
5309 MSIRECORD
* row
= 0;
5310 static const WCHAR ExecSeqQuery
[] = {0};
5312 rc
= MsiDatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5313 if (rc
!= ERROR_SUCCESS
)
5316 rc
= MsiViewExecute(view
, 0);
5317 if (rc
!= ERROR_SUCCESS
)
5320 msiobj_release(&view
->hdr
);
5326 rc
= MsiViewFetch(view
,&row
);
5327 if (rc
!= ERROR_SUCCESS
)
5333 msiobj_release(&row
->hdr
);
5336 msiobj_release(&view
->hdr
);