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
36 #include "wine/debug.h"
45 #include "wine/unicode.h"
48 #define CUSTOM_ACTION_TYPE_MASK 0x3F
50 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
52 typedef struct tagMSIFEATURE
55 WCHAR Feature_Parent
[96];
57 WCHAR Description
[0x100];
65 INT Components
[1024]; /* yes hardcoded limit.... I am bad */
69 typedef struct tagMSICOMPONENT
72 WCHAR ComponentId
[96];
75 WCHAR Condition
[0x100];
84 typedef struct tagMSIFOLDER
87 WCHAR TargetDefault
[96];
88 WCHAR SourceDefault
[96];
90 WCHAR ResolvedTarget
[MAX_PATH
];
91 WCHAR ResolvedSource
[MAX_PATH
];
92 WCHAR Property
[MAX_PATH
]; /* initialy set property */
95 /* 0 = uninitialized */
97 /* 2 = created remove if empty */
98 /* 3 = created persist if empty */
103 typedef struct tagMSIFILE
107 WCHAR FileName
[MAX_PATH
];
115 /* 0 = uninitialize */
116 /* 1 = not present */
117 /* 2 = present but replace */
118 /* 3 = present do not replace */
120 WCHAR SourcePath
[MAX_PATH
];
121 WCHAR TargetPath
[MAX_PATH
];
128 static UINT
ACTION_ProcessExecSequence(MSIHANDLE hPackage
, BOOL UIran
);
129 static UINT
ACTION_ProcessUISequence(MSIHANDLE hPackage
);
131 UINT
ACTION_PerformAction(MSIHANDLE hPackage
, const WCHAR
*action
);
133 static UINT
ACTION_LaunchConditions(MSIHANDLE hPackage
);
134 static UINT
ACTION_CostInitialize(MSIHANDLE hPackage
);
135 static UINT
ACTION_CreateFolders(MSIHANDLE hPackage
);
136 static UINT
ACTION_CostFinalize(MSIHANDLE hPackage
);
137 static UINT
ACTION_FileCost(MSIHANDLE hPackage
);
138 static UINT
ACTION_InstallFiles(MSIHANDLE hPackage
);
139 static UINT
ACTION_DuplicateFiles(MSIHANDLE hPackage
);
140 static UINT
ACTION_WriteRegistryValues(MSIHANDLE hPackage
);
141 static UINT
ACTION_CustomAction(MSIHANDLE hPackage
,const WCHAR
*action
);
142 static UINT
ACTION_InstallInitialize(MSIHANDLE hPackage
);
143 static UINT
ACTION_InstallValidate(MSIHANDLE hPackage
);
144 static UINT
ACTION_ProcessComponents(MSIHANDLE hPackage
);
145 static UINT
ACTION_RegisterTypeLibraries(MSIHANDLE hPackage
);
146 static UINT
ACTION_RegisterClassInfo(MSIHANDLE hPackage
);
147 static UINT
ACTION_RegisterProgIdInfo(MSIHANDLE hPackage
);
149 static UINT
HANDLE_CustomType1(MSIHANDLE hPackage
, const LPWSTR source
,
150 const LPWSTR target
, const INT type
);
151 static UINT
HANDLE_CustomType2(MSIHANDLE hPackage
, const LPWSTR source
,
152 const LPWSTR target
, const INT type
);
154 static DWORD
deformat_string(MSIHANDLE hPackage
, WCHAR
* ptr
,WCHAR
** data
);
155 static UINT
resolve_folder(MSIHANDLE hPackage
, LPCWSTR name
, LPWSTR path
,
156 BOOL source
, BOOL set_prop
, MSIFOLDER
**folder
);
158 static UINT
track_tempfile(MSIHANDLE hPackage
, LPCWSTR name
, LPCWSTR path
);
161 * consts and values used
163 static const WCHAR cszSourceDir
[] = {'S','o','u','r','c','e','D','i','r',0};
164 static const WCHAR cszRootDrive
[] = {'R','O','O','T','D','R','I','V','E',0};
165 static const WCHAR cszTargetDir
[] = {'T','A','R','G','E','T','D','I','R',0};
166 static const WCHAR cszTempFolder
[]= {'T','e','m','p','F','o','l','d','e','r',0};
167 static const WCHAR cszDatabase
[]={'D','A','T','A','B','A','S','E',0};
168 static const WCHAR c_collen
[] = {'C',':','\\',0};
170 static const WCHAR cszlsb
[]={'[',0};
171 static const WCHAR cszrsb
[]={']',0};
172 static const WCHAR cszbs
[]={'\\',0};
174 const static WCHAR szCreateFolders
[] =
175 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
176 const static WCHAR szCostFinalize
[] =
177 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
178 const static WCHAR szInstallFiles
[] =
179 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
180 const static WCHAR szDuplicateFiles
[] =
181 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
182 const static WCHAR szWriteRegistryValues
[] =
183 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
184 const static WCHAR szCostInitialize
[] =
185 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
186 const static WCHAR szFileCost
[] = {'F','i','l','e','C','o','s','t',0};
187 const static WCHAR szInstallInitialize
[] =
188 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
189 const static WCHAR szInstallValidate
[] =
190 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
191 const static WCHAR szLaunchConditions
[] =
192 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
193 const static WCHAR szProcessComponents
[] =
194 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
195 const static WCHAR szRegisterTypeLibraries
[] =
196 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r',
198 const static WCHAR szRegisterClassInfo
[] =
199 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
200 const static WCHAR szRegisterProgIdInfo
[] =
201 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
203 /********************************************************
204 * helper functions to get around current HACKS and such
205 ********************************************************/
206 inline static void reduce_to_longfilename(WCHAR
* filename
)
208 if (strchrW(filename
,'|'))
210 WCHAR newname
[MAX_PATH
];
211 strcpyW(newname
,strchrW(filename
,'|')+1);
212 strcpyW(filename
,newname
);
216 inline static char *strdupWtoA( const WCHAR
*str
)
221 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
223 if ((ret
= HeapAlloc( GetProcessHeap(), 0, len
)))
224 WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
229 inline static int get_loaded_component(MSIPACKAGE
* package
, LPCWSTR Component
)
234 for (i
= 0; i
< package
->loaded_components
; i
++)
236 if (strcmpW(Component
,package
->components
[i
].Component
)==0)
245 inline static int get_loaded_feature(MSIPACKAGE
* package
, LPCWSTR Feature
)
250 for (i
= 0; i
< package
->loaded_features
; i
++)
252 if (strcmpW(Feature
,package
->features
[i
].Feature
)==0)
261 inline static int get_loaded_file(MSIPACKAGE
* package
, LPCWSTR file
)
266 for (i
= 0; i
< package
->loaded_files
; i
++)
268 if (strcmpW(file
,package
->files
[i
].File
)==0)
277 static UINT
track_tempfile(MSIHANDLE hPackage
, LPCWSTR name
, LPCWSTR path
)
283 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
288 for (i
=0; i
< package
->loaded_files
; i
++)
289 if (strcmpW(package
->files
[i
].File
,name
)==0)
292 index
= package
->loaded_files
;
293 package
->loaded_files
++;
294 if (package
->loaded_files
== 1)
295 package
->files
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE
));
297 package
->files
= HeapReAlloc(GetProcessHeap(),0,
298 package
->files
, package
->loaded_files
* sizeof(MSIFILE
));
300 memset(&package
->files
[index
],0,sizeof(MSIFILE
));
302 strcpyW(package
->files
[index
].File
,name
);
303 strcpyW(package
->files
[index
].TargetPath
,path
);
304 package
->files
[index
].Temporary
= TRUE
;
306 TRACE("Tracking tempfile (%s)\n",debugstr_w(package
->files
[index
].File
));
311 void ACTION_remove_tracked_tempfiles(MSIPACKAGE
* package
)
318 for (i
= 0; i
< package
->loaded_files
; i
++)
320 if (package
->files
[i
].Temporary
)
321 DeleteFileW(package
->files
[i
].TargetPath
);
326 static void ui_progress(MSIHANDLE hPackage
, int a
, int b
, int c
, int d
)
330 row
= MsiCreateRecord(4);
331 MsiRecordSetInteger(row
,1,a
);
332 MsiRecordSetInteger(row
,2,b
);
333 MsiRecordSetInteger(row
,3,c
);
334 MsiRecordSetInteger(row
,4,d
);
335 MsiProcessMessage(hPackage
, INSTALLMESSAGE_PROGRESS
, row
);
339 static void ui_actiondata(MSIHANDLE hPackage
, LPCWSTR action
, MSIHANDLE record
)
341 static const WCHAR Query_t
[] =
342 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
343 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
344 ' ','\'','%','s','\'',0};
349 WCHAR
*ActionFormat
=NULL
;
355 sprintfW(Query
,Query_t
,action
);
356 db
= MsiGetActiveDatabase(hPackage
);
357 rc
= MsiDatabaseOpenViewW(db
, Query
, &view
);
359 MsiViewExecute(view
, 0);
360 rc
= MsiViewFetch(view
,&row
);
361 if (rc
!= ERROR_SUCCESS
)
364 MsiCloseHandle(view
);
368 if (MsiRecordIsNull(row
,3))
372 MsiCloseHandle(view
);
376 MsiRecordGetStringW(row
,3,NULL
,&sz
);
378 ActionFormat
= HeapAlloc(GetProcessHeap(),0,sz
*sizeof(WCHAR
));
379 MsiRecordGetStringW(row
,3,ActionFormat
,&sz
);
382 MsiCloseHandle(view
);
393 ptr2
= strchrW(ptr
,'[');
396 strncpyW(tmp
,ptr
,ptr2
-ptr
);
398 strcatW(message
,tmp
);
402 MsiRecordGetStringW(record
,field
,NULL
,&sz
);
404 data
= HeapAlloc(GetProcessHeap(),0,sz
*sizeof(WCHAR
));
405 MsiRecordGetStringW(record
,field
,data
,&sz
);
406 strcatW(message
,data
);
407 HeapFree(GetProcessHeap(),0,data
);
408 ptr
=strchrW(ptr2
,']');
413 strcatW(message
,ptr
);
418 row
= MsiCreateRecord(1);
419 MsiRecordSetStringW(row
,1,message
);
421 MsiProcessMessage(hPackage
, INSTALLMESSAGE_ACTIONDATA
, row
);
423 HeapFree(GetProcessHeap(),0,ActionFormat
);
427 static void ui_actionstart(MSIHANDLE hPackage
, LPCWSTR action
)
429 static const WCHAR template_s
[]=
430 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ','%','s','.',0};
431 static const WCHAR format
[] =
432 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
433 static const WCHAR Query_t
[] =
434 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
435 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
436 ' ','\'','%','s','\'',0};
442 WCHAR
*ActionText
=NULL
;
447 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
449 sprintfW(Query
,Query_t
,action
);
450 db
= MsiGetActiveDatabase(hPackage
);
451 rc
= MsiDatabaseOpenViewW(db
, Query
, &view
);
453 MsiViewExecute(view
, 0);
454 rc
= MsiViewFetch(view
,&row
);
455 if (rc
!= ERROR_SUCCESS
)
458 MsiCloseHandle(view
);
463 MsiRecordGetStringW(row
,2,NULL
,&sz
);
465 ActionText
= HeapAlloc(GetProcessHeap(),0,sz
*sizeof(WCHAR
));
466 MsiRecordGetStringW(row
,2,ActionText
,&sz
);
469 MsiCloseHandle(view
);
471 sprintfW(message
,template_s
,timet
,action
,ActionText
);
473 row
= MsiCreateRecord(1);
474 MsiRecordSetStringW(row
,1,message
);
476 MsiProcessMessage(hPackage
, INSTALLMESSAGE_ACTIONSTART
, row
);
478 HeapFree(GetProcessHeap(),0,ActionText
);
481 static void ui_actioninfo(MSIHANDLE hPackage
, LPCWSTR action
, BOOL start
,
485 static const WCHAR template_s
[]=
486 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ','%','s',
488 static const WCHAR template_e
[]=
489 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ','%','s',
490 '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ','%','i','.',0};
491 static const WCHAR format
[] =
492 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
496 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
498 sprintfW(message
,template_s
,timet
,action
);
500 sprintfW(message
,template_e
,timet
,action
,rc
);
502 row
= MsiCreateRecord(1);
503 MsiRecordSetStringW(row
,1,message
);
505 MsiProcessMessage(hPackage
, INSTALLMESSAGE_INFO
, row
);
509 /****************************************************
510 * TOP level entry points
511 *****************************************************/
513 UINT
ACTION_DoTopLevelINSTALL(MSIHANDLE hPackage
, LPCWSTR szPackagePath
,
514 LPCWSTR szCommandLine
)
523 WCHAR check
[MAX_PATH
];
527 strcpyW(pth
,szPackagePath
);
528 p
= strrchrW(pth
,'\\');
536 if (MsiGetPropertyW(hPackage
,cszSourceDir
,check
,&size
)
538 MsiSetPropertyW(hPackage
, cszSourceDir
, pth
);
544 ptr
= (LPWSTR
)szCommandLine
;
551 TRACE("Looking at %s\n",debugstr_w(ptr
));
553 ptr2
= strchrW(ptr
,'=');
558 strncpyW(prop
,ptr
,ptr2
-ptr
);
563 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
576 strncpyW(val
,ptr2
,len
);
582 TRACE("Found commandline property (%s) = (%s)\n", debugstr_w(prop
),
584 MsiSetPropertyW(hPackage
,prop
,val
);
589 if (MsiGetPropertyA(hPackage
,"UILevel",buffer
,&sz
) == ERROR_SUCCESS
)
591 if (atoi(buffer
) >= INSTALLUILEVEL_REDUCED
)
593 rc
= ACTION_ProcessUISequence(hPackage
);
594 if (rc
== ERROR_SUCCESS
)
595 rc
= ACTION_ProcessExecSequence(hPackage
,TRUE
);
598 rc
= ACTION_ProcessExecSequence(hPackage
,FALSE
);
601 rc
= ACTION_ProcessExecSequence(hPackage
,FALSE
);
607 static UINT
ACTION_ProcessExecSequence(MSIHANDLE hPackage
, BOOL UIran
)
611 static const CHAR
*ExecSeqQuery
=
612 "select * from InstallExecuteSequence where Sequence > %i order by Sequence";
617 db
= MsiGetActiveDatabase(hPackage
);
622 static const CHAR
*IVQuery
=
623 "select Sequence from InstallExecuteSequence where Action = `InstallValidate`" ;
625 MsiDatabaseOpenViewA(db
, IVQuery
, &view
);
626 MsiViewExecute(view
, 0);
627 MsiViewFetch(view
,&row
);
628 seq
= MsiRecordGetInteger(row
,1);
631 MsiCloseHandle(view
);
632 sprintf(Query
,ExecSeqQuery
,0);
635 sprintf(Query
,ExecSeqQuery
,0);
637 rc
= MsiDatabaseOpenViewA(db
, Query
, &view
);
640 if (rc
== ERROR_SUCCESS
)
642 rc
= MsiViewExecute(view
, 0);
644 if (rc
!= ERROR_SUCCESS
)
647 MsiCloseHandle(view
);
651 TRACE("Running the actions \n");
658 rc
= MsiViewFetch(view
,&row
);
659 if (rc
!= ERROR_SUCCESS
)
665 /* check conditions */
666 if (!MsiRecordIsNull(row
,2))
669 rc
= MsiRecordGetStringW(row
,2,buffer
,&sz
);
670 if (rc
!= ERROR_SUCCESS
)
676 /* this is a hack to skip errors in the condition code */
677 if (MsiEvaluateConditionW(hPackage
, buffer
) ==
687 rc
= MsiRecordGetStringW(row
,1,buffer
,&sz
);
688 if (rc
!= ERROR_SUCCESS
)
690 ERR("Error is %x\n",rc
);
695 rc
= ACTION_PerformAction(hPackage
,buffer
);
697 if (rc
!= ERROR_SUCCESS
)
699 ERR("Execution halted due to error (%i)\n",rc
);
708 MsiCloseHandle(view
);
716 static UINT
ACTION_ProcessUISequence(MSIHANDLE hPackage
)
720 static const CHAR
*ExecSeqQuery
=
721 "select * from InstallUISequence where Sequence > 0 order by Sequence";
724 db
= MsiGetActiveDatabase(hPackage
);
725 rc
= MsiDatabaseOpenViewA(db
, ExecSeqQuery
, &view
);
728 if (rc
== ERROR_SUCCESS
)
730 rc
= MsiViewExecute(view
, 0);
732 if (rc
!= ERROR_SUCCESS
)
735 MsiCloseHandle(view
);
739 TRACE("Running the actions \n");
747 rc
= MsiViewFetch(view
,&row
);
748 if (rc
!= ERROR_SUCCESS
)
754 /* check conditions */
755 if (!MsiRecordIsNull(row
,2))
758 rc
= MsiRecordGetStringW(row
,2,buffer
,&sz
);
759 if (rc
!= ERROR_SUCCESS
)
765 if (MsiEvaluateConditionW(hPackage
, buffer
) ==
775 rc
= MsiRecordGetStringW(row
,1,buffer
,&sz
);
776 if (rc
!= ERROR_SUCCESS
)
778 ERR("Error is %x\n",rc
);
783 rc
= ACTION_PerformAction(hPackage
,buffer
);
785 if (rc
!= ERROR_SUCCESS
)
787 ERR("Execution halted due to error (%i)\n",rc
);
796 MsiCloseHandle(view
);
803 /********************************************************
804 * ACTION helper functions and functions that perform the actions
805 *******************************************************/
808 * Alot of actions are really important even if they don't do anything
809 * explicit.. Lots of properties are set at the beginning of the installation
810 * CostFinalize does a bunch of work to translated the directories and such
812 * But until I get write access to the database that is hard, so I am going to
813 * hack it to see if I can get something to run.
815 UINT
ACTION_PerformAction(MSIHANDLE hPackage
, const WCHAR
*action
)
817 UINT rc
= ERROR_SUCCESS
;
819 TRACE("Performing action (%s)\n",debugstr_w(action
));
820 ui_actioninfo(hPackage
, action
, TRUE
, 0);
821 ui_actionstart(hPackage
, action
);
822 ui_progress(hPackage
,2,1,0,0);
824 /* pre install, setup and configureation block */
825 if (strcmpW(action
,szLaunchConditions
)==0)
826 rc
= ACTION_LaunchConditions(hPackage
);
827 else if (strcmpW(action
,szCostInitialize
)==0)
828 rc
= ACTION_CostInitialize(hPackage
);
829 else if (strcmpW(action
,szFileCost
)==0)
830 rc
= ACTION_FileCost(hPackage
);
831 else if (strcmpW(action
,szCostFinalize
)==0)
832 rc
= ACTION_CostFinalize(hPackage
);
833 else if (strcmpW(action
,szInstallValidate
)==0)
834 rc
= ACTION_InstallValidate(hPackage
);
837 else if (strcmpW(action
,szProcessComponents
)==0)
838 rc
= ACTION_ProcessComponents(hPackage
);
839 else if (strcmpW(action
,szInstallInitialize
)==0)
840 rc
= ACTION_InstallInitialize(hPackage
);
841 else if (strcmpW(action
,szCreateFolders
)==0)
842 rc
= ACTION_CreateFolders(hPackage
);
843 else if (strcmpW(action
,szInstallFiles
)==0)
844 rc
= ACTION_InstallFiles(hPackage
);
845 else if (strcmpW(action
,szDuplicateFiles
)==0)
846 rc
= ACTION_DuplicateFiles(hPackage
);
847 else if (strcmpW(action
,szWriteRegistryValues
)==0)
848 rc
= ACTION_WriteRegistryValues(hPackage
);
849 else if (strcmpW(action
,szRegisterTypeLibraries
)==0)
850 rc
= ACTION_RegisterTypeLibraries(hPackage
);
851 else if (strcmpW(action
,szRegisterClassInfo
)==0)
852 rc
= ACTION_RegisterClassInfo(hPackage
);
853 else if (strcmpW(action
,szRegisterProgIdInfo
)==0)
854 rc
= ACTION_RegisterProgIdInfo(hPackage
);
857 Current called during itunes but unimplemented and seem important
859 ResolveSource (sets SourceDir)
860 CreateShortcuts (would be nice to have soon)
864 else if ((rc
= ACTION_CustomAction(hPackage
,action
)) != ERROR_SUCCESS
)
866 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action
));
870 ui_actioninfo(hPackage
, action
, FALSE
, rc
);
875 static UINT
ACTION_CustomAction(MSIHANDLE hPackage
,const WCHAR
*action
)
877 UINT rc
= ERROR_SUCCESS
;
880 WCHAR ExecSeqQuery
[1024] =
881 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','C','u','s','t','o'
882 ,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i'
883 ,'o','n','`',' ','=',' ','`',0};
884 static const WCHAR end
[]={'`',0};
889 WCHAR
*deformated
=NULL
;
892 strcatW(ExecSeqQuery
,action
);
893 strcatW(ExecSeqQuery
,end
);
895 db
= MsiGetActiveDatabase(hPackage
);
896 rc
= MsiDatabaseOpenViewW(db
, ExecSeqQuery
, &view
);
899 if (rc
!= ERROR_SUCCESS
)
902 rc
= MsiViewExecute(view
, 0);
903 if (rc
!= ERROR_SUCCESS
)
906 MsiCloseHandle(view
);
910 rc
= MsiViewFetch(view
,&row
);
911 if (rc
!= ERROR_SUCCESS
)
914 MsiCloseHandle(view
);
918 type
= MsiRecordGetInteger(row
,2);
921 MsiRecordGetStringW(row
,3,source
,&sz
);
923 MsiRecordGetStringW(row
,4,target
,&sz
);
925 TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action
),type
,
926 debugstr_w(source
), debugstr_w(target
));
928 /* we are ignoring ALOT of flags and important synchronization stuff */
929 switch (type
& CUSTOM_ACTION_TYPE_MASK
)
931 case 1: /* DLL file stored in a Binary table stream */
932 rc
= HANDLE_CustomType1(hPackage
,source
,target
,type
);
934 case 2: /* Exe file stored in a Binary table strem */
935 rc
= HANDLE_CustomType2(hPackage
,source
,target
,type
);
937 case 35: /* Directory set with formatted text. */
938 case 51: /* Property set with formatted text. */
939 deformat_string(hPackage
,target
,&deformated
);
940 rc
= MsiSetPropertyW(hPackage
,source
,deformated
);
941 HeapFree(GetProcessHeap(),0,deformated
);
944 FIXME("UNHANDLED ACTION TYPE %i (%s %s)\n",
945 type
& CUSTOM_ACTION_TYPE_MASK
, debugstr_w(source
),
951 MsiCloseHandle(view
);
955 static UINT
store_binary_to_temp(MSIHANDLE hPackage
, const LPWSTR source
,
960 if (MsiGetPropertyW(hPackage
, cszTempFolder
, tmp_file
, &sz
)
962 GetTempPathW(MAX_PATH
,tmp_file
);
964 strcatW(tmp_file
,source
);
966 if (GetFileAttributesW(tmp_file
) != INVALID_FILE_ATTRIBUTES
)
968 TRACE("File already exists\n");
969 return ERROR_SUCCESS
;
973 /* write out the file */
978 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','B','i'
979 ,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`',0};
980 static const WCHAR end
[]={'`',0};
985 if (track_tempfile(hPackage
, source
, tmp_file
)!=0)
986 FIXME("File Name in temp tracking collision\n");
988 the_file
= CreateFileW(tmp_file
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
989 FILE_ATTRIBUTE_NORMAL
, NULL
);
991 if (the_file
== INVALID_HANDLE_VALUE
)
992 return ERROR_FUNCTION_FAILED
;
994 strcatW(Query
,source
);
997 db
= MsiGetActiveDatabase(hPackage
);
998 rc
= MsiDatabaseOpenViewW(db
, Query
, &view
);
1001 if (rc
!= ERROR_SUCCESS
)
1004 rc
= MsiViewExecute(view
, 0);
1005 if (rc
!= ERROR_SUCCESS
)
1008 MsiCloseHandle(view
);
1012 rc
= MsiViewFetch(view
,&row
);
1013 if (rc
!= ERROR_SUCCESS
)
1016 MsiCloseHandle(view
);
1024 rc
= MsiRecordReadStream(row
,2,buffer
,&sz
);
1025 if (rc
!= ERROR_SUCCESS
)
1027 ERR("Failed to get stream\n");
1028 CloseHandle(the_file
);
1029 DeleteFileW(tmp_file
);
1032 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
1033 } while (sz
== 1024);
1035 CloseHandle(the_file
);
1037 MsiCloseHandle(row
);
1039 MsiCloseHandle(view
);
1042 return ERROR_SUCCESS
;
1046 typedef UINT
CustomEntry(MSIHANDLE
);
1048 static UINT
HANDLE_CustomType1(MSIHANDLE hPackage
, const LPWSTR source
,
1049 const LPWSTR target
, const INT type
)
1051 WCHAR tmp_file
[MAX_PATH
];
1056 store_binary_to_temp(hPackage
, source
, tmp_file
);
1058 TRACE("Calling function %s from %s\n",debugstr_w(target
),
1059 debugstr_w(tmp_file
));
1063 FIXME("Asynchronous execution.. UNHANDLED\n");
1064 return ERROR_SUCCESS
;
1067 if (!strchrW(tmp_file
,'.'))
1069 static const WCHAR dot
[]={'.',0};
1070 strcatW(tmp_file
,dot
);
1073 DLL
= LoadLibraryW(tmp_file
);
1076 proc
= strdupWtoA( target
);
1077 fn
= (CustomEntry
*)GetProcAddress(DLL
,proc
);
1080 TRACE("Calling function\n");
1084 ERR("Cannot load functon\n");
1086 HeapFree(GetProcessHeap(),0,proc
);
1090 ERR("Unable to load library\n");
1092 return ERROR_SUCCESS
;
1095 static UINT
HANDLE_CustomType2(MSIHANDLE hPackage
, const LPWSTR source
,
1096 const LPWSTR target
, const INT type
)
1098 WCHAR tmp_file
[MAX_PATH
*2];
1100 PROCESS_INFORMATION info
;
1103 static const WCHAR spc
[] = {' ',0};
1105 memset(&si
,0,sizeof(STARTUPINFOW
));
1106 memset(&info
,0,sizeof(PROCESS_INFORMATION
));
1108 store_binary_to_temp(hPackage
, source
, tmp_file
);
1110 strcatW(tmp_file
,spc
);
1111 deformat_string(hPackage
,target
,&deformated
);
1112 strcatW(tmp_file
,deformated
);
1114 HeapFree(GetProcessHeap(),0,deformated
);
1116 TRACE("executing exe %s \n",debugstr_w(tmp_file
));
1118 rc
= CreateProcessW(NULL
, tmp_file
, NULL
, NULL
, FALSE
, 0, NULL
,
1119 c_collen
, &si
, &info
);
1123 ERR("Unable to execute command\n");
1124 return ERROR_SUCCESS
;
1128 WaitForSingleObject(info
.hProcess
,INFINITE
);
1130 return ERROR_SUCCESS
;
1133 /***********************************************************************
1136 * Recursively create all directories in the path.
1138 * shamelessly stolen from setupapi/queue.c
1140 static BOOL
create_full_pathW(const WCHAR
*path
)
1146 new_path
= HeapAlloc(GetProcessHeap(), 0, (strlenW(path
) + 1) *
1148 strcpyW(new_path
, path
);
1150 while((len
= strlenW(new_path
)) && new_path
[len
- 1] == '\\')
1151 new_path
[len
- 1] = 0;
1153 while(!CreateDirectoryW(new_path
, NULL
))
1156 DWORD last_error
= GetLastError();
1157 if(last_error
== ERROR_ALREADY_EXISTS
)
1160 if(last_error
!= ERROR_PATH_NOT_FOUND
)
1166 if(!(slash
= strrchrW(new_path
, '\\')))
1172 len
= slash
- new_path
;
1174 if(!create_full_pathW(new_path
))
1179 new_path
[len
] = '\\';
1182 HeapFree(GetProcessHeap(), 0, new_path
);
1187 * Also we cannot enable/disable components either, so for now I am just going
1188 * to do all the directories for all the components.
1190 static UINT
ACTION_CreateFolders(MSIHANDLE hPackage
)
1192 static const CHAR
*ExecSeqQuery
= "select Directory_ from CreateFolder";
1198 db
= MsiGetActiveDatabase(hPackage
);
1199 rc
= MsiDatabaseOpenViewA(db
, ExecSeqQuery
, &view
);
1202 if (rc
!= ERROR_SUCCESS
)
1205 rc
= MsiViewExecute(view
, 0);
1206 if (rc
!= ERROR_SUCCESS
)
1209 MsiCloseHandle(view
);
1216 WCHAR full_path
[MAX_PATH
];
1221 rc
= MsiViewFetch(view
,&row
);
1222 if (rc
!= ERROR_SUCCESS
)
1229 rc
= MsiRecordGetStringW(row
,1,dir
,&sz
);
1231 if (rc
!= ERROR_SUCCESS
)
1233 ERR("Unable to get folder id \n");
1234 MsiCloseHandle(row
);
1239 rc
= resolve_folder(hPackage
,dir
,full_path
,FALSE
,FALSE
,&folder
);
1241 if (rc
!= ERROR_SUCCESS
)
1243 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
1244 MsiCloseHandle(row
);
1248 TRACE("Folder is %s\n",debugstr_w(full_path
));
1251 uirow
= MsiCreateRecord(1);
1252 MsiRecordSetStringW(uirow
,1,full_path
);
1253 ui_actiondata(hPackage
,szCreateFolders
,uirow
);
1254 MsiCloseHandle(uirow
);
1256 if (folder
->State
== 0)
1257 create_full_pathW(full_path
);
1261 MsiCloseHandle(row
);
1264 MsiCloseHandle(view
);
1269 static int load_component(MSIPACKAGE
* package
, MSIHANDLE row
)
1271 int index
= package
->loaded_components
;
1274 /* fill in the data */
1276 package
->loaded_components
++;
1277 if (package
->loaded_components
== 1)
1278 package
->components
= HeapAlloc(GetProcessHeap(),0,
1279 sizeof(MSICOMPONENT
));
1281 package
->components
= HeapReAlloc(GetProcessHeap(),0,
1282 package
->components
, package
->loaded_components
*
1283 sizeof(MSICOMPONENT
));
1285 memset(&package
->components
[index
],0,sizeof(MSICOMPONENT
));
1288 MsiRecordGetStringW(row
,1,package
->components
[index
].Component
,&sz
);
1290 TRACE("Loading Component %s\n",
1291 debugstr_w(package
->components
[index
].Component
));
1294 if (!MsiRecordIsNull(row
,2))
1295 MsiRecordGetStringW(row
,2,package
->components
[index
].ComponentId
,&sz
);
1298 MsiRecordGetStringW(row
,3,package
->components
[index
].Directory
,&sz
);
1300 package
->components
[index
].Attributes
= MsiRecordGetInteger(row
,4);
1303 MsiRecordGetStringW(row
,5,package
->components
[index
].Condition
,&sz
);
1306 MsiRecordGetStringW(row
,6,package
->components
[index
].KeyPath
,&sz
);
1308 package
->components
[index
].State
= INSTALLSTATE_UNKNOWN
;
1309 package
->components
[index
].Enabled
= TRUE
;
1310 package
->components
[index
].FeatureState
= FALSE
;
1315 static void load_feature(MSIPACKAGE
* package
, MSIHANDLE row
)
1317 int index
= package
->loaded_features
;
1319 static const WCHAR Query1
[] = {'S','E','L','E','C','T',' ','C','o','m','p',
1320 'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',
1321 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',
1322 'a','t','u','r','e','_','=','\'','%','s','\'',0};
1323 static const WCHAR Query2
[] = {'S','E','L','E','C','T',' ','*',' ','F','R',
1324 'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',
1325 'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};
1332 /* fill in the data */
1334 package
->loaded_features
++;
1335 if (package
->loaded_features
== 1)
1336 package
->features
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE
));
1338 package
->features
= HeapReAlloc(GetProcessHeap(),0,package
->features
,
1339 package
->loaded_features
* sizeof(MSIFEATURE
));
1341 memset(&package
->features
[index
],0,sizeof(MSIFEATURE
));
1344 MsiRecordGetStringW(row
,1,package
->features
[index
].Feature
,&sz
);
1346 TRACE("Loading feature %s\n",debugstr_w(package
->features
[index
].Feature
));
1349 if (!MsiRecordIsNull(row
,2))
1350 MsiRecordGetStringW(row
,2,package
->features
[index
].Feature_Parent
,&sz
);
1353 if (!MsiRecordIsNull(row
,3))
1354 MsiRecordGetStringW(row
,3,package
->features
[index
].Title
,&sz
);
1357 if (!MsiRecordIsNull(row
,4))
1358 MsiRecordGetStringW(row
,4,package
->features
[index
].Description
,&sz
);
1360 if (!MsiRecordIsNull(row
,5))
1361 package
->features
[index
].Display
= MsiRecordGetInteger(row
,5);
1363 package
->features
[index
].Level
= MsiRecordGetInteger(row
,6);
1366 if (!MsiRecordIsNull(row
,7))
1367 MsiRecordGetStringW(row
,7,package
->features
[index
].Directory
,&sz
);
1369 package
->features
[index
].Attributes
= MsiRecordGetInteger(row
,8);
1370 package
->features
[index
].State
= INSTALLSTATE_UNKNOWN
;
1372 /* load feature components */
1374 sprintfW(Query
,Query1
,package
->features
[index
].Feature
);
1375 MsiDatabaseOpenViewW(package
->db
,Query
,&view
);
1376 MsiViewExecute(view
,0);
1380 WCHAR buffer
[0x100];
1383 INT cnt
= package
->features
[index
].ComponentCount
;
1385 rc
= MsiViewFetch(view
,&row2
);
1386 if (rc
!= ERROR_SUCCESS
)
1390 MsiRecordGetStringW(row2
,1,buffer
,&sz
);
1392 /* check to see if the component is already loaded */
1393 c_indx
= get_loaded_component(package
,buffer
);
1396 TRACE("Component %s already loaded at %i\n", debugstr_w(buffer
),
1398 package
->features
[index
].Components
[cnt
] = c_indx
;
1399 package
->features
[index
].ComponentCount
++;
1402 sprintfW(Query
,Query2
,buffer
);
1404 MsiDatabaseOpenViewW(package
->db
,Query
,&view2
);
1405 MsiViewExecute(view2
,0);
1410 rc
= MsiViewFetch(view2
,&row3
);
1411 if (rc
!= ERROR_SUCCESS
)
1413 c_indx
= load_component(package
,row3
);
1414 MsiCloseHandle(row3
);
1416 package
->features
[index
].Components
[cnt
] = c_indx
;
1417 package
->features
[index
].ComponentCount
++;
1419 MsiViewClose(view2
);
1420 MsiCloseHandle(view2
);
1421 MsiCloseHandle(row2
);
1424 MsiCloseHandle(view
);
1428 * I am not doing any of the costing functionality yet.
1429 * Mostly looking at doing the Component and Feature loading
1431 * The native MSI does ALOT of modification to tables here. Mostly adding alot
1432 * of temporary columns to the Feature and Component tables.
1434 * note: native msi also tracks the short filename. but i am only going to
1435 * track the long ones. Also looking at this directory table
1436 * it appears that the directory table does not get the parents
1437 * resolved base on property only based on their entrys in the
1440 static UINT
ACTION_CostInitialize(MSIHANDLE hPackage
)
1445 MSIPACKAGE
*package
;
1447 static const CHAR Query_all
[] = "SELECT * FROM Feature";
1449 MsiSetPropertyA(hPackage
,"CostingComplete","0");
1450 MsiSetPropertyW(hPackage
, cszRootDrive
, c_collen
);
1452 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
1455 MsiDatabaseOpenViewA(package
->db
,Query_all
,&view
);
1456 MsiViewExecute(view
,0);
1461 rc
= MsiViewFetch(view
,&row
);
1462 if (rc
!= ERROR_SUCCESS
)
1465 load_feature(package
,row
);
1466 MsiCloseHandle(row
);
1469 MsiCloseHandle(view
);
1471 return ERROR_SUCCESS
;
1474 static int load_file(MSIPACKAGE
* package
, MSIHANDLE row
)
1476 int index
= package
->loaded_files
;
1478 WCHAR buffer
[0x100];
1481 /* fill in the data */
1483 package
->loaded_files
++;
1484 if (package
->loaded_files
== 1)
1485 package
->files
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE
));
1487 package
->files
= HeapReAlloc(GetProcessHeap(),0,
1488 package
->files
, package
->loaded_files
* sizeof(MSIFILE
));
1490 memset(&package
->files
[index
],0,sizeof(MSIFILE
));
1493 MsiRecordGetStringW(row
,1,package
->files
[index
].File
,&sz
);
1496 MsiRecordGetStringW(row
,2,buffer
,&sz
);
1498 package
->files
[index
].ComponentIndex
= -1;
1499 for (i
= 0; i
< package
->loaded_components
; i
++)
1500 if (strcmpW(package
->components
[i
].Component
,buffer
)==0)
1502 package
->files
[index
].ComponentIndex
= i
;
1505 if (package
->files
[index
].ComponentIndex
== -1)
1506 ERR("Unfound Component %s\n",debugstr_w(buffer
));
1509 MsiRecordGetStringW(row
,3,package
->files
[index
].FileName
,&sz
);
1511 reduce_to_longfilename(package
->files
[index
].FileName
);
1513 package
->files
[index
].FileSize
= MsiRecordGetInteger(row
,4);
1516 if (!MsiRecordIsNull(row
,5))
1517 MsiRecordGetStringW(row
,5,package
->files
[index
].Version
,&sz
);
1520 if (!MsiRecordIsNull(row
,6))
1521 MsiRecordGetStringW(row
,6,package
->files
[index
].Language
,&sz
);
1523 if (!MsiRecordIsNull(row
,7))
1524 package
->files
[index
].Attributes
= MsiRecordGetInteger(row
,7);
1526 package
->files
[index
].Sequence
= MsiRecordGetInteger(row
,8);
1528 package
->files
[index
].Temporary
= FALSE
;
1529 package
->files
[index
].State
= 0;
1531 TRACE("File Loaded (%s)\n",debugstr_w(package
->files
[index
].File
));
1533 return ERROR_SUCCESS
;
1536 static UINT
ACTION_FileCost(MSIHANDLE hPackage
)
1540 MSIPACKAGE
*package
;
1542 static const CHAR Query
[] = "SELECT * FROM File Order by Sequence";
1544 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
1546 return ERROR_INVALID_HANDLE
;
1548 rc
= MsiDatabaseOpenViewA(package
->db
, Query
, &view
);
1549 if (rc
!= ERROR_SUCCESS
)
1552 rc
= MsiViewExecute(view
, 0);
1553 if (rc
!= ERROR_SUCCESS
)
1556 MsiCloseHandle(view
);
1562 rc
= MsiViewFetch(view
,&row
);
1563 if (rc
!= ERROR_SUCCESS
)
1568 load_file(package
,row
);
1569 MsiCloseHandle(row
);
1572 MsiCloseHandle(view
);
1574 return ERROR_SUCCESS
;
1577 static INT
load_folder(MSIHANDLE hPackage
, const WCHAR
* dir
)
1581 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',
1582 't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',
1583 'o','r','y','`',' ','=',' ','`',0};
1584 static const WCHAR end
[]={'`',0};
1587 WCHAR targetbuffer
[0x100];
1588 WCHAR
*srcdir
= NULL
;
1589 WCHAR
*targetdir
= NULL
;
1590 WCHAR parent
[0x100];
1593 MSIPACKAGE
*package
;
1596 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
1598 TRACE("Looking for dir %s\n",debugstr_w(dir
));
1600 for (i
= 0; i
< package
->loaded_folders
; i
++)
1602 if (strcmpW(package
->folders
[i
].Directory
,dir
)==0)
1604 TRACE(" %s retuning on index %i\n",debugstr_w(dir
),i
);
1609 TRACE("Working to load %s\n",debugstr_w(dir
));
1611 index
= package
->loaded_folders
;
1613 package
->loaded_folders
++;
1614 if (package
->loaded_folders
== 1)
1615 package
->folders
= HeapAlloc(GetProcessHeap(),0,
1618 package
->folders
= HeapReAlloc(GetProcessHeap(),0,
1619 package
->folders
, package
->loaded_folders
*
1622 memset(&package
->folders
[index
],0,sizeof(MSIFOLDER
));
1624 strcpyW(package
->folders
[index
].Directory
,dir
);
1629 rc
= MsiDatabaseOpenViewW(package
->db
, Query
, &view
);
1631 if (rc
!= ERROR_SUCCESS
)
1634 rc
= MsiViewExecute(view
, 0);
1635 if (rc
!= ERROR_SUCCESS
)
1638 MsiCloseHandle(view
);
1642 rc
= MsiViewFetch(view
,&row
);
1643 if (rc
!= ERROR_SUCCESS
)
1646 MsiCloseHandle(view
);
1651 MsiRecordGetStringW(row
,3,targetbuffer
,&sz
);
1652 targetdir
=targetbuffer
;
1654 /* split src and target dir */
1655 if (strchrW(targetdir
,':'))
1657 srcdir
=strchrW(targetdir
,':');
1664 /* for now only pick long filename versions */
1665 if (strchrW(targetdir
,'|'))
1667 targetdir
= strchrW(targetdir
,'|');
1671 if (srcdir
&& strchrW(srcdir
,'|'))
1673 srcdir
= strchrW(srcdir
,'|');
1678 /* now check for root dirs */
1679 if (targetdir
[0] == '.' && targetdir
[1] == 0)
1682 if (srcdir
&& srcdir
[0] == '.' && srcdir
[1] == 0)
1686 strcpyW(package
->folders
[index
].TargetDefault
,targetdir
);
1689 strcpyW(package
->folders
[index
].SourceDefault
,srcdir
);
1691 strcpyW(package
->folders
[index
].SourceDefault
,targetdir
);
1693 if (MsiRecordIsNull(row
,2))
1698 MsiRecordGetStringW(row
,2,parent
,&sz
);
1703 i
= load_folder(hPackage
,parent
);
1704 package
->folders
[index
].ParentIndex
= i
;
1705 TRACE("Parent is index %i... %s %s\n",
1706 package
->folders
[index
].ParentIndex
,
1707 debugstr_w(package
->folders
[package
->folders
[index
].ParentIndex
].Directory
),
1708 debugstr_w(parent
));
1711 package
->folders
[index
].ParentIndex
= -2;
1714 rc
= MsiGetPropertyW(hPackage
, dir
, package
->folders
[index
].Property
, &sz
);
1715 if (rc
!= ERROR_SUCCESS
)
1716 package
->folders
[index
].Property
[0]=0;
1718 MsiCloseHandle(row
);
1720 MsiCloseHandle(view
);
1721 TRACE(" %s retuning on index %i\n",debugstr_w(dir
),index
);
1725 static UINT
resolve_folder(MSIHANDLE hPackage
, LPCWSTR name
, LPWSTR path
,
1726 BOOL source
, BOOL set_prop
, MSIFOLDER
**folder
)
1728 MSIPACKAGE
*package
;
1730 UINT rc
= ERROR_SUCCESS
;
1733 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
1735 TRACE("Working to resolve %s\n",debugstr_w(name
));
1740 /* special resolving for Target and Source root dir */
1741 if (strcmpW(name
,cszTargetDir
)==0 || strcmpW(name
,cszSourceDir
)==0)
1746 rc
= MsiGetPropertyW(hPackage
,cszTargetDir
,path
,&sz
);
1747 if (rc
!= ERROR_SUCCESS
)
1750 rc
= MsiGetPropertyW(hPackage
,cszRootDrive
,path
,&sz
);
1752 MsiSetPropertyW(hPackage
,cszTargetDir
,path
);
1755 *folder
= &(package
->folders
[0]);
1761 rc
= MsiGetPropertyW(hPackage
,cszSourceDir
,path
,&sz
);
1762 if (rc
!= ERROR_SUCCESS
)
1765 rc
= MsiGetPropertyW(hPackage
,cszDatabase
,path
,&sz
);
1766 if (rc
== ERROR_SUCCESS
)
1768 LPWSTR ptr
= strrchrW(path
,'\\');
1777 *folder
= &(package
->folders
[0]);
1782 for (i
= 0; i
< package
->loaded_folders
; i
++)
1784 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
1788 if (i
>= package
->loaded_folders
)
1789 return ERROR_FUNCTION_FAILED
;
1792 *folder
= &(package
->folders
[i
]);
1794 if (!source
&& package
->folders
[i
].ResolvedTarget
[0])
1796 strcpyW(path
,package
->folders
[i
].ResolvedTarget
);
1797 TRACE(" already resolved to %s\n",debugstr_w(path
));
1798 return ERROR_SUCCESS
;
1800 else if (source
&& package
->folders
[i
].ResolvedSource
[0])
1802 strcpyW(path
,package
->folders
[i
].ResolvedSource
);
1803 return ERROR_SUCCESS
;
1805 else if (!source
&& package
->folders
[i
].Property
[0])
1807 strcpyW(path
,package
->folders
[i
].Property
);
1808 TRACE(" internally set to %s\n",debugstr_w(path
));
1810 MsiSetPropertyW(hPackage
,name
,path
);
1811 return ERROR_SUCCESS
;
1814 if (package
->folders
[i
].ParentIndex
>= 0)
1816 TRACE(" ! Parent is %s\n", debugstr_w(package
->folders
[
1817 package
->folders
[i
].ParentIndex
].Directory
));
1818 resolve_folder(hPackage
, package
->folders
[
1819 package
->folders
[i
].ParentIndex
].Directory
, path
,source
,
1824 if (package
->folders
[i
].TargetDefault
[0])
1826 strcatW(path
,package
->folders
[i
].TargetDefault
);
1827 strcatW(path
,cszbs
);
1829 strcpyW(package
->folders
[i
].ResolvedTarget
,path
);
1830 TRACE(" resolved into %s\n",debugstr_w(path
));
1832 MsiSetPropertyW(hPackage
,name
,path
);
1836 if (package
->folders
[i
].SourceDefault
[0])
1838 strcatW(path
,package
->folders
[i
].SourceDefault
);
1839 strcatW(path
,cszbs
);
1841 strcpyW(package
->folders
[i
].ResolvedSource
,path
);
1848 * Alot is done in this function aside from just the costing.
1849 * The costing needs to be implemented at some point but for now I am going
1850 * to focus on the directory building
1853 static UINT
ACTION_CostFinalize(MSIHANDLE hPackage
)
1855 static const CHAR
*ExecSeqQuery
= "select * from Directory";
1856 static const CHAR
*ConditionQuery
= "select * from Condition";
1859 MSIPACKAGE
*package
;
1862 TRACE("Building Directory properties\n");
1864 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
1866 rc
= MsiDatabaseOpenViewA(package
->db
, ExecSeqQuery
, &view
);
1868 if (rc
!= ERROR_SUCCESS
)
1871 rc
= MsiViewExecute(view
, 0);
1872 if (rc
!= ERROR_SUCCESS
)
1875 MsiCloseHandle(view
);
1882 WCHAR path
[MAX_PATH
];
1886 rc
= MsiViewFetch(view
,&row
);
1888 if (rc
!= ERROR_SUCCESS
)
1895 MsiRecordGetStringW(row
,1,name
,&sz
);
1897 /* This helper function now does ALL the work */
1898 TRACE("Dir %s ...\n",debugstr_w(name
));
1899 load_folder(hPackage
,name
);
1900 resolve_folder(hPackage
,name
,path
,FALSE
,TRUE
,NULL
);
1901 TRACE("resolves to %s\n",debugstr_w(path
));
1903 MsiCloseHandle(row
);
1906 MsiCloseHandle(view
);
1908 TRACE("File calculations %i files\n",package
->loaded_files
);
1910 for (i
= 0; i
< package
->loaded_files
; i
++)
1912 MSICOMPONENT
* comp
= NULL
;
1913 MSIFILE
* file
= NULL
;
1915 file
= &package
->files
[i
];
1916 if (file
->ComponentIndex
>= 0)
1917 comp
= &package
->components
[file
->ComponentIndex
];
1921 /* calculate target */
1922 resolve_folder(hPackage
, comp
->Directory
, file
->TargetPath
, FALSE
,
1924 strcatW(file
->TargetPath
,file
->FileName
);
1926 TRACE("file %s resolves to %s\n",
1927 debugstr_w(file
->File
),debugstr_w(file
->TargetPath
));
1929 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
1932 comp
->Cost
+= file
->FileSize
;
1936 if (file
->Version
[0])
1942 WCHAR filever
[0x100];
1943 static const WCHAR name
[] =
1944 {'\\','V','a','r','F','i','l','e','I','n','f','o',
1945 '\\','F','i','l','e','V','e','r','s','i','o','n',0};
1947 FIXME("Version comparison.. Untried Untested and most "
1948 "likely very very wrong\n");
1949 versize
= GetFileVersionInfoSizeW(file
->TargetPath
,&handle
);
1950 version
= HeapAlloc(GetProcessHeap(),0,versize
);
1951 GetFileVersionInfoW(file
->TargetPath
, 0, versize
, version
);
1953 VerQueryValueW(version
,name
,(LPVOID
)filever
,&sz
);
1954 HeapFree(GetProcessHeap(),0,version
);
1956 if (strcmpW(version
,file
->Version
)<0)
1959 FIXME("cost should be diff in size\n");
1960 comp
->Cost
+= file
->FileSize
;
1971 TRACE("Evaluating Condition Table\n");
1973 rc
= MsiDatabaseOpenViewA(package
->db
, ConditionQuery
, &view
);
1975 if (rc
!= ERROR_SUCCESS
)
1978 rc
= MsiViewExecute(view
, 0);
1979 if (rc
!= ERROR_SUCCESS
)
1982 MsiCloseHandle(view
);
1988 WCHAR Feature
[0x100];
1989 WCHAR Condition
[0x100];
1994 rc
= MsiViewFetch(view
,&row
);
1996 if (rc
!= ERROR_SUCCESS
)
2003 MsiRecordGetStringW(row
,1,Feature
,&sz
);
2005 MsiRecordGetStringW(row
,3,Condition
,&sz
);
2007 feature_index
= get_loaded_feature(package
,Feature
);
2008 if (feature_index
< 0)
2009 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature
));
2012 if (MsiEvaluateConditionW(hPackage
,Condition
) == MSICONDITION_TRUE
)
2014 int level
= MsiRecordGetInteger(row
,2);
2015 TRACE("Reseting feature %s to level %i\n",debugstr_w(Feature
),
2017 package
->features
[feature_index
].Level
= level
;
2021 MsiCloseHandle(row
);
2024 MsiCloseHandle(view
);
2026 TRACE("Enabling or Disabling Components\n");
2027 for (i
= 0; i
< package
->loaded_components
; i
++)
2029 if (package
->components
[i
].Condition
[0])
2031 if (MsiEvaluateConditionW(hPackage
,
2032 package
->components
[i
].Condition
) == MSICONDITION_FALSE
)
2034 TRACE("Disabling component %s\n",
2035 debugstr_w(package
->components
[i
].Component
));
2036 package
->components
[i
].Enabled
= FALSE
;
2041 MsiSetPropertyA(hPackage
,"CostingComplete","1");
2042 return ERROR_SUCCESS
;
2046 * This is a helper function for handling embedded cabinet media
2048 static UINT
writeout_cabinet_stream(MSIHANDLE hPackage
, WCHAR
* stream_name
,
2057 WCHAR tmp
[MAX_PATH
];
2059 db
= MsiGetActiveDatabase(hPackage
);
2060 rc
= read_raw_stream_data(db
,stream_name
,&data
,&size
);
2063 if (rc
!= ERROR_SUCCESS
)
2067 if (MsiGetPropertyW(hPackage
, cszTempFolder
, tmp
, &write
))
2068 GetTempPathW(MAX_PATH
,tmp
);
2070 GetTempFileNameW(tmp
,stream_name
,0,source
);
2072 track_tempfile(hPackage
,strrchrW(source
,'\\'), source
);
2073 the_file
= CreateFileW(source
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
2074 FILE_ATTRIBUTE_NORMAL
, NULL
);
2076 if (the_file
== INVALID_HANDLE_VALUE
)
2078 rc
= ERROR_FUNCTION_FAILED
;
2082 WriteFile(the_file
,data
,size
,&write
,NULL
);
2083 CloseHandle(the_file
);
2084 TRACE("wrote %li bytes to %s\n",write
,debugstr_w(source
));
2086 HeapFree(GetProcessHeap(),0,data
);
2091 /***********************************************************************
2092 * extract_cabinet_file
2094 * Extract files from a cab file.
2096 static void (WINAPI
*pExtractFiles
)( LPSTR
, LPSTR
, DWORD
, DWORD
, DWORD
, DWORD
);
2098 static BOOL
extract_cabinet_file_advpack( const WCHAR
*cabinet
,
2101 static HMODULE advpack
;
2103 char *cab_path
, *cab_file
;
2107 if (!advpack
&& !(advpack
= LoadLibraryA( "advpack.dll" )))
2109 ERR( "could not load advpack.dll\n" );
2112 if (!(pExtractFiles
= (void *)GetProcAddress( advpack
, "ExtractFiles"
2115 ERR( "could not find ExtractFiles in advpack.dll\n" );
2120 if (!(cab_file
= strdupWtoA( cabinet
))) return FALSE
;
2121 if (!(cab_path
= strdupWtoA( root
))) return FALSE
;
2123 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file
) );
2124 pExtractFiles( cab_file
, cab_path
, 0, 0, 0, 0 );
2125 HeapFree( GetProcessHeap(), 0, cab_file
);
2126 HeapFree( GetProcessHeap(), 0, cab_path
);
2130 static BOOL
extract_cabinet_file_cabinet( const WCHAR
*cabinet
,
2134 /* from cabinet.h */
2136 struct ExtractFileList
{
2138 struct ExtractFileList
*next
;
2139 BOOL unknown
; /* always 1L */
2143 long result1
; /* 0x000 */
2144 long unknown1
[3]; /* 0x004 */
2145 struct ExtractFileList
* filelist
; /* 0x010 */
2146 long filecount
; /* 0x014 */
2147 long unknown2
; /* 0x018 */
2148 char directory
[0x104]; /* 0x01c */
2149 char lastfile
[0x20c]; /* 0x120 */
2152 HRESULT WINAPI
Extract(EXTRACTdest
*dest
, LPCSTR what
);
2154 char *cab_path
, *src_path
;
2156 struct ExtractFileList fl
;
2158 if (!(cab_path
= strdupWtoA( cabinet
))) return FALSE
;
2159 if (!(src_path
= strdupWtoA( root
))) return FALSE
;
2161 memset(&exd
,0,sizeof(exd
));
2162 strcpy(exd
.directory
,src_path
);
2164 fl
.filename
= cab_path
;
2168 FIXME( "more aweful hack: extracting cabinet %s\n", debugstr_a(cab_path
) );
2169 Extract(&exd
,cab_path
);
2171 HeapFree( GetProcessHeap(), 0, cab_path
);
2172 HeapFree( GetProcessHeap(), 0, src_path
);
2176 static BOOL
extract_cabinet_file(const WCHAR
* source
, const WCHAR
* path
)
2178 TRACE("Extracting %s to %s\n",debugstr_w(source
), debugstr_w(path
));
2179 if (!extract_cabinet_file_advpack(source
,path
))
2180 return extract_cabinet_file_cabinet(source
,path
);
2184 static UINT
ready_media_for_file(MSIHANDLE hPackage
, UINT sequence
,
2190 WCHAR source
[MAX_PATH
];
2191 static const CHAR
*ExecSeqQuery
=
2192 "select * from Media where LastSequence >= %i order by LastSequence";
2197 static INT last_sequence
= 0;
2200 if (sequence
<= last_sequence
)
2202 TRACE("Media already ready (%i, %i)\n",sequence
,last_sequence
);
2203 return ERROR_SUCCESS
;
2206 sprintf(Query
,ExecSeqQuery
,sequence
);
2208 db
= MsiGetActiveDatabase(hPackage
);
2209 rc
= MsiDatabaseOpenViewA(db
, Query
, &view
);
2212 if (rc
!= ERROR_SUCCESS
)
2215 rc
= MsiViewExecute(view
, 0);
2216 if (rc
!= ERROR_SUCCESS
)
2219 MsiCloseHandle(view
);
2223 rc
= MsiViewFetch(view
,&row
);
2224 if (rc
!= ERROR_SUCCESS
)
2227 MsiCloseHandle(view
);
2230 seq
= MsiRecordGetInteger(row
,2);
2231 last_sequence
= seq
;
2233 if (!MsiRecordIsNull(row
,4))
2236 MsiRecordGetStringW(row
,4,cab
,&sz
);
2237 TRACE("Source is CAB %s\n",debugstr_w(cab
));
2238 /* the stream does not contain the # character */
2241 writeout_cabinet_stream(hPackage
,&cab
[1],source
);
2242 strcpyW(path
,source
);
2243 *(strrchrW(path
,'\\')+1)=0;
2248 if (MsiGetPropertyW(hPackage
, cszSourceDir
, source
, &sz
))
2250 ERR("No Source dir defined \n");
2251 rc
= ERROR_FUNCTION_FAILED
;
2255 strcpyW(path
,source
);
2256 strcatW(source
,cab
);
2257 /* extract the cab file into a folder in the temp folder */
2259 if (MsiGetPropertyW(hPackage
, cszTempFolder
,path
, &sz
)
2261 GetTempPathW(MAX_PATH
,path
);
2264 rc
= !extract_cabinet_file(source
,path
);
2266 MsiCloseHandle(row
);
2268 MsiCloseHandle(view
);
2272 inline static UINT
create_component_directory (MSIHANDLE hPackage
, MSIPACKAGE
*
2273 package
, INT component
)
2277 WCHAR install_path
[MAX_PATH
];
2279 rc
= resolve_folder(hPackage
, package
->components
[component
].Directory
,
2280 install_path
, FALSE
, FALSE
, &folder
);
2282 if (rc
!= ERROR_SUCCESS
)
2285 /* create the path */
2286 if (folder
->State
== 0)
2288 create_full_pathW(install_path
);
2295 static UINT
ACTION_InstallFiles(MSIHANDLE hPackage
)
2297 UINT rc
= ERROR_SUCCESS
;
2299 MSIPACKAGE
*package
;
2301 WCHAR uipath
[MAX_PATH
];
2303 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
2306 return ERROR_INVALID_HANDLE
;
2308 /* increment progress bar each time action data is sent */
2309 ui_progress(hPackage
,1,1,1,0);
2311 for (index
= 0; index
< package
->loaded_files
; index
++)
2313 WCHAR path_to_source
[MAX_PATH
];
2316 file
= &package
->files
[index
];
2318 if (file
->Temporary
)
2321 if (!package
->components
[file
->ComponentIndex
].Enabled
||
2322 !package
->components
[file
->ComponentIndex
].FeatureState
)
2324 TRACE("File %s is not scheduled for install\n",
2325 debugstr_w(file
->File
));
2329 if ((file
->State
== 1) || (file
->State
== 2))
2331 TRACE("Installing %s\n",debugstr_w(file
->File
));
2332 rc
= ready_media_for_file(hPackage
,file
->Sequence
,path_to_source
);
2335 * our file table could change here because a new temp file
2336 * may have been created
2338 file
= &package
->files
[index
];
2339 if (rc
!= ERROR_SUCCESS
)
2341 ERR("Unable to ready media\n");
2342 rc
= ERROR_FUNCTION_FAILED
;
2346 create_component_directory(hPackage
, package
, file
->ComponentIndex
);
2348 strcpyW(file
->SourcePath
, path_to_source
);
2349 strcatW(file
->SourcePath
, file
->File
);
2351 TRACE("file paths %s to %s\n",debugstr_w(file
->SourcePath
),
2352 debugstr_w(file
->TargetPath
));
2355 uirow
=MsiCreateRecord(9);
2356 MsiRecordSetStringW(uirow
,1,file
->File
);
2357 strcpyW(uipath
,file
->TargetPath
);
2358 *(strrchrW(uipath
,'\\')+1)=0;
2359 MsiRecordSetStringW(uirow
,9,uipath
);
2360 MsiRecordSetInteger(uirow
,6,file
->FileSize
);
2361 ui_actiondata(hPackage
,szInstallFiles
,uirow
);
2362 MsiCloseHandle(uirow
);
2364 rc
= !MoveFileW(file
->SourcePath
,file
->TargetPath
);
2365 ui_progress(hPackage
,2,0,0,0);
2369 ERR("Unable to move file (error %li)\n",GetLastError());
2380 inline static UINT
get_file_target(MSIHANDLE hPackage
, LPCWSTR file_key
,
2383 MSIPACKAGE
*package
;
2386 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
2388 return ERROR_INVALID_HANDLE
;
2390 for (index
= 0; index
< package
->loaded_files
; index
++)
2392 if (strcmpW(file_key
,package
->files
[index
].File
)==0)
2394 if (package
->files
[index
].State
>= 3)
2396 strcpyW(file_source
,package
->files
[index
].TargetPath
);
2397 return ERROR_SUCCESS
;
2400 return ERROR_FILE_NOT_FOUND
;
2404 return ERROR_FUNCTION_FAILED
;
2407 static UINT
ACTION_DuplicateFiles(MSIHANDLE hPackage
)
2412 static const CHAR
*ExecSeqQuery
= "select * from DuplicateFile";
2413 MSIPACKAGE
* package
;
2415 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
2417 return ERROR_INVALID_HANDLE
;
2419 rc
= MsiDatabaseOpenViewA(package
->db
, ExecSeqQuery
, &view
);
2421 if (rc
!= ERROR_SUCCESS
)
2424 rc
= MsiViewExecute(view
, 0);
2425 if (rc
!= ERROR_SUCCESS
)
2428 MsiCloseHandle(view
);
2434 WCHAR file_key
[0x100];
2435 WCHAR file_source
[MAX_PATH
];
2436 WCHAR dest_name
[0x100];
2437 WCHAR dest_path
[MAX_PATH
];
2438 WCHAR component
[0x100];
2439 INT component_index
;
2443 rc
= MsiViewFetch(view
,&row
);
2444 if (rc
!= ERROR_SUCCESS
)
2451 rc
= MsiRecordGetStringW(row
,2,component
,&sz
);
2452 if (rc
!= ERROR_SUCCESS
)
2454 ERR("Unable to get component\n");
2455 MsiCloseHandle(row
);
2459 component_index
= get_loaded_component(package
,component
);
2460 if (!package
->components
[component_index
].Enabled
||
2461 !package
->components
[component_index
].FeatureState
)
2463 TRACE("Skipping copy due to disabled component\n");
2464 MsiCloseHandle(row
);
2469 rc
= MsiRecordGetStringW(row
,3,file_key
,&sz
);
2470 if (rc
!= ERROR_SUCCESS
)
2472 ERR("Unable to get file key\n");
2473 MsiCloseHandle(row
);
2477 rc
= get_file_target(hPackage
,file_key
,file_source
);
2479 if (rc
!= ERROR_SUCCESS
)
2481 ERR("Original file unknown %s\n",debugstr_w(file_key
));
2482 MsiCloseHandle(row
);
2486 if (MsiRecordIsNull(row
,4))
2488 strcpyW(dest_name
,strrchrW(file_source
,'\\')+1);
2493 MsiRecordGetStringW(row
,4,dest_name
,&sz
);
2494 reduce_to_longfilename(dest_name
);
2497 if (MsiRecordIsNull(row
,5))
2499 strcpyW(dest_path
,file_source
);
2500 *strrchrW(dest_path
,'\\')=0;
2504 WCHAR destkey
[0x100];
2506 MsiRecordGetStringW(row
,5,destkey
,&sz
);
2508 rc
= resolve_folder(hPackage
, destkey
, dest_path
,FALSE
,FALSE
,NULL
);
2509 if (rc
!= ERROR_SUCCESS
)
2511 ERR("Unable to get destination folder\n");
2512 MsiCloseHandle(row
);
2517 strcatW(dest_path
,dest_name
);
2519 TRACE("Duplicating file %s to %s\n",debugstr_w(file_source
),
2520 debugstr_w(dest_path
));
2522 if (strcmpW(file_source
,dest_path
))
2523 rc
= !CopyFileW(file_source
,dest_path
,TRUE
);
2527 if (rc
!= ERROR_SUCCESS
)
2528 ERR("Failed to copy file\n");
2530 FIXME("We should track these duplicate files as well\n");
2532 MsiCloseHandle(row
);
2535 MsiCloseHandle(view
);
2541 /* OK this value is "interpretted" and then formatted based on the
2542 first few characters */
2543 static LPSTR
parse_value(MSIHANDLE hPackage
, WCHAR
*value
, DWORD
*type
,
2547 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2556 deformat_string(hPackage
, &value
[2], &deformated
);
2558 /* binary value type */
2561 *size
= strlenW(ptr
)/2;
2562 data
= HeapAlloc(GetProcessHeap(),0,*size
);
2574 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2577 HeapFree(GetProcessHeap(),0,deformated
);
2579 TRACE("Data %li bytes(%i)\n",*size
,count
);
2584 deformat_string(hPackage
, &value
[1], &deformated
);
2587 *size
= sizeof(DWORD
);
2588 data
= HeapAlloc(GetProcessHeap(),0,*size
);
2589 *(LPDWORD
)data
= atoiW(deformated
);
2590 TRACE("DWORD %i\n",*data
);
2592 HeapFree(GetProcessHeap(),0,deformated
);
2605 *type
=REG_EXPAND_SZ
;
2613 *size
= deformat_string(hPackage
, ptr
,(LPWSTR
*)&data
);
2618 static UINT
ACTION_WriteRegistryValues(MSIHANDLE hPackage
)
2623 static const CHAR
*ExecSeqQuery
= "select * from Registry";
2624 MSIPACKAGE
*package
;
2626 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
2628 return ERROR_INVALID_HANDLE
;
2630 rc
= MsiDatabaseOpenViewA(package
->db
, ExecSeqQuery
, &view
);
2632 if (rc
!= ERROR_SUCCESS
)
2635 rc
= MsiViewExecute(view
, 0);
2636 if (rc
!= ERROR_SUCCESS
)
2639 MsiCloseHandle(view
);
2643 /* increment progress bar each time action data is sent */
2644 ui_progress(hPackage
,1,1,1,0);
2648 static const WCHAR szHCR
[] =
2649 {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T','\\',0};
2650 static const WCHAR szHCU
[] =
2651 {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',0};
2652 static const WCHAR szHLM
[] =
2653 {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',
2655 static const WCHAR szHU
[] =
2656 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2661 LPSTR value_data
= NULL
;
2662 HKEY root_key
, hkey
;
2664 WCHAR component
[0x100];
2665 INT component_index
;
2672 rc
= MsiViewFetch(view
,&row
);
2673 if (rc
!= ERROR_SUCCESS
)
2680 MsiRecordGetStringW(row
,6,component
,&sz
);
2681 component_index
= get_loaded_component(package
,component
);
2683 if (!package
->components
[component_index
].Enabled
||
2684 !package
->components
[component_index
].FeatureState
)
2686 TRACE("Skipping write due to disabled component\n");
2687 MsiCloseHandle(row
);
2691 /* null values have special meanings during uninstalls and such */
2693 if(MsiRecordIsNull(row
,5))
2695 MsiCloseHandle(row
);
2699 root
= MsiRecordGetInteger(row
,2);
2701 MsiRecordGetStringW(row
,3,key
,&sz
);
2704 if (MsiRecordIsNull(row
,4))
2707 MsiRecordGetStringW(row
,4,name
,&sz
);
2709 /* get the root key */
2712 case 0: root_key
= HKEY_CLASSES_ROOT
;
2713 strcpyW(uikey
,szHCR
); break;
2714 case 1: root_key
= HKEY_CURRENT_USER
;
2715 strcpyW(uikey
,szHCU
); break;
2716 case 2: root_key
= HKEY_LOCAL_MACHINE
;
2717 strcpyW(uikey
,szHLM
); break;
2718 case 3: root_key
= HKEY_USERS
;
2719 strcpyW(uikey
,szHU
); break;
2721 ERR("Unknown root %i\n",root
);
2727 MsiCloseHandle(row
);
2732 if (RegCreateKeyW( root_key
, key
, &hkey
))
2734 ERR("Could not create key %s\n",debugstr_w(key
));
2735 MsiCloseHandle(row
);
2740 MsiRecordGetStringW(row
,5,NULL
,&sz
);
2742 value
= HeapAlloc(GetProcessHeap(),0,sz
* sizeof(WCHAR
));
2743 MsiRecordGetStringW(row
,5,value
,&sz
);
2744 value_data
= parse_value(hPackage
, value
, &type
, &size
);
2748 TRACE("Setting value %s\n",debugstr_w(name
));
2749 RegSetValueExW(hkey
, name
, 0, type
, value_data
, size
);
2751 uirow
= MsiCreateRecord(3);
2752 MsiRecordSetStringW(uirow
,2,name
);
2753 MsiRecordSetStringW(uirow
,1,uikey
);
2756 MsiRecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2758 MsiRecordSetStringW(uirow
,3,value
);
2760 ui_actiondata(hPackage
,szWriteRegistryValues
,uirow
);
2761 ui_progress(hPackage
,2,0,0,0);
2762 MsiCloseHandle(uirow
);
2764 HeapFree(GetProcessHeap(),0,value_data
);
2766 HeapFree(GetProcessHeap(),0,value
);
2768 MsiCloseHandle(row
);
2772 MsiCloseHandle(view
);
2777 * This helper function should probably go alot of places
2779 * Thinking about this, maybe this should become yet another Bison file
2781 static DWORD
deformat_string(MSIHANDLE hPackage
, WCHAR
* ptr
,WCHAR
** data
)
2790 /* scan for special characters */
2791 if (!strchrW(ptr
,'[') || (strchrW(ptr
,'[') && !strchrW(ptr
,']')))
2794 size
= (strlenW(ptr
)+1) * sizeof(WCHAR
);
2795 *data
= HeapAlloc(GetProcessHeap(),0,size
);
2800 /* formatted string located */
2801 mark
= strchrW(ptr
,'[');
2804 INT cnt
= (mark
- ptr
);
2805 TRACE("%i (%i) characters before marker\n",cnt
,(mark
-ptr
));
2806 size
= cnt
* sizeof(WCHAR
);
2807 size
+= sizeof(WCHAR
);
2808 *data
= HeapAlloc(GetProcessHeap(),0,size
);
2809 strncpyW(*data
,ptr
,cnt
);
2814 size
= sizeof(WCHAR
);
2815 *data
= HeapAlloc(GetProcessHeap(),0,size
);
2820 *strchrW(key
,']')=0;
2821 mark
= strchrW(mark
,']');
2823 TRACE("Current %s .. %s\n",debugstr_w(*data
),debugstr_w(mark
));
2825 if (MsiGetPropertyW(hPackage
, key
, value
,&sz
) == ERROR_SUCCESS
)
2828 chunk
= (strlenW(value
)+1) * sizeof(WCHAR
);
2830 newdata
= HeapReAlloc(GetProcessHeap(),0,*data
,size
);
2832 strcatW(*data
,value
);
2834 TRACE("Current %s .. %s\n",debugstr_w(*data
),debugstr_w(mark
));
2838 chunk
= (strlenW(mark
)+1) * sizeof(WCHAR
);
2840 newdata
= HeapReAlloc(GetProcessHeap(),0,*data
,size
);
2842 strcatW(*data
,mark
);
2844 (*data
)[strlenW(*data
)]=0;
2845 TRACE("Current %s .. %s\n",debugstr_w(*data
),debugstr_w(mark
));
2847 /* recursively do this to clean up */
2848 mark
= HeapAlloc(GetProcessHeap(),0,size
);
2849 strcpyW(mark
,*data
);
2850 TRACE("String at this point %s\n",debugstr_w(mark
));
2851 size
= deformat_string(hPackage
,mark
,data
);
2852 HeapFree(GetProcessHeap(),0,mark
);
2856 static UINT
ACTION_InstallInitialize(MSIHANDLE hPackage
)
2861 MSIPACKAGE
*package
;
2864 LPWSTR override
= NULL
;
2865 static const WCHAR addlocal
[]={'A','D','D','L','O','C','A','L',0};
2866 static const WCHAR all
[]={'A','L','L',0};
2868 /* I do not know if this is where it should happen.. but */
2870 TRACE("Checking Install Level\n");
2873 if (MsiGetPropertyA(hPackage
,"INSTALLLEVEL",level
,&sz
)==ERROR_SUCCESS
)
2874 install_level
= atoi(level
);
2879 rc
= MsiGetPropertyA(hPackage
,"ADDLOCAL",NULL
,&sz
);
2880 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2883 override
= HeapAlloc(GetProcessHeap(),0,sz
*sizeof(WCHAR
));
2884 MsiGetPropertyW(hPackage
, addlocal
,override
,&sz
);
2887 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
2889 return ERROR_INVALID_HANDLE
;
2892 * components FeatureState defaults to FALSE. the idea is we want to
2893 * enable the component is ANY feature that uses it is enabled to install
2895 for(i
= 0; i
< package
->loaded_features
; i
++)
2897 BOOL feature_state
= ((package
->features
[i
].Level
> 0) &&
2898 (package
->features
[i
].Level
<= install_level
));
2900 if (override
&& (strcmpiW(override
,all
)==0 ||
2901 strstrW(override
,package
->features
[i
].Feature
)))
2903 TRACE("Override of install level found\n");
2904 feature_state
= TRUE
;
2907 TRACE("Feature %s has a state of %i\n",
2908 debugstr_w(package
->features
[i
].Feature
), feature_state
);
2909 for( j
= 0; j
< package
->features
[i
].ComponentCount
; j
++)
2911 package
->components
[package
->features
[i
].Components
[j
]].FeatureState
2915 if (override
!= NULL
)
2916 HeapFree(GetProcessHeap(),0,override
);
2918 * so basically we ONLY want to install a component if its Enabled AND
2919 * FeatureState are both TRUE
2921 return ERROR_SUCCESS
;
2924 static UINT
ACTION_InstallValidate(MSIHANDLE hPackage
)
2927 static const CHAR q1
[]="SELECT * FROM Registry";
2932 MSIPACKAGE
* package
;
2934 TRACE(" InstallValidate \n");
2936 db
= MsiGetActiveDatabase(hPackage
);
2937 rc
= MsiDatabaseOpenViewA(db
, q1
, &view
);
2938 rc
= MsiViewExecute(view
, 0);
2941 rc
= MsiViewFetch(view
,&row
);
2942 if (rc
!= ERROR_SUCCESS
)
2949 MsiCloseHandle(row
);
2952 MsiCloseHandle(view
);
2955 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
2956 ui_progress(hPackage
,0,progress
+package
->loaded_files
,0,0);
2958 return ERROR_SUCCESS
;
2961 static UINT
ACTION_LaunchConditions(MSIHANDLE hPackage
)
2966 static const CHAR
*ExecSeqQuery
= "SELECT * from LaunchCondition";
2968 static const WCHAR title
[]=
2969 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2971 TRACE("Checking launch conditions\n");
2973 db
= MsiGetActiveDatabase(hPackage
);
2974 rc
= MsiDatabaseOpenViewA(db
, ExecSeqQuery
, &view
);
2977 if (rc
!= ERROR_SUCCESS
)
2980 rc
= MsiViewExecute(view
, 0);
2981 if (rc
!= ERROR_SUCCESS
)
2984 MsiCloseHandle(view
);
2989 while (rc
== ERROR_SUCCESS
)
2992 LPWSTR message
= NULL
;
2995 rc
= MsiViewFetch(view
,&row
);
2996 if (rc
!= ERROR_SUCCESS
)
3003 MsiRecordGetStringW(row
,1,NULL
,&sz
);
3005 cond
= HeapAlloc(GetProcessHeap(),0,sz
*sizeof(WCHAR
));
3006 MsiRecordGetStringW(row
,1,cond
,&sz
);
3008 if (MsiEvaluateConditionW(hPackage
,cond
) != MSICONDITION_TRUE
)
3011 MsiRecordGetStringW(row
,2,NULL
,&sz
);
3013 message
= HeapAlloc(GetProcessHeap(),0,sz
*sizeof(WCHAR
));
3014 MsiRecordGetStringW(row
,2,message
,&sz
);
3015 MessageBoxW(NULL
,message
,title
,MB_OK
);
3016 HeapFree(GetProcessHeap(),0,message
);
3017 rc
= ERROR_FUNCTION_FAILED
;
3019 HeapFree(GetProcessHeap(),0,cond
);
3020 MsiCloseHandle(row
);
3023 MsiCloseHandle(view
);
3027 static void resolve_keypath(MSIHANDLE hPackage
, MSIPACKAGE
* package
, INT
3028 component_index
, WCHAR
*keypath
)
3030 MSICOMPONENT
* cmp
= &package
->components
[component_index
];
3032 if (cmp
->KeyPath
[0]==0)
3034 resolve_folder(hPackage
,cmp
->Directory
,keypath
,FALSE
,FALSE
,NULL
);
3037 if ((cmp
->Attributes
& 0x4) || (cmp
->Attributes
& 0x20))
3039 FIXME("UNIMPLEMENTED keypath as Registry or ODBC Source\n");
3045 j
= get_loaded_file(package
,cmp
->KeyPath
);
3048 strcpyW(keypath
,package
->files
[j
].TargetPath
);
3052 static UINT
ACTION_ProcessComponents(MSIHANDLE hPackage
)
3054 MSIPACKAGE
* package
;
3055 WCHAR productcode
[0x100];
3056 WCHAR squished_pc
[0x100];
3057 WCHAR squished_cc
[0x100];
3061 HKEY hkey
=0,hkey2
=0,hkey3
=0;
3062 static const WCHAR szProductCode
[]=
3063 {'P','r','o','d','u','c','t','C','o','d','e',0};
3064 static const WCHAR szInstaller
[] = {
3065 'S','o','f','t','w','a','r','e','\\',
3066 'M','i','c','r','o','s','o','f','t','\\',
3067 'W','i','n','d','o','w','s','\\',
3068 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3069 'I','n','s','t','a','l','l','e','r',0 };
3070 static const WCHAR szFeatures
[] = {
3071 'F','e','a','t','u','r','e','s',0 };
3072 static const WCHAR szComponents
[] = {
3073 'C','o','m','p','o','n','e','n','t','s',0 };
3075 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
3077 return ERROR_INVALID_HANDLE
;
3079 /* writes the Component and Features values to the registry */
3081 rc
= MsiGetPropertyW(hPackage
,szProductCode
,productcode
,&sz
);
3083 if (rc
!= ERROR_SUCCESS
)
3084 return ERROR_SUCCESS
;
3086 squash_guid(productcode
,squished_pc
);
3087 rc
= RegCreateKeyW(HKEY_LOCAL_MACHINE
,szInstaller
,&hkey
);
3088 if (rc
!= ERROR_SUCCESS
)
3091 rc
= RegCreateKeyW(hkey
,szFeatures
,&hkey2
);
3092 if (rc
!= ERROR_SUCCESS
)
3095 rc
= RegCreateKeyW(hkey2
,squished_pc
,&hkey3
);
3096 if (rc
!= ERROR_SUCCESS
)
3099 /* I have no idea what goes in here */
3100 for (i
= 0; i
< package
->loaded_features
; i
++)
3101 RegSetValueExW(hkey3
,package
->features
[i
].Feature
,0,REG_SZ
,NULL
,0);
3106 rc
= RegCreateKeyW(hkey
,szComponents
,&hkey2
);
3107 if (rc
!= ERROR_SUCCESS
)
3110 for (i
= 0; i
< package
->loaded_components
; i
++)
3112 if (package
->components
[i
].ComponentId
[0]!=0)
3114 WCHAR keypath
[0x1000];
3117 squash_guid(package
->components
[i
].ComponentId
,squished_cc
);
3118 rc
= RegCreateKeyW(hkey2
,squished_cc
,&hkey3
);
3119 if (rc
!= ERROR_SUCCESS
)
3122 resolve_keypath(hPackage
,package
,i
,keypath
);
3124 RegSetValueExW(hkey3
,squished_pc
,0,REG_SZ
,(LPVOID
)keypath
,
3125 (strlenW(keypath
)+1)*sizeof(WCHAR
));
3129 uirow
= MsiCreateRecord(3);
3130 MsiRecordSetStringW(uirow
,1,productcode
);
3131 MsiRecordSetStringW(uirow
,2,package
->components
[i
].ComponentId
);
3132 MsiRecordSetStringW(uirow
,3,keypath
);
3133 ui_actiondata(hPackage
,szProcessComponents
,uirow
);
3134 MsiCloseHandle(uirow
);
3143 static UINT
ACTION_RegisterTypeLibraries(MSIHANDLE hPackage
)
3146 * ok this is a bit confusting.. I am given a _Component key and i believe
3147 * that the file that is being registered as a type library is the "key file
3148 * of that component" which i interpert to mean "The file in the KeyPath of
3154 static const CHAR
*Query
= "SELECT * from TypeLib";
3155 MSIPACKAGE
* package
;
3159 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
3161 return ERROR_INVALID_HANDLE
;
3163 rc
= MsiDatabaseOpenViewA(package
->db
, Query
, &view
);
3165 if (rc
!= ERROR_SUCCESS
)
3168 rc
= MsiViewExecute(view
, 0);
3169 if (rc
!= ERROR_SUCCESS
)
3172 MsiCloseHandle(view
);
3178 WCHAR component
[0x100];
3182 rc
= MsiViewFetch(view
,&row
);
3183 if (rc
!= ERROR_SUCCESS
)
3190 MsiRecordGetStringW(row
,3,component
,&sz
);
3192 index
= get_loaded_component(package
,component
);
3195 MsiCloseHandle(row
);
3199 if (!package
->components
[index
].Enabled
||
3200 !package
->components
[index
].FeatureState
)
3202 TRACE("Skipping typelib reg due to disabled component\n");
3203 MsiCloseHandle(row
);
3207 index
= get_loaded_file(package
,package
->components
[index
].KeyPath
);
3211 MsiCloseHandle(row
);
3215 res
= LoadTypeLib(package
->files
[index
].TargetPath
,&ptLib
);
3218 WCHAR help
[MAX_PATH
];
3219 WCHAR helpid
[0x100];
3222 MsiRecordGetStringW(row
,6,helpid
,&sz
);
3224 resolve_folder(hPackage
,helpid
,help
,FALSE
,FALSE
,NULL
);
3226 res
= RegisterTypeLib(ptLib
,package
->files
[index
].TargetPath
,help
);
3227 if (!SUCCEEDED(res
))
3228 ERR("Failed to register type library %s\n",
3229 debugstr_w(package
->files
[index
].TargetPath
));
3232 /* yes the row has more fields than i need, but #1 is
3233 correct and the only one i need. why make a new row */
3235 ui_actiondata(hPackage
,szRegisterTypeLibraries
,row
);
3237 TRACE("Registered %s\n",
3238 debugstr_w(package
->files
[index
].TargetPath
));
3242 ITypeLib_Release(ptLib
);
3245 ERR("Failed to load type library %s\n",
3246 debugstr_w(package
->files
[index
].TargetPath
));
3248 MsiCloseHandle(row
);
3251 MsiCloseHandle(view
);
3256 static UINT
register_appid(MSIHANDLE hPackage
, LPCWSTR clsid
, LPCWSTR app
)
3258 static const WCHAR szAppID
[] = { 'A','p','p','I','D',0 };
3262 static const WCHAR ExecSeqQuery
[] =
3263 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'
3264 ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};
3265 WCHAR Query
[0x1000];
3266 MSIPACKAGE
* package
;
3271 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
3273 return ERROR_INVALID_HANDLE
;
3276 sprintfW(Query
,ExecSeqQuery
,clsid
);
3278 rc
= MsiDatabaseOpenViewW(package
->db
, Query
, &view
);
3279 if (rc
!= ERROR_SUCCESS
)
3282 rc
= MsiViewExecute(view
, 0);
3283 if (rc
!= ERROR_SUCCESS
)
3286 MsiCloseHandle(view
);
3290 RegCreateKeyW(HKEY_CLASSES_ROOT
,szAppID
,&hkey2
);
3291 RegCreateKeyW(hkey2
,clsid
,&hkey3
);
3292 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,(LPVOID
)app
,
3293 (strlenW(app
)+1)*sizeof(WCHAR
));
3295 MsiViewFetch(view
,&row
);
3297 if (!MsiRecordIsNull(row
,2))
3299 LPWSTR deformated
=0;
3301 static const WCHAR szRemoteServerName
[] =
3302 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
3304 MsiRecordGetStringW(row
,2,NULL
,&sz
);
3306 buffer
= HeapAlloc(GetProcessHeap(),0,sz
* sizeof (WCHAR
));
3307 MsiRecordGetStringW(row
,2,buffer
,&sz
);
3308 size
= deformat_string(hPackage
,buffer
,&deformated
);
3309 RegSetValueExW(hkey3
,szRemoteServerName
,0,REG_SZ
,(LPVOID
)deformated
,
3311 HeapFree(GetProcessHeap(),0,deformated
);
3312 HeapFree(GetProcessHeap(),0,buffer
);
3315 if (!MsiRecordIsNull(row
,3))
3317 static const WCHAR szLocalService
[] =
3318 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
3321 MsiRecordGetStringW(row
,3,NULL
,&sz
);
3323 size
= sz
* sizeof(WCHAR
);
3324 buffer
= HeapAlloc(GetProcessHeap(),0,size
);
3325 MsiRecordGetStringW(row
,3,buffer
,&sz
);
3326 RegSetValueExW(hkey3
,szLocalService
,0,REG_SZ
,(LPVOID
)buffer
,size
);
3327 HeapFree(GetProcessHeap(),0,buffer
);
3330 if (!MsiRecordIsNull(row
,4))
3332 static const WCHAR szService
[] =
3333 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
3336 MsiRecordGetStringW(row
,4,NULL
,&sz
);
3338 size
= sz
* sizeof(WCHAR
);
3339 buffer
= HeapAlloc(GetProcessHeap(),0,size
);
3340 MsiRecordGetStringW(row
,4,buffer
,&sz
);
3341 RegSetValueExW(hkey3
,szService
,0,REG_SZ
,(LPVOID
)buffer
,size
);
3342 HeapFree(GetProcessHeap(),0,buffer
);
3345 if (!MsiRecordIsNull(row
,5))
3347 static const WCHAR szDLL
[] =
3348 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
3351 MsiRecordGetStringW(row
,5,NULL
,&sz
);
3353 size
= sz
* sizeof(WCHAR
);
3354 buffer
= HeapAlloc(GetProcessHeap(),0,size
);
3355 MsiRecordGetStringW(row
,5,buffer
,&sz
);
3356 RegSetValueExW(hkey3
,szDLL
,0,REG_SZ
,(LPVOID
)buffer
,size
);
3357 HeapFree(GetProcessHeap(),0,buffer
);
3360 if (!MsiRecordIsNull(row
,6))
3362 static const WCHAR szActivate
[] =
3363 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
3364 static const WCHAR szY
[] = {'Y',0};
3366 if (MsiRecordGetInteger(row
,6))
3367 RegSetValueExW(hkey3
,szActivate
,0,REG_SZ
,(LPVOID
)szY
,4);
3370 if (!MsiRecordIsNull(row
,7))
3372 static const WCHAR szRunAs
[] = {'R','u','n','A','s',0};
3373 static const WCHAR szUser
[] =
3374 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
3376 if (MsiRecordGetInteger(row
,7))
3377 RegSetValueExW(hkey3
,szRunAs
,0,REG_SZ
,(LPVOID
)szUser
,34);
3380 MsiCloseHandle(row
);
3382 MsiCloseHandle(view
);
3388 static UINT
ACTION_RegisterClassInfo(MSIHANDLE hPackage
)
3391 * again i am assuming the words, "Whose key file respesents" when refering
3392 * to a Component as to meanin that Components KeyPath file
3394 * Also there is a very strong connection between ClassInfo and ProgID
3395 * that i am mostly glossing over.
3396 * What would be more proper is to load the ClassInfo and the ProgID info
3397 * into memory data structures and then be able to enable and disable them
3398 * based on component.
3404 static const CHAR
*ExecSeqQuery
= "SELECT * from Class";
3405 MSIPACKAGE
* package
;
3406 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
3407 static const WCHAR szProgID
[] = { 'P','r','o','g','I','D',0 };
3408 static const WCHAR szAppID
[] = { 'A','p','p','I','D',0 };
3409 HKEY hkey
,hkey2
,hkey3
;
3411 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
3413 return ERROR_INVALID_HANDLE
;
3415 rc
= RegCreateKeyW(HKEY_CLASSES_ROOT
,szCLSID
,&hkey
);
3416 if (rc
!= ERROR_SUCCESS
)
3417 return ERROR_FUNCTION_FAILED
;
3419 rc
= MsiDatabaseOpenViewA(package
->db
, ExecSeqQuery
, &view
);
3421 if (rc
!= ERROR_SUCCESS
)
3424 rc
= MsiViewExecute(view
, 0);
3425 if (rc
!= ERROR_SUCCESS
)
3428 MsiCloseHandle(view
);
3435 WCHAR buffer
[0x100];
3440 rc
= MsiViewFetch(view
,&row
);
3441 if (rc
!= ERROR_SUCCESS
)
3448 MsiRecordGetStringW(row
,3,buffer
,&sz
);
3450 index
= get_loaded_component(package
,buffer
);
3454 MsiCloseHandle(row
);
3458 if (!package
->components
[index
].Enabled
||
3459 !package
->components
[index
].FeatureState
)
3461 TRACE("Skipping class reg due to disabled component\n");
3462 MsiCloseHandle(row
);
3467 MsiRecordGetStringW(row
,1,clsid
,&sz
);
3468 RegCreateKeyW(hkey
,clsid
,&hkey2
);
3470 if (!MsiRecordIsNull(row
,5))
3473 MsiRecordGetStringW(row
,5,desc
,&sz
);
3475 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)desc
,
3476 (strlenW(desc
)+1)*sizeof(WCHAR
));
3482 MsiRecordGetStringW(row
,2,buffer
,&sz
);
3484 RegCreateKeyW(hkey2
,buffer
,&hkey3
);
3486 index
= get_loaded_file(package
,package
->components
[index
].KeyPath
);
3487 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,
3488 (LPVOID
)package
->files
[index
].TargetPath
,
3489 (strlenW(package
->files
[index
].TargetPath
)+1)
3494 if (!MsiRecordIsNull(row
,4))
3497 MsiRecordGetStringW(row
,4,buffer
,&sz
);
3499 RegCreateKeyW(hkey2
,szProgID
,&hkey3
);
3501 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,(LPVOID
)buffer
,
3502 (strlenW(buffer
)+1)*sizeof(WCHAR
));
3507 if (!MsiRecordIsNull(row
,6))
3510 MsiRecordGetStringW(row
,6,buffer
,&sz
);
3512 RegSetValueExW(hkey2
,szAppID
,0,REG_SZ
,(LPVOID
)buffer
,
3513 (strlenW(buffer
)+1)*sizeof(WCHAR
));
3515 register_appid(hPackage
,buffer
,desc
);
3520 FIXME("Process the rest of the fields >7\n");
3522 ui_actiondata(hPackage
,szRegisterClassInfo
,row
);
3524 MsiCloseHandle(row
);
3527 MsiCloseHandle(view
);
3534 static UINT
register_progid_base(MSIHANDLE row
, LPWSTR clsid
)
3536 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
3538 WCHAR buffer
[0x1000];
3543 MsiRecordGetStringW(row
,1,buffer
,&sz
);
3544 RegCreateKeyW(HKEY_CLASSES_ROOT
,buffer
,&hkey
);
3546 if (!MsiRecordIsNull(row
,4))
3549 MsiRecordGetStringW(row
,4,buffer
,&sz
);
3550 RegSetValueExW(hkey
,NULL
,0,REG_SZ
,(LPVOID
)buffer
, (strlenW(buffer
)+1) *
3554 if (!MsiRecordIsNull(row
,3))
3558 MsiRecordGetStringW(row
,3,buffer
,&sz
);
3559 RegCreateKeyW(hkey
,szCLSID
,&hkey2
);
3560 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)buffer
, (strlenW(buffer
)+1) *
3564 strcpyW(clsid
,buffer
);
3570 FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
3571 return ERROR_FUNCTION_FAILED
;
3573 if (!MsiRecordIsNull(row
,5))
3574 FIXME ("UNHANDLED icon in Progid\n");
3575 return ERROR_SUCCESS
;
3578 static UINT
register_progid(MSIHANDLE hPackage
, MSIHANDLE row
, LPWSTR clsid
);
3580 static UINT
register_parent_progid(MSIHANDLE hPackage
, LPCWSTR parent
,
3586 static const WCHAR Query_t
[] =
3587 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'
3588 ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'
3590 WCHAR Query
[0x1000];
3591 MSIPACKAGE
* package
;
3593 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
3595 return ERROR_INVALID_HANDLE
;
3597 sprintfW(Query
,Query_t
,parent
);
3599 rc
= MsiDatabaseOpenViewW(package
->db
, Query
, &view
);
3601 if (rc
!= ERROR_SUCCESS
)
3604 rc
= MsiViewExecute(view
, 0);
3605 if (rc
!= ERROR_SUCCESS
)
3608 MsiCloseHandle(view
);
3612 rc
= MsiViewFetch(view
,&row
);
3613 if (rc
!= ERROR_SUCCESS
)
3616 MsiCloseHandle(view
);
3620 register_progid(hPackage
,row
,clsid
);
3622 MsiCloseHandle(row
);
3624 MsiCloseHandle(view
);
3628 static UINT
register_progid(MSIHANDLE hPackage
, MSIHANDLE row
, LPWSTR clsid
)
3630 UINT rc
= ERROR_SUCCESS
;
3632 if (MsiRecordIsNull(row
,2))
3633 rc
= register_progid_base(row
,clsid
);
3636 WCHAR buffer
[0x1000];
3639 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
3642 MsiRecordGetStringW(row
,2,buffer
,&sz
);
3643 rc
= register_parent_progid(hPackage
,buffer
,clsid
);
3646 MsiRecordGetStringW(row
,1,buffer
,&sz
);
3647 RegCreateKeyW(HKEY_CLASSES_ROOT
,buffer
,&hkey
);
3648 /* clasid is same as parent */
3649 RegCreateKeyW(hkey
,szCLSID
,&hkey2
);
3650 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)clsid
, (strlenW(clsid
)+1) *
3654 if (!MsiRecordIsNull(row
,4))
3657 MsiRecordGetStringW(row
,4,buffer
,&sz
);
3658 RegSetValueExW(hkey
,NULL
,0,REG_SZ
,(LPVOID
)buffer
,
3659 (strlenW(buffer
)+1) * sizeof(WCHAR
));
3662 if (!MsiRecordIsNull(row
,5))
3663 FIXME ("UNHANDLED icon in Progid\n");
3670 static UINT
ACTION_RegisterProgIdInfo(MSIHANDLE hPackage
)
3673 * Sigh, here i am just brute force registering all progid
3674 * this needs to be linked to the Classes that have been registerd
3675 * but the easiest way to do that is to load all these stuff into
3676 * memory for easy checking.
3678 * gives me something to continue to work toward
3683 static const CHAR
*Query
= "SELECT * FROM ProgId";
3684 MSIPACKAGE
* package
;
3686 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
3688 return ERROR_INVALID_HANDLE
;
3690 rc
= MsiDatabaseOpenViewA(package
->db
, Query
, &view
);
3692 if (rc
!= ERROR_SUCCESS
)
3695 rc
= MsiViewExecute(view
, 0);
3696 if (rc
!= ERROR_SUCCESS
)
3699 MsiCloseHandle(view
);
3705 WCHAR clsid
[0x1000];
3707 rc
= MsiViewFetch(view
,&row
);
3708 if (rc
!= ERROR_SUCCESS
)
3714 register_progid(hPackage
,row
,clsid
);
3716 MsiCloseHandle(row
);
3719 MsiCloseHandle(view
);
3723 /* Msi functions that seem approperate here */
3724 UINT WINAPI
MsiDoActionA( MSIHANDLE hInstall
, LPCSTR szAction
)
3729 TRACE(" exteral attempt at action %s\n",szAction
);
3732 return ERROR_FUNCTION_FAILED
;
3734 return ERROR_FUNCTION_FAILED
;
3736 len
= MultiByteToWideChar( CP_ACP
, 0, szAction
, -1, NULL
, 0);
3737 szwAction
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3740 return ERROR_FUNCTION_FAILED
;
3742 MultiByteToWideChar( CP_ACP
, 0, szAction
, -1, szwAction
, len
);
3744 rc
= MsiDoActionW(hInstall
, szwAction
);
3745 HeapFree(GetProcessHeap(),0,szwAction
);
3749 UINT WINAPI
MsiDoActionW( MSIHANDLE hInstall
, LPCWSTR szAction
)
3751 TRACE(" exteral attempt at action %s \n",debugstr_w(szAction
));
3752 return ACTION_PerformAction(hInstall
,szAction
);
3755 UINT WINAPI
MsiGetTargetPathA( MSIHANDLE hInstall
, LPCSTR szFolder
,
3756 LPSTR szPathBuf
, DWORD
* pcchPathBuf
)
3762 TRACE("getting folder %s %p %li\n",szFolder
,szPathBuf
, *pcchPathBuf
);
3765 return ERROR_FUNCTION_FAILED
;
3767 return ERROR_FUNCTION_FAILED
;
3769 len
= MultiByteToWideChar( CP_ACP
, 0, szFolder
, -1, NULL
, 0);
3770 szwFolder
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3773 return ERROR_FUNCTION_FAILED
;
3775 szwPathBuf
= HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf
* sizeof(WCHAR
));
3777 MultiByteToWideChar( CP_ACP
, 0, szFolder
, -1, szwFolder
, len
);
3779 rc
= MsiGetTargetPathW(hInstall
, szwFolder
, szwPathBuf
,pcchPathBuf
);
3781 WideCharToMultiByte( CP_ACP
, 0, szwPathBuf
, *pcchPathBuf
, szPathBuf
,
3782 *pcchPathBuf
, NULL
, NULL
);
3784 HeapFree(GetProcessHeap(),0,szwFolder
);
3785 HeapFree(GetProcessHeap(),0,szwPathBuf
);
3790 UINT WINAPI
MsiGetTargetPathW( MSIHANDLE hInstall
, LPCWSTR szFolder
, LPWSTR
3791 szPathBuf
, DWORD
* pcchPathBuf
)
3793 WCHAR path
[MAX_PATH
];
3796 TRACE("(%s %p %li)\n",debugstr_w(szFolder
),szPathBuf
,*pcchPathBuf
);
3798 rc
= resolve_folder(hInstall
, szFolder
, path
, FALSE
, FALSE
, NULL
);
3800 if (rc
== ERROR_SUCCESS
&& strlenW(path
) > *pcchPathBuf
)
3802 *pcchPathBuf
= strlenW(path
)+1;
3803 return ERROR_MORE_DATA
;
3805 else if (rc
== ERROR_SUCCESS
)
3807 *pcchPathBuf
= strlenW(path
)+1;
3808 strcpyW(szPathBuf
,path
);
3809 TRACE("Returning Path %s\n",debugstr_w(path
));
3816 UINT WINAPI
MsiGetSourcePathA( MSIHANDLE hInstall
, LPCSTR szFolder
,
3817 LPSTR szPathBuf
, DWORD
* pcchPathBuf
)
3823 TRACE("getting source %s %p %li\n",szFolder
,szPathBuf
, *pcchPathBuf
);
3826 return ERROR_FUNCTION_FAILED
;
3828 return ERROR_FUNCTION_FAILED
;
3830 len
= MultiByteToWideChar( CP_ACP
, 0, szFolder
, -1, NULL
, 0);
3831 szwFolder
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3834 return ERROR_FUNCTION_FAILED
;
3836 szwPathBuf
= HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf
* sizeof(WCHAR
));
3838 MultiByteToWideChar( CP_ACP
, 0, szFolder
, -1, szwFolder
, len
);
3840 rc
= MsiGetSourcePathW(hInstall
, szwFolder
, szwPathBuf
,pcchPathBuf
);
3842 WideCharToMultiByte( CP_ACP
, 0, szwPathBuf
, *pcchPathBuf
, szPathBuf
,
3843 *pcchPathBuf
, NULL
, NULL
);
3845 HeapFree(GetProcessHeap(),0,szwFolder
);
3846 HeapFree(GetProcessHeap(),0,szwPathBuf
);
3851 UINT WINAPI
MsiGetSourcePathW( MSIHANDLE hInstall
, LPCWSTR szFolder
, LPWSTR
3852 szPathBuf
, DWORD
* pcchPathBuf
)
3854 WCHAR path
[MAX_PATH
];
3857 TRACE("(%s %p %li)\n",debugstr_w(szFolder
),szPathBuf
,*pcchPathBuf
);
3858 rc
= resolve_folder(hInstall
, szFolder
, path
, TRUE
, FALSE
, NULL
);
3860 if (rc
== ERROR_SUCCESS
&& strlenW(path
) > *pcchPathBuf
)
3862 *pcchPathBuf
= strlenW(path
)+1;
3863 return ERROR_MORE_DATA
;
3865 else if (rc
== ERROR_SUCCESS
)
3867 *pcchPathBuf
= strlenW(path
)+1;
3868 strcpyW(szPathBuf
,path
);
3869 TRACE("Returning Path %s\n",debugstr_w(path
));
3876 UINT WINAPI
MsiSetTargetPathA(MSIHANDLE hInstall
, LPCSTR szFolder
,
3877 LPCSTR szFolderPath
)
3880 LPWSTR szwFolderPath
;
3884 return ERROR_FUNCTION_FAILED
;
3886 return ERROR_FUNCTION_FAILED
;
3888 len
= MultiByteToWideChar( CP_ACP
, 0, szFolder
, -1, NULL
, 0);
3889 szwFolder
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3892 return ERROR_FUNCTION_FAILED
;
3894 MultiByteToWideChar( CP_ACP
, 0, szFolder
, -1, szwFolder
, len
);
3896 len
= MultiByteToWideChar( CP_ACP
, 0, szFolderPath
, -1, NULL
, 0);
3897 szwFolderPath
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3901 HeapFree(GetProcessHeap(),0,szwFolder
);
3902 return ERROR_FUNCTION_FAILED
;
3905 MultiByteToWideChar( CP_ACP
, 0, szFolderPath
, -1, szwFolderPath
, len
);
3907 rc
= MsiSetTargetPathW(hInstall
, szwFolder
, szwFolderPath
);
3909 HeapFree(GetProcessHeap(),0,szwFolder
);
3910 HeapFree(GetProcessHeap(),0,szwFolderPath
);
3915 UINT WINAPI
MsiSetTargetPathW(MSIHANDLE hInstall
, LPCWSTR szFolder
,
3916 LPCWSTR szFolderPath
)
3918 MSIPACKAGE
*package
;
3920 WCHAR path
[MAX_PATH
];
3923 TRACE("(%s %s)\n",debugstr_w(szFolder
),debugstr_w(szFolderPath
));
3925 if (szFolderPath
[0]==0)
3926 return ERROR_FUNCTION_FAILED
;
3928 if (GetFileAttributesW(szFolderPath
) == INVALID_FILE_ATTRIBUTES
)
3929 return ERROR_FUNCTION_FAILED
;
3931 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
3934 return ERROR_INVALID_HANDLE
;
3936 resolve_folder(hInstall
,szFolder
,path
,FALSE
,FALSE
,&folder
);
3939 return ERROR_INVALID_PARAMETER
;
3941 strcpyW(folder
->Property
,szFolderPath
);
3943 for (i
= 0; i
< package
->loaded_folders
; i
++)
3944 package
->folders
[i
].ResolvedTarget
[0]=0;
3946 for (i
= 0; i
< package
->loaded_folders
; i
++)
3947 resolve_folder(hInstall
, package
->folders
[i
].Directory
, path
, FALSE
,
3950 return ERROR_SUCCESS
;
3953 BOOL WINAPI
MsiGetMode(MSIHANDLE hInstall
, DWORD iRunMode
)
3955 FIXME("STUB (%li)\n",iRunMode
);
3960 static UINT
ACTION_Template(MSIHANDLE hPackage
)
3965 static const CHAR
*ExecSeqQuery
;
3966 MSIPACKAGE
* package
;
3968 package
= msihandle2msiinfo(hPackage
, MSIHANDLETYPE_PACKAGE
);
3970 return ERROR_INVALID_HANDLE
;
3972 rc
= MsiDatabaseOpenViewA(package
->db
, ExecSeqQuery
, &view
);
3974 if (rc
!= ERROR_SUCCESS
)
3977 rc
= MsiViewExecute(view
, 0);
3978 if (rc
!= ERROR_SUCCESS
)
3981 MsiCloseHandle(view
);
3987 rc
= MsiViewFetch(view
,&row
);
3988 if (rc
!= ERROR_SUCCESS
)
3994 MsiCloseHandle(row
);
3997 MsiCloseHandle(view
);