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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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
39 #include "wine/debug.h"
44 #include "wine/unicode.h"
47 #define REG_PROGRESS_VALUE 13200
48 #define COMPONENT_PROGRESS_VALUE 24000
50 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
55 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
);
56 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
);
57 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
);
60 * consts and values used
62 static const WCHAR c_colon
[] = {'C',':','\\',0};
64 static const WCHAR szCreateFolders
[] =
65 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
66 static const WCHAR szCostFinalize
[] =
67 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
68 const WCHAR szInstallFiles
[] =
69 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
70 const WCHAR szDuplicateFiles
[] =
71 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
72 static const WCHAR szWriteRegistryValues
[] =
73 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
74 'V','a','l','u','e','s',0};
75 static const WCHAR szCostInitialize
[] =
76 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
77 static const WCHAR szFileCost
[] =
78 {'F','i','l','e','C','o','s','t',0};
79 static const WCHAR szInstallInitialize
[] =
80 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
81 static const WCHAR szInstallValidate
[] =
82 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
83 static const WCHAR szLaunchConditions
[] =
84 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
85 static const WCHAR szProcessComponents
[] =
86 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
87 static const WCHAR szRegisterTypeLibraries
[] =
88 {'R','e','g','i','s','t','e','r','T','y','p','e',
89 'L','i','b','r','a','r','i','e','s',0};
90 const WCHAR szRegisterClassInfo
[] =
91 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
92 const WCHAR szRegisterProgIdInfo
[] =
93 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
94 static const WCHAR szCreateShortcuts
[] =
95 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
96 static const WCHAR szPublishProduct
[] =
97 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
98 static const WCHAR szWriteIniValues
[] =
99 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
100 static const WCHAR szSelfRegModules
[] =
101 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
102 static const WCHAR szPublishFeatures
[] =
103 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
104 static const WCHAR szRegisterProduct
[] =
105 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
106 static const WCHAR szInstallExecute
[] =
107 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
108 static const WCHAR szInstallExecuteAgain
[] =
109 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
110 'A','g','a','i','n',0};
111 static const WCHAR szInstallFinalize
[] =
112 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
113 static const WCHAR szForceReboot
[] =
114 {'F','o','r','c','e','R','e','b','o','o','t',0};
115 static const WCHAR szResolveSource
[] =
116 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
117 static const WCHAR szAppSearch
[] =
118 {'A','p','p','S','e','a','r','c','h',0};
119 static const WCHAR szAllocateRegistrySpace
[] =
120 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
121 'S','p','a','c','e',0};
122 static const WCHAR szBindImage
[] =
123 {'B','i','n','d','I','m','a','g','e',0};
124 static const WCHAR szCCPSearch
[] =
125 {'C','C','P','S','e','a','r','c','h',0};
126 static const WCHAR szDeleteServices
[] =
127 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
128 static const WCHAR szDisableRollback
[] =
129 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
130 static const WCHAR szExecuteAction
[] =
131 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
132 const WCHAR szFindRelatedProducts
[] =
133 {'F','i','n','d','R','e','l','a','t','e','d',
134 'P','r','o','d','u','c','t','s',0};
135 static const WCHAR szInstallAdminPackage
[] =
136 {'I','n','s','t','a','l','l','A','d','m','i','n',
137 'P','a','c','k','a','g','e',0};
138 static const WCHAR szInstallSFPCatalogFile
[] =
139 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
141 static const WCHAR szIsolateComponents
[] =
142 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
143 const WCHAR szMigrateFeatureStates
[] =
144 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
145 'S','t','a','t','e','s',0};
146 const WCHAR szMoveFiles
[] =
147 {'M','o','v','e','F','i','l','e','s',0};
148 static const WCHAR szMsiPublishAssemblies
[] =
149 {'M','s','i','P','u','b','l','i','s','h',
150 'A','s','s','e','m','b','l','i','e','s',0};
151 static const WCHAR szMsiUnpublishAssemblies
[] =
152 {'M','s','i','U','n','p','u','b','l','i','s','h',
153 'A','s','s','e','m','b','l','i','e','s',0};
154 static const WCHAR szInstallODBC
[] =
155 {'I','n','s','t','a','l','l','O','D','B','C',0};
156 static const WCHAR szInstallServices
[] =
157 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
158 const WCHAR szPatchFiles
[] =
159 {'P','a','t','c','h','F','i','l','e','s',0};
160 static const WCHAR szPublishComponents
[] =
161 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
162 static const WCHAR szRegisterComPlus
[] =
163 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
164 const WCHAR szRegisterExtensionInfo
[] =
165 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
167 static const WCHAR szRegisterFonts
[] =
168 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
169 const WCHAR szRegisterMIMEInfo
[] =
170 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
171 static const WCHAR szRegisterUser
[] =
172 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
173 const WCHAR szRemoveDuplicateFiles
[] =
174 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
175 'F','i','l','e','s',0};
176 static const WCHAR szRemoveEnvironmentStrings
[] =
177 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
178 'S','t','r','i','n','g','s',0};
179 const WCHAR szRemoveExistingProducts
[] =
180 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
181 'P','r','o','d','u','c','t','s',0};
182 const WCHAR szRemoveFiles
[] =
183 {'R','e','m','o','v','e','F','i','l','e','s',0};
184 static const WCHAR szRemoveFolders
[] =
185 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
186 static const WCHAR szRemoveIniValues
[] =
187 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
188 static const WCHAR szRemoveODBC
[] =
189 {'R','e','m','o','v','e','O','D','B','C',0};
190 static const WCHAR szRemoveRegistryValues
[] =
191 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
192 'V','a','l','u','e','s',0};
193 static const WCHAR szRemoveShortcuts
[] =
194 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
195 static const WCHAR szRMCCPSearch
[] =
196 {'R','M','C','C','P','S','e','a','r','c','h',0};
197 static const WCHAR szScheduleReboot
[] =
198 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
199 static const WCHAR szSelfUnregModules
[] =
200 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
201 static const WCHAR szSetODBCFolders
[] =
202 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
203 static const WCHAR szStartServices
[] =
204 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
205 static const WCHAR szStopServices
[] =
206 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
207 static const WCHAR szUnpublishComponents
[] =
208 {'U','n','p','u','b','l','i','s','h',
209 'C','o','m','p','o','n','e','n','t','s',0};
210 static const WCHAR szUnpublishFeatures
[] =
211 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
212 const WCHAR szUnregisterClassInfo
[] =
213 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
215 static const WCHAR szUnregisterComPlus
[] =
216 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
217 const WCHAR szUnregisterExtensionInfo
[] =
218 {'U','n','r','e','g','i','s','t','e','r',
219 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
220 static const WCHAR szUnregisterFonts
[] =
221 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
222 const WCHAR szUnregisterMIMEInfo
[] =
223 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
224 const WCHAR szUnregisterProgIdInfo
[] =
225 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
227 static const WCHAR szUnregisterTypeLibraries
[] =
228 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
229 'L','i','b','r','a','r','i','e','s',0};
230 static const WCHAR szValidateProductID
[] =
231 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
232 static const WCHAR szWriteEnvironmentStrings
[] =
233 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
234 'S','t','r','i','n','g','s',0};
236 /* action handlers */
237 typedef UINT (*STANDARDACTIONHANDLER
)(MSIPACKAGE
*);
241 STANDARDACTIONHANDLER handler
;
244 static const struct _actions StandardActions
[];
247 /********************************************************
249 ********************************************************/
251 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
253 static const WCHAR Query_t
[] =
254 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
255 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
256 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
257 ' ','\'','%','s','\'',0};
260 row
= MSI_QueryGetRecord( package
->db
, Query_t
, action
);
263 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
264 msiobj_release(&row
->hdr
);
267 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
271 static const WCHAR template_s
[]=
272 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
274 static const WCHAR template_e
[]=
275 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
276 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
278 static const WCHAR format
[] =
279 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
283 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
285 sprintfW(message
,template_s
,timet
,action
);
287 sprintfW(message
,template_e
,timet
,action
,rc
);
289 row
= MSI_CreateRecord(1);
290 MSI_RecordSetStringW(row
,1,message
);
292 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
293 msiobj_release(&row
->hdr
);
296 static UINT
msi_parse_command_line( MSIPACKAGE
*package
, LPCWSTR szCommandLine
)
301 LPWSTR prop
= NULL
, val
= NULL
;
304 return ERROR_SUCCESS
;
316 TRACE("Looking at %s\n",debugstr_w(ptr
));
318 ptr2
= strchrW(ptr
,'=');
321 ERR("command line contains unknown string : %s\n", debugstr_w(ptr
));
328 prop
= msi_alloc((len
+1)*sizeof(WCHAR
));
329 memcpy(prop
,ptr
,len
*sizeof(WCHAR
));
335 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
348 val
= msi_alloc((len
+1)*sizeof(WCHAR
));
349 memcpy(val
,ptr2
,len
*sizeof(WCHAR
));
352 if (lstrlenW(prop
) > 0)
354 TRACE("Found commandline property (%s) = (%s)\n",
355 debugstr_w(prop
), debugstr_w(val
));
356 MSI_SetPropertyW(package
,prop
,val
);
362 return ERROR_SUCCESS
;
366 static LPWSTR
* msi_split_string( LPCWSTR str
, WCHAR sep
)
369 LPWSTR p
, *ret
= NULL
;
375 /* count the number of substrings */
376 for ( pc
= str
, count
= 0; pc
; count
++ )
378 pc
= strchrW( pc
, sep
);
383 /* allocate space for an array of substring pointers and the substrings */
384 ret
= msi_alloc( (count
+1) * sizeof (LPWSTR
) +
385 (lstrlenW(str
)+1) * sizeof(WCHAR
) );
389 /* copy the string and set the pointers */
390 p
= (LPWSTR
) &ret
[count
+1];
392 for( count
= 0; (ret
[count
] = p
); count
++ )
394 p
= strchrW( p
, sep
);
402 static UINT
msi_check_transform_applicable( MSIPACKAGE
*package
, IStorage
*patch
)
404 WCHAR szProductCode
[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
405 LPWSTR prod_code
, patch_product
;
408 prod_code
= msi_dup_property( package
, szProductCode
);
409 patch_product
= msi_get_suminfo_product( patch
);
411 TRACE("db = %s patch = %s\n", debugstr_w(prod_code
), debugstr_w(patch_product
));
413 if ( strstrW( patch_product
, prod_code
) )
416 ret
= ERROR_FUNCTION_FAILED
;
418 msi_free( patch_product
);
419 msi_free( prod_code
);
424 static UINT
msi_apply_substorage_transform( MSIPACKAGE
*package
,
425 MSIDATABASE
*patch_db
, LPCWSTR name
)
427 UINT ret
= ERROR_FUNCTION_FAILED
;
428 IStorage
*stg
= NULL
;
431 TRACE("%p %s\n", package
, debugstr_w(name
) );
435 ERR("expected a colon in %s\n", debugstr_w(name
));
436 return ERROR_FUNCTION_FAILED
;
439 r
= IStorage_OpenStorage( patch_db
->storage
, name
, NULL
, STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
442 ret
= msi_check_transform_applicable( package
, stg
);
443 if (ret
== ERROR_SUCCESS
)
444 msi_table_apply_transform( package
->db
, stg
);
446 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name
));
447 IStorage_Release( stg
);
450 ERR("failed to open substorage %s\n", debugstr_w(name
));
452 return ERROR_SUCCESS
;
455 static UINT
msi_check_patch_applicable( MSIPACKAGE
*package
, MSISUMMARYINFO
*si
)
457 static const WCHAR szProdID
[] = { 'P','r','o','d','u','c','t','I','D',0 };
458 LPWSTR guid_list
, *guids
, product_id
;
459 UINT i
, ret
= ERROR_FUNCTION_FAILED
;
461 product_id
= msi_dup_property( package
, szProdID
);
464 /* FIXME: the property ProductID should be written into the DB somewhere */
465 ERR("no product ID to check\n");
466 return ERROR_SUCCESS
;
469 guid_list
= msi_suminfo_dup_string( si
, PID_TEMPLATE
);
470 guids
= msi_split_string( guid_list
, ';' );
471 for ( i
= 0; guids
[i
] && ret
!= ERROR_SUCCESS
; i
++ )
473 if (!lstrcmpW( guids
[i
], product_id
))
477 msi_free( guid_list
);
478 msi_free( product_id
);
483 static UINT
msi_parse_patch_summary( MSIPACKAGE
*package
, MSIDATABASE
*patch_db
)
486 LPWSTR str
, *substorage
;
487 UINT i
, r
= ERROR_SUCCESS
;
489 si
= MSI_GetSummaryInformationW( patch_db
->storage
, 0 );
491 return ERROR_FUNCTION_FAILED
;
493 msi_check_patch_applicable( package
, si
);
495 /* enumerate the substorage */
496 str
= msi_suminfo_dup_string( si
, PID_LASTAUTHOR
);
497 substorage
= msi_split_string( str
, ';' );
498 for ( i
= 0; substorage
&& substorage
[i
] && r
== ERROR_SUCCESS
; i
++ )
499 r
= msi_apply_substorage_transform( package
, patch_db
, substorage
[i
] );
500 msi_free( substorage
);
503 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
505 msiobj_release( &si
->hdr
);
510 static UINT
msi_apply_patch_package( MSIPACKAGE
*package
, LPCWSTR file
)
512 MSIDATABASE
*patch_db
= NULL
;
515 TRACE("%p %s\n", package
, debugstr_w( file
) );
518 * We probably want to make sure we only open a patch collection here.
519 * Patch collections (.msp) and databases (.msi) have different GUIDs
520 * but currently MSI_OpenDatabaseW will accept both.
522 r
= MSI_OpenDatabaseW( file
, MSIDBOPEN_READONLY
, &patch_db
);
523 if ( r
!= ERROR_SUCCESS
)
525 ERR("failed to open patch collection %s\n", debugstr_w( file
) );
529 msi_parse_patch_summary( package
, patch_db
);
532 * There might be a CAB file in the patch package,
533 * so append it to the list of storage to search for streams.
535 append_storage_to_db( package
->db
, patch_db
->storage
);
537 msiobj_release( &patch_db
->hdr
);
539 return ERROR_SUCCESS
;
542 /* get the PATCH property, and apply all the patches it specifies */
543 static UINT
msi_apply_patches( MSIPACKAGE
*package
)
545 static const WCHAR szPatch
[] = { 'P','A','T','C','H',0 };
546 LPWSTR patch_list
, *patches
;
547 UINT i
, r
= ERROR_SUCCESS
;
549 patch_list
= msi_dup_property( package
, szPatch
);
551 TRACE("patches to be applied: %s\n", debugstr_w( patch_list
) );
553 patches
= msi_split_string( patch_list
, ';' );
554 for( i
=0; patches
&& patches
[i
] && r
== ERROR_SUCCESS
; i
++ )
555 r
= msi_apply_patch_package( package
, patches
[i
] );
558 msi_free( patch_list
);
563 static UINT
msi_apply_transforms( MSIPACKAGE
*package
)
565 static const WCHAR szTransforms
[] = {
566 'T','R','A','N','S','F','O','R','M','S',0 };
567 LPWSTR xform_list
, *xforms
;
568 UINT i
, r
= ERROR_SUCCESS
;
570 xform_list
= msi_dup_property( package
, szTransforms
);
571 xforms
= msi_split_string( xform_list
, ';' );
573 for( i
=0; xforms
&& xforms
[i
] && r
== ERROR_SUCCESS
; i
++ )
575 if (xforms
[i
][0] == ':')
576 r
= msi_apply_substorage_transform( package
, package
->db
, &xforms
[i
][1] );
578 r
= MSI_DatabaseApplyTransformW( package
->db
, xforms
[i
], 0 );
582 msi_free( xform_list
);
587 BOOL
ui_sequence_exists( MSIPACKAGE
*package
)
592 static const WCHAR ExecSeqQuery
[] =
593 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
594 '`','I','n','s','t','a','l','l',
595 'U','I','S','e','q','u','e','n','c','e','`',
596 ' ','W','H','E','R','E',' ',
597 '`','S','e','q','u','e','n','c','e','`',' ',
598 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
599 '`','S','e','q','u','e','n','c','e','`',0};
601 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
602 if (rc
== ERROR_SUCCESS
)
604 msiobj_release(&view
->hdr
);
611 /****************************************************
612 * TOP level entry points
613 *****************************************************/
615 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
616 LPCWSTR szCommandLine
)
619 BOOL ui
= FALSE
, ui_exists
;
620 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
621 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
622 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
624 MSI_SetPropertyW(package
, szAction
, szInstall
);
626 package
->script
= msi_alloc_zero(sizeof(MSISCRIPT
));
628 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
632 LPWSTR p
, check
, path
;
634 path
= strdupW(szPackagePath
);
635 p
= strrchrW(path
,'\\');
644 path
= msi_alloc(MAX_PATH
*sizeof(WCHAR
));
645 GetCurrentDirectoryW(MAX_PATH
,path
);
649 check
= msi_dup_property( package
, cszSourceDir
);
651 MSI_SetPropertyW(package
, cszSourceDir
, path
);
654 check
= msi_dup_property( package
, cszSOURCEDIR
);
656 MSI_SetPropertyW(package
, cszSOURCEDIR
, path
);
658 msi_free( package
->PackagePath
);
659 package
->PackagePath
= path
;
664 msi_parse_command_line( package
, szCommandLine
);
666 msi_apply_transforms( package
);
667 msi_apply_patches( package
);
669 if ( (msi_get_property_int(package
, szUILevel
, 0) & INSTALLUILEVEL_MASK
) >= INSTALLUILEVEL_REDUCED
)
671 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
672 rc
= ACTION_ProcessUISequence(package
);
674 ui_exists
= ui_sequence_exists(package
);
675 if (rc
== ERROR_SUCCESS
|| !ui_exists
)
677 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
678 rc
= ACTION_ProcessExecSequence(package
,ui_exists
);
682 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
686 /* install was halted but should be considered a success */
690 package
->script
->CurrentlyScripting
= FALSE
;
692 /* process the ending type action */
693 if (rc
== ERROR_SUCCESS
)
694 ACTION_PerformActionSequence(package
,-1,ui
);
695 else if (rc
== ERROR_INSTALL_USEREXIT
)
696 ACTION_PerformActionSequence(package
,-2,ui
);
697 else if (rc
== ERROR_INSTALL_SUSPEND
)
698 ACTION_PerformActionSequence(package
,-4,ui
);
700 ACTION_PerformActionSequence(package
,-3,ui
);
702 /* finish up running custom actions */
703 ACTION_FinishCustomActions(package
);
708 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
)
710 UINT rc
= ERROR_SUCCESS
;
712 static const WCHAR ExecSeqQuery
[] =
713 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
714 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
715 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
716 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
718 static const WCHAR UISeqQuery
[] =
719 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
720 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
721 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
722 ' ', '=',' ','%','i',0};
725 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
727 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
731 LPCWSTR action
, cond
;
733 TRACE("Running the actions\n");
735 /* check conditions */
736 cond
= MSI_RecordGetString(row
,2);
738 /* this is a hack to skip errors in the condition code */
739 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
742 action
= MSI_RecordGetString(row
,1);
745 ERR("failed to fetch action\n");
746 rc
= ERROR_FUNCTION_FAILED
;
751 rc
= ACTION_PerformUIAction(package
,action
);
753 rc
= ACTION_PerformAction(package
,action
,FALSE
);
755 msiobj_release(&row
->hdr
);
766 } iterate_action_param
;
768 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
770 iterate_action_param
*iap
= (iterate_action_param
*)param
;
772 LPCWSTR cond
, action
;
774 action
= MSI_RecordGetString(row
,1);
777 ERR("Error is retrieving action name\n");
778 return ERROR_FUNCTION_FAILED
;
781 /* check conditions */
782 cond
= MSI_RecordGetString(row
,2);
784 /* this is a hack to skip errors in the condition code */
785 if (MSI_EvaluateConditionW(iap
->package
, cond
) == MSICONDITION_FALSE
)
787 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action
));
788 return ERROR_SUCCESS
;
792 rc
= ACTION_PerformUIAction(iap
->package
,action
);
794 rc
= ACTION_PerformAction(iap
->package
,action
,FALSE
);
796 msi_dialog_check_messages( NULL
);
798 if (iap
->package
->CurrentInstallState
!= ERROR_SUCCESS
)
799 rc
= iap
->package
->CurrentInstallState
;
801 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
804 if (rc
!= ERROR_SUCCESS
)
805 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
810 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
814 static const WCHAR query
[] =
815 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
817 ' ','W','H','E','R','E',' ',
818 '`','S','e','q','u','e','n','c','e','`',' ',
819 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
820 '`','S','e','q','u','e','n','c','e','`',0};
821 iterate_action_param iap
;
824 * FIXME: probably should be checking UILevel in the
825 * ACTION_PerformUIAction/ACTION_PerformAction
826 * rather than saving the UI level here. Those
827 * two functions can be merged too.
829 iap
.package
= package
;
832 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
834 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
835 if (r
== ERROR_SUCCESS
)
837 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, &iap
);
838 msiobj_release(&view
->hdr
);
844 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
848 static const WCHAR ExecSeqQuery
[] =
849 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
850 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
851 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
852 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
853 'O','R','D','E','R',' ', 'B','Y',' ',
854 '`','S','e','q','u','e','n','c','e','`',0 };
856 static const WCHAR IVQuery
[] =
857 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
858 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
859 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
860 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
861 ' ','\'', 'I','n','s','t','a','l','l',
862 'V','a','l','i','d','a','t','e','\'', 0};
864 iterate_action_param iap
;
866 iap
.package
= package
;
869 if (package
->script
->ExecuteSequenceRun
)
871 TRACE("Execute Sequence already Run\n");
872 return ERROR_SUCCESS
;
875 package
->script
->ExecuteSequenceRun
= TRUE
;
877 /* get the sequence number */
880 row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
882 return ERROR_FUNCTION_FAILED
;
883 seq
= MSI_RecordGetInteger(row
,1);
884 msiobj_release(&row
->hdr
);
887 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
888 if (rc
== ERROR_SUCCESS
)
890 TRACE("Running the actions\n");
892 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
893 msiobj_release(&view
->hdr
);
899 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
903 static const WCHAR ExecSeqQuery
[] =
904 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
905 '`','I','n','s','t','a','l','l',
906 'U','I','S','e','q','u','e','n','c','e','`',
907 ' ','W','H','E','R','E',' ',
908 '`','S','e','q','u','e','n','c','e','`',' ',
909 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
910 '`','S','e','q','u','e','n','c','e','`',0};
911 iterate_action_param iap
;
913 iap
.package
= package
;
916 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
918 if (rc
== ERROR_SUCCESS
)
920 TRACE("Running the actions\n");
922 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
923 msiobj_release(&view
->hdr
);
929 /********************************************************
930 * ACTION helper functions and functions that perform the actions
931 *******************************************************/
932 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
933 UINT
* rc
, BOOL force
)
939 if (!run
&& !package
->script
->CurrentlyScripting
)
944 if (strcmpW(action
,szInstallFinalize
) == 0 ||
945 strcmpW(action
,szInstallExecute
) == 0 ||
946 strcmpW(action
,szInstallExecuteAgain
) == 0)
951 while (StandardActions
[i
].action
!= NULL
)
953 if (strcmpW(StandardActions
[i
].action
, action
)==0)
957 ui_actioninfo(package
, action
, TRUE
, 0);
958 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
959 ui_actioninfo(package
, action
, FALSE
, *rc
);
963 ui_actionstart(package
, action
);
964 if (StandardActions
[i
].handler
)
966 *rc
= StandardActions
[i
].handler(package
);
970 FIXME("unhandled standard action %s\n",debugstr_w(action
));
982 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
983 UINT
* rc
, BOOL force
)
988 arc
= ACTION_CustomAction(package
,action
, force
);
990 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
999 * A lot of actions are really important even if they don't do anything
1000 * explicit... Lots of properties are set at the beginning of the installation
1001 * CostFinalize does a bunch of work to translate the directories and such
1003 * But until I get write access to the database that is hard, so I am going to
1004 * hack it to see if I can get something to run.
1006 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, BOOL force
)
1008 UINT rc
= ERROR_SUCCESS
;
1011 TRACE("Performing action (%s)\n",debugstr_w(action
));
1013 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
1016 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, force
);
1020 FIXME("unhandled msi action %s\n",debugstr_w(action
));
1021 rc
= ERROR_FUNCTION_NOT_CALLED
;
1027 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
)
1029 UINT rc
= ERROR_SUCCESS
;
1030 BOOL handled
= FALSE
;
1032 TRACE("Performing action (%s)\n",debugstr_w(action
));
1034 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
1037 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, FALSE
);
1039 if( !handled
&& ACTION_DialogBox(package
,action
) == ERROR_SUCCESS
)
1044 FIXME("unhandled msi action %s\n",debugstr_w(action
));
1045 rc
= ERROR_FUNCTION_NOT_CALLED
;
1053 * Actual Action Handlers
1056 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
1058 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1064 dir
= MSI_RecordGetString(row
,1);
1067 ERR("Unable to get folder id\n");
1068 return ERROR_SUCCESS
;
1071 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,TRUE
,&folder
);
1074 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
1075 return ERROR_SUCCESS
;
1078 TRACE("Folder is %s\n",debugstr_w(full_path
));
1081 uirow
= MSI_CreateRecord(1);
1082 MSI_RecordSetStringW(uirow
,1,full_path
);
1083 ui_actiondata(package
,szCreateFolders
,uirow
);
1084 msiobj_release( &uirow
->hdr
);
1086 if (folder
->State
== 0)
1087 create_full_pathW(full_path
);
1091 msi_free(full_path
);
1092 return ERROR_SUCCESS
;
1095 /* FIXME: probably should merge this with the above function */
1096 static UINT
msi_create_directory( MSIPACKAGE
* package
, LPCWSTR dir
)
1098 UINT rc
= ERROR_SUCCESS
;
1100 LPWSTR install_path
;
1102 install_path
= resolve_folder(package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
1104 return ERROR_FUNCTION_FAILED
;
1106 /* create the path */
1107 if (folder
->State
== 0)
1109 create_full_pathW(install_path
);
1112 msi_free(install_path
);
1117 UINT
msi_create_component_directories( MSIPACKAGE
*package
)
1121 /* create all the folders required by the components are going to install */
1122 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1124 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
1126 msi_create_directory( package
, comp
->Directory
);
1129 return ERROR_SUCCESS
;
1133 * Also we cannot enable/disable components either, so for now I am just going
1134 * to do all the directories for all the components.
1136 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1138 static const WCHAR ExecSeqQuery
[] =
1139 {'S','E','L','E','C','T',' ',
1140 '`','D','i','r','e','c','t','o','r','y','_','`',
1141 ' ','F','R','O','M',' ',
1142 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1146 /* create all the empty folders specified in the CreateFolder table */
1147 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1148 if (rc
!= ERROR_SUCCESS
)
1149 return ERROR_SUCCESS
;
1151 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
1152 msiobj_release(&view
->hdr
);
1154 msi_create_component_directories( package
);
1159 static UINT
load_component( MSIRECORD
*row
, LPVOID param
)
1161 MSIPACKAGE
*package
= param
;
1164 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1166 return ERROR_FUNCTION_FAILED
;
1168 list_add_tail( &package
->components
, &comp
->entry
);
1170 /* fill in the data */
1171 comp
->Component
= msi_dup_record_field( row
, 1 );
1173 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1175 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1176 comp
->Directory
= msi_dup_record_field( row
, 3 );
1177 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1178 comp
->Condition
= msi_dup_record_field( row
, 5 );
1179 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1181 comp
->Installed
= INSTALLSTATE_UNKNOWN
;
1182 msi_component_set_state( comp
, INSTALLSTATE_UNKNOWN
);
1184 return ERROR_SUCCESS
;
1187 static UINT
load_all_components( MSIPACKAGE
*package
)
1189 static const WCHAR query
[] = {
1190 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1191 '`','C','o','m','p','o','n','e','n','t','`',0 };
1195 if (!list_empty(&package
->components
))
1196 return ERROR_SUCCESS
;
1198 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1199 if (r
!= ERROR_SUCCESS
)
1202 r
= MSI_IterateRecords(view
, NULL
, load_component
, package
);
1203 msiobj_release(&view
->hdr
);
1208 MSIPACKAGE
*package
;
1209 MSIFEATURE
*feature
;
1212 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1216 cl
= msi_alloc( sizeof (*cl
) );
1218 return ERROR_NOT_ENOUGH_MEMORY
;
1219 cl
->component
= comp
;
1220 list_add_tail( &feature
->Components
, &cl
->entry
);
1222 return ERROR_SUCCESS
;
1225 static UINT
add_feature_child( MSIFEATURE
*parent
, MSIFEATURE
*child
)
1229 fl
= msi_alloc( sizeof(*fl
) );
1231 return ERROR_NOT_ENOUGH_MEMORY
;
1232 fl
->feature
= child
;
1233 list_add_tail( &parent
->Children
, &fl
->entry
);
1235 return ERROR_SUCCESS
;
1238 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1240 _ilfs
* ilfs
= (_ilfs
*)param
;
1244 component
= MSI_RecordGetString(row
,1);
1246 /* check to see if the component is already loaded */
1247 comp
= get_loaded_component( ilfs
->package
, component
);
1250 ERR("unknown component %s\n", debugstr_w(component
));
1251 return ERROR_FUNCTION_FAILED
;
1254 add_feature_component( ilfs
->feature
, comp
);
1255 comp
->Enabled
= TRUE
;
1257 return ERROR_SUCCESS
;
1260 static MSIFEATURE
*find_feature_by_name( MSIPACKAGE
*package
, LPCWSTR name
)
1262 MSIFEATURE
*feature
;
1264 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1266 if ( !lstrcmpW( feature
->Feature
, name
) )
1273 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1275 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1276 MSIFEATURE
* feature
;
1277 static const WCHAR Query1
[] =
1278 {'S','E','L','E','C','T',' ',
1279 '`','C','o','m','p','o','n','e','n','t','_','`',
1280 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1281 'C','o','m','p','o','n','e','n','t','s','`',' ',
1282 'W','H','E','R','E',' ',
1283 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1288 /* fill in the data */
1290 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1292 return ERROR_NOT_ENOUGH_MEMORY
;
1294 list_init( &feature
->Children
);
1295 list_init( &feature
->Components
);
1297 feature
->Feature
= msi_dup_record_field( row
, 1 );
1299 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1301 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1302 feature
->Title
= msi_dup_record_field( row
, 3 );
1303 feature
->Description
= msi_dup_record_field( row
, 4 );
1305 if (!MSI_RecordIsNull(row
,5))
1306 feature
->Display
= MSI_RecordGetInteger(row
,5);
1308 feature
->Level
= MSI_RecordGetInteger(row
,6);
1309 feature
->Directory
= msi_dup_record_field( row
, 7 );
1310 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1312 feature
->Installed
= INSTALLSTATE_UNKNOWN
;
1313 msi_feature_set_state( feature
, INSTALLSTATE_UNKNOWN
);
1315 list_add_tail( &package
->features
, &feature
->entry
);
1317 /* load feature components */
1319 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1320 if (rc
!= ERROR_SUCCESS
)
1321 return ERROR_SUCCESS
;
1323 ilfs
.package
= package
;
1324 ilfs
.feature
= feature
;
1326 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1327 msiobj_release(&view
->hdr
);
1329 return ERROR_SUCCESS
;
1332 static UINT
find_feature_children(MSIRECORD
* row
, LPVOID param
)
1334 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1335 MSIFEATURE
*parent
, *child
;
1337 child
= find_feature_by_name( package
, MSI_RecordGetString( row
, 1 ) );
1339 return ERROR_FUNCTION_FAILED
;
1341 if (!child
->Feature_Parent
)
1342 return ERROR_SUCCESS
;
1344 parent
= find_feature_by_name( package
, child
->Feature_Parent
);
1346 return ERROR_FUNCTION_FAILED
;
1348 add_feature_child( parent
, child
);
1349 return ERROR_SUCCESS
;
1352 static UINT
load_all_features( MSIPACKAGE
*package
)
1354 static const WCHAR query
[] = {
1355 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1356 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1357 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1361 if (!list_empty(&package
->features
))
1362 return ERROR_SUCCESS
;
1364 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1365 if (r
!= ERROR_SUCCESS
)
1368 r
= MSI_IterateRecords( view
, NULL
, load_feature
, package
);
1369 if (r
!= ERROR_SUCCESS
)
1372 r
= MSI_IterateRecords( view
, NULL
, find_feature_children
, package
);
1373 msiobj_release( &view
->hdr
);
1378 static LPWSTR
folder_split_path(LPWSTR p
, WCHAR ch
)
1389 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1391 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1395 /* fill in the data */
1397 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1399 return ERROR_NOT_ENOUGH_MEMORY
;
1401 file
->File
= msi_dup_record_field( row
, 1 );
1403 component
= MSI_RecordGetString( row
, 2 );
1404 file
->Component
= get_loaded_component( package
, component
);
1406 if (!file
->Component
)
1407 ERR("Unfound Component %s\n",debugstr_w(component
));
1409 file
->FileName
= msi_dup_record_field( row
, 3 );
1410 reduce_to_longfilename( file
->FileName
);
1412 file
->ShortName
= msi_dup_record_field( row
, 3 );
1413 file
->LongName
= strdupW( folder_split_path(file
->ShortName
, '|'));
1415 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1416 file
->Version
= msi_dup_record_field( row
, 5 );
1417 file
->Language
= msi_dup_record_field( row
, 6 );
1418 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1419 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1421 file
->state
= msifs_invalid
;
1423 /* if the compressed bits are not set in the file attributes,
1424 * then read the information from the package word count property
1426 if (file
->Attributes
& msidbFileAttributesCompressed
)
1428 file
->IsCompressed
= TRUE
;
1430 else if (file
->Attributes
& msidbFileAttributesNoncompressed
)
1432 file
->IsCompressed
= FALSE
;
1436 file
->IsCompressed
= package
->WordCount
& MSIWORDCOUNT_COMPRESSED
;
1439 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1441 list_add_tail( &package
->files
, &file
->entry
);
1443 return ERROR_SUCCESS
;
1446 static UINT
load_all_files(MSIPACKAGE
*package
)
1450 static const WCHAR Query
[] =
1451 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1452 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1453 '`','S','e','q','u','e','n','c','e','`', 0};
1455 if (!list_empty(&package
->files
))
1456 return ERROR_SUCCESS
;
1458 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1459 if (rc
!= ERROR_SUCCESS
)
1460 return ERROR_SUCCESS
;
1462 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1463 msiobj_release(&view
->hdr
);
1465 return ERROR_SUCCESS
;
1468 static UINT
load_folder( MSIRECORD
*row
, LPVOID param
)
1470 MSIPACKAGE
*package
= param
;
1471 static const WCHAR szDot
[] = { '.',0 };
1472 static WCHAR szEmpty
[] = { 0 };
1473 LPWSTR p
, tgt_short
, tgt_long
, src_short
, src_long
;
1476 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1478 return ERROR_NOT_ENOUGH_MEMORY
;
1480 folder
->Directory
= msi_dup_record_field( row
, 1 );
1482 TRACE("%s\n", debugstr_w(folder
->Directory
));
1484 p
= msi_dup_record_field(row
, 3);
1486 /* split src and target dir */
1488 src_short
= folder_split_path( p
, ':' );
1490 /* split the long and short paths */
1491 tgt_long
= folder_split_path( tgt_short
, '|' );
1492 src_long
= folder_split_path( src_short
, '|' );
1494 /* check for no-op dirs */
1495 if (!lstrcmpW(szDot
, tgt_short
))
1496 tgt_short
= szEmpty
;
1497 if (!lstrcmpW(szDot
, src_short
))
1498 src_short
= szEmpty
;
1501 tgt_long
= tgt_short
;
1504 src_short
= tgt_short
;
1505 src_long
= tgt_long
;
1509 src_long
= src_short
;
1511 /* FIXME: use the target short path too */
1512 folder
->TargetDefault
= strdupW(tgt_long
);
1513 folder
->SourceShortPath
= strdupW(src_short
);
1514 folder
->SourceLongPath
= strdupW(src_long
);
1517 TRACE("TargetDefault = %s\n",debugstr_w( folder
->TargetDefault
));
1518 TRACE("SourceLong = %s\n", debugstr_w( folder
->SourceLongPath
));
1519 TRACE("SourceShort = %s\n", debugstr_w( folder
->SourceShortPath
));
1521 folder
->Parent
= msi_dup_record_field( row
, 2 );
1523 folder
->Property
= msi_dup_property( package
, folder
->Directory
);
1525 list_add_tail( &package
->folders
, &folder
->entry
);
1527 TRACE("returning %p\n", folder
);
1529 return ERROR_SUCCESS
;
1532 static UINT
load_all_folders( MSIPACKAGE
*package
)
1534 static const WCHAR query
[] = {
1535 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1536 '`','D','i','r','e','c','t','o','r','y','`',0 };
1540 if (!list_empty(&package
->folders
))
1541 return ERROR_SUCCESS
;
1543 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1544 if (r
!= ERROR_SUCCESS
)
1547 r
= MSI_IterateRecords(view
, NULL
, load_folder
, package
);
1548 msiobj_release(&view
->hdr
);
1553 * I am not doing any of the costing functionality yet.
1554 * Mostly looking at doing the Component and Feature loading
1556 * The native MSI does A LOT of modification to tables here. Mostly adding
1557 * a lot of temporary columns to the Feature and Component tables.
1559 * note: Native msi also tracks the short filename. But I am only going to
1560 * track the long ones. Also looking at this directory table
1561 * it appears that the directory table does not get the parents
1562 * resolved base on property only based on their entries in the
1565 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1567 static const WCHAR szCosting
[] =
1568 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1569 static const WCHAR szZero
[] = { '0', 0 };
1571 if ( 1 == msi_get_property_int( package
, szCosting
, 0 ) )
1572 return ERROR_SUCCESS
;
1574 MSI_SetPropertyW(package
, szCosting
, szZero
);
1575 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1577 load_all_components( package
);
1578 load_all_features( package
);
1579 load_all_files( package
);
1580 load_all_folders( package
);
1582 return ERROR_SUCCESS
;
1585 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1588 UINT rc
= ERROR_SUCCESS
;
1590 TRACE("Executing Script %i\n",script
);
1592 if (!package
->script
)
1594 ERR("no script!\n");
1595 return ERROR_FUNCTION_FAILED
;
1598 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1601 action
= package
->script
->Actions
[script
][i
];
1602 ui_actionstart(package
, action
);
1603 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1604 rc
= ACTION_PerformAction(package
, action
, TRUE
);
1605 if (rc
!= ERROR_SUCCESS
)
1608 msi_free_action_script(package
, script
);
1612 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1614 return ERROR_SUCCESS
;
1617 static void ACTION_GetComponentInstallStates(MSIPACKAGE
*package
)
1621 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1625 if (!comp
->ComponentId
)
1628 res
= MsiGetComponentPathW( package
->ProductCode
,
1629 comp
->ComponentId
, NULL
, NULL
);
1631 res
= INSTALLSTATE_ABSENT
;
1632 comp
->Installed
= res
;
1636 /* scan for and update current install states */
1637 static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE
*package
)
1640 MSIFEATURE
*feature
;
1642 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1645 INSTALLSTATE res
= INSTALLSTATE_ABSENT
;
1647 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1649 comp
= cl
->component
;
1651 if (!comp
->ComponentId
)
1653 res
= INSTALLSTATE_ABSENT
;
1657 if (res
== INSTALLSTATE_ABSENT
)
1658 res
= comp
->Installed
;
1661 if (res
== comp
->Installed
)
1664 if (res
!= INSTALLSTATE_DEFAULT
&& res
!= INSTALLSTATE_LOCAL
&&
1665 res
!= INSTALLSTATE_SOURCE
)
1667 res
= INSTALLSTATE_INCOMPLETE
;
1671 feature
->Installed
= res
;
1675 static BOOL
process_state_property (MSIPACKAGE
* package
, LPCWSTR property
,
1678 static const WCHAR all
[]={'A','L','L',0};
1680 MSIFEATURE
*feature
;
1682 override
= msi_dup_property( package
, property
);
1686 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1688 if (strcmpiW(override
,all
)==0)
1689 msi_feature_set_state( feature
, state
);
1692 LPWSTR ptr
= override
;
1693 LPWSTR ptr2
= strchrW(override
,',');
1697 if ((ptr2
&& strncmpW(ptr
,feature
->Feature
, ptr2
-ptr
)==0)
1698 || (!ptr2
&& strcmpW(ptr
,feature
->Feature
)==0))
1700 msi_feature_set_state( feature
, state
);
1706 ptr2
= strchrW(ptr
,',');
1718 UINT
MSI_SetFeatureStates(MSIPACKAGE
*package
)
1721 static const WCHAR szlevel
[] =
1722 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1723 static const WCHAR szAddLocal
[] =
1724 {'A','D','D','L','O','C','A','L',0};
1725 static const WCHAR szRemove
[] =
1726 {'R','E','M','O','V','E',0};
1727 static const WCHAR szReinstall
[] =
1728 {'R','E','I','N','S','T','A','L','L',0};
1729 BOOL override
= FALSE
;
1730 MSICOMPONENT
* component
;
1731 MSIFEATURE
*feature
;
1734 /* I do not know if this is where it should happen.. but */
1736 TRACE("Checking Install Level\n");
1738 install_level
= msi_get_property_int( package
, szlevel
, 1 );
1740 /* ok here is the _real_ rub
1741 * all these activation/deactivation things happen in order and things
1742 * later on the list override things earlier on the list.
1743 * 1) INSTALLLEVEL processing
1753 * 11) FILEADDDEFAULT
1754 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1755 * ignored for all the features. seems strange, especially since it is not
1756 * documented anywhere, but it is how it works.
1758 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1759 * REMOVE are the big ones, since we don't handle administrative installs
1762 override
|= process_state_property(package
,szAddLocal
,INSTALLSTATE_LOCAL
);
1763 override
|= process_state_property(package
,szRemove
,INSTALLSTATE_ABSENT
);
1764 override
|= process_state_property(package
,szReinstall
,INSTALLSTATE_LOCAL
);
1768 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1770 BOOL feature_state
= ((feature
->Level
> 0) &&
1771 (feature
->Level
<= install_level
));
1773 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1775 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1776 msi_feature_set_state( feature
, INSTALLSTATE_SOURCE
);
1777 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1778 msi_feature_set_state( feature
, INSTALLSTATE_ADVERTISED
);
1780 msi_feature_set_state( feature
, INSTALLSTATE_LOCAL
);
1784 /* disable child features of unselected parent features */
1785 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1789 if (feature
->Level
> 0 && feature
->Level
<= install_level
)
1792 LIST_FOR_EACH_ENTRY( fl
, &feature
->Children
, FeatureList
, entry
)
1793 msi_feature_set_state( fl
->feature
, INSTALLSTATE_UNKNOWN
);
1798 /* set the Preselected Property */
1799 static const WCHAR szPreselected
[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1800 static const WCHAR szOne
[] = { '1', 0 };
1802 MSI_SetPropertyW(package
,szPreselected
,szOne
);
1806 * now we want to enable or disable components base on feature
1809 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1813 TRACE("Examining Feature %s (Installed %i, Action %i)\n",
1814 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
);
1816 /* features with components that have compressed files are made local */
1817 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1819 if (cl
->component
->Enabled
&&
1820 cl
->component
->ForceLocalState
&&
1821 feature
->Action
== INSTALLSTATE_SOURCE
)
1823 msi_feature_set_state( feature
, INSTALLSTATE_LOCAL
);
1828 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1830 component
= cl
->component
;
1832 if (!component
->Enabled
)
1835 switch (feature
->Action
)
1837 case INSTALLSTATE_ADVERTISED
:
1838 component
->hasAdvertiseFeature
= 1;
1840 case INSTALLSTATE_SOURCE
:
1841 component
->hasSourceFeature
= 1;
1843 case INSTALLSTATE_LOCAL
:
1844 component
->hasLocalFeature
= 1;
1846 case INSTALLSTATE_DEFAULT
:
1847 if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1848 component
->hasAdvertiseFeature
= 1;
1849 else if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1850 component
->hasSourceFeature
= 1;
1852 component
->hasLocalFeature
= 1;
1860 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1862 /* if the component isn't enabled, leave it alone */
1863 if (!component
->Enabled
)
1866 /* check if it's local or source */
1867 if (!(component
->Attributes
& msidbComponentAttributesOptional
) &&
1868 (component
->hasLocalFeature
|| component
->hasSourceFeature
))
1870 if ((component
->Attributes
& msidbComponentAttributesSourceOnly
) &&
1871 !component
->ForceLocalState
)
1872 msi_component_set_state( component
, INSTALLSTATE_SOURCE
);
1874 msi_component_set_state( component
, INSTALLSTATE_LOCAL
);
1878 /* if any feature is local, the component must be local too */
1879 if (component
->hasLocalFeature
)
1881 msi_component_set_state( component
, INSTALLSTATE_LOCAL
);
1885 if (component
->hasSourceFeature
)
1887 msi_component_set_state( component
, INSTALLSTATE_SOURCE
);
1891 if (component
->hasAdvertiseFeature
)
1893 msi_component_set_state( component
, INSTALLSTATE_ADVERTISED
);
1897 TRACE("nobody wants component %s\n", debugstr_w(component
->Component
));
1900 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1902 if (component
->Action
== INSTALLSTATE_DEFAULT
)
1904 TRACE("%s was default, setting to local\n", debugstr_w(component
->Component
));
1905 msi_component_set_state( component
, INSTALLSTATE_LOCAL
);
1908 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1909 debugstr_w(component
->Component
), component
->Installed
, component
->Action
);
1913 return ERROR_SUCCESS
;
1916 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1918 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1922 name
= MSI_RecordGetString(row
,1);
1924 /* This helper function now does ALL the work */
1925 TRACE("Dir %s ...\n",debugstr_w(name
));
1926 path
= resolve_folder(package
,name
,FALSE
,TRUE
,TRUE
,NULL
);
1927 TRACE("resolves to %s\n",debugstr_w(path
));
1930 return ERROR_SUCCESS
;
1933 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
1935 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1937 MSIFEATURE
*feature
;
1939 name
= MSI_RecordGetString( row
, 1 );
1941 feature
= get_loaded_feature( package
, name
);
1943 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
1947 Condition
= MSI_RecordGetString(row
,3);
1949 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
1951 int level
= MSI_RecordGetInteger(row
,2);
1952 TRACE("Reseting feature %s to level %i\n", debugstr_w(name
), level
);
1953 feature
->Level
= level
;
1956 return ERROR_SUCCESS
;
1959 static LPWSTR
msi_get_disk_file_version( LPCWSTR filename
)
1961 static const WCHAR name_fmt
[] =
1962 {'%','u','.','%','u','.','%','u','.','%','u',0};
1963 static WCHAR name
[] = {'\\',0};
1964 VS_FIXEDFILEINFO
*lpVer
;
1965 WCHAR filever
[0x100];
1971 TRACE("%s\n", debugstr_w(filename
));
1973 versize
= GetFileVersionInfoSizeW( filename
, &handle
);
1977 version
= msi_alloc( versize
);
1978 GetFileVersionInfoW( filename
, 0, versize
, version
);
1980 VerQueryValueW( version
, name
, (LPVOID
*)&lpVer
, &sz
);
1981 msi_free( version
);
1983 sprintfW( filever
, name_fmt
,
1984 HIWORD(lpVer
->dwFileVersionMS
),
1985 LOWORD(lpVer
->dwFileVersionMS
),
1986 HIWORD(lpVer
->dwFileVersionLS
),
1987 LOWORD(lpVer
->dwFileVersionLS
));
1989 return strdupW( filever
);
1992 static UINT
msi_check_file_install_states( MSIPACKAGE
*package
)
1994 LPWSTR file_version
;
1997 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
1999 MSICOMPONENT
* comp
= file
->Component
;
2005 if (file
->IsCompressed
)
2006 comp
->ForceLocalState
= TRUE
;
2008 /* calculate target */
2009 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, TRUE
, NULL
);
2011 msi_free(file
->TargetPath
);
2013 TRACE("file %s is named %s\n",
2014 debugstr_w(file
->File
), debugstr_w(file
->FileName
));
2016 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
2020 TRACE("file %s resolves to %s\n",
2021 debugstr_w(file
->File
), debugstr_w(file
->TargetPath
));
2023 /* don't check files of components that aren't installed */
2024 if (comp
->Installed
== INSTALLSTATE_UNKNOWN
||
2025 comp
->Installed
== INSTALLSTATE_ABSENT
)
2027 file
->state
= msifs_missing
; /* assume files are missing */
2031 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
2033 file
->state
= msifs_missing
;
2034 comp
->Cost
+= file
->FileSize
;
2035 comp
->Installed
= INSTALLSTATE_INCOMPLETE
;
2039 if (file
->Version
&&
2040 (file_version
= msi_get_disk_file_version( file
->TargetPath
)))
2042 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
2043 debugstr_w(file_version
));
2044 /* FIXME: seems like a bad way to compare version numbers */
2045 if (lstrcmpiW(file_version
, file
->Version
)<0)
2047 file
->state
= msifs_overwrite
;
2048 comp
->Cost
+= file
->FileSize
;
2049 comp
->Installed
= INSTALLSTATE_INCOMPLETE
;
2052 file
->state
= msifs_present
;
2053 msi_free( file_version
);
2056 file
->state
= msifs_present
;
2059 return ERROR_SUCCESS
;
2063 * A lot is done in this function aside from just the costing.
2064 * The costing needs to be implemented at some point but for now I am going
2065 * to focus on the directory building
2068 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2070 static const WCHAR ExecSeqQuery
[] =
2071 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2072 '`','D','i','r','e','c','t','o','r','y','`',0};
2073 static const WCHAR ConditionQuery
[] =
2074 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2075 '`','C','o','n','d','i','t','i','o','n','`',0};
2076 static const WCHAR szCosting
[] =
2077 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2078 static const WCHAR szlevel
[] =
2079 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2080 static const WCHAR szOne
[] = { '1', 0 };
2086 if ( 1 == msi_get_property_int( package
, szCosting
, 0 ) )
2087 return ERROR_SUCCESS
;
2089 TRACE("Building Directory properties\n");
2091 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2092 if (rc
== ERROR_SUCCESS
)
2094 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
2096 msiobj_release(&view
->hdr
);
2099 /* read components states from the registry */
2100 ACTION_GetComponentInstallStates(package
);
2102 TRACE("File calculations\n");
2103 msi_check_file_install_states( package
);
2105 TRACE("Evaluating Condition Table\n");
2107 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
2108 if (rc
== ERROR_SUCCESS
)
2110 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeConditions
,
2112 msiobj_release(&view
->hdr
);
2115 TRACE("Enabling or Disabling Components\n");
2116 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2118 if (MSI_EvaluateConditionW(package
, comp
->Condition
) == MSICONDITION_FALSE
)
2120 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
2121 comp
->Enabled
= FALSE
;
2125 MSI_SetPropertyW(package
,szCosting
,szOne
);
2126 /* set default run level if not set */
2127 level
= msi_dup_property( package
, szlevel
);
2129 MSI_SetPropertyW(package
,szlevel
, szOne
);
2132 ACTION_UpdateFeatureInstallStates(package
);
2134 return MSI_SetFeatureStates(package
);
2137 /* OK this value is "interpreted" and then formatted based on the
2138 first few characters */
2139 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
2143 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2149 LPWSTR deformated
= NULL
;
2152 deformat_string(package
, &value
[2], &deformated
);
2154 /* binary value type */
2158 *size
= (strlenW(ptr
)/2)+1;
2160 *size
= strlenW(ptr
)/2;
2162 data
= msi_alloc(*size
);
2168 /* if uneven pad with a zero in front */
2174 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2176 TRACE("Uneven byte count\n");
2184 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2187 msi_free(deformated
);
2189 TRACE("Data %i bytes(%i)\n",*size
,count
);
2196 deformat_string(package
, &value
[1], &deformated
);
2199 *size
= sizeof(DWORD
);
2200 data
= msi_alloc(*size
);
2206 if ( (*p
< '0') || (*p
> '9') )
2212 if (deformated
[0] == '-')
2215 TRACE("DWORD %i\n",*(LPDWORD
)data
);
2217 msi_free(deformated
);
2222 static const WCHAR szMulti
[] = {'[','~',']',0};
2231 *type
=REG_EXPAND_SZ
;
2239 if (strstrW(value
,szMulti
))
2240 *type
= REG_MULTI_SZ
;
2242 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2247 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2249 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2250 static const WCHAR szHCR
[] =
2251 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2252 'R','O','O','T','\\',0};
2253 static const WCHAR szHCU
[] =
2254 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2255 'U','S','E','R','\\',0};
2256 static const WCHAR szHLM
[] =
2257 {'H','K','E','Y','_','L','O','C','A','L','_',
2258 'M','A','C','H','I','N','E','\\',0};
2259 static const WCHAR szHU
[] =
2260 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2262 LPSTR value_data
= NULL
;
2263 HKEY root_key
, hkey
;
2266 LPCWSTR szRoot
, component
, name
, key
, value
;
2271 BOOL check_first
= FALSE
;
2274 ui_progress(package
,2,0,0,0);
2281 component
= MSI_RecordGetString(row
, 6);
2282 comp
= get_loaded_component(package
,component
);
2284 return ERROR_SUCCESS
;
2286 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2288 TRACE("Skipping write due to disabled component %s\n",
2289 debugstr_w(component
));
2291 comp
->Action
= comp
->Installed
;
2293 return ERROR_SUCCESS
;
2296 comp
->Action
= INSTALLSTATE_LOCAL
;
2298 name
= MSI_RecordGetString(row
, 4);
2299 if( MSI_RecordIsNull(row
,5) && name
)
2301 /* null values can have special meanings */
2302 if (name
[0]=='-' && name
[1] == 0)
2303 return ERROR_SUCCESS
;
2304 else if ((name
[0]=='+' && name
[1] == 0) ||
2305 (name
[0] == '*' && name
[1] == 0))
2310 root
= MSI_RecordGetInteger(row
,2);
2311 key
= MSI_RecordGetString(row
, 3);
2313 /* get the root key */
2318 static const WCHAR szALLUSER
[] = {'A','L','L','U','S','E','R','S',0};
2319 LPWSTR all_users
= msi_dup_property( package
, szALLUSER
);
2320 if (all_users
&& all_users
[0] == '1')
2322 root_key
= HKEY_LOCAL_MACHINE
;
2327 root_key
= HKEY_CURRENT_USER
;
2330 msi_free(all_users
);
2333 case 0: root_key
= HKEY_CLASSES_ROOT
;
2336 case 1: root_key
= HKEY_CURRENT_USER
;
2339 case 2: root_key
= HKEY_LOCAL_MACHINE
;
2342 case 3: root_key
= HKEY_USERS
;
2346 ERR("Unknown root %i\n",root
);
2352 return ERROR_SUCCESS
;
2354 deformat_string(package
, key
, &deformated
);
2355 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2356 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2357 strcpyW(uikey
,szRoot
);
2358 strcatW(uikey
,deformated
);
2360 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2362 ERR("Could not create key %s\n",debugstr_w(deformated
));
2363 msi_free(deformated
);
2365 return ERROR_SUCCESS
;
2367 msi_free(deformated
);
2369 value
= MSI_RecordGetString(row
,5);
2371 value_data
= parse_value(package
, value
, &type
, &size
);
2374 static const WCHAR szEmpty
[] = {0};
2375 value_data
= (LPSTR
)strdupW(szEmpty
);
2380 deformat_string(package
, name
, &deformated
);
2382 /* get the double nulls to terminate SZ_MULTI */
2383 if (type
== REG_MULTI_SZ
)
2384 size
+=sizeof(WCHAR
);
2388 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2390 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2395 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2396 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2398 TRACE("value %s of %s checked already exists\n",
2399 debugstr_w(deformated
), debugstr_w(uikey
));
2403 TRACE("Checked and setting value %s of %s\n",
2404 debugstr_w(deformated
), debugstr_w(uikey
));
2405 if (deformated
|| size
)
2406 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2411 uirow
= MSI_CreateRecord(3);
2412 MSI_RecordSetStringW(uirow
,2,deformated
);
2413 MSI_RecordSetStringW(uirow
,1,uikey
);
2416 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2418 MSI_RecordSetStringW(uirow
,3,value
);
2420 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2421 msiobj_release( &uirow
->hdr
);
2423 msi_free(value_data
);
2424 msi_free(deformated
);
2427 return ERROR_SUCCESS
;
2430 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2434 static const WCHAR ExecSeqQuery
[] =
2435 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2436 '`','R','e','g','i','s','t','r','y','`',0 };
2438 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2439 if (rc
!= ERROR_SUCCESS
)
2440 return ERROR_SUCCESS
;
2442 /* increment progress bar each time action data is sent */
2443 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2445 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2447 msiobj_release(&view
->hdr
);
2451 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2453 package
->script
->CurrentlyScripting
= TRUE
;
2455 return ERROR_SUCCESS
;
2459 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2464 static const WCHAR q1
[]=
2465 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2466 '`','R','e','g','i','s','t','r','y','`',0};
2469 MSIFEATURE
*feature
;
2472 TRACE("InstallValidate\n");
2474 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2475 if (rc
== ERROR_SUCCESS
)
2477 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2478 msiobj_release( &view
->hdr
);
2479 total
+= progress
* REG_PROGRESS_VALUE
;
2482 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2483 total
+= COMPONENT_PROGRESS_VALUE
;
2485 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2486 total
+= file
->FileSize
;
2488 ui_progress(package
,0,total
,0,0);
2490 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2492 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2493 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2494 feature
->ActionRequest
);
2497 return ERROR_SUCCESS
;
2500 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2502 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2503 LPCWSTR cond
= NULL
;
2504 LPCWSTR message
= NULL
;
2505 static const WCHAR title
[]=
2506 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2508 cond
= MSI_RecordGetString(row
,1);
2510 if (MSI_EvaluateConditionW(package
,cond
) != MSICONDITION_TRUE
)
2513 message
= MSI_RecordGetString(row
,2);
2514 deformat_string(package
,message
,&deformated
);
2515 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2516 msi_free(deformated
);
2517 return ERROR_FUNCTION_FAILED
;
2520 return ERROR_SUCCESS
;
2523 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2526 MSIQUERY
* view
= NULL
;
2527 static const WCHAR ExecSeqQuery
[] =
2528 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2529 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2531 TRACE("Checking launch conditions\n");
2533 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2534 if (rc
!= ERROR_SUCCESS
)
2535 return ERROR_SUCCESS
;
2537 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2538 msiobj_release(&view
->hdr
);
2543 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2547 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,TRUE
,NULL
);
2549 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2551 MSIRECORD
* row
= 0;
2553 LPWSTR deformated
,buffer
,deformated_name
;
2555 static const WCHAR ExecSeqQuery
[] =
2556 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2557 '`','R','e','g','i','s','t','r','y','`',' ',
2558 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2559 ' ','=',' ' ,'\'','%','s','\'',0 };
2560 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2561 static const WCHAR fmt2
[]=
2562 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2564 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2568 root
= MSI_RecordGetInteger(row
,2);
2569 key
= MSI_RecordGetString(row
, 3);
2570 name
= MSI_RecordGetString(row
, 4);
2571 deformat_string(package
, key
, &deformated
);
2572 deformat_string(package
, name
, &deformated_name
);
2574 len
= strlenW(deformated
) + 6;
2575 if (deformated_name
)
2576 len
+=strlenW(deformated_name
);
2578 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2580 if (deformated_name
)
2581 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2583 sprintfW(buffer
,fmt
,root
,deformated
);
2585 msi_free(deformated
);
2586 msi_free(deformated_name
);
2587 msiobj_release(&row
->hdr
);
2591 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2593 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2598 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2601 return strdupW( file
->TargetPath
);
2606 static HKEY
openSharedDLLsKey(void)
2609 static const WCHAR path
[] =
2610 {'S','o','f','t','w','a','r','e','\\',
2611 'M','i','c','r','o','s','o','f','t','\\',
2612 'W','i','n','d','o','w','s','\\',
2613 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2614 'S','h','a','r','e','d','D','L','L','s',0};
2616 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2620 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2625 DWORD sz
= sizeof(count
);
2628 hkey
= openSharedDLLsKey();
2629 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2630 if (rc
!= ERROR_SUCCESS
)
2636 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2640 hkey
= openSharedDLLsKey();
2642 msi_reg_set_val_dword( hkey
, path
, count
);
2644 RegDeleteValueW(hkey
,path
);
2650 * Return TRUE if the count should be written out and FALSE if not
2652 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2654 MSIFEATURE
*feature
;
2658 /* only refcount DLLs */
2659 if (comp
->KeyPath
== NULL
||
2660 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2661 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2665 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2666 write
= (count
> 0);
2668 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2672 /* increment counts */
2673 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2677 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
))
2680 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2682 if ( cl
->component
== comp
)
2687 /* decrement counts */
2688 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2692 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ABSENT
))
2695 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2697 if ( cl
->component
== comp
)
2702 /* ref count all the files in the component */
2707 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2709 if (file
->Component
== comp
)
2710 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2714 /* add a count for permenent */
2715 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2718 comp
->RefCount
= count
;
2721 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2725 * Ok further analysis makes me think that this work is
2726 * actually done in the PublishComponents and PublishFeatures
2727 * step, and not here. It appears like the keypath and all that is
2728 * resolved in this step, however actually written in the Publish steps.
2729 * But we will leave it here for now because it is unclear
2731 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2733 WCHAR squished_pc
[GUID_SIZE
];
2734 WCHAR squished_cc
[GUID_SIZE
];
2737 HKEY hkey
=0,hkey2
=0;
2739 /* writes the Component and Features values to the registry */
2741 rc
= MSIREG_OpenComponents(&hkey
);
2742 if (rc
!= ERROR_SUCCESS
)
2745 squash_guid(package
->ProductCode
,squished_pc
);
2746 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2748 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2752 ui_progress(package
,2,0,0,0);
2753 if (!comp
->ComponentId
)
2756 squash_guid(comp
->ComponentId
,squished_cc
);
2758 msi_free(comp
->FullKeypath
);
2759 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2761 /* do the refcounting */
2762 ACTION_RefCountComponent( package
, comp
);
2764 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2765 debugstr_w(comp
->Component
),
2766 debugstr_w(squished_cc
),
2767 debugstr_w(comp
->FullKeypath
),
2770 * Write the keypath out if the component is to be registered
2771 * and delete the key if the component is to be deregistered
2773 if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2775 rc
= RegCreateKeyW(hkey
,squished_cc
,&hkey2
);
2776 if (rc
!= ERROR_SUCCESS
)
2779 if (!comp
->FullKeypath
)
2782 msi_reg_set_val_str( hkey2
, squished_pc
, comp
->FullKeypath
);
2784 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2786 static const WCHAR szPermKey
[] =
2787 { '0','0','0','0','0','0','0','0','0','0','0','0',
2788 '0','0','0','0','0','0','0','0','0','0','0','0',
2789 '0','0','0','0','0','0','0','0',0 };
2791 msi_reg_set_val_str( hkey2
, szPermKey
, comp
->FullKeypath
);
2796 else if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ABSENT
))
2800 rc
= RegOpenKeyW(hkey
,squished_cc
,&hkey2
);
2801 if (rc
!= ERROR_SUCCESS
)
2804 RegDeleteValueW(hkey2
,squished_pc
);
2806 /* if the key is empty delete it */
2807 res
= RegEnumKeyExW(hkey2
,0,NULL
,0,0,NULL
,0,NULL
);
2809 if (res
== ERROR_NO_MORE_ITEMS
)
2810 RegDeleteKeyW(hkey
,squished_cc
);
2815 uirow
= MSI_CreateRecord(3);
2816 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2817 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2818 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
2819 ui_actiondata(package
,szProcessComponents
,uirow
);
2820 msiobj_release( &uirow
->hdr
);
2834 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
2835 LPWSTR lpszName
, LONG_PTR lParam
)
2838 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
2839 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
2843 if (!IS_INTRESOURCE(lpszName
))
2845 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
2849 sz
= strlenW(tl_struct
->source
)+4;
2850 sz
*= sizeof(WCHAR
);
2852 if ((INT_PTR
)lpszName
== 1)
2853 tl_struct
->path
= strdupW(tl_struct
->source
);
2856 tl_struct
->path
= msi_alloc(sz
);
2857 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
2860 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
2861 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
2862 if (!SUCCEEDED(res
))
2864 msi_free(tl_struct
->path
);
2865 tl_struct
->path
= NULL
;
2870 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
2871 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
2873 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2877 msi_free(tl_struct
->path
);
2878 tl_struct
->path
= NULL
;
2880 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2881 ITypeLib_Release(tl_struct
->ptLib
);
2886 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
2888 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2892 typelib_struct tl_struct
;
2894 static const WCHAR szTYPELIB
[] = {'T','Y','P','E','L','I','B',0};
2896 component
= MSI_RecordGetString(row
,3);
2897 comp
= get_loaded_component(package
,component
);
2899 return ERROR_SUCCESS
;
2901 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2903 TRACE("Skipping typelib reg due to disabled component\n");
2905 comp
->Action
= comp
->Installed
;
2907 return ERROR_SUCCESS
;
2910 comp
->Action
= INSTALLSTATE_LOCAL
;
2912 file
= get_loaded_file( package
, comp
->KeyPath
);
2914 return ERROR_SUCCESS
;
2916 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
2920 guid
= MSI_RecordGetString(row
,1);
2921 CLSIDFromString((LPWSTR
)guid
, &tl_struct
.clsid
);
2922 tl_struct
.source
= strdupW( file
->TargetPath
);
2923 tl_struct
.path
= NULL
;
2925 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
2926 (LONG_PTR
)&tl_struct
);
2934 helpid
= MSI_RecordGetString(row
,6);
2937 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,TRUE
,NULL
);
2938 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
2941 if (!SUCCEEDED(res
))
2942 ERR("Failed to register type library %s\n",
2943 debugstr_w(tl_struct
.path
));
2946 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
2948 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
2951 ITypeLib_Release(tl_struct
.ptLib
);
2952 msi_free(tl_struct
.path
);
2955 ERR("Failed to load type library %s\n",
2956 debugstr_w(tl_struct
.source
));
2958 FreeLibrary(module
);
2959 msi_free(tl_struct
.source
);
2962 ERR("Could not load file! %s\n", debugstr_w(file
->TargetPath
));
2964 return ERROR_SUCCESS
;
2967 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
2970 * OK this is a bit confusing.. I am given a _Component key and I believe
2971 * that the file that is being registered as a type library is the "key file
2972 * of that component" which I interpret to mean "The file in the KeyPath of
2977 static const WCHAR Query
[] =
2978 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2979 '`','T','y','p','e','L','i','b','`',0};
2981 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2982 if (rc
!= ERROR_SUCCESS
)
2983 return ERROR_SUCCESS
;
2985 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
2986 msiobj_release(&view
->hdr
);
2990 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
2992 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2993 LPWSTR target_file
, target_folder
, filename
;
2994 LPCWSTR buffer
, extension
;
2996 static const WCHAR szlnk
[]={'.','l','n','k',0};
2997 IShellLinkW
*sl
= NULL
;
2998 IPersistFile
*pf
= NULL
;
3001 buffer
= MSI_RecordGetString(row
,4);
3002 comp
= get_loaded_component(package
,buffer
);
3004 return ERROR_SUCCESS
;
3006 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3008 TRACE("Skipping shortcut creation due to disabled component\n");
3010 comp
->Action
= comp
->Installed
;
3012 return ERROR_SUCCESS
;
3015 comp
->Action
= INSTALLSTATE_LOCAL
;
3017 ui_actiondata(package
,szCreateShortcuts
,row
);
3019 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
3020 &IID_IShellLinkW
, (LPVOID
*) &sl
);
3024 ERR("CLSID_ShellLink not available\n");
3028 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
3031 ERR("QueryInterface(IID_IPersistFile) failed\n");
3035 buffer
= MSI_RecordGetString(row
,2);
3036 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,TRUE
,NULL
);
3038 /* may be needed because of a bug somehwere else */
3039 create_full_pathW(target_folder
);
3041 filename
= msi_dup_record_field( row
, 3 );
3042 reduce_to_longfilename(filename
);
3044 extension
= strchrW(filename
,'.');
3045 if (!extension
|| strcmpiW(extension
,szlnk
))
3047 int len
= strlenW(filename
);
3048 filename
= msi_realloc(filename
, len
* sizeof(WCHAR
) + sizeof(szlnk
));
3049 memcpy(filename
+ len
, szlnk
, sizeof(szlnk
));
3051 target_file
= build_directory_name(2, target_folder
, filename
);
3052 msi_free(target_folder
);
3055 buffer
= MSI_RecordGetString(row
,5);
3056 if (strchrW(buffer
,'['))
3059 deformat_string(package
,buffer
,&deformated
);
3060 IShellLinkW_SetPath(sl
,deformated
);
3061 msi_free(deformated
);
3065 FIXME("poorly handled shortcut format, advertised shortcut\n");
3066 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
3069 if (!MSI_RecordIsNull(row
,6))
3072 buffer
= MSI_RecordGetString(row
,6);
3073 deformat_string(package
,buffer
,&deformated
);
3074 IShellLinkW_SetArguments(sl
,deformated
);
3075 msi_free(deformated
);
3078 if (!MSI_RecordIsNull(row
,7))
3080 buffer
= MSI_RecordGetString(row
,7);
3081 IShellLinkW_SetDescription(sl
,buffer
);
3084 if (!MSI_RecordIsNull(row
,8))
3085 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
3087 if (!MSI_RecordIsNull(row
,9))
3092 buffer
= MSI_RecordGetString(row
,9);
3094 Path
= build_icon_path(package
,buffer
);
3095 index
= MSI_RecordGetInteger(row
,10);
3097 /* no value means 0 */
3098 if (index
== MSI_NULL_INTEGER
)
3101 IShellLinkW_SetIconLocation(sl
,Path
,index
);
3105 if (!MSI_RecordIsNull(row
,11))
3106 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
3108 if (!MSI_RecordIsNull(row
,12))
3111 buffer
= MSI_RecordGetString(row
,12);
3112 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, TRUE
, NULL
);
3114 IShellLinkW_SetWorkingDirectory(sl
,Path
);
3118 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
3119 IPersistFile_Save(pf
,target_file
,FALSE
);
3121 msi_free(target_file
);
3125 IPersistFile_Release( pf
);
3127 IShellLinkW_Release( sl
);
3129 return ERROR_SUCCESS
;
3132 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
3137 static const WCHAR Query
[] =
3138 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3139 '`','S','h','o','r','t','c','u','t','`',0};
3141 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3142 if (rc
!= ERROR_SUCCESS
)
3143 return ERROR_SUCCESS
;
3145 res
= CoInitialize( NULL
);
3148 ERR("CoInitialize failed\n");
3149 return ERROR_FUNCTION_FAILED
;
3152 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
3153 msiobj_release(&view
->hdr
);
3160 static UINT
ITERATE_PublishProduct(MSIRECORD
*row
, LPVOID param
)
3162 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
3171 FileName
= MSI_RecordGetString(row
,1);
3174 ERR("Unable to get FileName\n");
3175 return ERROR_SUCCESS
;
3178 FilePath
= build_icon_path(package
,FileName
);
3180 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
3182 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
3183 FILE_ATTRIBUTE_NORMAL
, NULL
);
3185 if (the_file
== INVALID_HANDLE_VALUE
)
3187 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3189 return ERROR_SUCCESS
;
3196 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3197 if (rc
!= ERROR_SUCCESS
)
3199 ERR("Failed to get stream\n");
3200 CloseHandle(the_file
);
3201 DeleteFileW(FilePath
);
3204 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3205 } while (sz
== 1024);
3209 CloseHandle(the_file
);
3211 uirow
= MSI_CreateRecord(1);
3212 MSI_RecordSetStringW(uirow
,1,FileName
);
3213 ui_actiondata(package
,szPublishProduct
,uirow
);
3214 msiobj_release( &uirow
->hdr
);
3216 return ERROR_SUCCESS
;
3220 * 99% of the work done here is only done for
3221 * advertised installs. However this is where the
3222 * Icon table is processed and written out
3223 * so that is what I am going to do here.
3225 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3229 static const WCHAR Query
[]=
3230 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3231 '`','I','c','o','n','`',0};
3232 /* for registry stuff */
3235 static const WCHAR szProductLanguage
[] =
3236 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3237 static const WCHAR szARPProductIcon
[] =
3238 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3239 static const WCHAR szProductVersion
[] =
3240 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3244 MSIHANDLE hDb
, hSumInfo
;
3246 /* write out icon files */
3248 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3249 if (rc
== ERROR_SUCCESS
)
3251 MSI_IterateRecords(view
, NULL
, ITERATE_PublishProduct
, package
);
3252 msiobj_release(&view
->hdr
);
3255 /* ok there is a lot more done here but i need to figure out what */
3257 rc
= MSIREG_OpenProductsKey(package
->ProductCode
,&hkey
,TRUE
);
3258 if (rc
!= ERROR_SUCCESS
)
3261 rc
= MSIREG_OpenUserProductsKey(package
->ProductCode
,&hukey
,TRUE
);
3262 if (rc
!= ERROR_SUCCESS
)
3266 buffer
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTNAMEW
);
3267 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3270 langid
= msi_get_property_int( package
, szProductLanguage
, 0 );
3271 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3273 buffer
= msi_dup_property( package
, szARPProductIcon
);
3276 LPWSTR path
= build_icon_path(package
,buffer
);
3277 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3282 buffer
= msi_dup_property( package
, szProductVersion
);
3285 DWORD verdword
= msi_version_str_to_dword(buffer
);
3286 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3290 /* FIXME: Need to write more keys to the user registry */
3292 hDb
= alloc_msihandle( &package
->db
->hdr
);
3294 rc
= ERROR_NOT_ENOUGH_MEMORY
;
3297 rc
= MsiGetSummaryInformationW(hDb
, NULL
, 0, &hSumInfo
);
3298 MsiCloseHandle(hDb
);
3299 if (rc
== ERROR_SUCCESS
)
3301 WCHAR guidbuffer
[0x200];
3303 rc
= MsiSummaryInfoGetPropertyW(hSumInfo
, 9, NULL
, NULL
, NULL
,
3305 if (rc
== ERROR_SUCCESS
)
3307 WCHAR squashed
[GUID_SIZE
];
3308 /* for now we only care about the first guid */
3309 LPWSTR ptr
= strchrW(guidbuffer
,';');
3311 squash_guid(guidbuffer
,squashed
);
3312 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PACKAGECODEW
, squashed
);
3316 ERR("Unable to query Revision_Number...\n");
3319 MsiCloseHandle(hSumInfo
);
3323 ERR("Unable to open Summary Information\n");
3335 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3337 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3338 LPCWSTR component
,section
,key
,value
,identifier
,filename
,dirproperty
;
3339 LPWSTR deformated_section
, deformated_key
, deformated_value
;
3340 LPWSTR folder
, fullname
= NULL
;
3344 static const WCHAR szWindowsFolder
[] =
3345 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3347 component
= MSI_RecordGetString(row
, 8);
3348 comp
= get_loaded_component(package
,component
);
3350 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3352 TRACE("Skipping ini file due to disabled component %s\n",
3353 debugstr_w(component
));
3355 comp
->Action
= comp
->Installed
;
3357 return ERROR_SUCCESS
;
3360 comp
->Action
= INSTALLSTATE_LOCAL
;
3362 identifier
= MSI_RecordGetString(row
,1);
3363 filename
= MSI_RecordGetString(row
,2);
3364 dirproperty
= MSI_RecordGetString(row
,3);
3365 section
= MSI_RecordGetString(row
,4);
3366 key
= MSI_RecordGetString(row
,5);
3367 value
= MSI_RecordGetString(row
,6);
3368 action
= MSI_RecordGetInteger(row
,7);
3370 deformat_string(package
,section
,&deformated_section
);
3371 deformat_string(package
,key
,&deformated_key
);
3372 deformat_string(package
,value
,&deformated_value
);
3376 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, TRUE
, NULL
);
3378 folder
= msi_dup_property( package
, dirproperty
);
3381 folder
= msi_dup_property( package
, szWindowsFolder
);
3385 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
3389 fullname
= build_directory_name(2, folder
, filename
);
3393 TRACE("Adding value %s to section %s in %s\n",
3394 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3395 debugstr_w(fullname
));
3396 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3397 deformated_value
, fullname
);
3399 else if (action
== 1)
3402 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3403 returned
, 10, fullname
);
3404 if (returned
[0] == 0)
3406 TRACE("Adding value %s to section %s in %s\n",
3407 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3408 debugstr_w(fullname
));
3410 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3411 deformated_value
, fullname
);
3414 else if (action
== 3)
3415 FIXME("Append to existing section not yet implemented\n");
3417 uirow
= MSI_CreateRecord(4);
3418 MSI_RecordSetStringW(uirow
,1,identifier
);
3419 MSI_RecordSetStringW(uirow
,2,deformated_section
);
3420 MSI_RecordSetStringW(uirow
,3,deformated_key
);
3421 MSI_RecordSetStringW(uirow
,4,deformated_value
);
3422 ui_actiondata(package
,szWriteIniValues
,uirow
);
3423 msiobj_release( &uirow
->hdr
);
3427 msi_free(deformated_key
);
3428 msi_free(deformated_value
);
3429 msi_free(deformated_section
);
3430 return ERROR_SUCCESS
;
3433 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
3437 static const WCHAR ExecSeqQuery
[] =
3438 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3439 '`','I','n','i','F','i','l','e','`',0};
3441 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3442 if (rc
!= ERROR_SUCCESS
)
3444 TRACE("no IniFile table\n");
3445 return ERROR_SUCCESS
;
3448 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
3449 msiobj_release(&view
->hdr
);
3453 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
3455 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3460 static const WCHAR ExeStr
[] =
3461 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3462 static const WCHAR close
[] = {'\"',0};
3464 PROCESS_INFORMATION info
;
3469 memset(&si
,0,sizeof(STARTUPINFOW
));
3471 filename
= MSI_RecordGetString(row
,1);
3472 file
= get_loaded_file( package
, filename
);
3476 ERR("Unable to find file id %s\n",debugstr_w(filename
));
3477 return ERROR_SUCCESS
;
3480 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
3482 FullName
= msi_alloc(len
*sizeof(WCHAR
));
3483 strcpyW(FullName
,ExeStr
);
3484 strcatW( FullName
, file
->TargetPath
);
3485 strcatW(FullName
,close
);
3487 TRACE("Registering %s\n",debugstr_w(FullName
));
3488 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
3492 msi_dialog_check_messages(info
.hProcess
);
3497 uirow
= MSI_CreateRecord( 2 );
3498 uipath
= strdupW( file
->TargetPath
);
3499 p
= strrchrW(uipath
,'\\');
3502 MSI_RecordSetStringW( uirow
, 1, &p
[2] );
3503 MSI_RecordSetStringW( uirow
, 2, uipath
);
3504 ui_actiondata( package
, szSelfRegModules
, uirow
);
3505 msiobj_release( &uirow
->hdr
);
3507 /* FIXME: call ui_progress? */
3509 return ERROR_SUCCESS
;
3512 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
3516 static const WCHAR ExecSeqQuery
[] =
3517 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3518 '`','S','e','l','f','R','e','g','`',0};
3520 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3521 if (rc
!= ERROR_SUCCESS
)
3523 TRACE("no SelfReg table\n");
3524 return ERROR_SUCCESS
;
3527 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
3528 msiobj_release(&view
->hdr
);
3530 return ERROR_SUCCESS
;
3533 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
3535 MSIFEATURE
*feature
;
3540 rc
= MSIREG_OpenFeaturesKey(package
->ProductCode
,&hkey
,TRUE
);
3541 if (rc
!= ERROR_SUCCESS
)
3544 rc
= MSIREG_OpenUserFeaturesKey(package
->ProductCode
,&hukey
,TRUE
);
3545 if (rc
!= ERROR_SUCCESS
)
3548 /* here the guids are base 85 encoded */
3549 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
3555 BOOL absent
= FALSE
;
3558 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
) &&
3559 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_SOURCE
) &&
3560 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ADVERTISED
))
3564 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3568 if (feature
->Feature_Parent
)
3569 size
+= strlenW( feature
->Feature_Parent
)+2;
3571 data
= msi_alloc(size
* sizeof(WCHAR
));
3574 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3576 MSICOMPONENT
* component
= cl
->component
;
3580 if (component
->ComponentId
)
3582 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
3583 CLSIDFromString(component
->ComponentId
, &clsid
);
3584 encode_base85_guid(&clsid
,buf
);
3585 TRACE("to %s\n",debugstr_w(buf
));
3589 if (feature
->Feature_Parent
)
3591 static const WCHAR sep
[] = {'\2',0};
3593 strcatW(data
,feature
->Feature_Parent
);
3596 msi_reg_set_val_str( hkey
, feature
->Feature
, data
);
3600 if (feature
->Feature_Parent
)
3601 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
3604 RegSetValueExW(hukey
,feature
->Feature
,0,REG_SZ
,
3605 (LPBYTE
)feature
->Feature_Parent
,size
);
3609 size
+= 2*sizeof(WCHAR
);
3610 data
= msi_alloc(size
);
3613 if (feature
->Feature_Parent
)
3614 strcpyW( &data
[1], feature
->Feature_Parent
);
3615 RegSetValueExW(hukey
,feature
->Feature
,0,REG_SZ
,
3621 uirow
= MSI_CreateRecord( 1 );
3622 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
3623 ui_actiondata( package
, szPublishFeatures
, uirow
);
3624 msiobj_release( &uirow
->hdr
);
3625 /* FIXME: call ui_progress? */
3634 static UINT
msi_get_local_package_name( LPWSTR path
)
3636 static const WCHAR szInstaller
[] = {
3637 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3638 static const WCHAR fmt
[] = { '%','x','.','m','s','i',0};
3642 time
= GetTickCount();
3643 GetWindowsDirectoryW( path
, MAX_PATH
);
3644 lstrcatW( path
, szInstaller
);
3645 CreateDirectoryW( path
, NULL
);
3647 len
= lstrlenW(path
);
3648 for (i
=0; i
<0x10000; i
++)
3650 snprintfW( &path
[len
], MAX_PATH
- len
, fmt
, (time
+i
)&0xffff );
3651 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
,
3652 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
3653 if (handle
!= INVALID_HANDLE_VALUE
)
3655 CloseHandle(handle
);
3658 if (GetLastError() != ERROR_FILE_EXISTS
&&
3659 GetLastError() != ERROR_SHARING_VIOLATION
)
3660 return ERROR_FUNCTION_FAILED
;
3663 return ERROR_SUCCESS
;
3666 static UINT
msi_make_package_local( MSIPACKAGE
*package
, HKEY hkey
)
3668 static const WCHAR szOriginalDatabase
[] =
3669 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3670 WCHAR packagefile
[MAX_PATH
];
3674 r
= msi_get_local_package_name( packagefile
);
3675 if (r
!= ERROR_SUCCESS
)
3678 TRACE("Copying to local package %s\n",debugstr_w(packagefile
));
3680 msiFilePath
= msi_dup_property( package
, szOriginalDatabase
);
3681 r
= CopyFileW( msiFilePath
, packagefile
, FALSE
);
3682 msi_free( msiFilePath
);
3686 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3687 debugstr_w(msiFilePath
), debugstr_w(packagefile
), GetLastError());
3688 return ERROR_FUNCTION_FAILED
;
3691 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3692 msi_reg_set_val_str( hkey
, INSTALLPROPERTY_LOCALPACKAGEW
, packagefile
);
3693 return ERROR_SUCCESS
;
3696 static UINT
msi_write_uninstall_property_vals( MSIPACKAGE
*package
, HKEY hkey
)
3698 LPWSTR prop
, val
, key
;
3699 static const LPCSTR propval
[] = {
3700 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3701 "ARPCONTACT", "Contact",
3702 "ARPCOMMENTS", "Comments",
3703 "ProductName", "DisplayName",
3704 "ProductVersion", "DisplayVersion",
3705 "ARPHELPLINK", "HelpLink",
3706 "ARPHELPTELEPHONE", "HelpTelephone",
3707 "ARPINSTALLLOCATION", "InstallLocation",
3708 "SourceDir", "InstallSource",
3709 "Manufacturer", "Publisher",
3710 "ARPREADME", "Readme",
3712 "ARPURLINFOABOUT", "URLInfoAbout",
3713 "ARPURLUPDATEINFO", "URLUpdateInfo",
3716 const LPCSTR
*p
= propval
;
3720 prop
= strdupAtoW( *p
++ );
3721 key
= strdupAtoW( *p
++ );
3722 val
= msi_dup_property( package
, prop
);
3723 msi_reg_set_val_str( hkey
, key
, val
);
3728 return ERROR_SUCCESS
;
3731 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
3734 LPWSTR buffer
= NULL
;
3737 static const WCHAR szWindowsInstaller
[] =
3738 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3739 static const WCHAR szUpgradeCode
[] =
3740 {'U','p','g','r','a','d','e','C','o','d','e',0};
3741 static const WCHAR modpath_fmt
[] =
3742 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3743 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3744 static const WCHAR szModifyPath
[] =
3745 {'M','o','d','i','f','y','P','a','t','h',0};
3746 static const WCHAR szUninstallString
[] =
3747 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3748 static const WCHAR szEstimatedSize
[] =
3749 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3750 static const WCHAR szProductLanguage
[] =
3751 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3752 static const WCHAR szProductVersion
[] =
3753 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3756 static const WCHAR date_fmt
[] = {'%','i','%','i','%','i',0};
3757 LPWSTR upgrade_code
;
3760 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
,&hkey
,TRUE
);
3761 if (rc
!= ERROR_SUCCESS
)
3764 /* dump all the info i can grab */
3765 /* FIXME: Flesh out more information */
3767 msi_write_uninstall_property_vals( package
, hkey
);
3769 msi_reg_set_val_dword( hkey
, szWindowsInstaller
, 1 );
3771 msi_make_package_local( package
, hkey
);
3773 /* do ModifyPath and UninstallString */
3774 size
= deformat_string(package
,modpath_fmt
,&buffer
);
3775 RegSetValueExW(hkey
,szModifyPath
,0,REG_EXPAND_SZ
,(LPBYTE
)buffer
,size
);
3776 RegSetValueExW(hkey
,szUninstallString
,0,REG_EXPAND_SZ
,(LPBYTE
)buffer
,size
);
3779 /* FIXME: Write real Estimated Size when we have it */
3780 msi_reg_set_val_dword( hkey
, szEstimatedSize
, 0 );
3782 GetLocalTime(&systime
);
3783 sprintfW(szDate
,date_fmt
,systime
.wYear
,systime
.wMonth
,systime
.wDay
);
3784 msi_reg_set_val_str( hkey
, INSTALLPROPERTY_INSTALLDATEW
, szDate
);
3786 langid
= msi_get_property_int( package
, szProductLanguage
, 0 );
3787 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3789 buffer
= msi_dup_property( package
, szProductVersion
);
3792 DWORD verdword
= msi_version_str_to_dword(buffer
);
3794 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3795 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>>24 );
3796 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>>16)&0x00FF );
3800 /* Handle Upgrade Codes */
3801 upgrade_code
= msi_dup_property( package
, szUpgradeCode
);
3806 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &hkey2
, TRUE
);
3807 squash_guid(package
->ProductCode
,squashed
);
3808 msi_reg_set_val_str( hkey2
, squashed
, NULL
);
3810 MSIREG_OpenUserUpgradeCodesKey(upgrade_code
, &hkey2
, TRUE
);
3811 squash_guid(package
->ProductCode
,squashed
);
3812 msi_reg_set_val_str( hkey2
, squashed
, NULL
);
3815 msi_free(upgrade_code
);
3820 /* FIXME: call ui_actiondata */
3822 return ERROR_SUCCESS
;
3825 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
3827 return execute_script(package
,INSTALL_SCRIPT
);
3830 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
3834 /* turn off scheduling */
3835 package
->script
->CurrentlyScripting
= FALSE
;
3837 /* first do the same as an InstallExecute */
3838 rc
= ACTION_InstallExecute(package
);
3839 if (rc
!= ERROR_SUCCESS
)
3842 /* then handle Commit Actions */
3843 rc
= execute_script(package
,COMMIT_SCRIPT
);
3848 static UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
3850 static const WCHAR RunOnce
[] = {
3851 'S','o','f','t','w','a','r','e','\\',
3852 'M','i','c','r','o','s','o','f','t','\\',
3853 'W','i','n','d','o','w','s','\\',
3854 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3855 'R','u','n','O','n','c','e',0};
3856 static const WCHAR InstallRunOnce
[] = {
3857 'S','o','f','t','w','a','r','e','\\',
3858 'M','i','c','r','o','s','o','f','t','\\',
3859 'W','i','n','d','o','w','s','\\',
3860 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3861 'I','n','s','t','a','l','l','e','r','\\',
3862 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3864 static const WCHAR msiexec_fmt
[] = {
3866 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3867 '\"','%','s','\"',0};
3868 static const WCHAR install_fmt
[] = {
3869 '/','I',' ','\"','%','s','\"',' ',
3870 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3871 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3872 WCHAR buffer
[256], sysdir
[MAX_PATH
];
3874 WCHAR squished_pc
[100];
3876 squash_guid(package
->ProductCode
,squished_pc
);
3878 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
3879 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
3880 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
3883 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
3886 TRACE("Reboot command %s\n",debugstr_w(buffer
));
3888 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
3889 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
3891 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
3894 return ERROR_INSTALL_SUSPEND
;
3897 static UINT
msi_set_sourcedir_props(MSIPACKAGE
*package
)
3902 p
= strrchrW( package
->PackagePath
, '\\' );
3904 return ERROR_SUCCESS
;
3906 len
= p
- package
->PackagePath
+ 2;
3907 source
= msi_alloc( len
* sizeof(WCHAR
) );
3908 lstrcpynW( source
, package
->PackagePath
, len
);
3910 MSI_SetPropertyW( package
, cszSourceDir
, source
);
3911 MSI_SetPropertyW( package
, cszSOURCEDIR
, source
);
3915 return ERROR_SUCCESS
;
3918 static UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
3924 * We are currently doing what should be done here in the top level Install
3925 * however for Administrative and uninstalls this step will be needed
3927 if (!package
->PackagePath
)
3928 return ERROR_SUCCESS
;
3930 msi_set_sourcedir_props(package
);
3932 attrib
= GetFileAttributesW(package
->PackagePath
);
3933 if (attrib
== INVALID_FILE_ATTRIBUTES
)
3939 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
3940 MSIINSTALLCONTEXT_USERMANAGED
, MSICODE_PRODUCT
,
3941 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
3942 if (rc
== ERROR_MORE_DATA
)
3944 prompt
= msi_alloc(size
* sizeof(WCHAR
));
3945 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
3946 MSIINSTALLCONTEXT_USERMANAGED
, MSICODE_PRODUCT
,
3947 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
3950 prompt
= strdupW(package
->PackagePath
);
3952 msg
= generate_error_string(package
,1302,1,prompt
);
3953 while(attrib
== INVALID_FILE_ATTRIBUTES
)
3955 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
3958 rc
= ERROR_INSTALL_USEREXIT
;
3961 attrib
= GetFileAttributesW(package
->PackagePath
);
3967 return ERROR_SUCCESS
;
3972 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
3979 static const WCHAR szPropKeys
[][80] =
3981 {'P','r','o','d','u','c','t','I','D',0},
3982 {'U','S','E','R','N','A','M','E',0},
3983 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3987 static const WCHAR szRegKeys
[][80] =
3989 {'P','r','o','d','u','c','t','I','D',0},
3990 {'R','e','g','O','w','n','e','r',0},
3991 {'R','e','g','C','o','m','p','a','n','y',0},
3995 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
3997 return ERROR_SUCCESS
;
3999 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
,&hkey
,TRUE
);
4000 if (rc
!= ERROR_SUCCESS
)
4003 for( i
= 0; szPropKeys
[i
][0]; i
++ )
4005 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
4006 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
4011 msi_free(productid
);
4014 /* FIXME: call ui_actiondata */
4016 return ERROR_SUCCESS
;
4020 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
4024 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
4025 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
4030 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4032 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4033 LPCWSTR compgroupid
=NULL
;
4034 LPCWSTR feature
=NULL
;
4035 LPCWSTR text
= NULL
;
4036 LPCWSTR qualifier
= NULL
;
4037 LPCWSTR component
= NULL
;
4038 LPWSTR advertise
= NULL
;
4039 LPWSTR output
= NULL
;
4041 UINT rc
= ERROR_SUCCESS
;
4046 component
= MSI_RecordGetString(rec
,3);
4047 comp
= get_loaded_component(package
,component
);
4049 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) &&
4050 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
) &&
4051 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ADVERTISED
))
4053 TRACE("Skipping: Component %s not scheduled for install\n",
4054 debugstr_w(component
));
4056 return ERROR_SUCCESS
;
4059 compgroupid
= MSI_RecordGetString(rec
,1);
4060 qualifier
= MSI_RecordGetString(rec
,2);
4062 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
4063 if (rc
!= ERROR_SUCCESS
)
4066 text
= MSI_RecordGetString(rec
,4);
4067 feature
= MSI_RecordGetString(rec
,5);
4069 advertise
= create_component_advertise_string(package
, comp
, feature
);
4071 sz
= strlenW(advertise
);
4074 sz
+= lstrlenW(text
);
4077 sz
*= sizeof(WCHAR
);
4079 output
= msi_alloc_zero(sz
);
4080 strcpyW(output
,advertise
);
4081 msi_free(advertise
);
4084 strcatW(output
,text
);
4086 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
4093 uirow
= MSI_CreateRecord( 2 );
4094 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4095 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4096 ui_actiondata( package
, szPublishComponents
, uirow
);
4097 msiobj_release( &uirow
->hdr
);
4098 /* FIXME: call ui_progress? */
4104 * At present I am ignorning the advertised components part of this and only
4105 * focusing on the qualified component sets
4107 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
4111 static const WCHAR ExecSeqQuery
[] =
4112 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4113 '`','P','u','b','l','i','s','h',
4114 'C','o','m','p','o','n','e','n','t','`',0};
4116 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4117 if (rc
!= ERROR_SUCCESS
)
4118 return ERROR_SUCCESS
;
4120 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
4121 msiobj_release(&view
->hdr
);
4126 static UINT
ITERATE_InstallService(MSIRECORD
*rec
, LPVOID param
)
4128 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4131 SC_HANDLE hscm
, service
= NULL
;
4132 LPCWSTR name
, disp
, comp
, depends
, pass
;
4133 LPCWSTR load_order
, serv_name
, key
;
4134 DWORD serv_type
, start_type
;
4137 static const WCHAR query
[] =
4138 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4139 '`','C','o','m','p','o','n','e','n','t','`',' ',
4140 'W','H','E','R','E',' ',
4141 '`','C','o','m','p','o','n','e','n','t','`',' ',
4142 '=','\'','%','s','\'',0};
4144 hscm
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASEW
, GENERIC_WRITE
);
4147 ERR("Failed to open the SC Manager!\n");
4151 start_type
= MSI_RecordGetInteger(rec
, 5);
4152 if (start_type
== SERVICE_BOOT_START
|| start_type
== SERVICE_SYSTEM_START
)
4155 depends
= MSI_RecordGetString(rec
, 8);
4156 if (depends
&& *depends
)
4157 FIXME("Dependency list unhandled!\n");
4159 name
= MSI_RecordGetString(rec
, 2);
4160 disp
= MSI_RecordGetString(rec
, 3);
4161 serv_type
= MSI_RecordGetInteger(rec
, 4);
4162 err_control
= MSI_RecordGetInteger(rec
, 6);
4163 load_order
= MSI_RecordGetString(rec
, 7);
4164 serv_name
= MSI_RecordGetString(rec
, 9);
4165 pass
= MSI_RecordGetString(rec
, 10);
4166 comp
= MSI_RecordGetString(rec
, 12);
4168 /* fetch the service path */
4169 row
= MSI_QueryGetRecord(package
->db
, query
, comp
);
4172 ERR("Control query failed!\n");
4176 key
= MSI_RecordGetString(row
, 6);
4177 msiobj_release(&row
->hdr
);
4179 file
= get_loaded_file(package
, key
);
4182 ERR("Failed to load the service file\n");
4186 service
= CreateServiceW(hscm
, name
, disp
, GENERIC_ALL
, serv_type
,
4187 start_type
, err_control
, file
->TargetPath
,
4188 load_order
, NULL
, NULL
, serv_name
, pass
);
4191 if (GetLastError() != ERROR_SERVICE_EXISTS
)
4192 ERR("Failed to create service %s: %d\n", debugstr_w(name
), GetLastError());
4196 CloseServiceHandle(service
);
4197 CloseServiceHandle(hscm
);
4199 return ERROR_SUCCESS
;
4202 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
4206 static const WCHAR ExecSeqQuery
[] =
4207 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4208 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4210 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4211 if (rc
!= ERROR_SUCCESS
)
4212 return ERROR_SUCCESS
;
4214 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallService
, package
);
4215 msiobj_release(&view
->hdr
);
4220 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4221 static LPCWSTR
*msi_service_args_to_vector(LPCWSTR name
, LPWSTR args
, DWORD
*numargs
)
4227 static const WCHAR separator
[] = {'[','~',']',0};
4230 sep_len
= sizeof(separator
) / sizeof(WCHAR
) - 1;
4235 vector
= msi_alloc(sizeof(LPWSTR
));
4243 vector
[*numargs
- 1] = p
;
4245 if ((q
= strstrW(p
, separator
)))
4249 vector
= msi_realloc(vector
, (*numargs
+ 1) * sizeof(LPWSTR
));
4260 static MSICOMPONENT
*msi_find_component( MSIPACKAGE
*package
, LPCWSTR component
)
4264 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
4266 if (!lstrcmpW(comp
->Component
, component
))
4273 static UINT
ITERATE_StartService(MSIRECORD
*rec
, LPVOID param
)
4275 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4277 SC_HANDLE scm
, service
= NULL
;
4278 LPCWSTR name
, *vector
= NULL
;
4280 DWORD event
, numargs
;
4281 UINT r
= ERROR_FUNCTION_FAILED
;
4283 comp
= msi_find_component(package
, MSI_RecordGetString(rec
, 6));
4284 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4285 return ERROR_SUCCESS
;
4287 name
= MSI_RecordGetString(rec
, 2);
4288 event
= MSI_RecordGetInteger(rec
, 3);
4289 args
= strdupW(MSI_RecordGetString(rec
, 4));
4291 if (!(event
& msidbServiceControlEventStart
))
4292 return ERROR_SUCCESS
;
4294 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_CONNECT
);
4297 ERR("Failed to open the service control manager\n");
4301 service
= OpenServiceW(scm
, name
, SERVICE_START
);
4304 ERR("Failed to open service %s\n", debugstr_w(name
));
4308 vector
= msi_service_args_to_vector(name
, args
, &numargs
);
4310 if (!StartServiceW(service
, numargs
, vector
))
4312 ERR("Failed to start service %s\n", debugstr_w(name
));
4319 CloseServiceHandle(service
);
4320 CloseServiceHandle(scm
);
4327 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
4332 static const WCHAR query
[] = {
4333 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4334 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4336 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4337 if (rc
!= ERROR_SUCCESS
)
4338 return ERROR_SUCCESS
;
4340 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StartService
, package
);
4341 msiobj_release(&view
->hdr
);
4346 static MSIFILE
*msi_find_file( MSIPACKAGE
*package
, LPCWSTR filename
)
4350 LIST_FOR_EACH_ENTRY(file
, &package
->files
, MSIFILE
, entry
)
4352 if (!lstrcmpW(file
->File
, filename
))
4359 static UINT
ITERATE_InstallODBCDriver( MSIRECORD
*rec
, LPVOID param
)
4361 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4362 LPWSTR driver
, driver_path
, ptr
;
4363 WCHAR outpath
[MAX_PATH
];
4364 MSIFILE
*driver_file
, *setup_file
;
4367 UINT r
= ERROR_SUCCESS
;
4369 static const WCHAR driver_fmt
[] = {
4370 'D','r','i','v','e','r','=','%','s',0};
4371 static const WCHAR setup_fmt
[] = {
4372 'S','e','t','u','p','=','%','s',0};
4373 static const WCHAR usage_fmt
[] = {
4374 'F','i','l','e','U','s','a','g','e','=','1',0};
4376 desc
= MSI_RecordGetString(rec
, 3);
4378 driver_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
4379 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
4381 if (!driver_file
|| !setup_file
)
4383 ERR("ODBC Driver entry not found!\n");
4384 return ERROR_FUNCTION_FAILED
;
4387 len
= lstrlenW(desc
) + lstrlenW(driver_fmt
) + lstrlenW(driver_file
->FileName
) +
4388 lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
) +
4389 lstrlenW(usage_fmt
) + 1;
4390 driver
= msi_alloc(len
* sizeof(WCHAR
));
4392 return ERROR_OUTOFMEMORY
;
4395 lstrcpyW(ptr
, desc
);
4396 ptr
+= lstrlenW(ptr
) + 1;
4398 sprintfW(ptr
, driver_fmt
, driver_file
->FileName
);
4399 ptr
+= lstrlenW(ptr
) + 1;
4401 sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
4402 ptr
+= lstrlenW(ptr
) + 1;
4404 lstrcpyW(ptr
, usage_fmt
);
4405 ptr
+= lstrlenW(ptr
) + 1;
4408 driver_path
= strdupW(driver_file
->TargetPath
);
4409 ptr
= strrchrW(driver_path
, '\\');
4410 if (ptr
) *ptr
= '\0';
4412 if (!SQLInstallDriverExW(driver
, driver_path
, outpath
, MAX_PATH
,
4413 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
4415 ERR("Failed to install SQL driver!\n");
4416 r
= ERROR_FUNCTION_FAILED
;
4420 msi_free(driver_path
);
4425 static UINT
ACTION_InstallODBC( MSIPACKAGE
*package
)
4430 static const WCHAR query
[] = {
4431 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4432 'O','D','B','C','D','r','i','v','e','r',0 };
4434 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4435 if (rc
!= ERROR_SUCCESS
)
4436 return ERROR_SUCCESS
;
4438 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDriver
, package
);
4439 msiobj_release(&view
->hdr
);
4444 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
4445 LPCSTR action
, LPCWSTR table
)
4447 static const WCHAR query
[] = {
4448 'S','E','L','E','C','T',' ','*',' ',
4449 'F','R','O','M',' ','`','%','s','`',0 };
4450 MSIQUERY
*view
= NULL
;
4454 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
4455 if (r
== ERROR_SUCCESS
)
4457 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
4458 msiobj_release(&view
->hdr
);
4462 FIXME("%s -> %u ignored %s table values\n",
4463 action
, count
, debugstr_w(table
));
4465 return ERROR_SUCCESS
;
4468 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
4470 TRACE("%p\n", package
);
4471 return ERROR_SUCCESS
;
4474 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
4476 static const WCHAR table
[] =
4477 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4478 return msi_unimplemented_action_stub( package
, "RemoveIniValues", table
);
4481 static UINT
ACTION_MoveFiles( MSIPACKAGE
*package
)
4483 static const WCHAR table
[] = { 'M','o','v','e','F','i','l','e',0 };
4484 return msi_unimplemented_action_stub( package
, "MoveFiles", table
);
4487 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
4489 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
4490 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
4493 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
4495 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
4496 return msi_unimplemented_action_stub( package
, "BindImage", table
);
4499 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
4501 static const WCHAR table
[] = {
4502 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4503 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
4506 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
4508 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
4509 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
4512 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
4514 static const WCHAR table
[] = { 'S','e','l','f','R','e','g',0 };
4515 return msi_unimplemented_action_stub( package
, "SelfUnregModules", table
);
4518 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
4520 static const WCHAR table
[] = {
4521 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4522 return msi_unimplemented_action_stub( package
, "StopServices", table
);
4525 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
4527 static const WCHAR table
[] = {
4528 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4529 return msi_unimplemented_action_stub( package
, "DeleteServices", table
);
4531 static UINT
ACTION_ValidateProductID( MSIPACKAGE
*package
)
4533 static const WCHAR table
[] = {
4534 'P','r','o','d','u','c','t','I','D',0 };
4535 return msi_unimplemented_action_stub( package
, "ValidateProductID", table
);
4538 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
4540 static const WCHAR table
[] = {
4541 'E','n','v','i','r','o','n','m','e','n','t',0 };
4542 return msi_unimplemented_action_stub( package
, "WriteEnvironmentStrings", table
);
4545 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
4547 static const WCHAR table
[] = {
4548 'E','n','v','i','r','o','n','m','e','n','t',0 };
4549 return msi_unimplemented_action_stub( package
, "RemoveEnvironmentStrings", table
);
4552 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
4554 static const WCHAR table
[] = {
4555 'M','s','i','A','s','s','e','m','b','l','y',0 };
4556 return msi_unimplemented_action_stub( package
, "MsiPublishAssemblies", table
);
4559 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
4561 static const WCHAR table
[] = {
4562 'M','s','i','A','s','s','e','m','b','l','y',0 };
4563 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
4566 static UINT
ACTION_UnregisterFonts( MSIPACKAGE
*package
)
4568 static const WCHAR table
[] = { 'F','o','n','t',0 };
4569 return msi_unimplemented_action_stub( package
, "UnregisterFonts", table
);
4572 static UINT
ACTION_CCPSearch( MSIPACKAGE
*package
)
4574 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
4575 return msi_unimplemented_action_stub( package
, "CCPSearch", table
);
4578 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
4580 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
4581 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
4584 static UINT
ACTION_RegisterComPlus( MSIPACKAGE
*package
)
4586 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
4587 return msi_unimplemented_action_stub( package
, "RegisterComPlus", table
);
4590 static UINT
ACTION_UnregisterComPlus( MSIPACKAGE
*package
)
4592 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
4593 return msi_unimplemented_action_stub( package
, "UnregisterComPlus", table
);
4596 static const struct _actions StandardActions
[] = {
4597 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
4598 { szAppSearch
, ACTION_AppSearch
},
4599 { szBindImage
, ACTION_BindImage
},
4600 { szCCPSearch
, ACTION_CCPSearch
},
4601 { szCostFinalize
, ACTION_CostFinalize
},
4602 { szCostInitialize
, ACTION_CostInitialize
},
4603 { szCreateFolders
, ACTION_CreateFolders
},
4604 { szCreateShortcuts
, ACTION_CreateShortcuts
},
4605 { szDeleteServices
, ACTION_DeleteServices
},
4606 { szDisableRollback
, NULL
},
4607 { szDuplicateFiles
, ACTION_DuplicateFiles
},
4608 { szExecuteAction
, ACTION_ExecuteAction
},
4609 { szFileCost
, ACTION_FileCost
},
4610 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
4611 { szForceReboot
, ACTION_ForceReboot
},
4612 { szInstallAdminPackage
, NULL
},
4613 { szInstallExecute
, ACTION_InstallExecute
},
4614 { szInstallExecuteAgain
, ACTION_InstallExecute
},
4615 { szInstallFiles
, ACTION_InstallFiles
},
4616 { szInstallFinalize
, ACTION_InstallFinalize
},
4617 { szInstallInitialize
, ACTION_InstallInitialize
},
4618 { szInstallSFPCatalogFile
, NULL
},
4619 { szInstallValidate
, ACTION_InstallValidate
},
4620 { szIsolateComponents
, ACTION_IsolateComponents
},
4621 { szLaunchConditions
, ACTION_LaunchConditions
},
4622 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
4623 { szMoveFiles
, ACTION_MoveFiles
},
4624 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
4625 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
4626 { szInstallODBC
, ACTION_InstallODBC
},
4627 { szInstallServices
, ACTION_InstallServices
},
4628 { szPatchFiles
, ACTION_PatchFiles
},
4629 { szProcessComponents
, ACTION_ProcessComponents
},
4630 { szPublishComponents
, ACTION_PublishComponents
},
4631 { szPublishFeatures
, ACTION_PublishFeatures
},
4632 { szPublishProduct
, ACTION_PublishProduct
},
4633 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
4634 { szRegisterComPlus
, ACTION_RegisterComPlus
},
4635 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
4636 { szRegisterFonts
, ACTION_RegisterFonts
},
4637 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
4638 { szRegisterProduct
, ACTION_RegisterProduct
},
4639 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
4640 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
4641 { szRegisterUser
, ACTION_RegisterUser
},
4642 { szRemoveDuplicateFiles
, NULL
},
4643 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
4644 { szRemoveExistingProducts
, NULL
},
4645 { szRemoveFiles
, ACTION_RemoveFiles
},
4646 { szRemoveFolders
, NULL
},
4647 { szRemoveIniValues
, ACTION_RemoveIniValues
},
4648 { szRemoveODBC
, NULL
},
4649 { szRemoveRegistryValues
, NULL
},
4650 { szRemoveShortcuts
, NULL
},
4651 { szResolveSource
, ACTION_ResolveSource
},
4652 { szRMCCPSearch
, ACTION_RMCCPSearch
},
4653 { szScheduleReboot
, NULL
},
4654 { szSelfRegModules
, ACTION_SelfRegModules
},
4655 { szSelfUnregModules
, ACTION_SelfUnregModules
},
4656 { szSetODBCFolders
, NULL
},
4657 { szStartServices
, ACTION_StartServices
},
4658 { szStopServices
, ACTION_StopServices
},
4659 { szUnpublishComponents
, NULL
},
4660 { szUnpublishFeatures
, NULL
},
4661 { szUnregisterClassInfo
, NULL
},
4662 { szUnregisterComPlus
, ACTION_UnregisterComPlus
},
4663 { szUnregisterExtensionInfo
, NULL
},
4664 { szUnregisterFonts
, ACTION_UnregisterFonts
},
4665 { szUnregisterMIMEInfo
, NULL
},
4666 { szUnregisterProgIdInfo
, NULL
},
4667 { szUnregisterTypeLibraries
, NULL
},
4668 { szValidateProductID
, ACTION_ValidateProductID
},
4669 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
4670 { szWriteIniValues
, ACTION_WriteIniValues
},
4671 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},