2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 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
37 #include "wine/debug.h"
42 #include "wine/unicode.h"
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
49 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
54 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
);
55 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
);
56 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
);
59 * consts and values used
61 static const WCHAR c_colon
[] = {'C',':','\\',0};
63 static const WCHAR szCreateFolders
[] =
64 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 static const WCHAR szCostFinalize
[] =
66 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
67 const WCHAR szInstallFiles
[] =
68 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
69 const WCHAR szDuplicateFiles
[] =
70 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
71 static const WCHAR szWriteRegistryValues
[] =
72 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
73 'V','a','l','u','e','s',0};
74 static const WCHAR szCostInitialize
[] =
75 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 static const WCHAR szFileCost
[] =
77 {'F','i','l','e','C','o','s','t',0};
78 static const WCHAR szInstallInitialize
[] =
79 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 static const WCHAR szInstallValidate
[] =
81 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 static const WCHAR szLaunchConditions
[] =
83 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 static const WCHAR szProcessComponents
[] =
85 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 static const WCHAR szRegisterTypeLibraries
[] =
87 {'R','e','g','i','s','t','e','r','T','y','p','e',
88 'L','i','b','r','a','r','i','e','s',0};
89 const WCHAR szRegisterClassInfo
[] =
90 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
91 const WCHAR szRegisterProgIdInfo
[] =
92 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
93 static const WCHAR szCreateShortcuts
[] =
94 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 static const WCHAR szPublishProduct
[] =
96 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 static const WCHAR szWriteIniValues
[] =
98 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 static const WCHAR szSelfRegModules
[] =
100 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 static const WCHAR szPublishFeatures
[] =
102 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 static const WCHAR szRegisterProduct
[] =
104 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 static const WCHAR szInstallExecute
[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 static const WCHAR szInstallExecuteAgain
[] =
108 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
109 'A','g','a','i','n',0};
110 static const WCHAR szInstallFinalize
[] =
111 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 static const WCHAR szForceReboot
[] =
113 {'F','o','r','c','e','R','e','b','o','o','t',0};
114 static const WCHAR szResolveSource
[] =
115 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
116 const WCHAR szAppSearch
[] =
117 {'A','p','p','S','e','a','r','c','h',0};
118 static const WCHAR szAllocateRegistrySpace
[] =
119 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
120 'S','p','a','c','e',0};
121 static const WCHAR szBindImage
[] =
122 {'B','i','n','d','I','m','a','g','e',0};
123 static const WCHAR szCCPSearch
[] =
124 {'C','C','P','S','e','a','r','c','h',0};
125 static const WCHAR szDeleteServices
[] =
126 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szDisableRollback
[] =
128 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 static const WCHAR szExecuteAction
[] =
130 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
131 const WCHAR szFindRelatedProducts
[] =
132 {'F','i','n','d','R','e','l','a','t','e','d',
133 'P','r','o','d','u','c','t','s',0};
134 static const WCHAR szInstallAdminPackage
[] =
135 {'I','n','s','t','a','l','l','A','d','m','i','n',
136 'P','a','c','k','a','g','e',0};
137 static const WCHAR szInstallSFPCatalogFile
[] =
138 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
140 static const WCHAR szIsolateComponents
[] =
141 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
142 const WCHAR szMigrateFeatureStates
[] =
143 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
144 'S','t','a','t','e','s',0};
145 const WCHAR szMoveFiles
[] =
146 {'M','o','v','e','F','i','l','e','s',0};
147 static const WCHAR szMsiPublishAssemblies
[] =
148 {'M','s','i','P','u','b','l','i','s','h',
149 'A','s','s','e','m','b','l','i','e','s',0};
150 static const WCHAR szMsiUnpublishAssemblies
[] =
151 {'M','s','i','U','n','p','u','b','l','i','s','h',
152 'A','s','s','e','m','b','l','i','e','s',0};
153 static const WCHAR szInstallODBC
[] =
154 {'I','n','s','t','a','l','l','O','D','B','C',0};
155 static const WCHAR szInstallServices
[] =
156 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
157 const WCHAR szPatchFiles
[] =
158 {'P','a','t','c','h','F','i','l','e','s',0};
159 static const WCHAR szPublishComponents
[] =
160 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szRegisterComPlus
[] =
162 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 const WCHAR szRegisterExtensionInfo
[] =
164 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
166 static const WCHAR szRegisterFonts
[] =
167 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
168 const WCHAR szRegisterMIMEInfo
[] =
169 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
170 static const WCHAR szRegisterUser
[] =
171 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
172 const WCHAR szRemoveDuplicateFiles
[] =
173 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
174 'F','i','l','e','s',0};
175 static const WCHAR szRemoveEnvironmentStrings
[] =
176 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
177 'S','t','r','i','n','g','s',0};
178 const WCHAR szRemoveExistingProducts
[] =
179 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
180 'P','r','o','d','u','c','t','s',0};
181 const WCHAR szRemoveFiles
[] =
182 {'R','e','m','o','v','e','F','i','l','e','s',0};
183 static const WCHAR szRemoveFolders
[] =
184 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 static const WCHAR szRemoveIniValues
[] =
186 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 static const WCHAR szRemoveODBC
[] =
188 {'R','e','m','o','v','e','O','D','B','C',0};
189 static const WCHAR szRemoveRegistryValues
[] =
190 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
191 'V','a','l','u','e','s',0};
192 static const WCHAR szRemoveShortcuts
[] =
193 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 static const WCHAR szRMCCPSearch
[] =
195 {'R','M','C','C','P','S','e','a','r','c','h',0};
196 static const WCHAR szScheduleReboot
[] =
197 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 static const WCHAR szSelfUnregModules
[] =
199 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 static const WCHAR szSetODBCFolders
[] =
201 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 static const WCHAR szStartServices
[] =
203 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szStopServices
[] =
205 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 static const WCHAR szUnpublishComponents
[] =
207 {'U','n','p','u','b','l','i','s','h',
208 'C','o','m','p','o','n','e','n','t','s',0};
209 static const WCHAR szUnpublishFeatures
[] =
210 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
211 const WCHAR szUnregisterClassInfo
[] =
212 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
214 static const WCHAR szUnregisterComPlus
[] =
215 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
216 const WCHAR szUnregisterExtensionInfo
[] =
217 {'U','n','r','e','g','i','s','t','e','r',
218 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
219 static const WCHAR szUnregisterFonts
[] =
220 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
221 const WCHAR szUnregisterMIMEInfo
[] =
222 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
223 const WCHAR szUnregisterProgIdInfo
[] =
224 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
226 static const WCHAR szUnregisterTypeLibraries
[] =
227 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
228 'L','i','b','r','a','r','i','e','s',0};
229 static const WCHAR szValidateProductID
[] =
230 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 static const WCHAR szWriteEnvironmentStrings
[] =
232 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
233 'S','t','r','i','n','g','s',0};
235 /* action handlers */
236 typedef UINT (*STANDARDACTIONHANDLER
)(MSIPACKAGE
*);
240 STANDARDACTIONHANDLER handler
;
243 static struct _actions StandardActions
[];
246 /********************************************************
248 ********************************************************/
250 static void ce_actiontext(MSIPACKAGE
* package
, LPCWSTR action
)
252 static const WCHAR szActionText
[] =
253 {'A','c','t','i','o','n','T','e','x','t',0};
256 row
= MSI_CreateRecord(1);
257 MSI_RecordSetStringW(row
,1,action
);
258 ControlEvent_FireSubscribedEvent(package
,szActionText
, row
);
259 msiobj_release(&row
->hdr
);
262 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
264 static const WCHAR template_s
[]=
265 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
267 static const WCHAR format
[] =
268 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
269 static const WCHAR Query_t
[] =
270 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
271 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
272 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
273 ' ','\'','%','s','\'',0};
280 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
282 row
= MSI_QueryGetRecord( package
->db
, Query_t
, action
);
286 ActionText
= MSI_RecordGetString(row
,2);
287 deformat_string(package
, ActionText
, &deformated
);
289 sprintfW(message
,template_s
,timet
,action
,deformated
);
290 ce_actiontext(package
, deformated
);
291 msiobj_release(&row
->hdr
);
293 row
= MSI_CreateRecord(1);
294 MSI_RecordSetStringW(row
,1,message
);
296 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
297 msiobj_release(&row
->hdr
);
298 msi_free(deformated
);
301 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
305 static const WCHAR template_s
[]=
306 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
308 static const WCHAR template_e
[]=
309 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
310 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
312 static const WCHAR format
[] =
313 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
317 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
319 sprintfW(message
,template_s
,timet
,action
);
321 sprintfW(message
,template_e
,timet
,action
,rc
);
323 row
= MSI_CreateRecord(1);
324 MSI_RecordSetStringW(row
,1,message
);
326 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
327 msiobj_release(&row
->hdr
);
330 static int msi_get_property_int( MSIPACKAGE
*package
, LPCWSTR prop
, int def
)
332 LPWSTR str
= msi_dup_property( package
, prop
);
333 int val
= str
? atoiW( str
) : def
;
338 static UINT
msi_parse_command_line( MSIPACKAGE
*package
, LPCWSTR szCommandLine
)
343 LPWSTR prop
= NULL
, val
= NULL
;
346 return ERROR_SUCCESS
;
358 TRACE("Looking at %s\n",debugstr_w(ptr
));
360 ptr2
= strchrW(ptr
,'=');
363 ERR("command line contains unknown string : %s\n", debugstr_w(ptr
));
370 prop
= msi_alloc((len
+1)*sizeof(WCHAR
));
371 memcpy(prop
,ptr
,len
*sizeof(WCHAR
));
377 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
390 val
= msi_alloc((len
+1)*sizeof(WCHAR
));
391 memcpy(val
,ptr2
,len
*sizeof(WCHAR
));
394 if (lstrlenW(prop
) > 0)
396 TRACE("Found commandline property (%s) = (%s)\n",
397 debugstr_w(prop
), debugstr_w(val
));
398 MSI_SetPropertyW(package
,prop
,val
);
404 return ERROR_SUCCESS
;
408 static LPWSTR
* msi_split_string( LPCWSTR str
, WCHAR sep
)
410 LPWSTR p
, *ret
= NULL
;
416 /* count the number of substrings */
417 for ( p
= (LPWSTR
)str
, count
= 0; p
; count
++ )
419 p
= strchrW( p
, sep
);
424 /* allocate space for an array of substring pointers and the substrings */
425 ret
= msi_alloc( (count
+1) * sizeof (LPWSTR
) +
426 (lstrlenW(str
)+1) * sizeof(WCHAR
) );
430 /* copy the string and set the pointers */
431 p
= (LPWSTR
) &ret
[count
+1];
433 for( count
= 0; (ret
[count
] = p
); count
++ )
435 p
= strchrW( p
, sep
);
443 static UINT
msi_apply_substorage_transform( MSIPACKAGE
*package
,
444 MSIDATABASE
*patch_db
, LPCWSTR name
)
446 UINT ret
= ERROR_FUNCTION_FAILED
;
447 IStorage
*stg
= NULL
;
450 TRACE("%p %s\n", package
, debugstr_w(name
) );
454 ERR("expected a colon in %s\n", debugstr_w(name
));
455 return ERROR_FUNCTION_FAILED
;
458 r
= IStorage_OpenStorage( patch_db
->storage
, name
, NULL
, STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
461 ret
= msi_table_apply_transform( package
->db
, stg
);
462 IStorage_Release( stg
);
466 ERR("failed to open substorage %s\n", debugstr_w(name
));
471 static UINT
msi_check_patch_applicable( MSIPACKAGE
*package
, MSISUMMARYINFO
*si
)
473 static const WCHAR szProdID
[] = { 'P','r','o','d','u','c','t','I','D',0 };
474 LPWSTR guid_list
, *guids
, product_id
;
475 UINT i
, ret
= ERROR_FUNCTION_FAILED
;
477 product_id
= msi_dup_property( package
, szProdID
);
480 /* FIXME: the property ProductID should be written into the DB somewhere */
481 ERR("no product ID to check\n");
482 return ERROR_SUCCESS
;
485 guid_list
= msi_suminfo_dup_string( si
, PID_TEMPLATE
);
486 guids
= msi_split_string( guid_list
, ';' );
487 for ( i
= 0; guids
[i
] && ret
!= ERROR_SUCCESS
; i
++ )
489 if (!lstrcmpW( guids
[i
], product_id
))
493 msi_free( guid_list
);
494 msi_free( product_id
);
499 static UINT
msi_parse_patch_summary( MSIPACKAGE
*package
, MSIDATABASE
*patch_db
)
502 LPWSTR str
, *substorage
;
503 UINT i
, r
= ERROR_SUCCESS
;
505 si
= MSI_GetSummaryInformationW( patch_db
, 0 );
507 return ERROR_FUNCTION_FAILED
;
509 msi_check_patch_applicable( package
, si
);
511 /* enumerate the substorage */
512 str
= msi_suminfo_dup_string( si
, PID_LASTAUTHOR
);
513 substorage
= msi_split_string( str
, ';' );
514 for ( i
= 0; substorage
&& substorage
[i
] && r
== ERROR_SUCCESS
; i
++ )
515 r
= msi_apply_substorage_transform( package
, patch_db
, substorage
[i
] );
516 msi_free( substorage
);
519 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
521 msiobj_release( &si
->hdr
);
526 static UINT
msi_apply_patch_package( MSIPACKAGE
*package
, LPCWSTR file
)
528 MSIDATABASE
*patch_db
= NULL
;
531 TRACE("%p %s\n", package
, debugstr_w( file
) );
534 * We probably want to make sure we only open a patch collection here.
535 * Patch collections (.msp) and databases (.msi) have different GUIDs
536 * but currently MSI_OpenDatabaseW will accept both.
538 r
= MSI_OpenDatabaseW( file
, MSIDBOPEN_READONLY
, &patch_db
);
539 if ( r
!= ERROR_SUCCESS
)
541 ERR("failed to open patch collection %s\n", debugstr_w( file
) );
545 msi_parse_patch_summary( package
, patch_db
);
546 msiobj_release( &patch_db
->hdr
);
548 return ERROR_SUCCESS
;
551 /* get the PATCH property, and apply all the patches it specifies */
552 static UINT
msi_apply_patches( MSIPACKAGE
*package
)
554 static const WCHAR szPatch
[] = { 'P','A','T','C','H',0 };
555 LPWSTR patch_list
, *patches
;
556 UINT i
, r
= ERROR_SUCCESS
;
558 patch_list
= msi_dup_property( package
, szPatch
);
560 TRACE("patches to be applied: %s\n", debugstr_w( patch_list
) );
562 patches
= msi_split_string( patch_list
, ';' );
563 for( i
=0; patches
&& patches
[i
] && r
== ERROR_SUCCESS
; i
++ )
564 r
= msi_apply_patch_package( package
, patches
[i
] );
567 msi_free( patch_list
);
572 static UINT
msi_apply_transforms( MSIPACKAGE
*package
)
574 static const WCHAR szTransforms
[] = {
575 'T','R','A','N','S','F','O','R','M','S',0 };
576 LPWSTR xform_list
, *xforms
;
577 UINT i
, r
= ERROR_SUCCESS
;
579 xform_list
= msi_dup_property( package
, szTransforms
);
580 xforms
= msi_split_string( xform_list
, ';' );
582 for( i
=0; xforms
&& xforms
[i
] && r
== ERROR_SUCCESS
; i
++ )
584 if (xforms
[i
][0] == ':')
585 r
= msi_apply_substorage_transform( package
, package
->db
, &xforms
[i
][1] );
587 r
= MSI_DatabaseApplyTransformW( package
->db
, xforms
[i
], 0 );
591 msi_free( xform_list
);
596 /****************************************************
597 * TOP level entry points
598 *****************************************************/
600 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
601 LPCWSTR szCommandLine
)
605 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
606 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
607 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
609 MSI_SetPropertyW(package
, szAction
, szInstall
);
611 package
->script
= msi_alloc(sizeof(MSISCRIPT
));
612 memset(package
->script
,0,sizeof(MSISCRIPT
));
614 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
618 LPWSTR p
, check
, path
;
620 package
->PackagePath
= strdupW(szPackagePath
);
621 path
= strdupW(szPackagePath
);
622 p
= strrchrW(path
,'\\');
631 path
= msi_alloc(MAX_PATH
*sizeof(WCHAR
));
632 GetCurrentDirectoryW(MAX_PATH
,path
);
636 check
= msi_dup_property( package
, cszSourceDir
);
638 MSI_SetPropertyW(package
, cszSourceDir
, path
);
643 msi_parse_command_line( package
, szCommandLine
);
645 msi_apply_transforms( package
);
646 msi_apply_patches( package
);
648 if ( msi_get_property_int(package
, szUILevel
, 0) >= INSTALLUILEVEL_REDUCED
)
650 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
651 rc
= ACTION_ProcessUISequence(package
);
653 if (rc
== ERROR_SUCCESS
)
655 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
656 rc
= ACTION_ProcessExecSequence(package
,TRUE
);
660 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
664 /* install was halted but should be considered a success */
668 package
->script
->CurrentlyScripting
= FALSE
;
670 /* process the ending type action */
671 if (rc
== ERROR_SUCCESS
)
672 ACTION_PerformActionSequence(package
,-1,ui
);
673 else if (rc
== ERROR_INSTALL_USEREXIT
)
674 ACTION_PerformActionSequence(package
,-2,ui
);
675 else if (rc
== ERROR_INSTALL_SUSPEND
)
676 ACTION_PerformActionSequence(package
,-4,ui
);
678 ACTION_PerformActionSequence(package
,-3,ui
);
680 /* finish up running custom actions */
681 ACTION_FinishCustomActions(package
);
686 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
)
688 UINT rc
= ERROR_SUCCESS
;
690 static const WCHAR ExecSeqQuery
[] =
691 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
692 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
693 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
694 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
696 static const WCHAR UISeqQuery
[] =
697 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
698 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
699 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
700 ' ', '=',' ','%','i',0};
703 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
705 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
709 LPCWSTR action
, cond
;
711 TRACE("Running the actions\n");
713 /* check conditions */
714 cond
= MSI_RecordGetString(row
,2);
717 /* this is a hack to skip errors in the condition code */
718 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
722 action
= MSI_RecordGetString(row
,1);
725 ERR("failed to fetch action\n");
726 rc
= ERROR_FUNCTION_FAILED
;
731 rc
= ACTION_PerformUIAction(package
,action
);
733 rc
= ACTION_PerformAction(package
,action
,FALSE
);
735 msiobj_release(&row
->hdr
);
746 } iterate_action_param
;
748 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
750 iterate_action_param
*iap
= (iterate_action_param
*)param
;
752 LPCWSTR cond
, action
;
754 action
= MSI_RecordGetString(row
,1);
757 ERR("Error is retrieving action name\n");
758 return ERROR_FUNCTION_FAILED
;
761 /* check conditions */
762 cond
= MSI_RecordGetString(row
,2);
765 /* this is a hack to skip errors in the condition code */
766 if (MSI_EvaluateConditionW(iap
->package
, cond
) == MSICONDITION_FALSE
)
768 TRACE("Skipping action: %s (condition is false)\n",
770 return ERROR_SUCCESS
;
775 rc
= ACTION_PerformUIAction(iap
->package
,action
);
777 rc
= ACTION_PerformAction(iap
->package
,action
,FALSE
);
779 msi_dialog_check_messages( NULL
);
781 if (iap
->package
->CurrentInstallState
!= ERROR_SUCCESS
)
782 rc
= iap
->package
->CurrentInstallState
;
784 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
787 if (rc
!= ERROR_SUCCESS
)
788 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
793 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
797 static const WCHAR query
[] =
798 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
800 ' ','W','H','E','R','E',' ',
801 '`','S','e','q','u','e','n','c','e','`',' ',
802 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
803 '`','S','e','q','u','e','n','c','e','`',0};
804 iterate_action_param iap
;
807 * FIXME: probably should be checking UILevel in the
808 * ACTION_PerformUIAction/ACTION_PerformAction
809 * rather than saving the UI level here. Those
810 * two functions can be merged too.
812 iap
.package
= package
;
815 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
817 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
818 if (r
== ERROR_SUCCESS
)
820 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, &iap
);
821 msiobj_release(&view
->hdr
);
827 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
831 static const WCHAR ExecSeqQuery
[] =
832 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
833 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
834 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
835 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
836 'O','R','D','E','R',' ', 'B','Y',' ',
837 '`','S','e','q','u','e','n','c','e','`',0 };
839 static const WCHAR IVQuery
[] =
840 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
841 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
842 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
843 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
844 ' ','\'', 'I','n','s','t','a','l','l',
845 'V','a','l','i','d','a','t','e','\'', 0};
847 iterate_action_param iap
;
849 iap
.package
= package
;
852 if (package
->script
->ExecuteSequenceRun
)
854 TRACE("Execute Sequence already Run\n");
855 return ERROR_SUCCESS
;
858 package
->script
->ExecuteSequenceRun
= TRUE
;
860 /* get the sequence number */
863 row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
865 return ERROR_FUNCTION_FAILED
;
866 seq
= MSI_RecordGetInteger(row
,1);
867 msiobj_release(&row
->hdr
);
870 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
871 if (rc
== ERROR_SUCCESS
)
873 TRACE("Running the actions\n");
875 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
876 msiobj_release(&view
->hdr
);
882 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
886 static const WCHAR ExecSeqQuery
[] =
887 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
888 '`','I','n','s','t','a','l','l',
889 'U','I','S','e','q','u','e','n','c','e','`',
890 ' ','W','H','E','R','E',' ',
891 '`','S','e','q','u','e','n','c','e','`',' ',
892 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
893 '`','S','e','q','u','e','n','c','e','`',0};
894 iterate_action_param iap
;
896 iap
.package
= package
;
899 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
901 if (rc
== ERROR_SUCCESS
)
903 TRACE("Running the actions\n");
905 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
906 msiobj_release(&view
->hdr
);
912 /********************************************************
913 * ACTION helper functions and functions that perform the actions
914 *******************************************************/
915 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
916 UINT
* rc
, BOOL force
)
924 ERR("package was null!\n");
928 if (!run
&& !package
->script
->CurrentlyScripting
)
933 if (strcmpW(action
,szInstallFinalize
) == 0 ||
934 strcmpW(action
,szInstallExecute
) == 0 ||
935 strcmpW(action
,szInstallExecuteAgain
) == 0)
940 while (StandardActions
[i
].action
!= NULL
)
942 if (strcmpW(StandardActions
[i
].action
, action
)==0)
946 ui_actioninfo(package
, action
, TRUE
, 0);
947 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
948 ui_actioninfo(package
, action
, FALSE
, *rc
);
952 ui_actionstart(package
, action
);
953 if (StandardActions
[i
].handler
)
955 *rc
= StandardActions
[i
].handler(package
);
959 FIXME("unhandled standard action %s\n",debugstr_w(action
));
971 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
972 UINT
* rc
, BOOL force
)
977 arc
= ACTION_CustomAction(package
,action
, force
);
979 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
988 * A lot of actions are really important even if they don't do anything
989 * explicit... Lots of properties are set at the beginning of the installation
990 * CostFinalize does a bunch of work to translate the directories and such
992 * But until I get write access to the database that is hard, so I am going to
993 * hack it to see if I can get something to run.
995 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, BOOL force
)
997 UINT rc
= ERROR_SUCCESS
;
1000 TRACE("Performing action (%s)\n",debugstr_w(action
));
1002 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
1005 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, force
);
1009 FIXME("unhandled msi action %s\n",debugstr_w(action
));
1010 rc
= ERROR_FUNCTION_NOT_CALLED
;
1016 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
)
1018 UINT rc
= ERROR_SUCCESS
;
1019 BOOL handled
= FALSE
;
1021 TRACE("Performing action (%s)\n",debugstr_w(action
));
1023 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
1026 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, FALSE
);
1028 if( !handled
&& ACTION_DialogBox(package
,action
) == ERROR_SUCCESS
)
1033 FIXME("unhandled msi action %s\n",debugstr_w(action
));
1034 rc
= ERROR_FUNCTION_NOT_CALLED
;
1042 * Actual Action Handlers
1045 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
1047 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1053 dir
= MSI_RecordGetString(row
,1);
1056 ERR("Unable to get folder id\n");
1057 return ERROR_SUCCESS
;
1060 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,&folder
);
1063 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
1064 return ERROR_SUCCESS
;
1067 TRACE("Folder is %s\n",debugstr_w(full_path
));
1070 uirow
= MSI_CreateRecord(1);
1071 MSI_RecordSetStringW(uirow
,1,full_path
);
1072 ui_actiondata(package
,szCreateFolders
,uirow
);
1073 msiobj_release( &uirow
->hdr
);
1075 if (folder
->State
== 0)
1076 create_full_pathW(full_path
);
1080 msi_free(full_path
);
1081 return ERROR_SUCCESS
;
1084 /* FIXME: probably should merge this with the above function */
1085 static UINT
msi_create_directory( MSIPACKAGE
* package
, LPCWSTR dir
)
1087 UINT rc
= ERROR_SUCCESS
;
1089 LPWSTR install_path
;
1091 install_path
= resolve_folder(package
, dir
, FALSE
, FALSE
, &folder
);
1093 return ERROR_FUNCTION_FAILED
;
1095 /* create the path */
1096 if (folder
->State
== 0)
1098 create_full_pathW(install_path
);
1101 msi_free(install_path
);
1106 UINT
msi_create_component_directories( MSIPACKAGE
*package
)
1110 /* create all the folders required by the components are going to install */
1111 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1113 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
1115 msi_create_directory( package
, comp
->Directory
);
1118 return ERROR_SUCCESS
;
1122 * Also we cannot enable/disable components either, so for now I am just going
1123 * to do all the directories for all the components.
1125 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1127 static const WCHAR ExecSeqQuery
[] =
1128 {'S','E','L','E','C','T',' ',
1129 '`','D','i','r','e','c','t','o','r','y','_','`',
1130 ' ','F','R','O','M',' ',
1131 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1135 /* create all the empty folders specified in the CreateFolder table */
1136 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1137 if (rc
!= ERROR_SUCCESS
)
1138 return ERROR_SUCCESS
;
1140 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
1141 msiobj_release(&view
->hdr
);
1143 msi_create_component_directories( package
);
1148 static MSICOMPONENT
* load_component( MSIRECORD
* row
)
1152 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1156 /* fill in the data */
1157 comp
->Component
= msi_dup_record_field( row
, 1 );
1159 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1161 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1162 comp
->Directory
= msi_dup_record_field( row
, 3 );
1163 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1164 comp
->Condition
= msi_dup_record_field( row
, 5 );
1165 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1167 comp
->Installed
= INSTALLSTATE_ABSENT
;
1168 comp
->Action
= INSTALLSTATE_UNKNOWN
;
1169 comp
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
1171 comp
->Enabled
= TRUE
;
1177 MSIPACKAGE
*package
;
1178 MSIFEATURE
*feature
;
1181 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1185 cl
= msi_alloc( sizeof (*cl
) );
1187 return ERROR_NOT_ENOUGH_MEMORY
;
1188 cl
->component
= comp
;
1189 list_add_tail( &feature
->Components
, &cl
->entry
);
1191 return ERROR_SUCCESS
;
1194 static UINT
iterate_component_check( MSIRECORD
*row
, LPVOID param
)
1196 _ilfs
* ilfs
= (_ilfs
*)param
;
1197 MSIPACKAGE
*package
= ilfs
->package
;
1198 MSIFEATURE
*feature
= ilfs
->feature
;
1201 comp
= load_component( row
);
1203 return ERROR_FUNCTION_FAILED
;
1205 list_add_tail( &package
->components
, &comp
->entry
);
1206 add_feature_component( feature
, comp
);
1208 TRACE("Loaded new component %p\n", comp
);
1210 return ERROR_SUCCESS
;
1213 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1215 _ilfs
* ilfs
= (_ilfs
*)param
;
1220 static const WCHAR Query
[] =
1221 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1222 '`','C','o','m','p','o','n','e','n','t','`',' ',
1223 'W','H','E','R','E',' ',
1224 '`','C','o','m','p','o','n','e','n','t','`',' ',
1225 '=','\'','%','s','\'',0};
1227 component
= MSI_RecordGetString(row
,1);
1229 /* check to see if the component is already loaded */
1230 comp
= get_loaded_component( ilfs
->package
, component
);
1233 TRACE("Component %s already loaded\n", debugstr_w(component
) );
1234 add_feature_component( ilfs
->feature
, comp
);
1235 return ERROR_SUCCESS
;
1238 rc
= MSI_OpenQuery(ilfs
->package
->db
, &view
, Query
, component
);
1239 if (rc
!= ERROR_SUCCESS
)
1240 return ERROR_SUCCESS
;
1242 rc
= MSI_IterateRecords(view
, NULL
, iterate_component_check
, ilfs
);
1243 msiobj_release( &view
->hdr
);
1245 return ERROR_SUCCESS
;
1248 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1250 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1251 MSIFEATURE
* feature
;
1252 static const WCHAR Query1
[] =
1253 {'S','E','L','E','C','T',' ',
1254 '`','C','o','m','p','o','n','e','n','t','_','`',
1255 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1256 'C','o','m','p','o','n','e','n','t','s','`',' ',
1257 'W','H','E','R','E',' ',
1258 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1263 /* fill in the data */
1265 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1267 return ERROR_NOT_ENOUGH_MEMORY
;
1269 list_init( &feature
->Components
);
1271 feature
->Feature
= msi_dup_record_field( row
, 1 );
1273 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1275 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1276 feature
->Title
= msi_dup_record_field( row
, 3 );
1277 feature
->Description
= msi_dup_record_field( row
, 4 );
1279 if (!MSI_RecordIsNull(row
,5))
1280 feature
->Display
= MSI_RecordGetInteger(row
,5);
1282 feature
->Level
= MSI_RecordGetInteger(row
,6);
1283 feature
->Directory
= msi_dup_record_field( row
, 7 );
1284 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1286 feature
->Installed
= INSTALLSTATE_ABSENT
;
1287 feature
->Action
= INSTALLSTATE_UNKNOWN
;
1288 feature
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
1290 list_add_tail( &package
->features
, &feature
->entry
);
1292 /* load feature components */
1294 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1295 if (rc
!= ERROR_SUCCESS
)
1296 return ERROR_SUCCESS
;
1298 ilfs
.package
= package
;
1299 ilfs
.feature
= feature
;
1301 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1302 msiobj_release(&view
->hdr
);
1304 return ERROR_SUCCESS
;
1307 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1309 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1313 /* fill in the data */
1315 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1317 return ERROR_NOT_ENOUGH_MEMORY
;
1319 file
->File
= msi_dup_record_field( row
, 1 );
1321 component
= MSI_RecordGetString( row
, 2 );
1322 file
->Component
= get_loaded_component( package
, component
);
1324 if (!file
->Component
)
1325 ERR("Unfound Component %s\n",debugstr_w(component
));
1327 file
->FileName
= msi_dup_record_field( row
, 3 );
1328 reduce_to_longfilename( file
->FileName
);
1330 file
->ShortName
= msi_dup_record_field( row
, 3 );
1331 reduce_to_shortfilename( file
->ShortName
);
1333 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1334 file
->Version
= msi_dup_record_field( row
, 5 );
1335 file
->Language
= msi_dup_record_field( row
, 6 );
1336 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1337 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1339 file
->state
= msifs_invalid
;
1341 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1343 list_add_tail( &package
->files
, &file
->entry
);
1345 return ERROR_SUCCESS
;
1348 static UINT
load_all_files(MSIPACKAGE
*package
)
1352 static const WCHAR Query
[] =
1353 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1354 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1355 '`','S','e','q','u','e','n','c','e','`', 0};
1358 return ERROR_INVALID_HANDLE
;
1360 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1361 if (rc
!= ERROR_SUCCESS
)
1362 return ERROR_SUCCESS
;
1364 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1365 msiobj_release(&view
->hdr
);
1367 return ERROR_SUCCESS
;
1372 * I am not doing any of the costing functionality yet.
1373 * Mostly looking at doing the Component and Feature loading
1375 * The native MSI does A LOT of modification to tables here. Mostly adding
1376 * a lot of temporary columns to the Feature and Component tables.
1378 * note: Native msi also tracks the short filename. But I am only going to
1379 * track the long ones. Also looking at this directory table
1380 * it appears that the directory table does not get the parents
1381 * resolved base on property only based on their entries in the
1384 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1388 static const WCHAR Query_all
[] =
1389 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1390 '`','F','e','a','t','u','r','e','`',0};
1391 static const WCHAR szCosting
[] =
1392 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1393 static const WCHAR szZero
[] = { '0', 0 };
1395 if ( 1 == msi_get_property_int( package
, szCosting
, 0 ) )
1396 return ERROR_SUCCESS
;
1398 MSI_SetPropertyW(package
, szCosting
, szZero
);
1399 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1401 rc
= MSI_DatabaseOpenViewW(package
->db
,Query_all
,&view
);
1402 if (rc
!= ERROR_SUCCESS
)
1405 rc
= MSI_IterateRecords(view
, NULL
, load_feature
, package
);
1406 msiobj_release(&view
->hdr
);
1408 load_all_files(package
);
1410 return ERROR_SUCCESS
;
1413 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1416 UINT rc
= ERROR_SUCCESS
;
1418 TRACE("Executing Script %i\n",script
);
1420 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1423 action
= package
->script
->Actions
[script
][i
];
1424 ui_actionstart(package
, action
);
1425 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1426 rc
= ACTION_PerformAction(package
, action
, TRUE
);
1427 msi_free(package
->script
->Actions
[script
][i
]);
1428 if (rc
!= ERROR_SUCCESS
)
1431 msi_free(package
->script
->Actions
[script
]);
1433 package
->script
->ActionCount
[script
] = 0;
1434 package
->script
->Actions
[script
] = NULL
;
1438 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1440 return ERROR_SUCCESS
;
1444 static MSIFOLDER
*load_folder( MSIPACKAGE
*package
, LPCWSTR dir
)
1446 static const WCHAR Query
[] =
1447 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1448 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1449 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1450 ' ','=',' ','\'','%','s','\'',
1452 LPWSTR ptargetdir
, targetdir
, srcdir
;
1454 LPWSTR shortname
= NULL
;
1455 MSIRECORD
* row
= 0;
1458 TRACE("Looking for dir %s\n",debugstr_w(dir
));
1460 folder
= get_loaded_folder( package
, dir
);
1464 TRACE("Working to load %s\n",debugstr_w(dir
));
1466 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1470 folder
->Directory
= strdupW(dir
);
1472 row
= MSI_QueryGetRecord(package
->db
, Query
, dir
);
1476 ptargetdir
= targetdir
= msi_dup_record_field(row
,3);
1478 /* split src and target dir */
1479 if (strchrW(targetdir
,':'))
1481 srcdir
=strchrW(targetdir
,':');
1488 /* for now only pick long filename versions */
1489 if (strchrW(targetdir
,'|'))
1491 shortname
= targetdir
;
1492 targetdir
= strchrW(targetdir
,'|');
1496 /* for the sourcedir pick the short filename */
1497 if (srcdir
&& strchrW(srcdir
,'|'))
1499 LPWSTR p
= strchrW(srcdir
,'|');
1503 /* now check for root dirs */
1504 if (targetdir
[0] == '.' && targetdir
[1] == 0)
1509 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir
));
1510 msi_free( folder
->TargetDefault
);
1511 folder
->TargetDefault
= strdupW(targetdir
);
1515 folder
->SourceDefault
= strdupW(srcdir
);
1517 folder
->SourceDefault
= strdupW(shortname
);
1519 folder
->SourceDefault
= strdupW(targetdir
);
1520 msi_free(ptargetdir
);
1521 TRACE(" SourceDefault = %s\n", debugstr_w( folder
->SourceDefault
));
1523 parent
= MSI_RecordGetString(row
,2);
1526 folder
->Parent
= load_folder( package
, parent
);
1527 if ( folder
->Parent
)
1528 TRACE("loaded parent %p %s\n", folder
->Parent
,
1529 debugstr_w(folder
->Parent
->Directory
));
1531 ERR("failed to load parent folder %s\n", debugstr_w(parent
));
1534 folder
->Property
= msi_dup_property( package
, dir
);
1536 msiobj_release(&row
->hdr
);
1538 list_add_tail( &package
->folders
, &folder
->entry
);
1540 TRACE("%s returning %p\n",debugstr_w(dir
),folder
);
1545 /* scan for and update current install states */
1546 static void ACTION_UpdateInstallStates(MSIPACKAGE
*package
)
1549 MSIFEATURE
*feature
;
1551 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1554 res
= MsiGetComponentPathW( package
->ProductCode
,
1555 comp
->ComponentId
, NULL
, NULL
);
1557 res
= INSTALLSTATE_ABSENT
;
1558 comp
->Installed
= res
;
1561 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1564 INSTALLSTATE res
= -10;
1566 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1568 comp
= cl
->component
;
1571 res
= comp
->Installed
;
1574 if (res
== comp
->Installed
)
1577 if (res
!= comp
->Installed
)
1578 res
= INSTALLSTATE_INCOMPLETE
;
1581 feature
->Installed
= res
;
1585 static BOOL
process_state_property (MSIPACKAGE
* package
, LPCWSTR property
,
1588 static const WCHAR all
[]={'A','L','L',0};
1590 MSIFEATURE
*feature
;
1592 override
= msi_dup_property( package
, property
);
1596 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1598 if (strcmpiW(override
,all
)==0)
1600 feature
->ActionRequest
= state
;
1601 feature
->Action
= state
;
1605 LPWSTR ptr
= override
;
1606 LPWSTR ptr2
= strchrW(override
,',');
1610 if ((ptr2
&& strncmpW(ptr
,feature
->Feature
, ptr2
-ptr
)==0)
1611 || (!ptr2
&& strcmpW(ptr
,feature
->Feature
)==0))
1613 feature
->ActionRequest
= state
;
1614 feature
->Action
= state
;
1620 ptr2
= strchrW(ptr
,',');
1632 static UINT
SetFeatureStates(MSIPACKAGE
*package
)
1635 static const WCHAR szlevel
[] =
1636 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1637 static const WCHAR szAddLocal
[] =
1638 {'A','D','D','L','O','C','A','L',0};
1639 static const WCHAR szRemove
[] =
1640 {'R','E','M','O','V','E',0};
1641 static const WCHAR szReinstall
[] =
1642 {'R','E','I','N','S','T','A','L','L',0};
1643 BOOL override
= FALSE
;
1644 MSICOMPONENT
* component
;
1645 MSIFEATURE
*feature
;
1648 /* I do not know if this is where it should happen.. but */
1650 TRACE("Checking Install Level\n");
1652 install_level
= msi_get_property_int( package
, szlevel
, 1 );
1654 /* ok hereis the _real_ rub
1655 * all these activation/deactivation things happen in order and things
1656 * later on the list override things earlier on the list.
1657 * 1) INSTALLLEVEL processing
1667 * 11) FILEADDDEFAULT
1668 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1669 * ignored for all the features. seems strange, especially since it is not
1670 * documented anywhere, but it is how it works.
1672 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1673 * REMOVE are the big ones, since we don't handle administrative installs
1676 override
|= process_state_property(package
,szAddLocal
,INSTALLSTATE_LOCAL
);
1677 override
|= process_state_property(package
,szRemove
,INSTALLSTATE_ABSENT
);
1678 override
|= process_state_property(package
,szReinstall
,INSTALLSTATE_LOCAL
);
1682 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1684 BOOL feature_state
= ((feature
->Level
> 0) &&
1685 (feature
->Level
<= install_level
));
1687 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1689 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1691 feature
->ActionRequest
= INSTALLSTATE_SOURCE
;
1692 feature
->Action
= INSTALLSTATE_SOURCE
;
1694 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1696 feature
->ActionRequest
= INSTALLSTATE_ADVERTISED
;
1697 feature
->Action
= INSTALLSTATE_ADVERTISED
;
1701 feature
->ActionRequest
= INSTALLSTATE_LOCAL
;
1702 feature
->Action
= INSTALLSTATE_LOCAL
;
1709 /* set the Preselected Property */
1710 static const WCHAR szPreselected
[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1711 static const WCHAR szOne
[] = { '1', 0 };
1713 MSI_SetPropertyW(package
,szPreselected
,szOne
);
1717 * now we want to enable or disable components base on feature
1720 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1724 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1725 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
1726 feature
->ActionRequest
);
1728 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1730 component
= cl
->component
;
1732 if (!component
->Enabled
)
1734 component
->Action
= INSTALLSTATE_UNKNOWN
;
1735 component
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
1739 if (feature
->Action
== INSTALLSTATE_LOCAL
)
1741 component
->Action
= INSTALLSTATE_LOCAL
;
1742 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
1744 else if (feature
->ActionRequest
== INSTALLSTATE_SOURCE
)
1746 if ((component
->Action
== INSTALLSTATE_UNKNOWN
) ||
1747 (component
->Action
== INSTALLSTATE_ABSENT
) ||
1748 (component
->Action
== INSTALLSTATE_ADVERTISED
))
1751 component
->Action
= INSTALLSTATE_SOURCE
;
1752 component
->ActionRequest
= INSTALLSTATE_SOURCE
;
1755 else if (feature
->ActionRequest
== INSTALLSTATE_ADVERTISED
)
1757 if ((component
->Action
== INSTALLSTATE_UNKNOWN
) ||
1758 (component
->Action
== INSTALLSTATE_ABSENT
))
1761 component
->Action
= INSTALLSTATE_ADVERTISED
;
1762 component
->ActionRequest
= INSTALLSTATE_ADVERTISED
;
1765 else if (feature
->ActionRequest
== INSTALLSTATE_ABSENT
)
1767 if (component
->Action
== INSTALLSTATE_UNKNOWN
)
1769 component
->Action
= INSTALLSTATE_ABSENT
;
1770 component
->ActionRequest
= INSTALLSTATE_ABSENT
;
1777 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1779 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1780 debugstr_w(component
->Component
), component
->Installed
,
1781 component
->Action
, component
->ActionRequest
);
1785 return ERROR_SUCCESS
;
1788 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1790 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1794 name
= MSI_RecordGetString(row
,1);
1796 /* This helper function now does ALL the work */
1797 TRACE("Dir %s ...\n",debugstr_w(name
));
1798 load_folder(package
,name
);
1799 path
= resolve_folder(package
,name
,FALSE
,TRUE
,NULL
);
1800 TRACE("resolves to %s\n",debugstr_w(path
));
1803 return ERROR_SUCCESS
;
1806 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
1808 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1810 MSIFEATURE
*feature
;
1812 name
= MSI_RecordGetString( row
, 1 );
1814 feature
= get_loaded_feature( package
, name
);
1816 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
1820 Condition
= MSI_RecordGetString(row
,3);
1822 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
1824 int level
= MSI_RecordGetInteger(row
,2);
1825 TRACE("Reseting feature %s to level %i\n", debugstr_w(name
), level
);
1826 feature
->Level
= level
;
1829 return ERROR_SUCCESS
;
1834 * A lot is done in this function aside from just the costing.
1835 * The costing needs to be implemented at some point but for now I am going
1836 * to focus on the directory building
1839 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
1841 static const WCHAR ExecSeqQuery
[] =
1842 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1843 '`','D','i','r','e','c','t','o','r','y','`',0};
1844 static const WCHAR ConditionQuery
[] =
1845 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1846 '`','C','o','n','d','i','t','i','o','n','`',0};
1847 static const WCHAR szCosting
[] =
1848 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1849 static const WCHAR szlevel
[] =
1850 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1851 static const WCHAR szOne
[] = { '1', 0 };
1858 if ( 1 == msi_get_property_int( package
, szCosting
, 0 ) )
1859 return ERROR_SUCCESS
;
1861 TRACE("Building Directory properties\n");
1863 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1864 if (rc
== ERROR_SUCCESS
)
1866 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
1868 msiobj_release(&view
->hdr
);
1871 TRACE("File calculations\n");
1873 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
1875 MSICOMPONENT
* comp
= file
->Component
;
1881 /* calculate target */
1882 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, NULL
);
1884 msi_free(file
->TargetPath
);
1886 TRACE("file %s is named %s\n",
1887 debugstr_w(file
->File
),debugstr_w(file
->FileName
));
1889 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
1893 TRACE("file %s resolves to %s\n",
1894 debugstr_w(file
->File
),debugstr_w(file
->TargetPath
));
1896 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
1898 file
->state
= msifs_missing
;
1899 comp
->Cost
+= file
->FileSize
;
1909 static WCHAR name
[] = {'\\',0};
1910 static const WCHAR name_fmt
[] =
1911 {'%','u','.','%','u','.','%','u','.','%','u',0};
1912 WCHAR filever
[0x100];
1913 VS_FIXEDFILEINFO
*lpVer
;
1915 TRACE("Version comparison..\n");
1916 versize
= GetFileVersionInfoSizeW(file
->TargetPath
,&handle
);
1917 version
= msi_alloc(versize
);
1918 GetFileVersionInfoW(file
->TargetPath
, 0, versize
, version
);
1920 VerQueryValueW(version
, (LPWSTR
)name
, (LPVOID
*)&lpVer
, &sz
);
1922 sprintfW(filever
,name_fmt
,
1923 HIWORD(lpVer
->dwFileVersionMS
),
1924 LOWORD(lpVer
->dwFileVersionMS
),
1925 HIWORD(lpVer
->dwFileVersionLS
),
1926 LOWORD(lpVer
->dwFileVersionLS
));
1928 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
1929 debugstr_w(filever
));
1930 if (strcmpiW(filever
,file
->Version
)<0)
1932 file
->state
= msifs_overwrite
;
1933 /* FIXME: cost should be diff in size */
1934 comp
->Cost
+= file
->FileSize
;
1937 file
->state
= msifs_present
;
1941 file
->state
= msifs_present
;
1944 TRACE("Evaluating Condition Table\n");
1946 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
1947 if (rc
== ERROR_SUCCESS
)
1949 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeConditions
,
1951 msiobj_release(&view
->hdr
);
1954 TRACE("Enabling or Disabling Components\n");
1955 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1957 if (comp
->Condition
)
1959 if (MSI_EvaluateConditionW(package
,
1960 comp
->Condition
) == MSICONDITION_FALSE
)
1962 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
1963 comp
->Enabled
= FALSE
;
1968 MSI_SetPropertyW(package
,szCosting
,szOne
);
1969 /* set default run level if not set */
1970 level
= msi_dup_property( package
, szlevel
);
1972 MSI_SetPropertyW(package
,szlevel
, szOne
);
1975 ACTION_UpdateInstallStates(package
);
1977 return SetFeatureStates(package
);
1980 /* OK this value is "interpreted" and then formatted based on the
1981 first few characters */
1982 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
1986 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
1992 LPWSTR deformated
= NULL
;
1995 deformat_string(package
, &value
[2], &deformated
);
1997 /* binary value type */
2001 *size
= (strlenW(ptr
)/2)+1;
2003 *size
= strlenW(ptr
)/2;
2005 data
= msi_alloc(*size
);
2011 /* if uneven pad with a zero in front */
2017 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2019 TRACE("Uneven byte count\n");
2027 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2030 msi_free(deformated
);
2032 TRACE("Data %li bytes(%i)\n",*size
,count
);
2039 deformat_string(package
, &value
[1], &deformated
);
2042 *size
= sizeof(DWORD
);
2043 data
= msi_alloc(*size
);
2049 if ( (*p
< '0') || (*p
> '9') )
2055 if (deformated
[0] == '-')
2058 TRACE("DWORD %li\n",*(LPDWORD
)data
);
2060 msi_free(deformated
);
2065 static const WCHAR szMulti
[] = {'[','~',']',0};
2074 *type
=REG_EXPAND_SZ
;
2082 if (strstrW(value
,szMulti
))
2083 *type
= REG_MULTI_SZ
;
2085 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2090 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2092 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2093 static const WCHAR szHCR
[] =
2094 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2095 'R','O','O','T','\\',0};
2096 static const WCHAR szHCU
[] =
2097 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2098 'U','S','E','R','\\',0};
2099 static const WCHAR szHLM
[] =
2100 {'H','K','E','Y','_','L','O','C','A','L','_',
2101 'M','A','C','H','I','N','E','\\',0};
2102 static const WCHAR szHU
[] =
2103 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2105 LPSTR value_data
= NULL
;
2106 HKEY root_key
, hkey
;
2109 LPCWSTR szRoot
, component
, name
, key
, value
;
2114 BOOL check_first
= FALSE
;
2117 ui_progress(package
,2,0,0,0);
2124 component
= MSI_RecordGetString(row
, 6);
2125 comp
= get_loaded_component(package
,component
);
2127 return ERROR_SUCCESS
;
2129 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2131 TRACE("Skipping write due to disabled component %s\n",
2132 debugstr_w(component
));
2134 comp
->Action
= comp
->Installed
;
2136 return ERROR_SUCCESS
;
2139 comp
->Action
= INSTALLSTATE_LOCAL
;
2141 name
= MSI_RecordGetString(row
, 4);
2142 if( MSI_RecordIsNull(row
,5) && name
)
2144 /* null values can have special meanings */
2145 if (name
[0]=='-' && name
[1] == 0)
2146 return ERROR_SUCCESS
;
2147 else if ((name
[0]=='+' && name
[1] == 0) ||
2148 (name
[0] == '*' && name
[1] == 0))
2153 root
= MSI_RecordGetInteger(row
,2);
2154 key
= MSI_RecordGetString(row
, 3);
2156 /* get the root key */
2161 static const WCHAR szALLUSER
[] = {'A','L','L','U','S','E','R','S',0};
2162 LPWSTR all_users
= msi_dup_property( package
, szALLUSER
);
2163 if (all_users
&& all_users
[0] == '1')
2165 root_key
= HKEY_LOCAL_MACHINE
;
2170 root_key
= HKEY_CURRENT_USER
;
2173 msi_free(all_users
);
2176 case 0: root_key
= HKEY_CLASSES_ROOT
;
2179 case 1: root_key
= HKEY_CURRENT_USER
;
2182 case 2: root_key
= HKEY_LOCAL_MACHINE
;
2185 case 3: root_key
= HKEY_USERS
;
2189 ERR("Unknown root %i\n",root
);
2195 return ERROR_SUCCESS
;
2197 deformat_string(package
, key
, &deformated
);
2198 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2199 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2200 strcpyW(uikey
,szRoot
);
2201 strcatW(uikey
,deformated
);
2203 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2205 ERR("Could not create key %s\n",debugstr_w(deformated
));
2206 msi_free(deformated
);
2208 return ERROR_SUCCESS
;
2210 msi_free(deformated
);
2212 value
= MSI_RecordGetString(row
,5);
2214 value_data
= parse_value(package
, value
, &type
, &size
);
2217 static const WCHAR szEmpty
[] = {0};
2218 value_data
= (LPSTR
)strdupW(szEmpty
);
2223 deformat_string(package
, name
, &deformated
);
2225 /* get the double nulls to terminate SZ_MULTI */
2226 if (type
== REG_MULTI_SZ
)
2227 size
+=sizeof(WCHAR
);
2231 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2233 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2238 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2239 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2241 TRACE("value %s of %s checked already exists\n",
2242 debugstr_w(deformated
), debugstr_w(uikey
));
2246 TRACE("Checked and setting value %s of %s\n",
2247 debugstr_w(deformated
), debugstr_w(uikey
));
2248 if (deformated
|| size
)
2249 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2254 uirow
= MSI_CreateRecord(3);
2255 MSI_RecordSetStringW(uirow
,2,deformated
);
2256 MSI_RecordSetStringW(uirow
,1,uikey
);
2259 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2261 MSI_RecordSetStringW(uirow
,3,value
);
2263 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2264 msiobj_release( &uirow
->hdr
);
2266 msi_free(value_data
);
2267 msi_free(deformated
);
2270 return ERROR_SUCCESS
;
2273 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2277 static const WCHAR ExecSeqQuery
[] =
2278 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2279 '`','R','e','g','i','s','t','r','y','`',0 };
2282 return ERROR_INVALID_HANDLE
;
2284 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2285 if (rc
!= ERROR_SUCCESS
)
2286 return ERROR_SUCCESS
;
2288 /* increment progress bar each time action data is sent */
2289 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2291 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2293 msiobj_release(&view
->hdr
);
2297 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2299 package
->script
->CurrentlyScripting
= TRUE
;
2301 return ERROR_SUCCESS
;
2305 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2310 static const WCHAR q1
[]=
2311 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2312 '`','R','e','g','i','s','t','r','y','`',0};
2315 MSIFEATURE
*feature
;
2318 TRACE("InstallValidate\n");
2320 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2321 if (rc
== ERROR_SUCCESS
)
2323 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2324 msiobj_release( &view
->hdr
);
2325 total
+= progress
* REG_PROGRESS_VALUE
;
2328 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2329 total
+= COMPONENT_PROGRESS_VALUE
;
2331 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2332 total
+= file
->FileSize
;
2334 ui_progress(package
,0,total
,0,0);
2336 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2338 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2339 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2340 feature
->ActionRequest
);
2343 return ERROR_SUCCESS
;
2346 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2348 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2349 LPCWSTR cond
= NULL
;
2350 LPCWSTR message
= NULL
;
2351 static const WCHAR title
[]=
2352 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2354 cond
= MSI_RecordGetString(row
,1);
2356 if (MSI_EvaluateConditionW(package
,cond
) != MSICONDITION_TRUE
)
2359 message
= MSI_RecordGetString(row
,2);
2360 deformat_string(package
,message
,&deformated
);
2361 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2362 msi_free(deformated
);
2363 return ERROR_FUNCTION_FAILED
;
2366 return ERROR_SUCCESS
;
2369 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2372 MSIQUERY
* view
= NULL
;
2373 static const WCHAR ExecSeqQuery
[] =
2374 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2375 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2377 TRACE("Checking launch conditions\n");
2379 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2380 if (rc
!= ERROR_SUCCESS
)
2381 return ERROR_SUCCESS
;
2383 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2384 msiobj_release(&view
->hdr
);
2389 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2393 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,NULL
);
2395 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2397 MSIRECORD
* row
= 0;
2399 LPWSTR deformated
,buffer
,deformated_name
;
2401 static const WCHAR ExecSeqQuery
[] =
2402 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2403 '`','R','e','g','i','s','t','r','y','`',' ',
2404 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2405 ' ','=',' ' ,'\'','%','s','\'',0 };
2406 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2407 static const WCHAR fmt2
[]=
2408 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2410 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2414 root
= MSI_RecordGetInteger(row
,2);
2415 key
= MSI_RecordGetString(row
, 3);
2416 name
= MSI_RecordGetString(row
, 4);
2417 deformat_string(package
, key
, &deformated
);
2418 deformat_string(package
, name
, &deformated_name
);
2420 len
= strlenW(deformated
) + 6;
2421 if (deformated_name
)
2422 len
+=strlenW(deformated_name
);
2424 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2426 if (deformated_name
)
2427 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2429 sprintfW(buffer
,fmt
,root
,deformated
);
2431 msi_free(deformated
);
2432 msi_free(deformated_name
);
2433 msiobj_release(&row
->hdr
);
2437 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2439 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2444 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2447 return strdupW( file
->TargetPath
);
2452 static HKEY
openSharedDLLsKey(void)
2455 static const WCHAR path
[] =
2456 {'S','o','f','t','w','a','r','e','\\',
2457 'M','i','c','r','o','s','o','f','t','\\',
2458 'W','i','n','d','o','w','s','\\',
2459 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2460 'S','h','a','r','e','d','D','L','L','s',0};
2462 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2466 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2471 DWORD sz
= sizeof(count
);
2474 hkey
= openSharedDLLsKey();
2475 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2476 if (rc
!= ERROR_SUCCESS
)
2482 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2486 hkey
= openSharedDLLsKey();
2488 msi_reg_set_val_dword( hkey
, path
, count
);
2490 RegDeleteValueW(hkey
,path
);
2496 * Return TRUE if the count should be written out and FALSE if not
2498 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2500 MSIFEATURE
*feature
;
2504 /* only refcount DLLs */
2505 if (comp
->KeyPath
== NULL
||
2506 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2507 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2511 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2512 write
= (count
> 0);
2514 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2518 /* increment counts */
2519 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2523 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
))
2526 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2528 if ( cl
->component
== comp
)
2533 /* decrement counts */
2534 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2538 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ABSENT
))
2541 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2543 if ( cl
->component
== comp
)
2548 /* ref count all the files in the component */
2553 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2555 if (file
->Component
== comp
)
2556 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2560 /* add a count for permenent */
2561 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2564 comp
->RefCount
= count
;
2567 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2571 * Ok further analysis makes me think that this work is
2572 * actually done in the PublishComponents and PublishFeatures
2573 * step, and not here. It appears like the keypath and all that is
2574 * resolved in this step, however actually written in the Publish steps.
2575 * But we will leave it here for now because it is unclear
2577 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2579 WCHAR squished_pc
[GUID_SIZE
];
2580 WCHAR squished_cc
[GUID_SIZE
];
2583 HKEY hkey
=0,hkey2
=0;
2585 /* writes the Component and Features values to the registry */
2587 rc
= MSIREG_OpenComponents(&hkey
);
2588 if (rc
!= ERROR_SUCCESS
)
2591 squash_guid(package
->ProductCode
,squished_pc
);
2592 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2594 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2596 ui_progress(package
,2,0,0,0);
2597 if (comp
->ComponentId
)
2601 squash_guid(comp
->ComponentId
,squished_cc
);
2603 msi_free(comp
->FullKeypath
);
2604 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2606 /* do the refcounting */
2607 ACTION_RefCountComponent( package
, comp
);
2609 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2610 debugstr_w(comp
->Component
),
2611 debugstr_w(squished_cc
),
2612 debugstr_w(comp
->FullKeypath
),
2615 * Write the keypath out if the component is to be registered
2616 * and delete the key if the component is to be deregistered
2618 if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2620 rc
= RegCreateKeyW(hkey
,squished_cc
,&hkey2
);
2621 if (rc
!= ERROR_SUCCESS
)
2624 if (comp
->FullKeypath
)
2626 msi_reg_set_val_str( hkey2
, squished_pc
, comp
->FullKeypath
);
2628 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2630 static const WCHAR szPermKey
[] =
2631 { '0','0','0','0','0','0','0','0','0','0','0','0',
2632 '0','0','0','0','0','0','0','0','0','0','0','0',
2633 '0','0','0','0','0','0','0','0',0};
2635 msi_reg_set_val_str( hkey2
, szPermKey
, comp
->FullKeypath
);
2641 uirow
= MSI_CreateRecord(3);
2642 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2643 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2644 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
2645 ui_actiondata(package
,szProcessComponents
,uirow
);
2646 msiobj_release( &uirow
->hdr
);
2649 else if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ABSENT
))
2653 rc
= RegOpenKeyW(hkey
,squished_cc
,&hkey2
);
2654 if (rc
!= ERROR_SUCCESS
)
2657 RegDeleteValueW(hkey2
,squished_pc
);
2659 /* if the key is empty delete it */
2660 res
= RegEnumKeyExW(hkey2
,0,NULL
,0,0,NULL
,0,NULL
);
2662 if (res
== ERROR_NO_MORE_ITEMS
)
2663 RegDeleteKeyW(hkey
,squished_cc
);
2666 uirow
= MSI_CreateRecord(2);
2667 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2668 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2669 ui_actiondata(package
,szProcessComponents
,uirow
);
2670 msiobj_release( &uirow
->hdr
);
2687 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
2688 LPWSTR lpszName
, LONG_PTR lParam
)
2691 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
2692 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
2696 if (!IS_INTRESOURCE(lpszName
))
2698 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
2702 sz
= strlenW(tl_struct
->source
)+4;
2703 sz
*= sizeof(WCHAR
);
2705 if ((INT
)lpszName
== 1)
2706 tl_struct
->path
= strdupW(tl_struct
->source
);
2709 tl_struct
->path
= msi_alloc(sz
);
2710 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
2713 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
2714 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
2715 if (!SUCCEEDED(res
))
2717 msi_free(tl_struct
->path
);
2718 tl_struct
->path
= NULL
;
2723 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
2724 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
2726 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2730 msi_free(tl_struct
->path
);
2731 tl_struct
->path
= NULL
;
2733 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2734 ITypeLib_Release(tl_struct
->ptLib
);
2739 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
2741 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2745 typelib_struct tl_struct
;
2747 static const WCHAR szTYPELIB
[] = {'T','Y','P','E','L','I','B',0};
2749 component
= MSI_RecordGetString(row
,3);
2750 comp
= get_loaded_component(package
,component
);
2752 return ERROR_SUCCESS
;
2754 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2756 TRACE("Skipping typelib reg due to disabled component\n");
2758 comp
->Action
= comp
->Installed
;
2760 return ERROR_SUCCESS
;
2763 comp
->Action
= INSTALLSTATE_LOCAL
;
2765 file
= get_loaded_file( package
, comp
->KeyPath
);
2767 return ERROR_SUCCESS
;
2769 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
2773 guid
= MSI_RecordGetString(row
,1);
2774 CLSIDFromString((LPWSTR
)guid
, &tl_struct
.clsid
);
2775 tl_struct
.source
= strdupW( file
->TargetPath
);
2776 tl_struct
.path
= NULL
;
2778 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
2779 (LONG_PTR
)&tl_struct
);
2787 helpid
= MSI_RecordGetString(row
,6);<