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 if (!package
->script
)
1422 ERR("no script!\n");
1423 return ERROR_FUNCTION_FAILED
;
1426 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1429 action
= package
->script
->Actions
[script
][i
];
1430 ui_actionstart(package
, action
);
1431 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1432 rc
= ACTION_PerformAction(package
, action
, TRUE
);
1433 msi_free(package
->script
->Actions
[script
][i
]);
1434 if (rc
!= ERROR_SUCCESS
)
1437 msi_free(package
->script
->Actions
[script
]);
1439 package
->script
->ActionCount
[script
] = 0;
1440 package
->script
->Actions
[script
] = NULL
;
1444 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1446 return ERROR_SUCCESS
;
1450 static MSIFOLDER
*load_folder( MSIPACKAGE
*package
, LPCWSTR dir
)
1452 static const WCHAR Query
[] =
1453 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1454 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1455 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1456 ' ','=',' ','\'','%','s','\'',
1458 LPWSTR ptargetdir
, targetdir
, srcdir
;
1460 LPWSTR shortname
= NULL
;
1461 MSIRECORD
* row
= 0;
1464 TRACE("Looking for dir %s\n",debugstr_w(dir
));
1466 folder
= get_loaded_folder( package
, dir
);
1470 TRACE("Working to load %s\n",debugstr_w(dir
));
1472 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1476 folder
->Directory
= strdupW(dir
);
1478 row
= MSI_QueryGetRecord(package
->db
, Query
, dir
);
1482 ptargetdir
= targetdir
= msi_dup_record_field(row
,3);
1484 /* split src and target dir */
1485 if (strchrW(targetdir
,':'))
1487 srcdir
=strchrW(targetdir
,':');
1494 /* for now only pick long filename versions */
1495 if (strchrW(targetdir
,'|'))
1497 shortname
= targetdir
;
1498 targetdir
= strchrW(targetdir
,'|');
1502 /* for the sourcedir pick the short filename */
1503 if (srcdir
&& strchrW(srcdir
,'|'))
1505 LPWSTR p
= strchrW(srcdir
,'|');
1509 /* now check for root dirs */
1510 if (targetdir
[0] == '.' && targetdir
[1] == 0)
1515 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir
));
1516 msi_free( folder
->TargetDefault
);
1517 folder
->TargetDefault
= strdupW(targetdir
);
1521 folder
->SourceDefault
= strdupW(srcdir
);
1523 folder
->SourceDefault
= strdupW(shortname
);
1525 folder
->SourceDefault
= strdupW(targetdir
);
1526 msi_free(ptargetdir
);
1527 TRACE(" SourceDefault = %s\n", debugstr_w( folder
->SourceDefault
));
1529 parent
= MSI_RecordGetString(row
,2);
1532 folder
->Parent
= load_folder( package
, parent
);
1533 if ( folder
->Parent
)
1534 TRACE("loaded parent %p %s\n", folder
->Parent
,
1535 debugstr_w(folder
->Parent
->Directory
));
1537 ERR("failed to load parent folder %s\n", debugstr_w(parent
));
1540 folder
->Property
= msi_dup_property( package
, dir
);
1542 msiobj_release(&row
->hdr
);
1544 list_add_tail( &package
->folders
, &folder
->entry
);
1546 TRACE("%s returning %p\n",debugstr_w(dir
),folder
);
1551 /* scan for and update current install states */
1552 static void ACTION_UpdateInstallStates(MSIPACKAGE
*package
)
1555 MSIFEATURE
*feature
;
1557 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1560 res
= MsiGetComponentPathW( package
->ProductCode
,
1561 comp
->ComponentId
, NULL
, NULL
);
1563 res
= INSTALLSTATE_ABSENT
;
1564 comp
->Installed
= res
;
1567 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1570 INSTALLSTATE res
= -10;
1572 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1574 comp
= cl
->component
;
1577 res
= comp
->Installed
;
1580 if (res
== comp
->Installed
)
1583 if (res
!= comp
->Installed
)
1584 res
= INSTALLSTATE_INCOMPLETE
;
1587 feature
->Installed
= res
;
1591 static BOOL
process_state_property (MSIPACKAGE
* package
, LPCWSTR property
,
1594 static const WCHAR all
[]={'A','L','L',0};
1596 MSIFEATURE
*feature
;
1598 override
= msi_dup_property( package
, property
);
1602 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1604 if (strcmpiW(override
,all
)==0)
1606 feature
->ActionRequest
= state
;
1607 feature
->Action
= state
;
1611 LPWSTR ptr
= override
;
1612 LPWSTR ptr2
= strchrW(override
,',');
1616 if ((ptr2
&& strncmpW(ptr
,feature
->Feature
, ptr2
-ptr
)==0)
1617 || (!ptr2
&& strcmpW(ptr
,feature
->Feature
)==0))
1619 feature
->ActionRequest
= state
;
1620 feature
->Action
= state
;
1626 ptr2
= strchrW(ptr
,',');
1638 static UINT
SetFeatureStates(MSIPACKAGE
*package
)
1641 static const WCHAR szlevel
[] =
1642 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1643 static const WCHAR szAddLocal
[] =
1644 {'A','D','D','L','O','C','A','L',0};
1645 static const WCHAR szRemove
[] =
1646 {'R','E','M','O','V','E',0};
1647 static const WCHAR szReinstall
[] =
1648 {'R','E','I','N','S','T','A','L','L',0};
1649 BOOL override
= FALSE
;
1650 MSICOMPONENT
* component
;
1651 MSIFEATURE
*feature
;
1654 /* I do not know if this is where it should happen.. but */
1656 TRACE("Checking Install Level\n");
1658 install_level
= msi_get_property_int( package
, szlevel
, 1 );
1660 /* ok hereis the _real_ rub
1661 * all these activation/deactivation things happen in order and things
1662 * later on the list override things earlier on the list.
1663 * 1) INSTALLLEVEL processing
1673 * 11) FILEADDDEFAULT
1674 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1675 * ignored for all the features. seems strange, especially since it is not
1676 * documented anywhere, but it is how it works.
1678 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1679 * REMOVE are the big ones, since we don't handle administrative installs
1682 override
|= process_state_property(package
,szAddLocal
,INSTALLSTATE_LOCAL
);
1683 override
|= process_state_property(package
,szRemove
,INSTALLSTATE_ABSENT
);
1684 override
|= process_state_property(package
,szReinstall
,INSTALLSTATE_LOCAL
);
1688 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1690 BOOL feature_state
= ((feature
->Level
> 0) &&
1691 (feature
->Level
<= install_level
));
1693 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1695 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1697 feature
->ActionRequest
= INSTALLSTATE_SOURCE
;
1698 feature
->Action
= INSTALLSTATE_SOURCE
;
1700 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1702 feature
->ActionRequest
= INSTALLSTATE_ADVERTISED
;
1703 feature
->Action
= INSTALLSTATE_ADVERTISED
;
1707 feature
->ActionRequest
= INSTALLSTATE_LOCAL
;
1708 feature
->Action
= INSTALLSTATE_LOCAL
;
1715 /* set the Preselected Property */
1716 static const WCHAR szPreselected
[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1717 static const WCHAR szOne
[] = { '1', 0 };
1719 MSI_SetPropertyW(package
,szPreselected
,szOne
);
1723 * now we want to enable or disable components base on feature
1726 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1730 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1731 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
1732 feature
->ActionRequest
);
1734 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1736 component
= cl
->component
;
1738 if (!component
->Enabled
)
1740 component
->Action
= INSTALLSTATE_UNKNOWN
;
1741 component
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
1745 if (feature
->Action
== INSTALLSTATE_LOCAL
)
1747 component
->Action
= INSTALLSTATE_LOCAL
;
1748 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
1750 else if (feature
->ActionRequest
== INSTALLSTATE_SOURCE
)
1752 if ((component
->Action
== INSTALLSTATE_UNKNOWN
) ||
1753 (component
->Action
== INSTALLSTATE_ABSENT
) ||
1754 (component
->Action
== INSTALLSTATE_ADVERTISED
))
1757 component
->Action
= INSTALLSTATE_SOURCE
;
1758 component
->ActionRequest
= INSTALLSTATE_SOURCE
;
1761 else if (feature
->ActionRequest
== INSTALLSTATE_ADVERTISED
)
1763 if ((component
->Action
== INSTALLSTATE_UNKNOWN
) ||
1764 (component
->Action
== INSTALLSTATE_ABSENT
))
1767 component
->Action
= INSTALLSTATE_ADVERTISED
;
1768 component
->ActionRequest
= INSTALLSTATE_ADVERTISED
;
1771 else if (feature
->ActionRequest
== INSTALLSTATE_ABSENT
)
1773 if (component
->Action
== INSTALLSTATE_UNKNOWN
)
1775 component
->Action
= INSTALLSTATE_ABSENT
;
1776 component
->ActionRequest
= INSTALLSTATE_ABSENT
;
1783 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1785 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1786 debugstr_w(component
->Component
), component
->Installed
,
1787 component
->Action
, component
->ActionRequest
);
1791 return ERROR_SUCCESS
;
1794 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1796 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1800 name
= MSI_RecordGetString(row
,1);
1802 /* This helper function now does ALL the work */
1803 TRACE("Dir %s ...\n",debugstr_w(name
));
1804 load_folder(package
,name
);
1805 path
= resolve_folder(package
,name
,FALSE
,TRUE
,NULL
);
1806 TRACE("resolves to %s\n",debugstr_w(path
));
1809 return ERROR_SUCCESS
;
1812 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
1814 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1816 MSIFEATURE
*feature
;
1818 name
= MSI_RecordGetString( row
, 1 );
1820 feature
= get_loaded_feature( package
, name
);
1822 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
1826 Condition
= MSI_RecordGetString(row
,3);
1828 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
1830 int level
= MSI_RecordGetInteger(row
,2);
1831 TRACE("Reseting feature %s to level %i\n", debugstr_w(name
), level
);
1832 feature
->Level
= level
;
1835 return ERROR_SUCCESS
;
1840 * A lot is done in this function aside from just the costing.
1841 * The costing needs to be implemented at some point but for now I am going
1842 * to focus on the directory building
1845 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
1847 static const WCHAR ExecSeqQuery
[] =
1848 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1849 '`','D','i','r','e','c','t','o','r','y','`',0};
1850 static const WCHAR ConditionQuery
[] =
1851 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1852 '`','C','o','n','d','i','t','i','o','n','`',0};
1853 static const WCHAR szCosting
[] =
1854 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1855 static const WCHAR szlevel
[] =
1856 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1857 static const WCHAR szOne
[] = { '1', 0 };
1864 if ( 1 == msi_get_property_int( package
, szCosting
, 0 ) )
1865 return ERROR_SUCCESS
;
1867 TRACE("Building Directory properties\n");
1869 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1870 if (rc
== ERROR_SUCCESS
)
1872 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
1874 msiobj_release(&view
->hdr
);
1877 TRACE("File calculations\n");
1879 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
1881 MSICOMPONENT
* comp
= file
->Component
;
1887 /* calculate target */
1888 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, NULL
);
1890 msi_free(file
->TargetPath
);
1892 TRACE("file %s is named %s\n",
1893 debugstr_w(file
->File
),debugstr_w(file
->FileName
));
1895 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
1899 TRACE("file %s resolves to %s\n",
1900 debugstr_w(file
->File
),debugstr_w(file
->TargetPath
));
1902 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
1904 file
->state
= msifs_missing
;
1905 comp
->Cost
+= file
->FileSize
;
1915 static WCHAR name
[] = {'\\',0};
1916 static const WCHAR name_fmt
[] =
1917 {'%','u','.','%','u','.','%','u','.','%','u',0};
1918 WCHAR filever
[0x100];
1919 VS_FIXEDFILEINFO
*lpVer
;
1921 TRACE("Version comparison..\n");
1922 versize
= GetFileVersionInfoSizeW(file
->TargetPath
,&handle
);
1923 version
= msi_alloc(versize
);
1924 GetFileVersionInfoW(file
->TargetPath
, 0, versize
, version
);
1926 VerQueryValueW(version
, name
, (LPVOID
*)&lpVer
, &sz
);
1928 sprintfW(filever
,name_fmt
,
1929 HIWORD(lpVer
->dwFileVersionMS
),
1930 LOWORD(lpVer
->dwFileVersionMS
),
1931 HIWORD(lpVer
->dwFileVersionLS
),
1932 LOWORD(lpVer
->dwFileVersionLS
));
1934 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
1935 debugstr_w(filever
));
1936 if (strcmpiW(filever
,file
->Version
)<0)
1938 file
->state
= msifs_overwrite
;
1939 /* FIXME: cost should be diff in size */
1940 comp
->Cost
+= file
->FileSize
;
1943 file
->state
= msifs_present
;
1947 file
->state
= msifs_present
;
1950 TRACE("Evaluating Condition Table\n");
1952 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
1953 if (rc
== ERROR_SUCCESS
)
1955 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeConditions
,
1957 msiobj_release(&view
->hdr
);
1960 TRACE("Enabling or Disabling Components\n");
1961 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1963 if (comp
->Condition
)
1965 if (MSI_EvaluateConditionW(package
,
1966 comp
->Condition
) == MSICONDITION_FALSE
)
1968 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
1969 comp
->Enabled
= FALSE
;
1974 MSI_SetPropertyW(package
,szCosting
,szOne
);
1975 /* set default run level if not set */
1976 level
= msi_dup_property( package
, szlevel
);
1978 MSI_SetPropertyW(package
,szlevel
, szOne
);
1981 ACTION_UpdateInstallStates(package
);
1983 return SetFeatureStates(package
);
1986 /* OK this value is "interpreted" and then formatted based on the
1987 first few characters */
1988 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
1992 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
1998 LPWSTR deformated
= NULL
;
2001 deformat_string(package
, &value
[2], &deformated
);
2003 /* binary value type */
2007 *size
= (strlenW(ptr
)/2)+1;
2009 *size
= strlenW(ptr
)/2;
2011 data
= msi_alloc(*size
);
2017 /* if uneven pad with a zero in front */
2023 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2025 TRACE("Uneven byte count\n");
2033 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2036 msi_free(deformated
);
2038 TRACE("Data %li bytes(%i)\n",*size
,count
);
2045 deformat_string(package
, &value
[1], &deformated
);
2048 *size
= sizeof(DWORD
);
2049 data
= msi_alloc(*size
);
2055 if ( (*p
< '0') || (*p
> '9') )
2061 if (deformated
[0] == '-')
2064 TRACE("DWORD %li\n",*(LPDWORD
)data
);
2066 msi_free(deformated
);
2071 static const WCHAR szMulti
[] = {'[','~',']',0};
2080 *type
=REG_EXPAND_SZ
;
2088 if (strstrW(value
,szMulti
))
2089 *type
= REG_MULTI_SZ
;
2091 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2096 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2098 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2099 static const WCHAR szHCR
[] =
2100 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2101 'R','O','O','T','\\',0};
2102 static const WCHAR szHCU
[] =
2103 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2104 'U','S','E','R','\\',0};
2105 static const WCHAR szHLM
[] =
2106 {'H','K','E','Y','_','L','O','C','A','L','_',
2107 'M','A','C','H','I','N','E','\\',0};
2108 static const WCHAR szHU
[] =
2109 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2111 LPSTR value_data
= NULL
;
2112 HKEY root_key
, hkey
;
2115 LPCWSTR szRoot
, component
, name
, key
, value
;
2120 BOOL check_first
= FALSE
;
2123 ui_progress(package
,2,0,0,0);
2130 component
= MSI_RecordGetString(row
, 6);
2131 comp
= get_loaded_component(package
,component
);
2133 return ERROR_SUCCESS
;
2135 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2137 TRACE("Skipping write due to disabled component %s\n",
2138 debugstr_w(component
));
2140 comp
->Action
= comp
->Installed
;
2142 return ERROR_SUCCESS
;
2145 comp
->Action
= INSTALLSTATE_LOCAL
;
2147 name
= MSI_RecordGetString(row
, 4);
2148 if( MSI_RecordIsNull(row
,5) && name
)
2150 /* null values can have special meanings */
2151 if (name
[0]=='-' && name
[1] == 0)
2152 return ERROR_SUCCESS
;
2153 else if ((name
[0]=='+' && name
[1] == 0) ||
2154 (name
[0] == '*' && name
[1] == 0))
2159 root
= MSI_RecordGetInteger(row
,2);
2160 key
= MSI_RecordGetString(row
, 3);
2162 /* get the root key */
2167 static const WCHAR szALLUSER
[] = {'A','L','L','U','S','E','R','S',0};
2168 LPWSTR all_users
= msi_dup_property( package
, szALLUSER
);
2169 if (all_users
&& all_users
[0] == '1')
2171 root_key
= HKEY_LOCAL_MACHINE
;
2176 root_key
= HKEY_CURRENT_USER
;
2179 msi_free(all_users
);
2182 case 0: root_key
= HKEY_CLASSES_ROOT
;
2185 case 1: root_key
= HKEY_CURRENT_USER
;
2188 case 2: root_key
= HKEY_LOCAL_MACHINE
;
2191 case 3: root_key
= HKEY_USERS
;
2195 ERR("Unknown root %i\n",root
);
2201 return ERROR_SUCCESS
;
2203 deformat_string(package
, key
, &deformated
);
2204 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2205 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2206 strcpyW(uikey
,szRoot
);
2207 strcatW(uikey
,deformated
);
2209 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2211 ERR("Could not create key %s\n",debugstr_w(deformated
));
2212 msi_free(deformated
);
2214 return ERROR_SUCCESS
;
2216 msi_free(deformated
);
2218 value
= MSI_RecordGetString(row
,5);
2220 value_data
= parse_value(package
, value
, &type
, &size
);
2223 static const WCHAR szEmpty
[] = {0};
2224 value_data
= (LPSTR
)strdupW(szEmpty
);
2229 deformat_string(package
, name
, &deformated
);
2231 /* get the double nulls to terminate SZ_MULTI */
2232 if (type
== REG_MULTI_SZ
)
2233 size
+=sizeof(WCHAR
);
2237 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2239 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2244 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2245 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2247 TRACE("value %s of %s checked already exists\n",
2248 debugstr_w(deformated
), debugstr_w(uikey
));
2252 TRACE("Checked and setting value %s of %s\n",
2253 debugstr_w(deformated
), debugstr_w(uikey
));
2254 if (deformated
|| size
)
2255 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2260 uirow
= MSI_CreateRecord(3);
2261 MSI_RecordSetStringW(uirow
,2,deformated
);
2262 MSI_RecordSetStringW(uirow
,1,uikey
);
2265 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2267 MSI_RecordSetStringW(uirow
,3,value
);
2269 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2270 msiobj_release( &uirow
->hdr
);
2272 msi_free(value_data
);
2273 msi_free(deformated
);
2276 return ERROR_SUCCESS
;
2279 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2283 static const WCHAR ExecSeqQuery
[] =
2284 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2285 '`','R','e','g','i','s','t','r','y','`',0 };
2288 return ERROR_INVALID_HANDLE
;
2290 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2291 if (rc
!= ERROR_SUCCESS
)
2292 return ERROR_SUCCESS
;
2294 /* increment progress bar each time action data is sent */
2295 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2297 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2299 msiobj_release(&view
->hdr
);
2303 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2305 package
->script
->CurrentlyScripting
= TRUE
;
2307 return ERROR_SUCCESS
;
2311 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2316 static const WCHAR q1
[]=
2317 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2318 '`','R','e','g','i','s','t','r','y','`',0};
2321 MSIFEATURE
*feature
;
2324 TRACE("InstallValidate\n");
2326 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2327 if (rc
== ERROR_SUCCESS
)
2329 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2330 msiobj_release( &view
->hdr
);
2331 total
+= progress
* REG_PROGRESS_VALUE
;
2334 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2335 total
+= COMPONENT_PROGRESS_VALUE
;
2337 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2338 total
+= file
->FileSize
;
2340 ui_progress(package
,0,total
,0,0);
2342 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2344 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2345 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2346 feature
->ActionRequest
);
2349 return ERROR_SUCCESS
;
2352 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2354 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2355 LPCWSTR cond
= NULL
;
2356 LPCWSTR message
= NULL
;
2357 static const WCHAR title
[]=
2358 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2360 cond
= MSI_RecordGetString(row
,1);
2362 if (MSI_EvaluateConditionW(package
,cond
) != MSICONDITION_TRUE
)
2365 message
= MSI_RecordGetString(row
,2);
2366 deformat_string(package
,message
,&deformated
);
2367 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2368 msi_free(deformated
);
2369 return ERROR_FUNCTION_FAILED
;
2372 return ERROR_SUCCESS
;
2375 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2378 MSIQUERY
* view
= NULL
;
2379 static const WCHAR ExecSeqQuery
[] =
2380 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2381 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2383 TRACE("Checking launch conditions\n");
2385 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2386 if (rc
!= ERROR_SUCCESS
)
2387 return ERROR_SUCCESS
;
2389 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2390 msiobj_release(&view
->hdr
);
2395 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2399 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,NULL
);
2401 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2403 MSIRECORD
* row
= 0;
2405 LPWSTR deformated
,buffer
,deformated_name
;
2407 static const WCHAR ExecSeqQuery
[] =
2408 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2409 '`','R','e','g','i','s','t','r','y','`',' ',
2410 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2411 ' ','=',' ' ,'\'','%','s','\'',0 };
2412 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2413 static const WCHAR fmt2
[]=
2414 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2416 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2420 root
= MSI_RecordGetInteger(row
,2);
2421 key
= MSI_RecordGetString(row
, 3);
2422 name
= MSI_RecordGetString(row
, 4);
2423 deformat_string(package
, key
, &deformated
);
2424 deformat_string(package
, name
, &deformated_name
);
2426 len
= strlenW(deformated
) + 6;
2427 if (deformated_name
)
2428 len
+=strlenW(deformated_name
);
2430 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2432 if (deformated_name
)
2433 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2435 sprintfW(buffer
,fmt
,root
,deformated
);
2437 msi_free(deformated
);
2438 msi_free(deformated_name
);
2439 msiobj_release(&row
->hdr
);
2443 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2445 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2450 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2453 return strdupW( file
->TargetPath
);
2458 static HKEY
openSharedDLLsKey(void)
2461 static const WCHAR path
[] =
2462 {'S','o','f','t','w','a','r','e','\\',
2463 'M','i','c','r','o','s','o','f','t','\\',
2464 'W','i','n','d','o','w','s','\\',
2465 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2466 'S','h','a','r','e','d','D','L','L','s',0};
2468 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2472 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2477 DWORD sz
= sizeof(count
);
2480 hkey
= openSharedDLLsKey();
2481 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2482 if (rc
!= ERROR_SUCCESS
)
2488 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2492 hkey
= openSharedDLLsKey();
2494 msi_reg_set_val_dword( hkey
, path
, count
);
2496 RegDeleteValueW(hkey
,path
);
2502 * Return TRUE if the count should be written out and FALSE if not
2504 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2506 MSIFEATURE
*feature
;
2510 /* only refcount DLLs */
2511 if (comp
->KeyPath
== NULL
||
2512 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2513 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2517 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2518 write
= (count
> 0);
2520 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2524 /* increment counts */
2525 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2529 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
))
2532 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2534 if ( cl
->component
== comp
)
2539 /* decrement counts */
2540 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2544 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ABSENT
))
2547 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2549 if ( cl
->component
== comp
)
2554 /* ref count all the files in the component */
2559 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2561 if (file
->Component
== comp
)
2562 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2566 /* add a count for permenent */
2567 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2570 comp
->RefCount
= count
;
2573 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2577 * Ok further analysis makes me think that this work is
2578 * actually done in the PublishComponents and PublishFeatures
2579 * step, and not here. It appears like the keypath and all that is
2580 * resolved in this step, however actually written in the Publish steps.
2581 * But we will leave it here for now because it is unclear
2583 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2585 WCHAR squished_pc
[GUID_SIZE
];
2586 WCHAR squished_cc
[GUID_SIZE
];
2589 HKEY hkey
=0,hkey2
=0;
2591 /* writes the Component and Features values to the registry */
2593 rc
= MSIREG_OpenComponents(&hkey
);
2594 if (rc
!= ERROR_SUCCESS
)
2597 squash_guid(package
->ProductCode
,squished_pc
);
2598 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2600 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2602 ui_progress(package
,2,0,0,0);
2603 if (comp
->ComponentId
)
2607 squash_guid(comp
->ComponentId
,squished_cc
);
2609 msi_free(comp
->FullKeypath
);
2610 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2612 /* do the refcounting */
2613 ACTION_RefCountComponent( package
, comp
);
2615 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2616 debugstr_w(comp
->Component
),
2617 debugstr_w(squished_cc
),
2618 debugstr_w(comp
->FullKeypath
),
2621 * Write the keypath out if the component is to be registered
2622 * and delete the key if the component is to be deregistered
2624 if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2626 rc
= RegCreateKeyW(hkey
,squished_cc
,&hkey2
);
2627 if (rc
!= ERROR_SUCCESS
)
2630 if (comp
->FullKeypath
)
2632 msi_reg_set_val_str( hkey2
, squished_pc
, comp
->FullKeypath
);
2634 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2636 static const WCHAR szPermKey
[] =
2637 { '0','0','0','0','0','0','0','0','0','0','0','0',
2638 '0','0','0','0','0','0','0','0','0','0','0','0',
2639 '0','0','0','0','0','0','0','0',0};
2641 msi_reg_set_val_str( hkey2
, szPermKey
, comp
->FullKeypath
);
2647 uirow
= MSI_CreateRecord(3);
2648 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2649 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2650 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
2651 ui_actiondata(package
,szProcessComponents
,uirow
);
2652 msiobj_release( &uirow
->hdr
);
2655 else if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ABSENT
))
2659 rc
= RegOpenKeyW(hkey
,squished_cc
,&hkey2
);
2660 if (rc
!= ERROR_SUCCESS
)
2663 RegDeleteValueW(hkey2
,squished_pc
);
2665 /* if the key is empty delete it */
2666 res
= RegEnumKeyExW(hkey2
,0,NULL
,0,0,NULL
,0,NULL
);
2668 if (res
== ERROR_NO_MORE_ITEMS
)
2669 RegDeleteKeyW(hkey
,squished_cc
);
2672 uirow
= MSI_CreateRecord(2);
2673 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2674 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2675 ui_actiondata(package
,szProcessComponents
,uirow
);
2676 msiobj_release( &uirow
->hdr
);
2693 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
2694 LPWSTR lpszName
, LONG_PTR lParam
)
2697 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
2698 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
2702 if (!IS_INTRESOURCE(lpszName
))
2704 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
2708 sz
= strlenW(tl_struct
->source
)+4;
2709 sz
*= sizeof(WCHAR
);
2711 if ((INT
)lpszName
== 1)
2712 tl_struct
->path
= strdupW(tl_struct
->source
);
2715 tl_struct
->path
= msi_alloc(sz
);
2716 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
2719 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
2720 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
2721 if (!SUCCEEDED(res
))
2723 msi_free(tl_struct
->path
);
2724 tl_struct
->path
= NULL
;
2729 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
2730 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
2732 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2736 msi_free(tl_struct
->path
);
2737 tl_struct
->path
= NULL
;
2739 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2740 ITypeLib_Release(tl_struct
->ptLib
);
2745 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
2747 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2751 typelib_struct tl_struct
;
2753 static const WCHAR szTYPELIB
[] = {'T','Y','P','E','L','I','B',0};
2755 component
= MSI_RecordGetString(row
,3);
2756 comp
= get_loaded_component(package
,component
);
2758 return ERROR_SUCCESS
;
2760 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2762 TRACE("Skipping typelib reg due to disabled component\n");
2764 comp
->Action
= comp
->Installed
;
2766 return ERROR_SUCCESS
;
2769 comp
->Action
= INSTALLSTATE_LOCAL
;
2771 file
= get_loaded_file( package
, comp
->KeyPath
);
2773 return ERROR_SUCCESS
;
2775 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
2779 guid
= MSI_RecordGetString(row
,1);
2780 CLSIDFromString((LPWSTR
)guid
, &tl_struct
.clsid
);
2781 tl_struct
.source
= strdupW( file
->TargetPath
);
2782 tl_struct
.path
= NULL
;
2784 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
2785 (LONG_PTR
)&tl_struct
);
2793 helpid
= MSI_RecordGetString(row
,6);
2796 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,NULL
);
2797 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
2800 if (!SUCCEEDED(res
))
2801 ERR("Failed to register type library %s\n",
2802 debugstr_w(tl_struct
.path
));
2805 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
2807 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
2810 ITypeLib_Release(tl_struct
.ptLib
);
2811 msi_free(tl_struct
.path
);
2814 ERR("Failed to load type library %s\n",
2815 debugstr_w(tl_struct
.source
));
2817 FreeLibrary(module
);
2818 msi_free(tl_struct
.source
);
2821 ERR("Could not load file! %s\n", debugstr_w(file
->TargetPath
));
2823 return ERROR_SUCCESS
;
2826 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
2829 * OK this is a bit confusing.. I am given a _Component key and I believe
2830 * that the file that is being registered as a type library is the "key file
2831 * of that component" which I interpret to mean "The file in the KeyPath of
2836 static const WCHAR Query
[] =
2837 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2838 '`','T','y','p','e','L','i','b','`',0};
2840 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2841 if (rc
!= ERROR_SUCCESS
)
2842 return ERROR_SUCCESS
;
2844 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
2845 msiobj_release(&view
->hdr
);
2849 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
2851 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2852 LPWSTR target_file
, target_folder
;
2854 WCHAR filename
[0x100];
2857 static const WCHAR szlnk
[]={'.','l','n','k',0};
2862 buffer
= MSI_RecordGetString(row
,4);
2863 comp
= get_loaded_component(package
,buffer
);
2865 return ERROR_SUCCESS
;
2867 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2869 TRACE("Skipping shortcut creation due to disabled component\n");
2871 comp
->Action
= comp
->Installed
;
2873 return ERROR_SUCCESS
;
2876 comp
->Action
= INSTALLSTATE_LOCAL
;
2878 ui_actiondata(package
,szCreateShortcuts
,row
);
2880 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
2881 &IID_IShellLinkW
, (LPVOID
*) &sl
);
2885 ERR("Is IID_IShellLink\n");
2886 return ERROR_SUCCESS
;
2889 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
2892 ERR("Is IID_IPersistFile\n");
2893 return ERROR_SUCCESS
;
2896 buffer
= MSI_RecordGetString(row
,2);
2897 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,NULL
);
2899 /* may be needed because of a bug somehwere else */
2900 create_full_pathW(target_folder
);
2903 MSI_RecordGetStringW(row
,3,filename
,&sz
);
2904 reduce_to_longfilename(filename
);
2905 if (!strchrW(filename
,'.') || strcmpiW(strchrW(filename
,'.'),szlnk
))
2906 strcatW(filename
,szlnk
);
2907 target_file
= build_directory_name(2, target_folder
, filename
);
2908 msi_free(target_folder
);
2910 buffer
= MSI_RecordGetString(row
,5);
2911 if (strchrW(buffer
,'['))
2914 deformat_string(package
,buffer
,&deformated
);
2915 IShellLinkW_SetPath(sl
,deformated
);
2916 msi_free(deformated
);
2920 FIXME("poorly handled shortcut format, advertised shortcut\n");
2921 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
2924 if (!MSI_RecordIsNull(row
,6))
2927 buffer
= MSI_RecordGetString(row
,6);
2928 deformat_string(package
,buffer
,&deformated
);
2929 IShellLinkW_SetArguments(sl
,deformated
);
2930 msi_free(deformated
);
2933 if (!MSI_RecordIsNull(row
,7))
2935 buffer
= MSI_RecordGetString(row
,7);
2936 IShellLinkW_SetDescription(sl
,buffer
);
2939 if (!MSI_RecordIsNull(row
,8))
2940 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
2942 if (!MSI_RecordIsNull(row
,9))
2947 buffer
= MSI_RecordGetString(row
,9);
2949 Path
= build_icon_path(package
,buffer
);
2950 index
= MSI_RecordGetInteger(row
,10);
2952 IShellLinkW_SetIconLocation(sl
,Path
,index
);
2956 if (!MSI_RecordIsNull(row
,11))
2957 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
2959 if (!MSI_RecordIsNull(row
,12))
2962 buffer
= MSI_RecordGetString(row
,12);
2963 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, NULL
);
2964 IShellLinkW_SetWorkingDirectory(sl
,Path
);
2968 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
2969 IPersistFile_Save(pf
,target_file
,FALSE
);
2971 msi_free(target_file
);
2973 IPersistFile_Release( pf
);
2974 IShellLinkW_Release( sl
);
2976 return ERROR_SUCCESS
;
2979 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
2984 static const WCHAR Query
[] =
2985 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2986 '`','S','h','o','r','t','c','u','t','`',0};
2988 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2989 if (rc
!= ERROR_SUCCESS
)
2990 return ERROR_SUCCESS
;
2992 res
= CoInitialize( NULL
);
2995 ERR("CoInitialize failed\n");
2996 return ERROR_FUNCTION_FAILED
;
2999 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
3000 msiobj_release(&view
->hdr
);
3007 static UINT
ITERATE_PublishProduct(MSIRECORD
*row
, LPVOID param
)
3009 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
3017 FileName
= MSI_RecordGetString(row
,1);
3020 ERR("Unable to get FileName\n");
3021 return ERROR_SUCCESS
;
3024 FilePath
= build_icon_path(package
,FileName
);
3026 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
3028 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
3029 FILE_ATTRIBUTE_NORMAL
, NULL
);
3031 if (the_file
== INVALID_HANDLE_VALUE
)
3033 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3035 return ERROR_SUCCESS
;
3042 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3043 if (rc
!= ERROR_SUCCESS
)
3045 ERR("Failed to get stream\n");
3046 CloseHandle(the_file
);
3047 DeleteFileW(FilePath
);
3050 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3051 } while (sz
== 1024);
3055 CloseHandle(the_file
);
3056 return ERROR_SUCCESS
;
3060 * 99% of the work done here is only done for
3061 * advertised installs. However this is where the
3062 * Icon table is processed and written out
3063 * so that is what I am going to do here.
3065 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3069 static const WCHAR Query
[]=
3070 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3071 '`','I','c','o','n','`',0};
3072 /* for registry stuff */
3075 static const WCHAR szProductLanguage
[] =
3076 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3077 static const WCHAR szARPProductIcon
[] =
3078 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3079 static const WCHAR szProductVersion
[] =
3080 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3084 MSIHANDLE hDb
, hSumInfo
;
3086 /* write out icon files */
3088 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3089 if (rc
== ERROR_SUCCESS
)
3091 MSI_IterateRecords(view
, NULL
, ITERATE_PublishProduct
, package
);
3092 msiobj_release(&view
->hdr
);
3095 /* ok there is a lot more done here but i need to figure out what */
3097 rc
= MSIREG_OpenProductsKey(package
->ProductCode
,&hkey
,TRUE
);
3098 if (rc
!= ERROR_SUCCESS
)
3101 rc
= MSIREG_OpenUserProductsKey(package
->ProductCode
,&hukey
,TRUE
);
3102 if (rc
!= ERROR_SUCCESS
)
3106 buffer
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTNAMEW
);
3107 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3110 langid
= msi_get_property_int( package
, szProductLanguage
, 0 );
3111 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3113 buffer
= msi_dup_property( package
, szARPProductIcon
);
3116 LPWSTR path
= build_icon_path(package
,buffer
);
3117 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3122 buffer
= msi_dup_property( package
, szProductVersion
);
3125 DWORD verdword
= build_version_dword(buffer
);
3126 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3130 /* FIXME: Need to write more keys to the user registry */
3132 hDb
= alloc_msihandle( &package
->db
->hdr
);
3133 rc
= MsiGetSummaryInformationW(hDb
, NULL
, 0, &hSumInfo
);
3134 MsiCloseHandle(hDb
);
3135 if (rc
== ERROR_SUCCESS
)
3137 WCHAR guidbuffer
[0x200];
3139 rc
= MsiSummaryInfoGetPropertyW(hSumInfo
, 9, NULL
, NULL
, NULL
,
3141 if (rc
== ERROR_SUCCESS
)
3143 WCHAR squashed
[GUID_SIZE
];
3144 /* for now we only care about the first guid */
3145 LPWSTR ptr
= strchrW(guidbuffer
,';');
3147 squash_guid(guidbuffer
,squashed
);
3148 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PACKAGECODEW
, squashed
);
3152 ERR("Unable to query Revision_Number...\n");
3155 MsiCloseHandle(hSumInfo
);
3159 ERR("Unable to open Summary Information\n");
3171 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3173 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3174 LPCWSTR component
,section
,key
,value
,identifier
,filename
,dirproperty
;
3175 LPWSTR deformated_section
, deformated_key
, deformated_value
;
3176 LPWSTR folder
, fullname
= NULL
;
3180 static const WCHAR szWindowsFolder
[] =
3181 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3183 component
= MSI_RecordGetString(row
, 8);
3184 comp
= get_loaded_component(package
,component
);
3186 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3188 TRACE("Skipping ini file due to disabled component %s\n",
3189 debugstr_w(component
));
3191 comp
->Action
= comp
->Installed
;
3193 return ERROR_SUCCESS
;
3196 comp
->Action
= INSTALLSTATE_LOCAL
;
3198 identifier
= MSI_RecordGetString(row
,1);
3199 filename
= MSI_RecordGetString(row
,2);
3200 dirproperty
= MSI_RecordGetString(row
,3);
3201 section
= MSI_RecordGetString(row
,4);
3202 key
= MSI_RecordGetString(row
,5);
3203 value
= MSI_RecordGetString(row
,6);
3204 action
= MSI_RecordGetInteger(row
,7);
3206 deformat_string(package
,section
,&deformated_section
);
3207 deformat_string(package
,key
,&deformated_key
);
3208 deformat_string(package
,value
,&deformated_value
);
3212 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, NULL
);
3214 folder
= msi_dup_property( package
, dirproperty
);
3217 folder
= msi_dup_property( package
, szWindowsFolder
);
3221 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
3225 fullname
= build_directory_name(2, folder
, filename
);
3229 TRACE("Adding value %s to section %s in %s\n",
3230 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3231 debugstr_w(fullname
));
3232 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3233 deformated_value
, fullname
);
3235 else if (action
== 1)
3238 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3239 returned
, 10, fullname
);
3240 if (returned
[0] == 0)
3242 TRACE("Adding value %s to section %s in %s\n",
3243 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3244 debugstr_w(fullname
));
3246 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3247 deformated_value
, fullname
);
3250 else if (action
== 3)
3251 FIXME("Append to existing section not yet implemented\n");
3253 uirow
= MSI_CreateRecord(4);
3254 MSI_RecordSetStringW(uirow
,1,identifier
);
3255 MSI_RecordSetStringW(uirow
,2,deformated_section
);
3256 MSI_RecordSetStringW(uirow
,3,deformated_key
);
3257 MSI_RecordSetStringW(uirow
,4,deformated_value
);
3258 ui_actiondata(package
,szWriteIniValues
,uirow
);
3259 msiobj_release( &uirow
->hdr
);
3263 msi_free(deformated_key
);
3264 msi_free(deformated_value
);
3265 msi_free(deformated_section
);
3266 return ERROR_SUCCESS
;
3269 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
3273 static const WCHAR ExecSeqQuery
[] =
3274 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3275 '`','I','n','i','F','i','l','e','`',0};
3277 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3278 if (rc
!= ERROR_SUCCESS
)
3280 TRACE("no IniFile table\n");
3281 return ERROR_SUCCESS
;
3284 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
3285 msiobj_release(&view
->hdr
);
3289 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
3291 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3296 static const WCHAR ExeStr
[] =
3297 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3298 static const WCHAR close
[] = {'\"',0};
3300 PROCESS_INFORMATION info
;
3303 memset(&si
,0,sizeof(STARTUPINFOW
));
3305 filename
= MSI_RecordGetString(row
,1);
3306 file
= get_loaded_file( package
, filename
);
3310 ERR("Unable to find file id %s\n",debugstr_w(filename
));
3311 return ERROR_SUCCESS
;
3314 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
3316 FullName
= msi_alloc(len
*sizeof(WCHAR
));
3317 strcpyW(FullName
,ExeStr
);
3318 strcatW( FullName
, file
->TargetPath
);
3319 strcatW(FullName
,close
);
3321 TRACE("Registering %s\n",debugstr_w(FullName
));
3322 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
3326 msi_dialog_check_messages(info
.hProcess
);
3329 return ERROR_SUCCESS
;
3332 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
3336 static const WCHAR ExecSeqQuery
[] =
3337 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3338 '`','S','e','l','f','R','e','g','`',0};
3340 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3341 if (rc
!= ERROR_SUCCESS
)
3343 TRACE("no SelfReg table\n");
3344 return ERROR_SUCCESS
;
3347 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
3348 msiobj_release(&view
->hdr
);
3350 return ERROR_SUCCESS
;
3353 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
3355 MSIFEATURE
*feature
;
3360 rc
= MSIREG_OpenFeaturesKey(package
->ProductCode
,&hkey
,TRUE
);
3361 if (rc
!= ERROR_SUCCESS
)
3364 rc
= MSIREG_OpenUserFeaturesKey(package
->ProductCode
,&hukey
,TRUE
);
3365 if (rc
!= ERROR_SUCCESS
)
3368 /* here the guids are base 85 encoded */
3369 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
3375 BOOL absent
= FALSE
;
3377 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
) &&
3378 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_SOURCE
) &&
3379 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ADVERTISED
))
3383 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3387 if (feature
->Feature_Parent
)
3388 size
+= strlenW( feature
->Feature_Parent
)+2;
3390 data
= msi_alloc(size
* sizeof(WCHAR
));
3393 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3395 MSICOMPONENT
* component
= cl
->component
;
3398 memset(buf
,0,sizeof(buf
));
3399 if (component
->ComponentId
)
3401 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
3402 CLSIDFromString(component
->ComponentId
, &clsid
);
3403 encode_base85_guid(&clsid
,buf
);
3404 TRACE("to %s\n",debugstr_w(buf
));
3408 if (feature
->Feature_Parent
)
3410 static const WCHAR sep
[] = {'\2',0};
3412 strcatW(data
,feature
->Feature_Parent
);
3415 msi_reg_set_val_str( hkey
, feature
->Feature
, data
);
3419 if (feature
->Feature_Parent
)
3420 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
3423 RegSetValueExW(hukey
,feature
->Feature
,0,REG_SZ
,
3424 (LPBYTE
)feature
->Feature_Parent
,size
);
3428 size
+= 2*sizeof(WCHAR
);
3429 data
= msi_alloc(size
);
3432 if (feature
->Feature_Parent
)
3433 strcpyW( &data
[1], feature
->Feature_Parent
);
3434 RegSetValueExW(hukey
,feature
->Feature
,0,REG_SZ
,
3446 static UINT
msi_make_package_local( MSIPACKAGE
*package
, HKEY hkey
)
3448 static const WCHAR installerPathFmt
[] = {
3449 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3450 static const WCHAR fmt
[] = {
3452 'I','n','s','t','a','l','l','e','r','\\',
3453 '%','x','.','m','s','i',0};
3454 static const WCHAR szOriginalDatabase
[] =
3455 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3456 WCHAR windir
[MAX_PATH
], path
[MAX_PATH
], packagefile
[MAX_PATH
];
3461 /* copy the package locally */
3462 num
= GetTickCount() & 0xffff;
3466 GetWindowsDirectoryW( windir
, MAX_PATH
);
3467 snprintfW( packagefile
, MAX_PATH
, fmt
, windir
, num
);
3470 HANDLE handle
= CreateFileW(packagefile
,GENERIC_WRITE
, 0, NULL
,
3471 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
3472 if (handle
!= INVALID_HANDLE_VALUE
)
3474 CloseHandle(handle
);
3477 if (GetLastError() != ERROR_FILE_EXISTS
&&
3478 GetLastError() != ERROR_SHARING_VIOLATION
)
3480 if (!(++num
& 0xffff)) num
= 1;
3481 sprintfW(packagefile
,fmt
,num
);
3482 } while (num
!= start
);
3484 snprintfW( path
, MAX_PATH
, installerPathFmt
, windir
);
3485 create_full_pathW(path
);
3487 TRACE("Copying to local package %s\n",debugstr_w(packagefile
));
3489 msiFilePath
= msi_dup_property( package
, szOriginalDatabase
);
3490 r
= CopyFileW( msiFilePath
, packagefile
, FALSE
);
3491 msi_free( msiFilePath
);
3495 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3496 debugstr_w(msiFilePath
), debugstr_w(packagefile
), GetLastError());
3497 return ERROR_FUNCTION_FAILED
;
3500 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3501 msi_reg_set_val_str( hkey
, INSTALLPROPERTY_LOCALPACKAGEW
, packagefile
);
3502 return ERROR_SUCCESS
;
3505 static UINT
msi_write_uninstall_property_vals( MSIPACKAGE
*package
, HKEY hkey
)
3507 LPWSTR prop
, val
, key
;
3508 static const LPCSTR propval
[] = {
3509 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3510 "ARPCONTACT", "Contact",
3511 "ARPCOMMENTS", "Comments",
3512 "ProductName", "DisplayName",
3513 "ProductVersion", "DisplayVersion",
3514 "ARPHELPLINK", "HelpLink",
3515 "ARPHELPTELEPHONE", "HelpTelephone",
3516 "ARPINSTALLLOCATION", "InstallLocation",
3517 "SourceDir", "InstallSource",
3518 "Manufacturer", "Publisher",
3519 "ARPREADME", "Readme",
3521 "ARPURLINFOABOUT", "URLInfoAbout",
3522 "ARPURLUPDATEINFO", "URLUpdateInfo",
3525 const LPCSTR
*p
= propval
;
3529 prop
= strdupAtoW( *p
++ );
3530 key
= strdupAtoW( *p
++ );
3531 val
= msi_dup_property( package
, prop
);
3532 msi_reg_set_val_str( hkey
, key
, val
);
3537 return ERROR_SUCCESS
;
3540 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
3543 LPWSTR buffer
= NULL
;
3546 static const WCHAR szWindowsInstaller
[] =
3547 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3548 static const WCHAR szUpgradeCode
[] =
3549 {'U','p','g','r','a','d','e','C','o','d','e',0};
3550 static const WCHAR modpath_fmt
[] =
3551 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3552 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3553 static const WCHAR szModifyPath
[] =
3554 {'M','o','d','i','f','y','P','a','t','h',0};
3555 static const WCHAR szUninstallString
[] =
3556 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3557 static const WCHAR szEstimatedSize
[] =
3558 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3559 static const WCHAR szProductLanguage
[] =
3560 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3561 static const WCHAR szProductVersion
[] =
3562 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3565 static const WCHAR date_fmt
[] = {'%','i','%','i','%','i',0};
3566 LPWSTR upgrade_code
;
3569 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
,&hkey
,TRUE
);
3570 if (rc
!= ERROR_SUCCESS
)
3573 /* dump all the info i can grab */
3574 /* FIXME: Flesh out more information */
3576 msi_write_uninstall_property_vals( package
, hkey
);
3578 msi_reg_set_val_dword( hkey
, szWindowsInstaller
, 1 );
3580 msi_make_package_local( package
, hkey
);
3582 /* do ModifyPath and UninstallString */
3583 size
= deformat_string(package
,modpath_fmt
,&buffer
);
3584 RegSetValueExW(hkey
,szModifyPath
,0,REG_EXPAND_SZ
,(LPBYTE
)buffer
,size
);
3585 RegSetValueExW(hkey
,szUninstallString
,0,REG_EXPAND_SZ
,(LPBYTE
)buffer
,size
);
3588 /* FIXME: Write real Estimated Size when we have it */
3589 msi_reg_set_val_dword( hkey
, szEstimatedSize
, 0 );
3591 GetLocalTime(&systime
);
3592 sprintfW(szDate
,date_fmt
,systime
.wYear
,systime
.wMonth
,systime
.wDay
);
3593 msi_reg_set_val_str( hkey
, INSTALLPROPERTY_INSTALLDATEW
, szDate
);
3595 langid
= msi_get_property_int( package
, szProductLanguage
, 0 );
3596 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3598 buffer
= msi_dup_property( package
, szProductVersion
);
3601 DWORD verdword
= build_version_dword(buffer
);
3603 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3604 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>>24 );
3605 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>>16)&0x00FF );
3609 /* Handle Upgrade Codes */
3610 upgrade_code
= msi_dup_property( package
, szUpgradeCode
);
3615 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &hkey2
, TRUE
);
3616 squash_guid(package
->ProductCode
,squashed
);
3617 msi_reg_set_val_str( hkey2
, squashed
, NULL
);
3619 MSIREG_OpenUserUpgradeCodesKey(upgrade_code
, &hkey2
, TRUE
);
3620 squash_guid(package
->ProductCode
,squashed
);
3621 msi_reg_set_val_str( hkey2
, squashed
, NULL
);
3624 msi_free(upgrade_code
);
3629 return ERROR_SUCCESS
;
3632 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
3634 return execute_script(package
,INSTALL_SCRIPT
);
3637 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
3641 /* turn off scheduleing */
3642 package
->script
->CurrentlyScripting
= FALSE
;
3644 /* first do the same as an InstallExecute */
3645 rc
= ACTION_InstallExecute(package
);
3646 if (rc
!= ERROR_SUCCESS
)
3649 /* then handle Commit Actions */
3650 rc
= execute_script(package
,COMMIT_SCRIPT
);
3655 static UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
3657 static const WCHAR RunOnce
[] = {
3658 'S','o','f','t','w','a','r','e','\\',
3659 'M','i','c','r','o','s','o','f','t','\\',
3660 'W','i','n','d','o','w','s','\\',
3661 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3662 'R','u','n','O','n','c','e',0};
3663 static const WCHAR InstallRunOnce
[] = {
3664 'S','o','f','t','w','a','r','e','\\',
3665 'M','i','c','r','o','s','o','f','t','\\',
3666 'W','i','n','d','o','w','s','\\',
3667 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3668 'I','n','s','t','a','l','l','e','r','\\',
3669 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3671 static const WCHAR msiexec_fmt
[] = {
3673 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3674 '\"','%','s','\"',0};
3675 static const WCHAR install_fmt
[] = {
3676 '/','I',' ','\"','%','s','\"',' ',
3677 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3678 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3679 WCHAR buffer
[256], sysdir
[MAX_PATH
];
3681 WCHAR squished_pc
[100];
3683 squash_guid(package
->ProductCode
,squished_pc
);
3685 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
3686 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
3687 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
3690 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
3693 TRACE("Reboot command %s\n",debugstr_w(buffer
));
3695 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
3696 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
3698 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
3701 return ERROR_INSTALL_SUSPEND
;
3704 UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
3709 * we are currently doing what should be done here in the top level Install
3710 * however for Adminastrative and uninstalls this step will be needed
3712 if (!package
->PackagePath
)
3713 return ERROR_SUCCESS
;
3715 attrib
= GetFileAttributesW(package
->PackagePath
);
3716 if (attrib
== INVALID_FILE_ATTRIBUTES
)
3722 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
3723 MSIINSTALLCONTEXT_USERMANAGED
, MSICODE_PRODUCT
,
3724 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
3725 if (rc
== ERROR_MORE_DATA
)
3727 prompt
= msi_alloc(size
* sizeof(WCHAR
));
3728 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
3729 MSIINSTALLCONTEXT_USERMANAGED
, MSICODE_PRODUCT
,
3730 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
3733 prompt
= strdupW(package
->PackagePath
);
3735 msg
= generate_error_string(package
,1302,1,prompt
);
3736 while(attrib
== INVALID_FILE_ATTRIBUTES
)
3738 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
3741 rc
= ERROR_INSTALL_USEREXIT
;
3744 attrib
= GetFileAttributesW(package
->PackagePath
);
3750 return ERROR_SUCCESS
;
3755 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
3762 static const WCHAR szPropKeys
[][80] =
3764 {'P','r','o','d','u','c','t','I','D',0},
3765 {'U','S','E','R','N','A','M','E',0},
3766 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3770 static const WCHAR szRegKeys
[][80] =
3772 {'P','r','o','d','u','c','t','I','D',0},
3773 {'R','e','g','O','w','n','e','r',0},
3774 {'R','e','g','C','o','m','p','a','n','y',0},
3778 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
3780 return ERROR_SUCCESS
;
3782 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
,&hkey
,TRUE
);
3783 if (rc
!= ERROR_SUCCESS
)
3786 for( i
= 0; szPropKeys
[i
][0]; i
++ )
3788 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
3789 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
3794 msi_free(productid
);
3797 return ERROR_SUCCESS
;
3801 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
3805 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
3806 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
3812 * Code based off of code located here
3813 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3815 * Using string index 4 (full font name) instead of 1 (family name)
3817 static LPWSTR
load_ttfname_from(LPCWSTR filename
)
3823 typedef struct _tagTT_OFFSET_TABLE
{
3824 USHORT uMajorVersion
;
3825 USHORT uMinorVersion
;
3826 USHORT uNumOfTables
;
3827 USHORT uSearchRange
;
3828 USHORT uEntrySelector
;
3832 typedef struct _tagTT_TABLE_DIRECTORY
{
3833 char szTag
[4]; /* table name */
3834 ULONG uCheckSum
; /* Check sum */
3835 ULONG uOffset
; /* Offset from beginning of file */
3836 ULONG uLength
; /* length of the table in bytes */
3837 }TT_TABLE_DIRECTORY
;
3839 typedef struct _tagTT_NAME_TABLE_HEADER
{
3840 USHORT uFSelector
; /* format selector. Always 0 */
3841 USHORT uNRCount
; /* Name Records count */
3842 USHORT uStorageOffset
; /* Offset for strings storage,
3843 * from start of the table */
3844 }TT_NAME_TABLE_HEADER
;
3846 typedef struct _tagTT_NAME_RECORD
{
3851 USHORT uStringLength
;
3852 USHORT uStringOffset
; /* from start of storage area */
3855 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3856 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3858 handle
= CreateFileW(filename
,GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
3859 FILE_ATTRIBUTE_NORMAL
, 0 );
3860 if (handle
!= INVALID_HANDLE_VALUE
)
3862 TT_TABLE_DIRECTORY tblDir
;
3863 BOOL bFound
= FALSE
;
3864 TT_OFFSET_TABLE ttOffsetTable
;
3867 ReadFile(handle
,&ttOffsetTable
, sizeof(TT_OFFSET_TABLE
),&dwRead
,NULL
);
3868 ttOffsetTable
.uNumOfTables
= SWAPWORD(ttOffsetTable
.uNumOfTables
);
3869 ttOffsetTable
.uMajorVersion
= SWAPWORD(ttOffsetTable
.uMajorVersion
);
3870 ttOffsetTable
.uMinorVersion
= SWAPWORD(ttOffsetTable
.uMinorVersion
);
3872 if (ttOffsetTable
.uMajorVersion
!= 1 ||
3873 ttOffsetTable
.uMinorVersion
!= 0)
3876 for (i
=0; i
< ttOffsetTable
.uNumOfTables
; i
++)
3878 ReadFile(handle
,&tblDir
, sizeof(TT_TABLE_DIRECTORY
),&dwRead
,NULL
);
3879 if (strncmp(tblDir
.szTag
,"name",4)==0)
3882 tblDir
.uLength
= SWAPLONG(tblDir
.uLength
);
3883 tblDir
.uOffset
= SWAPLONG(tblDir
.uOffset
);
3890 TT_NAME_TABLE_HEADER ttNTHeader
;
3891 TT_NAME_RECORD ttRecord
;
3893 SetFilePointer(handle
, tblDir
.uOffset
, NULL
, FILE_BEGIN
);
3894 ReadFile(handle
,&ttNTHeader
, sizeof(TT_NAME_TABLE_HEADER
),
3897 ttNTHeader
.uNRCount
= SWAPWORD(ttNTHeader
.uNRCount
);
3898 ttNTHeader
.uStorageOffset
= SWAPWORD(ttNTHeader
.uStorageOffset
);
3900 for(i
=0; i
<ttNTHeader
.uNRCount
; i
++)
3902 ReadFile(handle
,&ttRecord
, sizeof(TT_NAME_RECORD
),&dwRead
,NULL
);
3903 ttRecord
.uNameID
= SWAPWORD(ttRecord
.uNameID
);
3904 /* 4 is the Full Font Name */
3905 if(ttRecord
.uNameID
== 4)
3909 static LPCSTR tt
= " (TrueType)";
3911 ttRecord
.uStringLength
= SWAPWORD(ttRecord
.uStringLength
);
3912 ttRecord
.uStringOffset
= SWAPWORD(ttRecord
.uStringOffset
);
3913 nPos
= SetFilePointer(handle
, 0, NULL
, FILE_CURRENT
);
3914 SetFilePointer(handle
, tblDir
.uOffset
+
3915 ttRecord
.uStringOffset
+
3916 ttNTHeader
.uStorageOffset
,
3918 buf
= msi_alloc( ttRecord
.uStringLength
+ 1 + strlen(tt
) );
3919 memset(buf
, 0, ttRecord
.uStringLength
+ 1 + strlen(tt
));
3920 ReadFile(handle
, buf
, ttRecord
.uStringLength
, &dwRead
, NULL
);
3921 if (strlen(buf
) > 0)
3924 ret
= strdupAtoW(buf
);
3930 SetFilePointer(handle
,nPos
, NULL
, FILE_BEGIN
);
3934 CloseHandle(handle
);
3937 ERR("Unable to open font file %s\n", debugstr_w(filename
));
3939 TRACE("Returning fontname %s\n",debugstr_w(ret
));
3943 static UINT
ITERATE_RegisterFonts(MSIRECORD
*row
, LPVOID param
)
3945 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3949 static const WCHAR regfont1
[] =
3950 {'S','o','f','t','w','a','r','e','\\',
3951 'M','i','c','r','o','s','o','f','t','\\',
3952 'W','i','n','d','o','w','s',' ','N','T','\\',
3953 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3954 'F','o','n','t','s',0};
3955 static const WCHAR regfont2
[] =
3956 {'S','o','f','t','w','a','r','e','\\',
3957 'M','i','c','r','o','s','o','f','t','\\',
3958 'W','i','n','d','o','w','s','\\',
3959 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3960 'F','o','n','t','s',0};
3964 filename
= MSI_RecordGetString( row
, 1 );
3965 file
= get_loaded_file( package
, filename
);
3968 ERR("Unable to load file\n");
3969 return ERROR_SUCCESS
;
3972 /* check to make sure that component is installed */
3973 if (!ACTION_VerifyComponentForAction( file
->Component
, INSTALLSTATE_LOCAL
))
3975 TRACE("Skipping: Component not scheduled for install\n");
3976 return ERROR_SUCCESS
;
3979 RegCreateKeyW(HKEY_LOCAL_MACHINE
,regfont1
,&hkey1
);
3980 RegCreateKeyW(HKEY_LOCAL_MACHINE
,regfont2
,&hkey2
);
3982 if (MSI_RecordIsNull(row
,2))
3983 name
= load_ttfname_from( file
->TargetPath
);
3985 name
= msi_dup_record_field(row
,2);
3989 msi_reg_set_val_str( hkey1
, name
, file
->FileName
);
3990 msi_reg_set_val_str( hkey2
, name
, file
->FileName
);
3996 return ERROR_SUCCESS
;
3999 static UINT
ACTION_RegisterFonts(MSIPACKAGE
*package
)
4003 static const WCHAR ExecSeqQuery
[] =
4004 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4005 '`','F','o','n','t','`',0};
4007 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4008 if (rc
!= ERROR_SUCCESS
)
4010 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc
);
4011 return ERROR_SUCCESS
;
4014 MSI_IterateRecords(view
, NULL
, ITERATE_RegisterFonts
, package
);
4015 msiobj_release(&view
->hdr
);
4017 return ERROR_SUCCESS
;
4020 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4022 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4023 LPCWSTR compgroupid
=NULL
;
4024 LPCWSTR feature
=NULL
;
4025 LPCWSTR text
= NULL
;
4026 LPCWSTR qualifier
= NULL
;
4027 LPCWSTR component
= NULL
;
4028 LPWSTR advertise
= NULL
;
4029 LPWSTR output
= NULL
;
4031 UINT rc
= ERROR_SUCCESS
;
4035 component
= MSI_RecordGetString(rec
,3);
4036 comp
= get_loaded_component(package
,component
);
4038 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) &&
4039 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
) &&
4040 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ADVERTISED
))
4042 TRACE("Skipping: Component %s not scheduled for install\n",
4043 debugstr_w(component
));
4045 return ERROR_SUCCESS
;
4048 compgroupid
= MSI_RecordGetString(rec
,1);
4050 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
4051 if (rc
!= ERROR_SUCCESS
)
4054 text
= MSI_RecordGetString(rec
,4);
4055 qualifier
= MSI_RecordGetString(rec
,2);
4056 feature
= MSI_RecordGetString(rec
,5);
4058 advertise
= create_component_advertise_string(package
, comp
, feature
);
4060 sz
= strlenW(advertise
);
4063 sz
+= lstrlenW(text
);
4066 sz
*= sizeof(WCHAR
);
4068 output
= msi_alloc(sz
);
4069 memset(output
,0,sz
);
4070 strcpyW(output
,advertise
);
4071 msi_free(advertise
);
4074 strcatW(output
,text
);
4076 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
4086 * At present I am ignorning the advertised components part of this and only
4087 * focusing on the qualified component sets
4089 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
4093 static const WCHAR ExecSeqQuery
[] =
4094 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4095 '`','P','u','b','l','i','s','h',
4096 'C','o','m','p','o','n','e','n','t','`',0};
4098 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4099 if (rc
!= ERROR_SUCCESS
)
4100 return ERROR_SUCCESS
;
4102 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
4103 msiobj_release(&view
->hdr
);
4108 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
4109 LPCSTR action
, LPCWSTR table
)
4111 static const WCHAR query
[] = {
4112 'S','E','L','E','C','T',' ','*',' ',
4113 'F','R','O','M',' ','`','%','s','`',0 };
4114 MSIQUERY
*view
= NULL
;
4118 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
4119 if (r
== ERROR_SUCCESS
)
4121 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
4122 msiobj_release(&view
->hdr
);
4126 FIXME("%s -> %lu ignored %s table values\n",
4127 action
, count
, debugstr_w(table
));
4129 return ERROR_SUCCESS
;
4132 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
4134 TRACE("%p\n", package
);
4135 return ERROR_SUCCESS
;
4138 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
4140 static const WCHAR table
[] =
4141 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4142 return msi_unimplemented_action_stub( package
, "RemoveIniValues", table
);
4145 static UINT
ACTION_MoveFiles( MSIPACKAGE
*package
)
4147 static const WCHAR table
[] = { 'M','o','v','e','F','i','l','e',0 };
4148 return msi_unimplemented_action_stub( package
, "MoveFiles", table
);
4151 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
4153 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
4154 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
4157 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
4159 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
4160 return msi_unimplemented_action_stub( package
, "BindImage", table
);
4163 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
4165 static const WCHAR table
[] = {
4166 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4167 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
4170 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
4172 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
4173 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
4176 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
4178 static const WCHAR table
[] = { 'S','e','l','f','R','e','g',0 };
4179 return msi_unimplemented_action_stub( package
, "SelfUnregModules", table
);
4182 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
4184 static const WCHAR table
[] = {
4185 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4186 return msi_unimplemented_action_stub( package
, "InstallServices", table
);
4189 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
4191 static const WCHAR table
[] = {
4192 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4193 return msi_unimplemented_action_stub( package
, "StartServices", table
);
4196 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
4198 static const WCHAR table
[] = {
4199 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4200 return msi_unimplemented_action_stub( package
, "StopServices", table
);
4203 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
4205 static const WCHAR table
[] = {
4206 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4207 return msi_unimplemented_action_stub( package
, "DeleteServices", table
);
4210 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
4212 static const WCHAR table
[] = {
4213 'E','n','v','i','r','o','n','m','e','n','t',0 };
4214 return msi_unimplemented_action_stub( package
, "WriteEnvironmentStrings", table
);
4217 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
4219 static const WCHAR table
[] = {
4220 'E','n','v','i','r','o','n','m','e','n','t',0 };
4221 return msi_unimplemented_action_stub( package
, "RemoveEnvironmentStrings", table
);
4224 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
4226 static const WCHAR table
[] = {
4227 'M','s','i','A','s','s','e','m','b','l','y',0 };
4228 return msi_unimplemented_action_stub( package
, "MsiPublishAssemblies", table
);
4231 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
4233 static const WCHAR table
[] = {
4234 'M','s','i','A','s','s','e','m','b','l','y',0 };
4235 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
4238 static UINT
ACTION_UnregisterFonts( MSIPACKAGE
*package
)
4240 static const WCHAR table
[] = { 'F','o','n','t',0 };
4241 return msi_unimplemented_action_stub( package
, "UnregisterFonts", table
);
4244 static UINT
ACTION_CCPSearch( MSIPACKAGE
*package
)
4246 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
4247 return msi_unimplemented_action_stub( package
, "CCPSearch", table
);
4250 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
4252 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
4253 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
4256 static struct _actions StandardActions
[] = {
4257 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
4258 { szAppSearch
, ACTION_AppSearch
},
4259 { szBindImage
, ACTION_BindImage
},
4260 { szCCPSearch
, ACTION_CCPSearch
},
4261 { szCostFinalize
, ACTION_CostFinalize
},
4262 { szCostInitialize
, ACTION_CostInitialize
},
4263 { szCreateFolders
, ACTION_CreateFolders
},
4264 { szCreateShortcuts
, ACTION_CreateShortcuts
},
4265 { szDeleteServices
, ACTION_DeleteServices
},
4266 { szDisableRollback
, NULL
},
4267 { szDuplicateFiles
, ACTION_DuplicateFiles
},
4268 { szExecuteAction
, ACTION_ExecuteAction
},
4269 { szFileCost
, ACTION_FileCost
},
4270 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
4271 { szForceReboot
, ACTION_ForceReboot
},
4272 { szInstallAdminPackage
, NULL
},
4273 { szInstallExecute
, ACTION_InstallExecute
},
4274 { szInstallExecuteAgain
, ACTION_InstallExecute
},
4275 { szInstallFiles
, ACTION_InstallFiles
},
4276 { szInstallFinalize
, ACTION_InstallFinalize
},
4277 { szInstallInitialize
, ACTION_InstallInitialize
},
4278 { szInstallSFPCatalogFile
, NULL
},
4279 { szInstallValidate
, ACTION_InstallValidate
},
4280 { szIsolateComponents
, ACTION_IsolateComponents
},
4281 { szLaunchConditions
, ACTION_LaunchConditions
},
4282 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
4283 { szMoveFiles
, ACTION_MoveFiles
},
4284 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
4285 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
4286 { szInstallODBC
, NULL
},
4287 { szInstallServices
, ACTION_InstallServices
},
4288 { szPatchFiles
, ACTION_PatchFiles
},
4289 { szProcessComponents
, ACTION_ProcessComponents
},
4290 { szPublishComponents
, ACTION_PublishComponents
},
4291 { szPublishFeatures
, ACTION_PublishFeatures
},
4292 { szPublishProduct
, ACTION_PublishProduct
},
4293 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
4294 { szRegisterComPlus
, NULL
},
4295 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
4296 { szRegisterFonts
, ACTION_RegisterFonts
},
4297 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
4298 { szRegisterProduct
, ACTION_RegisterProduct
},
4299 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
4300 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
4301 { szRegisterUser
, ACTION_RegisterUser
},
4302 { szRemoveDuplicateFiles
, NULL
},
4303 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
4304 { szRemoveExistingProducts
, NULL
},
4305 { szRemoveFiles
, ACTION_RemoveFiles
},
4306 { szRemoveFolders
, NULL
},
4307 { szRemoveIniValues
, ACTION_RemoveIniValues
},
4308 { szRemoveODBC
, NULL
},
4309 { szRemoveRegistryValues
, NULL
},
4310 { szRemoveShortcuts
, NULL
},
4311 { szResolveSource
, ACTION_ResolveSource
},
4312 { szRMCCPSearch
, ACTION_RMCCPSearch
},
4313 { szScheduleReboot
, NULL
},
4314 { szSelfRegModules
, ACTION_SelfRegModules
},
4315 { szSelfUnregModules
, ACTION_SelfUnregModules
},
4316 { szSetODBCFolders
, NULL
},
4317 { szStartServices
, ACTION_StartServices
},
4318 { szStopServices
, ACTION_StopServices
},
4319 { szUnpublishComponents
, NULL
},
4320 { szUnpublishFeatures
, NULL
},
4321 { szUnregisterClassInfo
, NULL
},
4322 { szUnregisterComPlus
, NULL
},
4323 { szUnregisterExtensionInfo
, NULL
},
4324 { szUnregisterFonts
, ACTION_UnregisterFonts
},
4325 { szUnregisterMIMEInfo
, NULL
},
4326 { szUnregisterProgIdInfo
, NULL
},
4327 { szUnregisterTypeLibraries
, NULL
},
4328 { szValidateProductID
, NULL
},
4329 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
4330 { szWriteIniValues
, ACTION_WriteIniValues
},
4331 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},