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
31 #include "wine/debug.h"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
51 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
);
52 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
);
53 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
);
54 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
, UINT
* rc
, BOOL force
);
57 * consts and values used
59 static const WCHAR c_colon
[] = {'C',':','\\',0};
61 static const WCHAR szCreateFolders
[] =
62 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
63 static const WCHAR szCostFinalize
[] =
64 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
65 const WCHAR szInstallFiles
[] =
66 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
67 const WCHAR szDuplicateFiles
[] =
68 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
69 static const WCHAR szWriteRegistryValues
[] =
70 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
71 'V','a','l','u','e','s',0};
72 static const WCHAR szCostInitialize
[] =
73 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
74 static const WCHAR szFileCost
[] =
75 {'F','i','l','e','C','o','s','t',0};
76 static const WCHAR szInstallInitialize
[] =
77 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
78 static const WCHAR szInstallValidate
[] =
79 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
80 static const WCHAR szLaunchConditions
[] =
81 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
82 static const WCHAR szProcessComponents
[] =
83 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
84 static const WCHAR szRegisterTypeLibraries
[] =
85 {'R','e','g','i','s','t','e','r','T','y','p','e',
86 'L','i','b','r','a','r','i','e','s',0};
87 const WCHAR szRegisterClassInfo
[] =
88 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
89 const WCHAR szRegisterProgIdInfo
[] =
90 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
91 static const WCHAR szCreateShortcuts
[] =
92 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
93 static const WCHAR szPublishProduct
[] =
94 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
95 static const WCHAR szWriteIniValues
[] =
96 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
97 static const WCHAR szSelfRegModules
[] =
98 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
99 static const WCHAR szPublishFeatures
[] =
100 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
101 static const WCHAR szRegisterProduct
[] =
102 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
103 static const WCHAR szInstallExecute
[] =
104 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
105 static const WCHAR szInstallExecuteAgain
[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
107 'A','g','a','i','n',0};
108 static const WCHAR szInstallFinalize
[] =
109 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
110 static const WCHAR szForceReboot
[] =
111 {'F','o','r','c','e','R','e','b','o','o','t',0};
112 static const WCHAR szResolveSource
[] =
113 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
114 static const WCHAR szAppSearch
[] =
115 {'A','p','p','S','e','a','r','c','h',0};
116 static const WCHAR szAllocateRegistrySpace
[] =
117 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
118 'S','p','a','c','e',0};
119 static const WCHAR szBindImage
[] =
120 {'B','i','n','d','I','m','a','g','e',0};
121 static const WCHAR szCCPSearch
[] =
122 {'C','C','P','S','e','a','r','c','h',0};
123 static const WCHAR szDeleteServices
[] =
124 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
125 static const WCHAR szDisableRollback
[] =
126 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
127 static const WCHAR szExecuteAction
[] =
128 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
129 const WCHAR szFindRelatedProducts
[] =
130 {'F','i','n','d','R','e','l','a','t','e','d',
131 'P','r','o','d','u','c','t','s',0};
132 static const WCHAR szInstallAdminPackage
[] =
133 {'I','n','s','t','a','l','l','A','d','m','i','n',
134 'P','a','c','k','a','g','e',0};
135 static const WCHAR szInstallSFPCatalogFile
[] =
136 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
138 static const WCHAR szIsolateComponents
[] =
139 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
140 const WCHAR szMigrateFeatureStates
[] =
141 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
142 'S','t','a','t','e','s',0};
143 const WCHAR szMoveFiles
[] =
144 {'M','o','v','e','F','i','l','e','s',0};
145 static const WCHAR szMsiPublishAssemblies
[] =
146 {'M','s','i','P','u','b','l','i','s','h',
147 'A','s','s','e','m','b','l','i','e','s',0};
148 static const WCHAR szMsiUnpublishAssemblies
[] =
149 {'M','s','i','U','n','p','u','b','l','i','s','h',
150 'A','s','s','e','m','b','l','i','e','s',0};
151 static const WCHAR szInstallODBC
[] =
152 {'I','n','s','t','a','l','l','O','D','B','C',0};
153 static const WCHAR szInstallServices
[] =
154 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
155 const WCHAR szPatchFiles
[] =
156 {'P','a','t','c','h','F','i','l','e','s',0};
157 static const WCHAR szPublishComponents
[] =
158 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
159 static const WCHAR szRegisterComPlus
[] =
160 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
161 const WCHAR szRegisterExtensionInfo
[] =
162 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
164 static const WCHAR szRegisterFonts
[] =
165 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
166 const WCHAR szRegisterMIMEInfo
[] =
167 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
168 static const WCHAR szRegisterUser
[] =
169 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
170 const WCHAR szRemoveDuplicateFiles
[] =
171 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
172 'F','i','l','e','s',0};
173 static const WCHAR szRemoveEnvironmentStrings
[] =
174 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
175 'S','t','r','i','n','g','s',0};
176 const WCHAR szRemoveExistingProducts
[] =
177 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
178 'P','r','o','d','u','c','t','s',0};
179 const WCHAR szRemoveFiles
[] =
180 {'R','e','m','o','v','e','F','i','l','e','s',0};
181 static const WCHAR szRemoveFolders
[] =
182 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
183 static const WCHAR szRemoveIniValues
[] =
184 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
185 static const WCHAR szRemoveODBC
[] =
186 {'R','e','m','o','v','e','O','D','B','C',0};
187 static const WCHAR szRemoveRegistryValues
[] =
188 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
189 'V','a','l','u','e','s',0};
190 static const WCHAR szRemoveShortcuts
[] =
191 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
192 static const WCHAR szRMCCPSearch
[] =
193 {'R','M','C','C','P','S','e','a','r','c','h',0};
194 static const WCHAR szScheduleReboot
[] =
195 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
196 static const WCHAR szSelfUnregModules
[] =
197 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
198 static const WCHAR szSetODBCFolders
[] =
199 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
200 static const WCHAR szStartServices
[] =
201 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
202 static const WCHAR szStopServices
[] =
203 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szUnpublishComponents
[] =
205 {'U','n','p','u','b','l','i','s','h',
206 'C','o','m','p','o','n','e','n','t','s',0};
207 static const WCHAR szUnpublishFeatures
[] =
208 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
209 const WCHAR szUnregisterClassInfo
[] =
210 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
212 static const WCHAR szUnregisterComPlus
[] =
213 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
214 const WCHAR szUnregisterExtensionInfo
[] =
215 {'U','n','r','e','g','i','s','t','e','r',
216 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
217 static const WCHAR szUnregisterFonts
[] =
218 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
219 const WCHAR szUnregisterMIMEInfo
[] =
220 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
221 const WCHAR szUnregisterProgIdInfo
[] =
222 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
224 static const WCHAR szUnregisterTypeLibraries
[] =
225 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
226 'L','i','b','r','a','r','i','e','s',0};
227 static const WCHAR szValidateProductID
[] =
228 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
229 static const WCHAR szWriteEnvironmentStrings
[] =
230 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
231 'S','t','r','i','n','g','s',0};
233 /* action handlers */
234 typedef UINT (*STANDARDACTIONHANDLER
)(MSIPACKAGE
*);
238 STANDARDACTIONHANDLER handler
;
242 /********************************************************
244 ********************************************************/
246 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
248 static const WCHAR Query_t
[] =
249 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
250 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
251 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
252 ' ','\'','%','s','\'',0};
255 row
= MSI_QueryGetRecord( package
->db
, Query_t
, action
);
258 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
259 msiobj_release(&row
->hdr
);
262 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
266 static const WCHAR template_s
[]=
267 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
269 static const WCHAR template_e
[]=
270 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
271 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
273 static const WCHAR format
[] =
274 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
278 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
280 sprintfW(message
,template_s
,timet
,action
);
282 sprintfW(message
,template_e
,timet
,action
,rc
);
284 row
= MSI_CreateRecord(1);
285 MSI_RecordSetStringW(row
,1,message
);
287 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
288 msiobj_release(&row
->hdr
);
291 UINT
msi_parse_command_line( MSIPACKAGE
*package
, LPCWSTR szCommandLine
)
296 LPWSTR prop
= NULL
, val
= NULL
;
299 return ERROR_SUCCESS
;
311 TRACE("Looking at %s\n",debugstr_w(ptr
));
313 ptr2
= strchrW(ptr
,'=');
316 ERR("command line contains unknown string : %s\n", debugstr_w(ptr
));
323 prop
= msi_alloc((len
+1)*sizeof(WCHAR
));
324 memcpy(prop
,ptr
,len
*sizeof(WCHAR
));
330 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
343 val
= msi_alloc((len
+1)*sizeof(WCHAR
));
344 memcpy(val
,ptr2
,len
*sizeof(WCHAR
));
347 if (lstrlenW(prop
) > 0)
349 TRACE("Found commandline property (%s) = (%s)\n",
350 debugstr_w(prop
), debugstr_w(val
));
351 MSI_SetPropertyW(package
,prop
,val
);
357 return ERROR_SUCCESS
;
361 static LPWSTR
* msi_split_string( LPCWSTR str
, WCHAR sep
)
364 LPWSTR p
, *ret
= NULL
;
370 /* count the number of substrings */
371 for ( pc
= str
, count
= 0; pc
; count
++ )
373 pc
= strchrW( pc
, sep
);
378 /* allocate space for an array of substring pointers and the substrings */
379 ret
= msi_alloc( (count
+1) * sizeof (LPWSTR
) +
380 (lstrlenW(str
)+1) * sizeof(WCHAR
) );
384 /* copy the string and set the pointers */
385 p
= (LPWSTR
) &ret
[count
+1];
387 for( count
= 0; (ret
[count
] = p
); count
++ )
389 p
= strchrW( p
, sep
);
397 static UINT
msi_check_transform_applicable( MSIPACKAGE
*package
, IStorage
*patch
)
399 WCHAR szProductCode
[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
400 LPWSTR prod_code
, patch_product
;
403 prod_code
= msi_dup_property( package
, szProductCode
);
404 patch_product
= msi_get_suminfo_product( patch
);
406 TRACE("db = %s patch = %s\n", debugstr_w(prod_code
), debugstr_w(patch_product
));
408 if ( strstrW( patch_product
, prod_code
) )
411 ret
= ERROR_FUNCTION_FAILED
;
413 msi_free( patch_product
);
414 msi_free( prod_code
);
419 static UINT
msi_apply_substorage_transform( MSIPACKAGE
*package
,
420 MSIDATABASE
*patch_db
, LPCWSTR name
)
422 UINT ret
= ERROR_FUNCTION_FAILED
;
423 IStorage
*stg
= NULL
;
426 TRACE("%p %s\n", package
, debugstr_w(name
) );
430 ERR("expected a colon in %s\n", debugstr_w(name
));
431 return ERROR_FUNCTION_FAILED
;
434 r
= IStorage_OpenStorage( patch_db
->storage
, name
, NULL
, STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
437 ret
= msi_check_transform_applicable( package
, stg
);
438 if (ret
== ERROR_SUCCESS
)
439 msi_table_apply_transform( package
->db
, stg
);
441 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name
));
442 IStorage_Release( stg
);
445 ERR("failed to open substorage %s\n", debugstr_w(name
));
447 return ERROR_SUCCESS
;
450 static UINT
msi_check_patch_applicable( MSIPACKAGE
*package
, MSISUMMARYINFO
*si
)
452 static const WCHAR szProdCode
[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
453 LPWSTR guid_list
, *guids
, product_code
;
454 UINT i
, ret
= ERROR_FUNCTION_FAILED
;
456 product_code
= msi_dup_property( package
, szProdCode
);
459 /* FIXME: the property ProductCode should be written into the DB somewhere */
460 ERR("no product code to check\n");
461 return ERROR_SUCCESS
;
464 guid_list
= msi_suminfo_dup_string( si
, PID_TEMPLATE
);
465 guids
= msi_split_string( guid_list
, ';' );
466 for ( i
= 0; guids
[i
] && ret
!= ERROR_SUCCESS
; i
++ )
468 if (!lstrcmpW( guids
[i
], product_code
))
472 msi_free( guid_list
);
473 msi_free( product_code
);
478 static UINT
msi_parse_patch_summary( MSIPACKAGE
*package
, MSIDATABASE
*patch_db
)
481 LPWSTR str
, *substorage
;
482 UINT i
, r
= ERROR_SUCCESS
;
484 si
= MSI_GetSummaryInformationW( patch_db
->storage
, 0 );
486 return ERROR_FUNCTION_FAILED
;
488 msi_check_patch_applicable( package
, si
);
490 /* enumerate the substorage */
491 str
= msi_suminfo_dup_string( si
, PID_LASTAUTHOR
);
492 substorage
= msi_split_string( str
, ';' );
493 for ( i
= 0; substorage
&& substorage
[i
] && r
== ERROR_SUCCESS
; i
++ )
494 r
= msi_apply_substorage_transform( package
, patch_db
, substorage
[i
] );
495 msi_free( substorage
);
498 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
500 msiobj_release( &si
->hdr
);
505 static UINT
msi_apply_patch_package( MSIPACKAGE
*package
, LPCWSTR file
)
507 MSIDATABASE
*patch_db
= NULL
;
510 TRACE("%p %s\n", package
, debugstr_w( file
) );
513 * We probably want to make sure we only open a patch collection here.
514 * Patch collections (.msp) and databases (.msi) have different GUIDs
515 * but currently MSI_OpenDatabaseW will accept both.
517 r
= MSI_OpenDatabaseW( file
, MSIDBOPEN_READONLY
, &patch_db
);
518 if ( r
!= ERROR_SUCCESS
)
520 ERR("failed to open patch collection %s\n", debugstr_w( file
) );
524 msi_parse_patch_summary( package
, patch_db
);
527 * There might be a CAB file in the patch package,
528 * so append it to the list of storage to search for streams.
530 append_storage_to_db( package
->db
, patch_db
->storage
);
532 msiobj_release( &patch_db
->hdr
);
534 return ERROR_SUCCESS
;
537 /* get the PATCH property, and apply all the patches it specifies */
538 static UINT
msi_apply_patches( MSIPACKAGE
*package
)
540 static const WCHAR szPatch
[] = { 'P','A','T','C','H',0 };
541 LPWSTR patch_list
, *patches
;
542 UINT i
, r
= ERROR_SUCCESS
;
544 patch_list
= msi_dup_property( package
, szPatch
);
546 TRACE("patches to be applied: %s\n", debugstr_w( patch_list
) );
548 patches
= msi_split_string( patch_list
, ';' );
549 for( i
=0; patches
&& patches
[i
] && r
== ERROR_SUCCESS
; i
++ )
550 r
= msi_apply_patch_package( package
, patches
[i
] );
553 msi_free( patch_list
);
558 static UINT
msi_apply_transforms( MSIPACKAGE
*package
)
560 static const WCHAR szTransforms
[] = {
561 'T','R','A','N','S','F','O','R','M','S',0 };
562 LPWSTR xform_list
, *xforms
;
563 UINT i
, r
= ERROR_SUCCESS
;
565 xform_list
= msi_dup_property( package
, szTransforms
);
566 xforms
= msi_split_string( xform_list
, ';' );
568 for( i
=0; xforms
&& xforms
[i
] && r
== ERROR_SUCCESS
; i
++ )
570 if (xforms
[i
][0] == ':')
571 r
= msi_apply_substorage_transform( package
, package
->db
, xforms
[i
] );
573 r
= MSI_DatabaseApplyTransformW( package
->db
, xforms
[i
], 0 );
577 msi_free( xform_list
);
582 static BOOL
ui_sequence_exists( MSIPACKAGE
*package
)
587 static const WCHAR ExecSeqQuery
[] =
588 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
589 '`','I','n','s','t','a','l','l',
590 'U','I','S','e','q','u','e','n','c','e','`',
591 ' ','W','H','E','R','E',' ',
592 '`','S','e','q','u','e','n','c','e','`',' ',
593 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
594 '`','S','e','q','u','e','n','c','e','`',0};
596 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
597 if (rc
== ERROR_SUCCESS
)
599 msiobj_release(&view
->hdr
);
606 static UINT
msi_set_sourcedir_props(MSIPACKAGE
*package
, BOOL replace
)
609 LPWSTR source
, check
;
612 static const WCHAR szOriginalDatabase
[] =
613 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
615 db
= msi_dup_property( package
, szOriginalDatabase
);
617 return ERROR_OUTOFMEMORY
;
619 p
= strrchrW( db
, '\\' );
622 p
= strrchrW( db
, '/' );
626 return ERROR_SUCCESS
;
631 source
= msi_alloc( len
* sizeof(WCHAR
) );
632 lstrcpynW( source
, db
, len
);
634 check
= msi_dup_property( package
, cszSourceDir
);
635 if (!check
|| replace
)
636 MSI_SetPropertyW( package
, cszSourceDir
, source
);
640 check
= msi_dup_property( package
, cszSOURCEDIR
);
641 if (!check
|| replace
)
642 MSI_SetPropertyW( package
, cszSOURCEDIR
, source
);
648 return ERROR_SUCCESS
;
651 /****************************************************
652 * TOP level entry points
653 *****************************************************/
655 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
656 LPCWSTR szCommandLine
)
659 BOOL ui
= FALSE
, ui_exists
;
660 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
661 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
662 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
664 MSI_SetPropertyW(package
, szAction
, szInstall
);
666 package
->script
= msi_alloc_zero(sizeof(MSISCRIPT
));
668 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
675 dir
= strdupW(szPackagePath
);
676 p
= strrchrW(dir
, '\\');
680 file
= szPackagePath
+ (p
- dir
);
685 dir
= msi_alloc(MAX_PATH
*sizeof(WCHAR
));
686 GetCurrentDirectoryW(MAX_PATH
, dir
);
687 lstrcatW(dir
, cszbs
);
688 file
= szPackagePath
;
691 msi_free( package
->PackagePath
);
692 package
->PackagePath
= msi_alloc((lstrlenW(dir
) + lstrlenW(file
) + 1) * sizeof(WCHAR
));
693 if (!package
->PackagePath
)
696 return ERROR_OUTOFMEMORY
;
699 lstrcpyW(package
->PackagePath
, dir
);
700 lstrcatW(package
->PackagePath
, file
);
703 msi_set_sourcedir_props(package
, FALSE
);
706 msi_parse_command_line( package
, szCommandLine
);
708 msi_apply_transforms( package
);
709 msi_apply_patches( package
);
711 /* properties may have been added by a transform */
712 msi_clone_properties( package
);
714 if ( (msi_get_property_int(package
, szUILevel
, 0) & INSTALLUILEVEL_MASK
) >= INSTALLUILEVEL_REDUCED
)
716 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
717 rc
= ACTION_ProcessUISequence(package
);
719 ui_exists
= ui_sequence_exists(package
);
720 if (rc
== ERROR_SUCCESS
|| !ui_exists
)
722 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
723 rc
= ACTION_ProcessExecSequence(package
,ui_exists
);
727 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
729 package
->script
->CurrentlyScripting
= FALSE
;
731 /* process the ending type action */
732 if (rc
== ERROR_SUCCESS
)
733 ACTION_PerformActionSequence(package
,-1,ui
);
734 else if (rc
== ERROR_INSTALL_USEREXIT
)
735 ACTION_PerformActionSequence(package
,-2,ui
);
736 else if (rc
== ERROR_INSTALL_SUSPEND
)
737 ACTION_PerformActionSequence(package
,-4,ui
);
739 ACTION_PerformActionSequence(package
,-3,ui
);
741 /* finish up running custom actions */
742 ACTION_FinishCustomActions(package
);
747 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
)
749 UINT rc
= ERROR_SUCCESS
;
751 static const WCHAR ExecSeqQuery
[] =
752 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
753 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
754 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
755 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
757 static const WCHAR UISeqQuery
[] =
758 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
759 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
760 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
761 ' ', '=',' ','%','i',0};
764 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
766 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
770 LPCWSTR action
, cond
;
772 TRACE("Running the actions\n");
774 /* check conditions */
775 cond
= MSI_RecordGetString(row
,2);
777 /* this is a hack to skip errors in the condition code */
778 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
781 action
= MSI_RecordGetString(row
,1);
784 ERR("failed to fetch action\n");
785 rc
= ERROR_FUNCTION_FAILED
;
790 rc
= ACTION_PerformUIAction(package
,action
,-1);
792 rc
= ACTION_PerformAction(package
,action
,-1,FALSE
);
794 msiobj_release(&row
->hdr
);
805 } iterate_action_param
;
807 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
809 iterate_action_param
*iap
= (iterate_action_param
*)param
;
811 LPCWSTR cond
, action
;
813 action
= MSI_RecordGetString(row
,1);
816 ERR("Error is retrieving action name\n");
817 return ERROR_FUNCTION_FAILED
;
820 /* check conditions */
821 cond
= MSI_RecordGetString(row
,2);
823 /* this is a hack to skip errors in the condition code */
824 if (MSI_EvaluateConditionW(iap
->package
, cond
) == MSICONDITION_FALSE
)
826 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action
));
827 return ERROR_SUCCESS
;
831 rc
= ACTION_PerformUIAction(iap
->package
,action
,-1);
833 rc
= ACTION_PerformAction(iap
->package
,action
,-1,FALSE
);
835 msi_dialog_check_messages( NULL
);
837 if (iap
->package
->CurrentInstallState
!= ERROR_SUCCESS
)
838 rc
= iap
->package
->CurrentInstallState
;
840 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
843 if (rc
!= ERROR_SUCCESS
)
844 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
849 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
853 static const WCHAR query
[] =
854 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
856 ' ','W','H','E','R','E',' ',
857 '`','S','e','q','u','e','n','c','e','`',' ',
858 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
859 '`','S','e','q','u','e','n','c','e','`',0};
860 iterate_action_param iap
;
863 * FIXME: probably should be checking UILevel in the
864 * ACTION_PerformUIAction/ACTION_PerformAction
865 * rather than saving the UI level here. Those
866 * two functions can be merged too.
868 iap
.package
= package
;
871 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
873 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
874 if (r
== ERROR_SUCCESS
)
876 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, &iap
);
877 msiobj_release(&view
->hdr
);
883 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
887 static const WCHAR ExecSeqQuery
[] =
888 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
889 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
890 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
891 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
892 'O','R','D','E','R',' ', 'B','Y',' ',
893 '`','S','e','q','u','e','n','c','e','`',0 };
895 static const WCHAR IVQuery
[] =
896 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
897 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
898 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
899 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
900 ' ','\'', 'I','n','s','t','a','l','l',
901 'V','a','l','i','d','a','t','e','\'', 0};
903 iterate_action_param iap
;
905 iap
.package
= package
;
908 if (package
->script
->ExecuteSequenceRun
)
910 TRACE("Execute Sequence already Run\n");
911 return ERROR_SUCCESS
;
914 package
->script
->ExecuteSequenceRun
= TRUE
;
916 /* get the sequence number */
919 row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
921 return ERROR_FUNCTION_FAILED
;
922 seq
= MSI_RecordGetInteger(row
,1);
923 msiobj_release(&row
->hdr
);
926 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
927 if (rc
== ERROR_SUCCESS
)
929 TRACE("Running the actions\n");
931 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
932 msiobj_release(&view
->hdr
);
938 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
942 static const WCHAR ExecSeqQuery
[] =
943 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
944 '`','I','n','s','t','a','l','l',
945 'U','I','S','e','q','u','e','n','c','e','`',
946 ' ','W','H','E','R','E',' ',
947 '`','S','e','q','u','e','n','c','e','`',' ',
948 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
949 '`','S','e','q','u','e','n','c','e','`',0};
950 iterate_action_param iap
;
952 iap
.package
= package
;
955 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
957 if (rc
== ERROR_SUCCESS
)
959 TRACE("Running the actions\n");
961 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
962 msiobj_release(&view
->hdr
);
968 /********************************************************
969 * ACTION helper functions and functions that perform the actions
970 *******************************************************/
971 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
972 UINT
* rc
, UINT script
, BOOL force
)
977 arc
= ACTION_CustomAction(package
, action
, script
, force
);
979 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
988 * A lot of actions are really important even if they don't do anything
989 * explicit... Lots of properties are set at the beginning of the installation
990 * CostFinalize does a bunch of work to translate the directories and such
992 * But until I get write access to the database that is hard, so I am going to
993 * hack it to see if I can get something to run.
995 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
, BOOL force
)
997 UINT rc
= ERROR_SUCCESS
;
1000 TRACE("Performing action (%s)\n",debugstr_w(action
));
1002 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
1005 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, force
);
1009 WARN("unhandled msi action %s\n",debugstr_w(action
));
1010 rc
= ERROR_FUNCTION_NOT_CALLED
;
1016 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
)
1018 UINT rc
= ERROR_SUCCESS
;
1019 BOOL handled
= FALSE
;
1021 TRACE("Performing action (%s)\n",debugstr_w(action
));
1023 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
1026 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, FALSE
);
1028 if( !handled
&& ACTION_DialogBox(package
,action
) == ERROR_SUCCESS
)
1033 WARN("unhandled msi action %s\n",debugstr_w(action
));
1034 rc
= ERROR_FUNCTION_NOT_CALLED
;
1042 * Actual Action Handlers
1045 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
1047 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1053 dir
= MSI_RecordGetString(row
,1);
1056 ERR("Unable to get folder id\n");
1057 return ERROR_SUCCESS
;
1060 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,TRUE
,&folder
);
1063 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
1064 return ERROR_SUCCESS
;
1067 TRACE("Folder is %s\n",debugstr_w(full_path
));
1070 uirow
= MSI_CreateRecord(1);
1071 MSI_RecordSetStringW(uirow
,1,full_path
);
1072 ui_actiondata(package
,szCreateFolders
,uirow
);
1073 msiobj_release( &uirow
->hdr
);
1075 if (folder
->State
== 0)
1076 create_full_pathW(full_path
);
1080 msi_free(full_path
);
1081 return ERROR_SUCCESS
;
1084 /* FIXME: probably should merge this with the above function */
1085 static UINT
msi_create_directory( MSIPACKAGE
* package
, LPCWSTR dir
)
1087 UINT rc
= ERROR_SUCCESS
;
1089 LPWSTR install_path
;
1091 install_path
= resolve_folder(package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
1093 return ERROR_FUNCTION_FAILED
;
1095 /* create the path */
1096 if (folder
->State
== 0)
1098 create_full_pathW(install_path
);
1101 msi_free(install_path
);
1106 UINT
msi_create_component_directories( MSIPACKAGE
*package
)
1110 /* create all the folders required by the components are going to install */
1111 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1113 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
1115 msi_create_directory( package
, comp
->Directory
);
1118 return ERROR_SUCCESS
;
1122 * Also we cannot enable/disable components either, so for now I am just going
1123 * to do all the directories for all the components.
1125 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1127 static const WCHAR ExecSeqQuery
[] =
1128 {'S','E','L','E','C','T',' ',
1129 '`','D','i','r','e','c','t','o','r','y','_','`',
1130 ' ','F','R','O','M',' ',
1131 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1135 /* create all the empty folders specified in the CreateFolder table */
1136 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1137 if (rc
!= ERROR_SUCCESS
)
1138 return ERROR_SUCCESS
;
1140 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
1141 msiobj_release(&view
->hdr
);
1143 msi_create_component_directories( package
);
1148 static UINT
load_component( MSIRECORD
*row
, LPVOID param
)
1150 MSIPACKAGE
*package
= param
;
1153 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1155 return ERROR_FUNCTION_FAILED
;
1157 list_add_tail( &package
->components
, &comp
->entry
);
1159 /* fill in the data */
1160 comp
->Component
= msi_dup_record_field( row
, 1 );
1162 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1164 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1165 comp
->Directory
= msi_dup_record_field( row
, 3 );
1166 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1167 comp
->Condition
= msi_dup_record_field( row
, 5 );
1168 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1170 comp
->Installed
= INSTALLSTATE_UNKNOWN
;
1171 msi_component_set_state( comp
, INSTALLSTATE_UNKNOWN
);
1173 return ERROR_SUCCESS
;
1176 static UINT
load_all_components( MSIPACKAGE
*package
)
1178 static const WCHAR query
[] = {
1179 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1180 '`','C','o','m','p','o','n','e','n','t','`',0 };
1184 if (!list_empty(&package
->components
))
1185 return ERROR_SUCCESS
;
1187 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1188 if (r
!= ERROR_SUCCESS
)
1191 r
= MSI_IterateRecords(view
, NULL
, load_component
, package
);
1192 msiobj_release(&view
->hdr
);
1197 MSIPACKAGE
*package
;
1198 MSIFEATURE
*feature
;
1201 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1205 cl
= msi_alloc( sizeof (*cl
) );
1207 return ERROR_NOT_ENOUGH_MEMORY
;
1208 cl
->component
= comp
;
1209 list_add_tail( &feature
->Components
, &cl
->entry
);
1211 return ERROR_SUCCESS
;
1214 static UINT
add_feature_child( MSIFEATURE
*parent
, MSIFEATURE
*child
)
1218 fl
= msi_alloc( sizeof(*fl
) );
1220 return ERROR_NOT_ENOUGH_MEMORY
;
1221 fl
->feature
= child
;
1222 list_add_tail( &parent
->Children
, &fl
->entry
);
1224 return ERROR_SUCCESS
;
1227 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1229 _ilfs
* ilfs
= (_ilfs
*)param
;
1233 component
= MSI_RecordGetString(row
,1);
1235 /* check to see if the component is already loaded */
1236 comp
= get_loaded_component( ilfs
->package
, component
);
1239 ERR("unknown component %s\n", debugstr_w(component
));
1240 return ERROR_FUNCTION_FAILED
;
1243 add_feature_component( ilfs
->feature
, comp
);
1244 comp
->Enabled
= TRUE
;
1246 return ERROR_SUCCESS
;
1249 static MSIFEATURE
*find_feature_by_name( MSIPACKAGE
*package
, LPCWSTR name
)
1251 MSIFEATURE
*feature
;
1256 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1258 if ( !lstrcmpW( feature
->Feature
, name
) )
1265 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1267 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1268 MSIFEATURE
* feature
;
1269 static const WCHAR Query1
[] =
1270 {'S','E','L','E','C','T',' ',
1271 '`','C','o','m','p','o','n','e','n','t','_','`',
1272 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1273 'C','o','m','p','o','n','e','n','t','s','`',' ',
1274 'W','H','E','R','E',' ',
1275 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1280 /* fill in the data */
1282 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1284 return ERROR_NOT_ENOUGH_MEMORY
;
1286 list_init( &feature
->Children
);
1287 list_init( &feature
->Components
);
1289 feature
->Feature
= msi_dup_record_field( row
, 1 );
1291 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1293 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1294 feature
->Title
= msi_dup_record_field( row
, 3 );
1295 feature
->Description
= msi_dup_record_field( row
, 4 );
1297 if (!MSI_RecordIsNull(row
,5))
1298 feature
->Display
= MSI_RecordGetInteger(row
,5);
1300 feature
->Level
= MSI_RecordGetInteger(row
,6);
1301 feature
->Directory
= msi_dup_record_field( row
, 7 );
1302 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1304 feature
->Installed
= INSTALLSTATE_UNKNOWN
;
1305 msi_feature_set_state( feature
, INSTALLSTATE_UNKNOWN
);
1307 list_add_tail( &package
->features
, &feature
->entry
);
1309 /* load feature components */
1311 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1312 if (rc
!= ERROR_SUCCESS
)
1313 return ERROR_SUCCESS
;
1315 ilfs
.package
= package
;
1316 ilfs
.feature
= feature
;
1318 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1319 msiobj_release(&view
->hdr
);
1321 return ERROR_SUCCESS
;
1324 static UINT
find_feature_children(MSIRECORD
* row
, LPVOID param
)
1326 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1327 MSIFEATURE
*parent
, *child
;
1329 child
= find_feature_by_name( package
, MSI_RecordGetString( row
, 1 ) );
1331 return ERROR_FUNCTION_FAILED
;
1333 if (!child
->Feature_Parent
)
1334 return ERROR_SUCCESS
;
1336 parent
= find_feature_by_name( package
, child
->Feature_Parent
);
1338 return ERROR_FUNCTION_FAILED
;
1340 add_feature_child( parent
, child
);
1341 return ERROR_SUCCESS
;
1344 static UINT
load_all_features( MSIPACKAGE
*package
)
1346 static const WCHAR query
[] = {
1347 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1348 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1349 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1353 if (!list_empty(&package
->features
))
1354 return ERROR_SUCCESS
;
1356 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1357 if (r
!= ERROR_SUCCESS
)
1360 r
= MSI_IterateRecords( view
, NULL
, load_feature
, package
);
1361 if (r
!= ERROR_SUCCESS
)
1364 r
= MSI_IterateRecords( view
, NULL
, find_feature_children
, package
);
1365 msiobj_release( &view
->hdr
);
1370 static LPWSTR
folder_split_path(LPWSTR p
, WCHAR ch
)
1381 static UINT
load_file_hash(MSIPACKAGE
*package
, MSIFILE
*file
)
1383 static const WCHAR query
[] = {
1384 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1385 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1386 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1387 MSIQUERY
*view
= NULL
;
1388 MSIRECORD
*row
= NULL
;
1391 TRACE("%s\n", debugstr_w(file
->File
));
1393 r
= MSI_OpenQuery(package
->db
, &view
, query
, file
->File
);
1394 if (r
!= ERROR_SUCCESS
)
1397 r
= MSI_ViewExecute(view
, NULL
);
1398 if (r
!= ERROR_SUCCESS
)
1401 r
= MSI_ViewFetch(view
, &row
);
1402 if (r
!= ERROR_SUCCESS
)
1405 file
->hash
.dwFileHashInfoSize
= sizeof(MSIFILEHASHINFO
);
1406 file
->hash
.dwData
[0] = MSI_RecordGetInteger(row
, 3);
1407 file
->hash
.dwData
[1] = MSI_RecordGetInteger(row
, 4);
1408 file
->hash
.dwData
[2] = MSI_RecordGetInteger(row
, 5);
1409 file
->hash
.dwData
[3] = MSI_RecordGetInteger(row
, 6);
1412 if (view
) msiobj_release(&view
->hdr
);
1413 if (row
) msiobj_release(&row
->hdr
);
1417 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1419 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1423 /* fill in the data */
1425 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1427 return ERROR_NOT_ENOUGH_MEMORY
;
1429 file
->File
= msi_dup_record_field( row
, 1 );
1431 component
= MSI_RecordGetString( row
, 2 );
1432 file
->Component
= get_loaded_component( package
, component
);
1434 if (!file
->Component
)
1435 ERR("Unfound Component %s\n",debugstr_w(component
));
1437 file
->FileName
= msi_dup_record_field( row
, 3 );
1438 reduce_to_longfilename( file
->FileName
);
1440 file
->ShortName
= msi_dup_record_field( row
, 3 );
1441 file
->LongName
= strdupW( folder_split_path(file
->ShortName
, '|'));
1443 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1444 file
->Version
= msi_dup_record_field( row
, 5 );
1445 file
->Language
= msi_dup_record_field( row
, 6 );
1446 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1447 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1449 file
->state
= msifs_invalid
;
1451 /* if the compressed bits are not set in the file attributes,
1452 * then read the information from the package word count property
1454 if (file
->Attributes
& msidbFileAttributesCompressed
)
1456 file
->IsCompressed
= TRUE
;
1458 else if (file
->Attributes
& msidbFileAttributesNoncompressed
)
1460 file
->IsCompressed
= FALSE
;
1464 file
->IsCompressed
= package
->WordCount
& MSIWORDCOUNT_COMPRESSED
;
1467 load_file_hash(package
, file
);
1469 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1471 list_add_tail( &package
->files
, &file
->entry
);
1473 return ERROR_SUCCESS
;
1476 static UINT
load_all_files(MSIPACKAGE
*package
)
1480 static const WCHAR Query
[] =
1481 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1482 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1483 '`','S','e','q','u','e','n','c','e','`', 0};
1485 if (!list_empty(&package
->files
))
1486 return ERROR_SUCCESS
;
1488 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1489 if (rc
!= ERROR_SUCCESS
)
1490 return ERROR_SUCCESS
;
1492 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1493 msiobj_release(&view
->hdr
);
1495 return ERROR_SUCCESS
;
1498 static UINT
load_folder( MSIRECORD
*row
, LPVOID param
)
1500 MSIPACKAGE
*package
= param
;
1501 static const WCHAR szDot
[] = { '.',0 };
1502 static WCHAR szEmpty
[] = { 0 };
1503 LPWSTR p
, tgt_short
, tgt_long
, src_short
, src_long
;
1506 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1508 return ERROR_NOT_ENOUGH_MEMORY
;
1510 folder
->Directory
= msi_dup_record_field( row
, 1 );
1512 TRACE("%s\n", debugstr_w(folder
->Directory
));
1514 p
= msi_dup_record_field(row
, 3);
1516 /* split src and target dir */
1518 src_short
= folder_split_path( p
, ':' );
1520 /* split the long and short paths */
1521 tgt_long
= folder_split_path( tgt_short
, '|' );
1522 src_long
= folder_split_path( src_short
, '|' );
1524 /* check for no-op dirs */
1525 if (!lstrcmpW(szDot
, tgt_short
))
1526 tgt_short
= szEmpty
;
1527 if (!lstrcmpW(szDot
, src_short
))
1528 src_short
= szEmpty
;
1531 tgt_long
= tgt_short
;
1534 src_short
= tgt_short
;
1535 src_long
= tgt_long
;
1539 src_long
= src_short
;
1541 /* FIXME: use the target short path too */
1542 folder
->TargetDefault
= strdupW(tgt_long
);
1543 folder
->SourceShortPath
= strdupW(src_short
);
1544 folder
->SourceLongPath
= strdupW(src_long
);
1547 TRACE("TargetDefault = %s\n",debugstr_w( folder
->TargetDefault
));
1548 TRACE("SourceLong = %s\n", debugstr_w( folder
->SourceLongPath
));
1549 TRACE("SourceShort = %s\n", debugstr_w( folder
->SourceShortPath
));
1551 folder
->Parent
= msi_dup_record_field( row
, 2 );
1553 folder
->Property
= msi_dup_property( package
, folder
->Directory
);
1555 list_add_tail( &package
->folders
, &folder
->entry
);
1557 TRACE("returning %p\n", folder
);
1559 return ERROR_SUCCESS
;
1562 static UINT
load_all_folders( MSIPACKAGE
*package
)
1564 static const WCHAR query
[] = {
1565 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1566 '`','D','i','r','e','c','t','o','r','y','`',0 };
1570 if (!list_empty(&package
->folders
))
1571 return ERROR_SUCCESS
;
1573 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1574 if (r
!= ERROR_SUCCESS
)
1577 r
= MSI_IterateRecords(view
, NULL
, load_folder
, package
);
1578 msiobj_release(&view
->hdr
);
1583 * I am not doing any of the costing functionality yet.
1584 * Mostly looking at doing the Component and Feature loading
1586 * The native MSI does A LOT of modification to tables here. Mostly adding
1587 * a lot of temporary columns to the Feature and Component tables.
1589 * note: Native msi also tracks the short filename. But I am only going to
1590 * track the long ones. Also looking at this directory table
1591 * it appears that the directory table does not get the parents
1592 * resolved base on property only based on their entries in the
1595 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1597 static const WCHAR szCosting
[] =
1598 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1599 static const WCHAR szZero
[] = { '0', 0 };
1601 MSI_SetPropertyW(package
, szCosting
, szZero
);
1602 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1604 load_all_components( package
);
1605 load_all_features( package
);
1606 load_all_files( package
);
1607 load_all_folders( package
);
1609 return ERROR_SUCCESS
;
1612 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1615 UINT rc
= ERROR_SUCCESS
;
1617 TRACE("Executing Script %i\n",script
);
1619 if (!package
->script
)
1621 ERR("no script!\n");
1622 return ERROR_FUNCTION_FAILED
;
1625 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1628 action
= package
->script
->Actions
[script
][i
];
1629 ui_actionstart(package
, action
);
1630 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1631 rc
= ACTION_PerformAction(package
, action
, script
, TRUE
);
1632 if (rc
!= ERROR_SUCCESS
)
1635 msi_free_action_script(package
, script
);
1639 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1641 return ERROR_SUCCESS
;
1644 static void ACTION_GetComponentInstallStates(MSIPACKAGE
*package
)
1648 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1652 if (!comp
->ComponentId
)
1655 res
= MsiGetComponentPathW( package
->ProductCode
,
1656 comp
->ComponentId
, NULL
, NULL
);
1658 res
= INSTALLSTATE_ABSENT
;
1659 comp
->Installed
= res
;
1663 /* scan for and update current install states */
1664 static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE
*package
)
1667 MSIFEATURE
*feature
;
1669 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1672 INSTALLSTATE res
= INSTALLSTATE_ABSENT
;
1674 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1676 comp
= cl
->component
;
1678 if (!comp
->ComponentId
)
1680 res
= INSTALLSTATE_ABSENT
;
1684 if (res
== INSTALLSTATE_ABSENT
)
1685 res
= comp
->Installed
;
1688 if (res
== comp
->Installed
)
1691 if (res
!= INSTALLSTATE_DEFAULT
&& res
!= INSTALLSTATE_LOCAL
&&
1692 res
!= INSTALLSTATE_SOURCE
)
1694 res
= INSTALLSTATE_INCOMPLETE
;
1698 feature
->Installed
= res
;
1702 static BOOL
process_state_property (MSIPACKAGE
* package
, LPCWSTR property
,
1705 static const WCHAR all
[]={'A','L','L',0};
1707 MSIFEATURE
*feature
;
1709 override
= msi_dup_property( package
, property
);
1713 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1715 if (strcmpiW(override
,all
)==0)
1716 msi_feature_set_state( feature
, state
);
1719 LPWSTR ptr
= override
;
1720 LPWSTR ptr2
= strchrW(override
,',');
1724 if ((ptr2
&& strncmpW(ptr
,feature
->Feature
, ptr2
-ptr
)==0)
1725 || (!ptr2
&& strcmpW(ptr
,feature
->Feature
)==0))
1727 msi_feature_set_state( feature
, state
);
1733 ptr2
= strchrW(ptr
,',');
1745 UINT
MSI_SetFeatureStates(MSIPACKAGE
*package
)
1748 static const WCHAR szlevel
[] =
1749 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1750 static const WCHAR szAddLocal
[] =
1751 {'A','D','D','L','O','C','A','L',0};
1752 static const WCHAR szAddSource
[] =
1753 {'A','D','D','S','O','U','R','C','E',0};
1754 static const WCHAR szRemove
[] =
1755 {'R','E','M','O','V','E',0};
1756 static const WCHAR szReinstall
[] =
1757 {'R','E','I','N','S','T','A','L','L',0};
1758 BOOL override
= FALSE
;
1759 MSICOMPONENT
* component
;
1760 MSIFEATURE
*feature
;
1763 /* I do not know if this is where it should happen.. but */
1765 TRACE("Checking Install Level\n");
1767 install_level
= msi_get_property_int( package
, szlevel
, 1 );
1769 /* ok here is the _real_ rub
1770 * all these activation/deactivation things happen in order and things
1771 * later on the list override things earlier on the list.
1772 * 1) INSTALLLEVEL processing
1782 * 11) FILEADDDEFAULT
1784 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1785 * REMOVE are the big ones, since we don't handle administrative installs
1788 override
|= process_state_property(package
,szAddLocal
,INSTALLSTATE_LOCAL
);
1789 override
|= process_state_property(package
,szRemove
,INSTALLSTATE_ABSENT
);
1790 override
|= process_state_property(package
,szAddSource
,INSTALLSTATE_SOURCE
);
1791 override
|= process_state_property(package
,szReinstall
,INSTALLSTATE_LOCAL
);
1795 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1797 BOOL feature_state
= ((feature
->Level
> 0) &&
1798 (feature
->Level
<= install_level
));
1800 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1802 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1803 msi_feature_set_state( feature
, INSTALLSTATE_SOURCE
);
1804 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1805 msi_feature_set_state( feature
, INSTALLSTATE_ADVERTISED
);
1807 msi_feature_set_state( feature
, INSTALLSTATE_LOCAL
);
1811 /* disable child features of unselected parent features */
1812 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1816 if (feature
->Level
> 0 && feature
->Level
<= install_level
)
1819 LIST_FOR_EACH_ENTRY( fl
, &feature
->Children
, FeatureList
, entry
)
1820 msi_feature_set_state( fl
->feature
, INSTALLSTATE_UNKNOWN
);
1825 /* set the Preselected Property */
1826 static const WCHAR szPreselected
[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1827 static const WCHAR szOne
[] = { '1', 0 };
1829 MSI_SetPropertyW(package
,szPreselected
,szOne
);
1833 * now we want to enable or disable components base on feature
1836 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1840 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1841 debugstr_w(feature
->Feature
), feature
->Level
, feature
->Installed
, feature
->Action
);
1843 if (!feature
->Level
)
1846 /* features with components that have compressed files are made local */
1847 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1849 if (cl
->component
->Enabled
&&
1850 cl
->component
->ForceLocalState
&&
1851 feature
->Action
== INSTALLSTATE_SOURCE
)
1853 msi_feature_set_state( feature
, INSTALLSTATE_LOCAL
);
1858 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1860 component
= cl
->component
;
1862 if (!component
->Enabled
)
1865 switch (feature
->Action
)
1867 case INSTALLSTATE_ABSENT
:
1868 component
->anyAbsent
= 1;
1870 case INSTALLSTATE_ADVERTISED
:
1871 component
->hasAdvertiseFeature
= 1;
1873 case INSTALLSTATE_SOURCE
:
1874 component
->hasSourceFeature
= 1;
1876 case INSTALLSTATE_LOCAL
:
1877 component
->hasLocalFeature
= 1;
1879 case INSTALLSTATE_DEFAULT
:
1880 if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1881 component
->hasAdvertiseFeature
= 1;
1882 else if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1883 component
->hasSourceFeature
= 1;
1885 component
->hasLocalFeature
= 1;
1893 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1895 /* if the component isn't enabled, leave it alone */
1896 if (!component
->Enabled
)
1899 /* check if it's local or source */
1900 if (!(component
->Attributes
& msidbComponentAttributesOptional
) &&
1901 (component
->hasLocalFeature
|| component
->hasSourceFeature
))
1903 if ((component
->Attributes
& msidbComponentAttributesSourceOnly
) &&
1904 !component
->ForceLocalState
)
1905 msi_component_set_state( component
, INSTALLSTATE_SOURCE
);
1907 msi_component_set_state( component
, INSTALLSTATE_LOCAL
);
1911 /* if any feature is local, the component must be local too */
1912 if (component
->hasLocalFeature
)
1914 msi_component_set_state( component
, INSTALLSTATE_LOCAL
);
1918 if (component
->hasSourceFeature
)
1920 msi_component_set_state( component
, INSTALLSTATE_SOURCE
);
1924 if (component
->hasAdvertiseFeature
)
1926 msi_component_set_state( component
, INSTALLSTATE_ADVERTISED
);
1930 TRACE("nobody wants component %s\n", debugstr_w(component
->Component
));
1931 if (component
->anyAbsent
)
1932 msi_component_set_state(component
, INSTALLSTATE_ABSENT
);
1935 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1937 if (component
->Action
== INSTALLSTATE_DEFAULT
)
1939 TRACE("%s was default, setting to local\n", debugstr_w(component
->Component
));
1940 msi_component_set_state( component
, INSTALLSTATE_LOCAL
);
1943 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1944 debugstr_w(component
->Component
), component
->Installed
, component
->Action
);
1948 return ERROR_SUCCESS
;
1951 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1953 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1958 name
= MSI_RecordGetString(row
,1);
1960 f
= get_loaded_folder(package
, name
);
1961 if (!f
) return ERROR_SUCCESS
;
1963 /* reset the ResolvedTarget */
1964 msi_free(f
->ResolvedTarget
);
1965 f
->ResolvedTarget
= NULL
;
1967 /* This helper function now does ALL the work */
1968 TRACE("Dir %s ...\n",debugstr_w(name
));
1969 path
= resolve_folder(package
,name
,FALSE
,TRUE
,TRUE
,NULL
);
1970 TRACE("resolves to %s\n",debugstr_w(path
));
1973 return ERROR_SUCCESS
;
1976 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
1978 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1980 MSIFEATURE
*feature
;
1982 name
= MSI_RecordGetString( row
, 1 );
1984 feature
= get_loaded_feature( package
, name
);
1986 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
1990 Condition
= MSI_RecordGetString(row
,3);
1992 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
1994 int level
= MSI_RecordGetInteger(row
,2);
1995 TRACE("Resetting feature %s to level %i\n", debugstr_w(name
), level
);
1996 feature
->Level
= level
;
1999 return ERROR_SUCCESS
;
2002 static LPWSTR
msi_get_disk_file_version( LPCWSTR filename
)
2004 static const WCHAR name_fmt
[] =
2005 {'%','u','.','%','u','.','%','u','.','%','u',0};
2006 static const WCHAR name
[] = {'\\',0};
2007 VS_FIXEDFILEINFO
*lpVer
;
2008 WCHAR filever
[0x100];
2014 TRACE("%s\n", debugstr_w(filename
));
2016 versize
= GetFileVersionInfoSizeW( filename
, &handle
);
2020 version
= msi_alloc( versize
);
2021 GetFileVersionInfoW( filename
, 0, versize
, version
);
2023 if (!VerQueryValueW( version
, name
, (LPVOID
*)&lpVer
, &sz
))
2025 msi_free( version
);
2029 sprintfW( filever
, name_fmt
,
2030 HIWORD(lpVer
->dwFileVersionMS
),
2031 LOWORD(lpVer
->dwFileVersionMS
),
2032 HIWORD(lpVer
->dwFileVersionLS
),
2033 LOWORD(lpVer
->dwFileVersionLS
));
2035 msi_free( version
);
2037 return strdupW( filever
);
2040 static UINT
msi_check_file_install_states( MSIPACKAGE
*package
)
2042 LPWSTR file_version
;
2045 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2047 MSICOMPONENT
* comp
= file
->Component
;
2053 if (file
->IsCompressed
)
2054 comp
->ForceLocalState
= TRUE
;
2056 /* calculate target */
2057 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, TRUE
, NULL
);
2059 msi_free(file
->TargetPath
);
2061 TRACE("file %s is named %s\n",
2062 debugstr_w(file
->File
), debugstr_w(file
->FileName
));
2064 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
2068 TRACE("file %s resolves to %s\n",
2069 debugstr_w(file
->File
), debugstr_w(file
->TargetPath
));
2071 /* don't check files of components that aren't installed */
2072 if (comp
->Installed
== INSTALLSTATE_UNKNOWN
||
2073 comp
->Installed
== INSTALLSTATE_ABSENT
)
2075 file
->state
= msifs_missing
; /* assume files are missing */
2079 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
2081 file
->state
= msifs_missing
;
2082 comp
->Cost
+= file
->FileSize
;
2083 comp
->Installed
= INSTALLSTATE_INCOMPLETE
;
2087 if (file
->Version
&&
2088 (file_version
= msi_get_disk_file_version( file
->TargetPath
)))
2090 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
2091 debugstr_w(file_version
));
2092 /* FIXME: seems like a bad way to compare version numbers */
2093 if (lstrcmpiW(file_version
, file
->Version
)<0)
2095 file
->state
= msifs_overwrite
;
2096 comp
->Cost
+= file
->FileSize
;
2097 comp
->Installed
= INSTALLSTATE_INCOMPLETE
;
2100 file
->state
= msifs_present
;
2101 msi_free( file_version
);
2104 file
->state
= msifs_present
;
2107 return ERROR_SUCCESS
;
2111 * A lot is done in this function aside from just the costing.
2112 * The costing needs to be implemented at some point but for now I am going
2113 * to focus on the directory building
2116 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2118 static const WCHAR ExecSeqQuery
[] =
2119 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2120 '`','D','i','r','e','c','t','o','r','y','`',0};
2121 static const WCHAR ConditionQuery
[] =
2122 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2123 '`','C','o','n','d','i','t','i','o','n','`',0};
2124 static const WCHAR szCosting
[] =
2125 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2126 static const WCHAR szlevel
[] =
2127 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2128 static const WCHAR szOutOfDiskSpace
[] =
2129 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2130 static const WCHAR szOne
[] = { '1', 0 };
2131 static const WCHAR szZero
[] = { '0', 0 };
2137 if ( 1 == msi_get_property_int( package
, szCosting
, 0 ) )
2138 return ERROR_SUCCESS
;
2140 TRACE("Building Directory properties\n");
2142 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2143 if (rc
== ERROR_SUCCESS
)
2145 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
2147 msiobj_release(&view
->hdr
);
2150 /* read components states from the registry */
2151 ACTION_GetComponentInstallStates(package
);
2153 TRACE("File calculations\n");
2154 msi_check_file_install_states( package
);
2156 TRACE("Evaluating Condition Table\n");
2158 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
2159 if (rc
== ERROR_SUCCESS
)
2161 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeConditions
,
2163 msiobj_release(&view
->hdr
);
2166 TRACE("Enabling or Disabling Components\n");
2167 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2169 if (MSI_EvaluateConditionW(package
, comp
->Condition
) == MSICONDITION_FALSE
)
2171 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
2172 comp
->Enabled
= FALSE
;
2176 MSI_SetPropertyW(package
,szCosting
,szOne
);
2177 /* set default run level if not set */
2178 level
= msi_dup_property( package
, szlevel
);
2180 MSI_SetPropertyW(package
,szlevel
, szOne
);
2183 /* FIXME: check volume disk space */
2184 MSI_SetPropertyW(package
, szOutOfDiskSpace
, szZero
);
2186 ACTION_UpdateFeatureInstallStates(package
);
2188 return MSI_SetFeatureStates(package
);
2191 /* OK this value is "interpreted" and then formatted based on the
2192 first few characters */
2193 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
2198 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2204 LPWSTR deformated
= NULL
;
2207 deformat_string(package
, &value
[2], &deformated
);
2209 /* binary value type */
2213 *size
= (strlenW(ptr
)/2)+1;
2215 *size
= strlenW(ptr
)/2;
2217 data
= msi_alloc(*size
);
2223 /* if uneven pad with a zero in front */
2229 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2231 TRACE("Uneven byte count\n");
2239 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2242 msi_free(deformated
);
2244 TRACE("Data %i bytes(%i)\n",*size
,count
);
2251 deformat_string(package
, &value
[1], &deformated
);
2254 *size
= sizeof(DWORD
);
2255 data
= msi_alloc(*size
);
2261 if ( (*p
< '0') || (*p
> '9') )
2267 if (deformated
[0] == '-')
2270 TRACE("DWORD %i\n",*(LPDWORD
)data
);
2272 msi_free(deformated
);
2277 static const WCHAR szMulti
[] = {'[','~',']',0};
2286 *type
=REG_EXPAND_SZ
;
2294 if (strstrW(value
,szMulti
))
2295 *type
= REG_MULTI_SZ
;
2297 /* remove initial delimiter */
2298 if (!strncmpW(value
, szMulti
, 3))
2301 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2303 /* add double NULL terminator */
2304 if (*type
== REG_MULTI_SZ
)
2306 *size
+= 2 * sizeof(WCHAR
); /* two NULL terminators */
2307 data
= msi_realloc_zero(data
, *size
);
2313 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2315 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2316 static const WCHAR szHCR
[] =
2317 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2318 'R','O','O','T','\\',0};
2319 static const WCHAR szHCU
[] =
2320 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2321 'U','S','E','R','\\',0};
2322 static const WCHAR szHLM
[] =
2323 {'H','K','E','Y','_','L','O','C','A','L','_',
2324 'M','A','C','H','I','N','E','\\',0};
2325 static const WCHAR szHU
[] =
2326 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2328 LPSTR value_data
= NULL
;
2329 HKEY root_key
, hkey
;
2332 LPCWSTR szRoot
, component
, name
, key
, value
;
2337 BOOL check_first
= FALSE
;
2340 ui_progress(package
,2,0,0,0);
2347 component
= MSI_RecordGetString(row
, 6);
2348 comp
= get_loaded_component(package
,component
);
2350 return ERROR_SUCCESS
;
2352 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2354 TRACE("Skipping write due to disabled component %s\n",
2355 debugstr_w(component
));
2357 comp
->Action
= comp
->Installed
;
2359 return ERROR_SUCCESS
;
2362 comp
->Action
= INSTALLSTATE_LOCAL
;
2364 name
= MSI_RecordGetString(row
, 4);
2365 if( MSI_RecordIsNull(row
,5) && name
)
2367 /* null values can have special meanings */
2368 if (name
[0]=='-' && name
[1] == 0)
2369 return ERROR_SUCCESS
;
2370 else if ((name
[0]=='+' && name
[1] == 0) ||
2371 (name
[0] == '*' && name
[1] == 0))
2376 root
= MSI_RecordGetInteger(row
,2);
2377 key
= MSI_RecordGetString(row
, 3);
2379 /* get the root key */
2384 static const WCHAR szALLUSER
[] = {'A','L','L','U','S','E','R','S',0};
2385 LPWSTR all_users
= msi_dup_property( package
, szALLUSER
);
2386 if (all_users
&& all_users
[0] == '1')
2388 root_key
= HKEY_LOCAL_MACHINE
;
2393 root_key
= HKEY_CURRENT_USER
;
2396 msi_free(all_users
);
2399 case 0: root_key
= HKEY_CLASSES_ROOT
;
2402 case 1: root_key
= HKEY_CURRENT_USER
;
2405 case 2: root_key
= HKEY_LOCAL_MACHINE
;
2408 case 3: root_key
= HKEY_USERS
;
2412 ERR("Unknown root %i\n",root
);
2418 return ERROR_SUCCESS
;
2420 deformat_string(package
, key
, &deformated
);
2421 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2422 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2423 strcpyW(uikey
,szRoot
);
2424 strcatW(uikey
,deformated
);
2426 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2428 ERR("Could not create key %s\n",debugstr_w(deformated
));
2429 msi_free(deformated
);
2431 return ERROR_SUCCESS
;
2433 msi_free(deformated
);
2435 value
= MSI_RecordGetString(row
,5);
2437 value_data
= parse_value(package
, value
, &type
, &size
);
2440 static const WCHAR szEmpty
[] = {0};
2441 value_data
= (LPSTR
)strdupW(szEmpty
);
2442 size
= sizeof(szEmpty
);
2446 deformat_string(package
, name
, &deformated
);
2450 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2452 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2457 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2458 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2460 TRACE("value %s of %s checked already exists\n",
2461 debugstr_w(deformated
), debugstr_w(uikey
));
2465 TRACE("Checked and setting value %s of %s\n",
2466 debugstr_w(deformated
), debugstr_w(uikey
));
2467 if (deformated
|| size
)
2468 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2473 uirow
= MSI_CreateRecord(3);
2474 MSI_RecordSetStringW(uirow
,2,deformated
);
2475 MSI_RecordSetStringW(uirow
,1,uikey
);
2478 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2480 MSI_RecordSetStringW(uirow
,3,value
);
2482 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2483 msiobj_release( &uirow
->hdr
);
2485 msi_free(value_data
);
2486 msi_free(deformated
);
2489 return ERROR_SUCCESS
;
2492 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2496 static const WCHAR ExecSeqQuery
[] =
2497 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2498 '`','R','e','g','i','s','t','r','y','`',0 };
2500 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2501 if (rc
!= ERROR_SUCCESS
)
2502 return ERROR_SUCCESS
;
2504 /* increment progress bar each time action data is sent */
2505 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2507 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2509 msiobj_release(&view
->hdr
);
2513 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2515 package
->script
->CurrentlyScripting
= TRUE
;
2517 return ERROR_SUCCESS
;
2521 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2526 static const WCHAR q1
[]=
2527 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2528 '`','R','e','g','i','s','t','r','y','`',0};
2531 MSIFEATURE
*feature
;
2534 TRACE("InstallValidate\n");
2536 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2537 if (rc
== ERROR_SUCCESS
)
2539 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2540 msiobj_release( &view
->hdr
);
2541 total
+= progress
* REG_PROGRESS_VALUE
;
2544 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2545 total
+= COMPONENT_PROGRESS_VALUE
;
2547 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2548 total
+= file
->FileSize
;
2550 ui_progress(package
,0,total
,0,0);
2552 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2554 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2555 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2556 feature
->ActionRequest
);
2559 return ERROR_SUCCESS
;
2562 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2564 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2565 LPCWSTR cond
= NULL
;
2566 LPCWSTR message
= NULL
;
2569 static const WCHAR title
[]=
2570 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2572 cond
= MSI_RecordGetString(row
,1);
2574 r
= MSI_EvaluateConditionW(package
,cond
);
2575 if (r
== MSICONDITION_FALSE
)
2577 if ((gUILevel
& INSTALLUILEVEL_MASK
) != INSTALLUILEVEL_NONE
)
2580 message
= MSI_RecordGetString(row
,2);
2581 deformat_string(package
,message
,&deformated
);
2582 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2583 msi_free(deformated
);
2586 return ERROR_INSTALL_FAILURE
;
2589 return ERROR_SUCCESS
;
2592 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2595 MSIQUERY
* view
= NULL
;
2596 static const WCHAR ExecSeqQuery
[] =
2597 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2598 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2600 TRACE("Checking launch conditions\n");
2602 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2603 if (rc
!= ERROR_SUCCESS
)
2604 return ERROR_SUCCESS
;
2606 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2607 msiobj_release(&view
->hdr
);
2612 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2616 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,TRUE
,NULL
);
2618 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2620 MSIRECORD
* row
= 0;
2622 LPWSTR deformated
,buffer
,deformated_name
;
2624 static const WCHAR ExecSeqQuery
[] =
2625 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2626 '`','R','e','g','i','s','t','r','y','`',' ',
2627 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2628 ' ','=',' ' ,'\'','%','s','\'',0 };
2629 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2630 static const WCHAR fmt2
[]=
2631 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2633 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2637 root
= MSI_RecordGetInteger(row
,2);
2638 key
= MSI_RecordGetString(row
, 3);
2639 name
= MSI_RecordGetString(row
, 4);
2640 deformat_string(package
, key
, &deformated
);
2641 deformat_string(package
, name
, &deformated_name
);
2643 len
= strlenW(deformated
) + 6;
2644 if (deformated_name
)
2645 len
+=strlenW(deformated_name
);
2647 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2649 if (deformated_name
)
2650 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2652 sprintfW(buffer
,fmt
,root
,deformated
);
2654 msi_free(deformated
);
2655 msi_free(deformated_name
);
2656 msiobj_release(&row
->hdr
);
2660 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2662 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2667 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2670 return strdupW( file
->TargetPath
);
2675 static HKEY
openSharedDLLsKey(void)
2678 static const WCHAR path
[] =
2679 {'S','o','f','t','w','a','r','e','\\',
2680 'M','i','c','r','o','s','o','f','t','\\',
2681 'W','i','n','d','o','w','s','\\',
2682 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2683 'S','h','a','r','e','d','D','L','L','s',0};
2685 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2689 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2694 DWORD sz
= sizeof(count
);
2697 hkey
= openSharedDLLsKey();
2698 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2699 if (rc
!= ERROR_SUCCESS
)
2705 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2709 hkey
= openSharedDLLsKey();
2711 msi_reg_set_val_dword( hkey
, path
, count
);
2713 RegDeleteValueW(hkey
,path
);
2719 * Return TRUE if the count should be written out and FALSE if not
2721 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2723 MSIFEATURE
*feature
;
2727 /* only refcount DLLs */
2728 if (comp
->KeyPath
== NULL
||
2729 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2730 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2734 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2735 write
= (count
> 0);
2737 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2741 /* increment counts */
2742 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2746 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
))
2749 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2751 if ( cl
->component
== comp
)
2756 /* decrement counts */
2757 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2761 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ABSENT
))
2764 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2766 if ( cl
->component
== comp
)
2771 /* ref count all the files in the component */
2776 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2778 if (file
->Component
== comp
)
2779 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2783 /* add a count for permanent */
2784 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2787 comp
->RefCount
= count
;
2790 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2794 * Ok further analysis makes me think that this work is
2795 * actually done in the PublishComponents and PublishFeatures
2796 * step, and not here. It appears like the keypath and all that is
2797 * resolved in this step, however actually written in the Publish steps.
2798 * But we will leave it here for now because it is unclear
2800 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2802 WCHAR squished_pc
[GUID_SIZE
];
2803 WCHAR squished_cc
[GUID_SIZE
];
2806 HKEY hkey
=0,hkey2
=0;
2810 /* writes the Component and Features values to the registry */
2812 rc
= MSIREG_OpenComponents(&hkey
);
2813 if (rc
!= ERROR_SUCCESS
)
2816 squash_guid(package
->ProductCode
,squished_pc
);
2817 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2819 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2823 ui_progress(package
,2,0,0,0);
2824 if (!comp
->ComponentId
)
2827 squash_guid(comp
->ComponentId
,squished_cc
);
2829 msi_free(comp
->FullKeypath
);
2830 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2832 /* do the refcounting */
2833 ACTION_RefCountComponent( package
, comp
);
2835 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2836 debugstr_w(comp
->Component
),
2837 debugstr_w(squished_cc
),
2838 debugstr_w(comp
->FullKeypath
),
2841 * Write the keypath out if the component is to be registered
2842 * and delete the key if the component is to be unregistered
2844 if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2846 rc
= RegCreateKeyW(hkey
,squished_cc
,&hkey2
);
2847 if (rc
!= ERROR_SUCCESS
)
2850 if (!comp
->FullKeypath
)
2853 msi_reg_set_val_str( hkey2
, squished_pc
, comp
->FullKeypath
);
2855 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2857 static const WCHAR szPermKey
[] =
2858 { '0','0','0','0','0','0','0','0','0','0','0','0',
2859 '0','0','0','0','0','0','0','0','0','0','0','0',
2860 '0','0','0','0','0','0','0','0',0 };
2862 msi_reg_set_val_str( hkey2
, szPermKey
, comp
->FullKeypath
);
2867 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, &hkey2
, TRUE
);
2868 if (rc
!= ERROR_SUCCESS
)
2871 msi_reg_set_val_str(hkey2
, squished_pc
, comp
->FullKeypath
);
2874 else if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ABSENT
))
2878 rc
= RegOpenKeyW(hkey
,squished_cc
,&hkey2
);
2879 if (rc
!= ERROR_SUCCESS
)
2882 RegDeleteValueW(hkey2
,squished_pc
);
2884 /* if the key is empty delete it */
2885 res
= RegEnumKeyExW(hkey2
,0,NULL
,0,0,NULL
,0,NULL
);
2887 if (res
== ERROR_NO_MORE_ITEMS
)
2888 RegDeleteKeyW(hkey
,squished_cc
);
2890 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
);
2894 uirow
= MSI_CreateRecord(3);
2895 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2896 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2897 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
2898 ui_actiondata(package
,szProcessComponents
,uirow
);
2899 msiobj_release( &uirow
->hdr
);
2913 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
2914 LPWSTR lpszName
, LONG_PTR lParam
)
2917 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
2918 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
2922 if (!IS_INTRESOURCE(lpszName
))
2924 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
2928 sz
= strlenW(tl_struct
->source
)+4;
2929 sz
*= sizeof(WCHAR
);
2931 if ((INT_PTR
)lpszName
== 1)
2932 tl_struct
->path
= strdupW(tl_struct
->source
);
2935 tl_struct
->path
= msi_alloc(sz
);
2936 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
2939 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
2940 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
2941 if (!SUCCEEDED(res
))
2943 msi_free(tl_struct
->path
);
2944 tl_struct
->path
= NULL
;
2949 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
2950 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
2952 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2956 msi_free(tl_struct
->path
);
2957 tl_struct
->path
= NULL
;
2959 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2960 ITypeLib_Release(tl_struct
->ptLib
);
2965 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
2967 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2971 typelib_struct tl_struct
;
2973 static const WCHAR szTYPELIB
[] = {'T','Y','P','E','L','I','B',0};
2975 component
= MSI_RecordGetString(row
,3);
2976 comp
= get_loaded_component(package
,component
);
2978 return ERROR_SUCCESS
;
2980 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2982 TRACE("Skipping typelib reg due to disabled component\n");
2984 comp
->Action
= comp
->Installed
;
2986 return ERROR_SUCCESS
;
2989 comp
->Action
= INSTALLSTATE_LOCAL
;
2991 file
= get_loaded_file( package
, comp
->KeyPath
);
2993 return ERROR_SUCCESS
;
2995 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
2999 guid
= MSI_RecordGetString(row
,1);
3000 CLSIDFromString((LPWSTR
)guid
, &tl_struct
.clsid
);
3001 tl_struct
.source
= strdupW( file
->TargetPath
);
3002 tl_struct
.path
= NULL
;
3004 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
3005 (LONG_PTR
)&tl_struct
);
3013 helpid
= MSI_RecordGetString(row
,6);
3016 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,TRUE
,NULL
);
3017 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
3020 if (!SUCCEEDED(res
))
3021 ERR("Failed to register type library %s\n",
3022 debugstr_w(tl_struct
.path
));
3025 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
3027 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
3030 ITypeLib_Release(tl_struct
.ptLib
);
3031 msi_free(tl_struct
.path
);
3034 ERR("Failed to load type library %s\n",
3035 debugstr_w(tl_struct
.source
));
3037 FreeLibrary(module
);
3038 msi_free(tl_struct
.source
);
3041 ERR("Could not load file! %s\n", debugstr_w(file
->TargetPath
));
3043 return ERROR_SUCCESS
;
3046 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
3049 * OK this is a bit confusing.. I am given a _Component key and I believe
3050 * that the file that is being registered as a type library is the "key file
3051 * of that component" which I interpret to mean "The file in the KeyPath of
3056 static const WCHAR Query
[] =
3057 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3058 '`','T','y','p','e','L','i','b','`',0};
3060 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3061 if (rc
!= ERROR_SUCCESS
)
3062 return ERROR_SUCCESS
;
3064 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
3065 msiobj_release(&view
->hdr
);
3069 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
3071 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3072 LPWSTR target_file
, target_folder
, filename
;
3073 LPCWSTR buffer
, extension
;
3075 static const WCHAR szlnk
[]={'.','l','n','k',0};
3076 IShellLinkW
*sl
= NULL
;
3077 IPersistFile
*pf
= NULL
;
3080 buffer
= MSI_RecordGetString(row
,4);
3081 comp
= get_loaded_component(package
,buffer
);
3083 return ERROR_SUCCESS
;
3085 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3087 TRACE("Skipping shortcut creation due to disabled component\n");
3089 comp
->Action
= comp
->Installed
;
3091 return ERROR_SUCCESS
;
3094 comp
->Action
= INSTALLSTATE_LOCAL
;
3096 ui_actiondata(package
,szCreateShortcuts
,row
);
3098 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
3099 &IID_IShellLinkW
, (LPVOID
*) &sl
);
3103 ERR("CLSID_ShellLink not available\n");
3107 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
3110 ERR("QueryInterface(IID_IPersistFile) failed\n");
3114 buffer
= MSI_RecordGetString(row
,2);
3115 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,TRUE
,NULL
);
3117 /* may be needed because of a bug somewhere else */
3118 create_full_pathW(target_folder
);
3120 filename
= msi_dup_record_field( row
, 3 );
3121 reduce_to_longfilename(filename
);
3123 extension
= strchrW(filename
,'.');
3124 if (!extension
|| strcmpiW(extension
,szlnk
))
3126 int len
= strlenW(filename
);
3127 filename
= msi_realloc(filename
, len
* sizeof(WCHAR
) + sizeof(szlnk
));
3128 memcpy(filename
+ len
, szlnk
, sizeof(szlnk
));
3130 target_file
= build_directory_name(2, target_folder
, filename
);
3131 msi_free(target_folder
);
3134 buffer
= MSI_RecordGetString(row
,5);
3135 if (strchrW(buffer
,'['))
3138 deformat_string(package
,buffer
,&deformated
);
3139 IShellLinkW_SetPath(sl
,deformated
);
3140 msi_free(deformated
);
3144 FIXME("poorly handled shortcut format, advertised shortcut\n");
3145 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
3148 if (!MSI_RecordIsNull(row
,6))
3151 buffer
= MSI_RecordGetString(row
,6);
3152 deformat_string(package
,buffer
,&deformated
);
3153 IShellLinkW_SetArguments(sl
,deformated
);
3154 msi_free(deformated
);
3157 if (!MSI_RecordIsNull(row
,7))
3159 buffer
= MSI_RecordGetString(row
,7);
3160 IShellLinkW_SetDescription(sl
,buffer
);
3163 if (!MSI_RecordIsNull(row
,8))
3164 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
3166 if (!MSI_RecordIsNull(row
,9))
3171 buffer
= MSI_RecordGetString(row
,9);
3173 Path
= build_icon_path(package
,buffer
);
3174 index
= MSI_RecordGetInteger(row
,10);
3176 /* no value means 0 */
3177 if (index
== MSI_NULL_INTEGER
)
3180 IShellLinkW_SetIconLocation(sl
,Path
,index
);
3184 if (!MSI_RecordIsNull(row
,11))
3185 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
3187 if (!MSI_RecordIsNull(row
,12))
3190 buffer
= MSI_RecordGetString(row
,12);
3191 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, TRUE
, NULL
);
3193 IShellLinkW_SetWorkingDirectory(sl
,Path
);
3197 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
3198 IPersistFile_Save(pf
,target_file
,FALSE
);
3200 msi_free(target_file
);
3204 IPersistFile_Release( pf
);
3206 IShellLinkW_Release( sl
);
3208 return ERROR_SUCCESS
;
3211 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
3216 static const WCHAR Query
[] =
3217 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3218 '`','S','h','o','r','t','c','u','t','`',0};
3220 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3221 if (rc
!= ERROR_SUCCESS
)
3222 return ERROR_SUCCESS
;
3224 res
= CoInitialize( NULL
);
3227 ERR("CoInitialize failed\n");
3228 return ERROR_FUNCTION_FAILED
;
3231 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
3232 msiobj_release(&view
->hdr
);
3239 static UINT
ITERATE_PublishProduct(MSIRECORD
*row
, LPVOID param
)
3241 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
3250 FileName
= MSI_RecordGetString(row
,1);
3253 ERR("Unable to get FileName\n");
3254 return ERROR_SUCCESS
;
3257 FilePath
= build_icon_path(package
,FileName
);
3259 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
3261 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
3262 FILE_ATTRIBUTE_NORMAL
, NULL
);
3264 if (the_file
== INVALID_HANDLE_VALUE
)
3266 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3268 return ERROR_SUCCESS
;
3275 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3276 if (rc
!= ERROR_SUCCESS
)
3278 ERR("Failed to get stream\n");
3279 CloseHandle(the_file
);
3280 DeleteFileW(FilePath
);
3283 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3284 } while (sz
== 1024);
3288 CloseHandle(the_file
);
3290 uirow
= MSI_CreateRecord(1);
3291 MSI_RecordSetStringW(uirow
,1,FileName
);
3292 ui_actiondata(package
,szPublishProduct
,uirow
);
3293 msiobj_release( &uirow
->hdr
);
3295 return ERROR_SUCCESS
;
3298 static BOOL
msi_check_publish(MSIPACKAGE
*package
)
3300 MSIFEATURE
*feature
;
3302 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3304 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
3312 * 99% of the work done here is only done for
3313 * advertised installs. However this is where the
3314 * Icon table is processed and written out
3315 * so that is what I am going to do here.
3317 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3322 MSISOURCELISTINFO
*info
;
3324 static const WCHAR Query
[]=
3325 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3326 '`','I','c','o','n','`',0};
3327 /* for registry stuff */
3330 HKEY hudkey
=0, props
=0;
3332 static const WCHAR szProductLanguage
[] =
3333 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3334 static const WCHAR szARPProductIcon
[] =
3335 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3336 static const WCHAR szProductVersion
[] =
3337 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3338 static const WCHAR szSourceList
[] =
3339 {'S','o','u','r','c','e','L','i','s','t',0};
3340 static const WCHAR szEmpty
[] = {0};
3344 MSIHANDLE hDb
, hSumInfo
;
3346 /* FIXME: also need to publish if the product is in advertise mode */
3347 if (!msi_check_publish(package
))
3348 return ERROR_SUCCESS
;
3350 /* write out icon files */
3352 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3353 if (rc
== ERROR_SUCCESS
)
3355 MSI_IterateRecords(view
, NULL
, ITERATE_PublishProduct
, package
);
3356 msiobj_release(&view
->hdr
);
3359 /* ok there is a lot more done here but i need to figure out what */
3361 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3363 rc
= MSIREG_OpenLocalClassesProductKey(package
->ProductCode
, &hukey
, TRUE
);
3364 if (rc
!= ERROR_SUCCESS
)
3367 rc
= MSIREG_OpenLocalSystemInstallProps(package
->ProductCode
, &props
, TRUE
);
3368 if (rc
!= ERROR_SUCCESS
)
3373 rc
= MSIREG_OpenProductsKey(package
->ProductCode
,&hkey
,TRUE
);
3374 if (rc
!= ERROR_SUCCESS
)
3377 rc
= MSIREG_OpenUserProductsKey(package
->ProductCode
,&hukey
,TRUE
);
3378 if (rc
!= ERROR_SUCCESS
)
3381 rc
= MSIREG_OpenCurrentUserInstallProps(package
->ProductCode
, &props
, TRUE
);
3382 if (rc
!= ERROR_SUCCESS
)
3386 rc
= RegCreateKeyW(hukey
, szSourceList
, &source
);
3387 if (rc
!= ERROR_SUCCESS
)
3390 RegCloseKey(source
);
3392 rc
= MSIREG_OpenUserDataProductKey(package
->ProductCode
,&hudkey
,TRUE
);
3393 if (rc
!= ERROR_SUCCESS
)
3396 buffer
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTNAMEW
);
3397 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3400 langid
= msi_get_property_int( package
, szProductLanguage
, 0 );
3401 msi_reg_set_val_dword( hukey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3403 packname
= strrchrW( package
->PackagePath
, '\\' ) + 1;
3404 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PACKAGENAMEW
, packname
);
3407 msi_reg_set_val_dword( hukey
, INSTALLPROPERTY_AUTHORIZED_LUA_APPW
, 0 );
3408 msi_reg_set_val_dword( props
, INSTALLPROPERTY_INSTANCETYPEW
, 0 );
3410 buffer
= msi_dup_property( package
, szARPProductIcon
);
3413 LPWSTR path
= build_icon_path(package
,buffer
);
3414 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3419 buffer
= msi_dup_property( package
, szProductVersion
);
3422 DWORD verdword
= msi_version_str_to_dword(buffer
);
3423 msi_reg_set_val_dword( hukey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3427 buffer
= strrchrW( package
->PackagePath
, '\\') + 1;
3428 rc
= MsiSourceListSetInfoW( package
->ProductCode
, NULL
,
3429 package
->Context
, MSICODE_PRODUCT
,
3430 INSTALLPROPERTY_PACKAGENAMEW
, buffer
);
3431 if (rc
!= ERROR_SUCCESS
)
3434 rc
= MsiSourceListSetInfoW( package
->ProductCode
, NULL
,
3435 package
->Context
, MSICODE_PRODUCT
,
3436 INSTALLPROPERTY_MEDIAPACKAGEPATHW
, szEmpty
);
3437 if (rc
!= ERROR_SUCCESS
)
3440 rc
= MsiSourceListSetInfoW( package
->ProductCode
, NULL
,
3441 package
->Context
, MSICODE_PRODUCT
,
3442 INSTALLPROPERTY_DISKPROMPTW
, szEmpty
);
3443 if (rc
!= ERROR_SUCCESS
)
3446 /* FIXME: Need to write more keys to the user registry */
3448 hDb
= alloc_msihandle( &package
->db
->hdr
);
3450 rc
= ERROR_NOT_ENOUGH_MEMORY
;
3453 rc
= MsiGetSummaryInformationW(hDb
, NULL
, 0, &hSumInfo
);
3454 MsiCloseHandle(hDb
);
3455 if (rc
== ERROR_SUCCESS
)
3457 WCHAR guidbuffer
[0x200];
3459 rc
= MsiSummaryInfoGetPropertyW(hSumInfo
, 9, NULL
, NULL
, NULL
,
3461 if (rc
== ERROR_SUCCESS
)
3463 /* for now we only care about the first guid */
3464 LPWSTR ptr
= strchrW(guidbuffer
,';');
3466 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PACKAGECODEW
, guidbuffer
);
3470 ERR("Unable to query Revision_Number...\n");
3473 MsiCloseHandle(hSumInfo
);
3477 ERR("Unable to open Summary Information\n");
3481 /* publish the SourceList info */
3482 LIST_FOR_EACH_ENTRY(info
, &package
->sourcelist_info
, MSISOURCELISTINFO
, entry
)
3484 if (!lstrcmpW(info
->property
, INSTALLPROPERTY_LASTUSEDSOURCEW
))
3485 msi_set_last_used_source(package
->ProductCode
, NULL
, info
->context
,
3486 info
->options
, info
->value
);
3488 MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3489 info
->context
, info
->options
,
3490 info
->property
, info
->value
);
3493 LIST_FOR_EACH_ENTRY(disk
, &package
->sourcelist_media
, MSIMEDIADISK
, entry
)
3495 MsiSourceListAddMediaDiskW(package
->ProductCode
, NULL
,
3496 disk
->context
, disk
->options
,
3497 disk
->disk_id
, disk
->volume_label
, disk
->disk_prompt
);
3503 RegCloseKey(hudkey
);
3509 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3511 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3512 LPCWSTR component
,section
,key
,value
,identifier
,filename
,dirproperty
;
3513 LPWSTR deformated_section
, deformated_key
, deformated_value
;
3514 LPWSTR folder
, fullname
= NULL
;
3518 static const WCHAR szWindowsFolder
[] =
3519 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3521 component
= MSI_RecordGetString(row
, 8);
3522 comp
= get_loaded_component(package
,component
);
3524 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3526 TRACE("Skipping ini file due to disabled component %s\n",
3527 debugstr_w(component
));
3529 comp
->Action
= comp
->Installed
;
3531 return ERROR_SUCCESS
;
3534 comp
->Action
= INSTALLSTATE_LOCAL
;
3536 identifier
= MSI_RecordGetString(row
,1);
3537 filename
= MSI_RecordGetString(row
,2);
3538 dirproperty
= MSI_RecordGetString(row
,3);
3539 section
= MSI_RecordGetString(row
,4);
3540 key
= MSI_RecordGetString(row
,5);
3541 value
= MSI_RecordGetString(row
,6);
3542 action
= MSI_RecordGetInteger(row
,7);
3544 deformat_string(package
,section
,&deformated_section
);
3545 deformat_string(package
,key
,&deformated_key
);
3546 deformat_string(package
,value
,&deformated_value
);
3550 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, TRUE
, NULL
);
3552 folder
= msi_dup_property( package
, dirproperty
);
3555 folder
= msi_dup_property( package
, szWindowsFolder
);
3559 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
3563 fullname
= build_directory_name(2, folder
, filename
);
3567 TRACE("Adding value %s to section %s in %s\n",
3568 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3569 debugstr_w(fullname
));
3570 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3571 deformated_value
, fullname
);
3573 else if (action
== 1)
3576 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3577 returned
, 10, fullname
);
3578 if (returned
[0] == 0)
3580 TRACE("Adding value %s to section %s in %s\n",
3581 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3582 debugstr_w(fullname
));
3584 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3585 deformated_value
, fullname
);
3588 else if (action
== 3)
3589 FIXME("Append to existing section not yet implemented\n");
3591 uirow
= MSI_CreateRecord(4);
3592 MSI_RecordSetStringW(uirow
,1,identifier
);
3593 MSI_RecordSetStringW(uirow
,2,deformated_section
);
3594 MSI_RecordSetStringW(uirow
,3,deformated_key
);
3595 MSI_RecordSetStringW(uirow
,4,deformated_value
);
3596 ui_actiondata(package
,szWriteIniValues
,uirow
);
3597 msiobj_release( &uirow
->hdr
);
3601 msi_free(deformated_key
);
3602 msi_free(deformated_value
);
3603 msi_free(deformated_section
);
3604 return ERROR_SUCCESS
;
3607 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
3611 static const WCHAR ExecSeqQuery
[] =
3612 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3613 '`','I','n','i','F','i','l','e','`',0};
3615 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3616 if (rc
!= ERROR_SUCCESS
)
3618 TRACE("no IniFile table\n");
3619 return ERROR_SUCCESS
;
3622 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
3623 msiobj_release(&view
->hdr
);
3627 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
3629 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3634 static const WCHAR ExeStr
[] =
3635 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3636 static const WCHAR close
[] = {'\"',0};
3638 PROCESS_INFORMATION info
;
3643 memset(&si
,0,sizeof(STARTUPINFOW
));
3645 filename
= MSI_RecordGetString(row
,1);
3646 file
= get_loaded_file( package
, filename
);
3650 ERR("Unable to find file id %s\n",debugstr_w(filename
));
3651 return ERROR_SUCCESS
;
3654 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
3656 FullName
= msi_alloc(len
*sizeof(WCHAR
));
3657 strcpyW(FullName
,ExeStr
);
3658 strcatW( FullName
, file
->TargetPath
);
3659 strcatW(FullName
,close
);
3661 TRACE("Registering %s\n",debugstr_w(FullName
));
3662 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
3666 msi_dialog_check_messages(info
.hProcess
);
3671 uirow
= MSI_CreateRecord( 2 );
3672 uipath
= strdupW( file
->TargetPath
);
3673 p
= strrchrW(uipath
,'\\');
3676 MSI_RecordSetStringW( uirow
, 1, &p
[1] );
3677 MSI_RecordSetStringW( uirow
, 2, uipath
);
3678 ui_actiondata( package
, szSelfRegModules
, uirow
);
3679 msiobj_release( &uirow
->hdr
);
3681 /* FIXME: call ui_progress? */
3683 return ERROR_SUCCESS
;
3686 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
3690 static const WCHAR ExecSeqQuery
[] =
3691 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3692 '`','S','e','l','f','R','e','g','`',0};
3694 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3695 if (rc
!= ERROR_SUCCESS
)
3697 TRACE("no SelfReg table\n");
3698 return ERROR_SUCCESS
;
3701 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
3702 msiobj_release(&view
->hdr
);
3704 return ERROR_SUCCESS
;
3707 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
3709 MSIFEATURE
*feature
;
3715 if (!msi_check_publish(package
))
3716 return ERROR_SUCCESS
;
3718 rc
= MSIREG_OpenFeaturesKey(package
->ProductCode
,&hkey
,TRUE
);
3719 if (rc
!= ERROR_SUCCESS
)
3722 rc
= MSIREG_OpenUserFeaturesKey(package
->ProductCode
,&hukey
,TRUE
);
3723 if (rc
!= ERROR_SUCCESS
)
3726 rc
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, &userdata
, TRUE
);
3727 if (rc
!= ERROR_SUCCESS
)
3730 /* here the guids are base 85 encoded */
3731 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
3737 BOOL absent
= FALSE
;
3740 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
) &&
3741 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_SOURCE
) &&
3742 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ADVERTISED
))
3746 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3750 if (feature
->Feature_Parent
)
3751 size
+= strlenW( feature
->Feature_Parent
)+2;
3753 data
= msi_alloc(size
* sizeof(WCHAR
));
3756 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3758 MSICOMPONENT
* component
= cl
->component
;
3762 if (component
->ComponentId
)
3764 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
3765 CLSIDFromString(component
->ComponentId
, &clsid
);
3766 encode_base85_guid(&clsid
,buf
);
3767 TRACE("to %s\n",debugstr_w(buf
));
3772 if (feature
->Feature_Parent
)
3774 static const WCHAR sep
[] = {'\2',0};
3776 strcatW(data
,feature
->Feature_Parent
);
3779 msi_reg_set_val_str( hkey
, feature
->Feature
, data
);
3780 msi_reg_set_val_str( userdata
, feature
->Feature
, data
);
3784 if (feature
->Feature_Parent
)
3785 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
3788 static const WCHAR emptyW
[] = {0};
3789 size
+= sizeof(WCHAR
);
3790 RegSetValueExW(hukey
,feature
->Feature
,0,REG_SZ
,
3791 (LPBYTE
)(feature
->Feature_Parent
? feature
->Feature_Parent
: emptyW
),size
);
3795 size
+= 2*sizeof(WCHAR
);
3796 data
= msi_alloc(size
);
3799 if (feature
->Feature_Parent
)
3800 strcpyW( &data
[1], feature
->Feature_Parent
);
3801 RegSetValueExW(hukey
,feature
->Feature
,0,REG_SZ
,
3807 uirow
= MSI_CreateRecord( 1 );
3808 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
3809 ui_actiondata( package
, szPublishFeatures
, uirow
);
3810 msiobj_release( &uirow
->hdr
);
3811 /* FIXME: call ui_progress? */
3820 static UINT
msi_unpublish_feature(MSIPACKAGE
*package
, MSIFEATURE
*feature
)
3825 TRACE("unpublishing feature %s\n", debugstr_w(feature
->Feature
));
3827 r
= MSIREG_OpenUserFeaturesKey(package
->ProductCode
, &hkey
, FALSE
);
3828 if (r
== ERROR_SUCCESS
)
3830 RegDeleteValueW(hkey
, feature
->Feature
);
3834 r
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, &hkey
, FALSE
);
3835 if (r
== ERROR_SUCCESS
)
3837 RegDeleteValueW(hkey
, feature
->Feature
);
3841 return ERROR_SUCCESS
;
3844 static BOOL
msi_check_unpublish(MSIPACKAGE
*package
)
3846 MSIFEATURE
*feature
;
3848 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3850 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3857 static UINT
ACTION_UnpublishFeatures(MSIPACKAGE
*package
)
3859 MSIFEATURE
*feature
;
3861 if (!msi_check_unpublish(package
))
3862 return ERROR_SUCCESS
;
3864 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3866 msi_unpublish_feature(package
, feature
);
3869 return ERROR_SUCCESS
;
3872 static UINT
msi_get_local_package_name( LPWSTR path
)
3874 static const WCHAR szInstaller
[] = {
3875 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3876 static const WCHAR fmt
[] = { '%','x','.','m','s','i',0};
3880 time
= GetTickCount();
3881 GetWindowsDirectoryW( path
, MAX_PATH
);
3882 lstrcatW( path
, szInstaller
);
3883 CreateDirectoryW( path
, NULL
);
3885 len
= lstrlenW(path
);
3886 for (i
=0; i
<0x10000; i
++)
3888 snprintfW( &path
[len
], MAX_PATH
- len
, fmt
, (time
+i
)&0xffff );
3889 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
,
3890 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
3891 if (handle
!= INVALID_HANDLE_VALUE
)
3893 CloseHandle(handle
);
3896 if (GetLastError() != ERROR_FILE_EXISTS
&&
3897 GetLastError() != ERROR_SHARING_VIOLATION
)
3898 return ERROR_FUNCTION_FAILED
;
3901 return ERROR_SUCCESS
;
3904 static UINT
msi_make_package_local( MSIPACKAGE
*package
, HKEY hkey
)
3906 WCHAR packagefile
[MAX_PATH
];
3910 r
= msi_get_local_package_name( packagefile
);
3911 if (r
!= ERROR_SUCCESS
)
3914 TRACE("Copying to local package %s\n",debugstr_w(packagefile
));
3916 r
= CopyFileW( package
->db
->path
, packagefile
, FALSE
);
3920 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3921 debugstr_w(package
->db
->path
), debugstr_w(packagefile
), GetLastError());
3922 return ERROR_FUNCTION_FAILED
;
3925 msi_reg_set_val_str( hkey
, INSTALLPROPERTY_LOCALPACKAGEW
, packagefile
);
3927 r
= MSIREG_OpenCurrentUserInstallProps(package
->ProductCode
, &props
, TRUE
);
3928 if (r
!= ERROR_SUCCESS
)
3931 msi_reg_set_val_str(props
, INSTALLPROPERTY_LOCALPACKAGEW
, packagefile
);
3933 return ERROR_SUCCESS
;
3936 static UINT
msi_write_uninstall_property_vals( MSIPACKAGE
*package
, HKEY hkey
)
3938 LPWSTR prop
, val
, key
;
3939 static const LPCSTR propval
[] = {
3940 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3941 "ARPCONTACT", "Contact",
3942 "ARPCOMMENTS", "Comments",
3943 "ProductName", "DisplayName",
3944 "ProductVersion", "DisplayVersion",
3945 "ARPHELPLINK", "HelpLink",
3946 "ARPHELPTELEPHONE", "HelpTelephone",
3947 "ARPINSTALLLOCATION", "InstallLocation",
3948 "SourceDir", "InstallSource",
3949 "Manufacturer", "Publisher",
3950 "ARPREADME", "Readme",
3952 "ARPURLINFOABOUT", "URLInfoAbout",
3953 "ARPURLUPDATEINFO", "URLUpdateInfo",
3956 const LPCSTR
*p
= propval
;
3960 prop
= strdupAtoW( *p
++ );
3961 key
= strdupAtoW( *p
++ );
3962 val
= msi_dup_property( package
, prop
);
3963 msi_reg_set_val_str( hkey
, key
, val
);
3968 return ERROR_SUCCESS
;
3971 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
3974 HKEY hudkey
=0, props
=0;
3975 LPWSTR buffer
= NULL
;
3978 static const WCHAR szWindowsInstaller
[] =
3979 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3980 static const WCHAR szUpgradeCode
[] =
3981 {'U','p','g','r','a','d','e','C','o','d','e',0};
3982 static const WCHAR modpath_fmt
[] =
3983 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3984 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3985 static const WCHAR szModifyPath
[] =
3986 {'M','o','d','i','f','y','P','a','t','h',0};
3987 static const WCHAR szUninstallString
[] =
3988 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3989 static const WCHAR szEstimatedSize
[] =
3990 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3991 static const WCHAR szProductLanguage
[] =
3992 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3993 static const WCHAR szProductVersion
[] =
3994 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3995 static const WCHAR szProductName
[] =
3996 {'P','r','o','d','u','c','t','N','a','m','e',0};
3997 static const WCHAR szDisplayName
[] =
3998 {'D','i','s','p','l','a','y','N','a','m','e',0};
3999 static const WCHAR szDisplayVersion
[] =
4000 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4001 static const WCHAR szManufacturer
[] =
4002 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4005 static const WCHAR date_fmt
[] = {'%','i','%','0','2','i','%','0','2','i',0};
4006 LPWSTR upgrade_code
;
4009 /* FIXME: also need to publish if the product is in advertise mode */
4010 if (!msi_check_publish(package
))
4011 return ERROR_SUCCESS
;
4013 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
,&hkey
,TRUE
);
4014 if (rc
!= ERROR_SUCCESS
)
4017 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4019 rc
= MSIREG_OpenLocalSystemInstallProps(package
->ProductCode
, &props
, TRUE
);
4020 if (rc
!= ERROR_SUCCESS
)
4025 rc
= MSIREG_OpenCurrentUserInstallProps(package
->ProductCode
, &props
, TRUE
);
4026 if (rc
!= ERROR_SUCCESS
)
4030 /* dump all the info i can grab */
4031 /* FIXME: Flesh out more information */
4033 msi_write_uninstall_property_vals( package
, hkey
);
4035 msi_reg_set_val_dword( hkey
, szWindowsInstaller
, 1 );
4037 msi_make_package_local( package
, hkey
);
4039 /* do ModifyPath and UninstallString */
4040 size
= deformat_string(package
,modpath_fmt
,&buffer
);
4041 RegSetValueExW(hkey
,szModifyPath
,0,REG_EXPAND_SZ
,(LPBYTE
)buffer
,size
);
4042 RegSetValueExW(hkey
,szUninstallString
,0,REG_EXPAND_SZ
,(LPBYTE
)buffer
,size
);
4045 /* FIXME: Write real Estimated Size when we have it */
4046 msi_reg_set_val_dword( hkey
, szEstimatedSize
, 0 );
4048 buffer
= msi_dup_property( package
, szProductName
);
4049 msi_reg_set_val_str( props
, szDisplayName
, buffer
);
4052 buffer
= msi_dup_property( package
, cszSourceDir
);
4053 msi_reg_set_val_str( props
, INSTALLPROPERTY_INSTALLSOURCEW
, buffer
);
4056 buffer
= msi_dup_property( package
, szManufacturer
);
4057 msi_reg_set_val_str( props
, INSTALLPROPERTY_PUBLISHERW
, buffer
);
4060 GetLocalTime(&systime
);
4061 sprintfW(szDate
,date_fmt
,systime
.wYear
,systime
.wMonth
,systime
.wDay
);
4062 msi_reg_set_val_str( hkey
, INSTALLPROPERTY_INSTALLDATEW
, szDate
);
4063 msi_reg_set_val_str( props
, INSTALLPROPERTY_INSTALLDATEW
, szDate
);
4065 langid
= msi_get_property_int( package
, szProductLanguage
, 0 );
4066 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
4068 buffer
= msi_dup_property( package
, szProductVersion
);
4069 msi_reg_set_val_str( props
, szDisplayVersion
, buffer
);
4072 DWORD verdword
= msi_version_str_to_dword(buffer
);
4074 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
4075 msi_reg_set_val_dword( props
, INSTALLPROPERTY_VERSIONW
, verdword
);
4076 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>>24 );
4077 msi_reg_set_val_dword( props
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>>24 );
4078 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>>16)&0x00FF );
4079 msi_reg_set_val_dword( props
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>>16)&0x00FF );
4083 /* Handle Upgrade Codes */
4084 upgrade_code
= msi_dup_property( package
, szUpgradeCode
);
4089 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &hkey2
, TRUE
);
4090 squash_guid(package
->ProductCode
,squashed
);
4091 msi_reg_set_val_str( hkey2
, squashed
, NULL
);
4093 MSIREG_OpenUserUpgradeCodesKey(upgrade_code
, &hkey2
, TRUE
);
4094 squash_guid(package
->ProductCode
,squashed
);
4095 msi_reg_set_val_str( hkey2
, squashed
, NULL
);
4098 msi_free(upgrade_code
);
4103 rc
= MSIREG_OpenUserDataProductKey(package
->ProductCode
, &hudkey
, TRUE
);
4104 if (rc
!= ERROR_SUCCESS
)
4107 RegCloseKey(hudkey
);
4109 msi_reg_set_val_dword( props
, szWindowsInstaller
, 1 );
4112 return ERROR_SUCCESS
;
4115 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
4117 return execute_script(package
,INSTALL_SCRIPT
);
4120 static UINT
msi_unpublish_product(MSIPACKAGE
*package
)
4122 LPWSTR remove
= NULL
;
4123 LPWSTR
*features
= NULL
;
4124 BOOL full_uninstall
= TRUE
;
4125 MSIFEATURE
*feature
;
4127 static const WCHAR szRemove
[] = {'R','E','M','O','V','E',0};
4128 static const WCHAR szAll
[] = {'A','L','L',0};
4130 remove
= msi_dup_property(package
, szRemove
);
4132 return ERROR_SUCCESS
;
4134 features
= msi_split_string(remove
, ',');
4138 ERR("REMOVE feature list is empty!\n");
4139 return ERROR_FUNCTION_FAILED
;
4142 if (!lstrcmpW(features
[0], szAll
))
4143 full_uninstall
= TRUE
;
4146 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4148 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
4149 full_uninstall
= FALSE
;
4153 if (!full_uninstall
)
4156 MSIREG_DeleteProductKey(package
->ProductCode
);
4157 MSIREG_DeleteUserProductKey(package
->ProductCode
);
4158 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4159 MSIREG_DeleteUserFeaturesKey(package
->ProductCode
);
4160 MSIREG_DeleteUninstallKey(package
->ProductCode
);
4165 return ERROR_SUCCESS
;
4168 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
4172 rc
= msi_unpublish_product(package
);
4173 if (rc
!= ERROR_SUCCESS
)
4176 /* turn off scheduling */
4177 package
->script
->CurrentlyScripting
= FALSE
;
4179 /* first do the same as an InstallExecute */
4180 rc
= ACTION_InstallExecute(package
);
4181 if (rc
!= ERROR_SUCCESS
)
4184 /* then handle Commit Actions */
4185 rc
= execute_script(package
,COMMIT_SCRIPT
);
4190 UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
4192 static const WCHAR RunOnce
[] = {
4193 'S','o','f','t','w','a','r','e','\\',
4194 'M','i','c','r','o','s','o','f','t','\\',
4195 'W','i','n','d','o','w','s','\\',
4196 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4197 'R','u','n','O','n','c','e',0};
4198 static const WCHAR InstallRunOnce
[] = {
4199 'S','o','f','t','w','a','r','e','\\',
4200 'M','i','c','r','o','s','o','f','t','\\',
4201 'W','i','n','d','o','w','s','\\',
4202 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4203 'I','n','s','t','a','l','l','e','r','\\',
4204 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4206 static const WCHAR msiexec_fmt
[] = {
4208 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4209 '\"','%','s','\"',0};
4210 static const WCHAR install_fmt
[] = {
4211 '/','I',' ','\"','%','s','\"',' ',
4212 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4213 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4214 WCHAR buffer
[256], sysdir
[MAX_PATH
];
4216 WCHAR squished_pc
[100];
4218 squash_guid(package
->ProductCode
,squished_pc
);
4220 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
4221 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
4222 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
4225 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4228 TRACE("Reboot command %s\n",debugstr_w(buffer
));
4230 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
4231 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
4233 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4236 return ERROR_INSTALL_SUSPEND
;
4239 static UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
4245 * We are currently doing what should be done here in the top level Install
4246 * however for Administrative and uninstalls this step will be needed
4248 if (!package
->PackagePath
)
4249 return ERROR_SUCCESS
;
4251 msi_set_sourcedir_props(package
, TRUE
);
4253 attrib
= GetFileAttributesW(package
->db
->path
);
4254 if (attrib
== INVALID_FILE_ATTRIBUTES
)
4260 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4261 package
->Context
, MSICODE_PRODUCT
,
4262 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
4263 if (rc
== ERROR_MORE_DATA
)
4265 prompt
= msi_alloc(size
* sizeof(WCHAR
));
4266 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4267 package
->Context
, MSICODE_PRODUCT
,
4268 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
4271 prompt
= strdupW(package
->db
->path
);
4273 msg
= generate_error_string(package
,1302,1,prompt
);
4274 while(attrib
== INVALID_FILE_ATTRIBUTES
)
4276 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
4279 rc
= ERROR_INSTALL_USEREXIT
;
4282 attrib
= GetFileAttributesW(package
->db
->path
);
4288 return ERROR_SUCCESS
;
4293 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
4300 static const WCHAR szPropKeys
[][80] =
4302 {'P','r','o','d','u','c','t','I','D',0},
4303 {'U','S','E','R','N','A','M','E',0},
4304 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4308 static const WCHAR szRegKeys
[][80] =
4310 {'P','r','o','d','u','c','t','I','D',0},
4311 {'R','e','g','O','w','n','e','r',0},
4312 {'R','e','g','C','o','m','p','a','n','y',0},
4316 if (msi_check_unpublish(package
))
4318 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4319 return ERROR_SUCCESS
;
4322 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
4324 return ERROR_SUCCESS
;
4326 rc
= MSIREG_OpenCurrentUserInstallProps(package
->ProductCode
, &hkey
, TRUE
);
4327 if (rc
!= ERROR_SUCCESS
)
4330 for( i
= 0; szPropKeys
[i
][0]; i
++ )
4332 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
4333 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
4338 msi_free(productid
);
4341 /* FIXME: call ui_actiondata */
4347 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
4351 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
4352 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
4357 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4359 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4360 LPCWSTR compgroupid
=NULL
;
4361 LPCWSTR feature
=NULL
;
4362 LPCWSTR text
= NULL
;
4363 LPCWSTR qualifier
= NULL
;
4364 LPCWSTR component
= NULL
;
4365 LPWSTR advertise
= NULL
;
4366 LPWSTR output
= NULL
;
4368 UINT rc
= ERROR_SUCCESS
;
4373 component
= MSI_RecordGetString(rec
,3);
4374 comp
= get_loaded_component(package
,component
);
4376 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) &&
4377 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
) &&
4378 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ADVERTISED
))
4380 TRACE("Skipping: Component %s not scheduled for install\n",
4381 debugstr_w(component
));
4383 return ERROR_SUCCESS
;
4386 compgroupid
= MSI_RecordGetString(rec
,1);
4387 qualifier
= MSI_RecordGetString(rec
,2);
4389 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
4390 if (rc
!= ERROR_SUCCESS
)
4393 text
= MSI_RecordGetString(rec
,4);
4394 feature
= MSI_RecordGetString(rec
,5);
4396 advertise
= create_component_advertise_string(package
, comp
, feature
);
4398 sz
= strlenW(advertise
);
4401 sz
+= lstrlenW(text
);
4404 sz
*= sizeof(WCHAR
);
4406 output
= msi_alloc_zero(sz
);
4407 strcpyW(output
,advertise
);
4408 msi_free(advertise
);
4411 strcatW(output
,text
);
4413 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
4420 uirow
= MSI_CreateRecord( 2 );
4421 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4422 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4423 ui_actiondata( package
, szPublishComponents
, uirow
);
4424 msiobj_release( &uirow
->hdr
);
4425 /* FIXME: call ui_progress? */
4431 * At present I am ignorning the advertised components part of this and only
4432 * focusing on the qualified component sets
4434 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
4438 static const WCHAR ExecSeqQuery
[] =
4439 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4440 '`','P','u','b','l','i','s','h',
4441 'C','o','m','p','o','n','e','n','t','`',0};
4443 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4444 if (rc
!= ERROR_SUCCESS
)
4445 return ERROR_SUCCESS
;
4447 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
4448 msiobj_release(&view
->hdr
);
4453 static UINT
ITERATE_InstallService(MSIRECORD
*rec
, LPVOID param
)
4455 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4458 SC_HANDLE hscm
, service
= NULL
;
4459 LPCWSTR comp
, depends
, pass
;
4460 LPWSTR name
= NULL
, disp
= NULL
;
4461 LPCWSTR load_order
, serv_name
, key
;
4462 DWORD serv_type
, start_type
;
4465 static const WCHAR query
[] =
4466 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4467 '`','C','o','m','p','o','n','e','n','t','`',' ',
4468 'W','H','E','R','E',' ',
4469 '`','C','o','m','p','o','n','e','n','t','`',' ',
4470 '=','\'','%','s','\'',0};
4472 hscm
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASEW
, GENERIC_WRITE
);
4475 ERR("Failed to open the SC Manager!\n");
4479 start_type
= MSI_RecordGetInteger(rec
, 5);
4480 if (start_type
== SERVICE_BOOT_START
|| start_type
== SERVICE_SYSTEM_START
)
4483 depends
= MSI_RecordGetString(rec
, 8);
4484 if (depends
&& *depends
)
4485 FIXME("Dependency list unhandled!\n");
4487 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
4488 deformat_string(package
, MSI_RecordGetString(rec
, 3), &disp
);
4489 serv_type
= MSI_RecordGetInteger(rec
, 4);
4490 err_control
= MSI_RecordGetInteger(rec
, 6);
4491 load_order
= MSI_RecordGetString(rec
, 7);
4492 serv_name
= MSI_RecordGetString(rec
, 9);
4493 pass
= MSI_RecordGetString(rec
, 10);
4494 comp
= MSI_RecordGetString(rec
, 12);
4496 /* fetch the service path */
4497 row
= MSI_QueryGetRecord(package
->db
, query
, comp
);
4500 ERR("Control query failed!\n");
4504 key
= MSI_RecordGetString(row
, 6);
4506 file
= get_loaded_file(package
, key
);
4507 msiobj_release(&row
->hdr
);
4510 ERR("Failed to load the service file\n");
4514 service
= CreateServiceW(hscm
, name
, disp
, GENERIC_ALL
, serv_type
,
4515 start_type
, err_control
, file
->TargetPath
,
4516 load_order
, NULL
, NULL
, serv_name
, pass
);
4519 if (GetLastError() != ERROR_SERVICE_EXISTS
)
4520 ERR("Failed to create service %s: %d\n", debugstr_w(name
), GetLastError());
4524 CloseServiceHandle(service
);
4525 CloseServiceHandle(hscm
);
4529 return ERROR_SUCCESS
;
4532 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
4536 static const WCHAR ExecSeqQuery
[] =
4537 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4538 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4540 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4541 if (rc
!= ERROR_SUCCESS
)
4542 return ERROR_SUCCESS
;
4544 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallService
, package
);
4545 msiobj_release(&view
->hdr
);
4550 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4551 static LPCWSTR
*msi_service_args_to_vector(LPWSTR args
, DWORD
*numargs
)
4553 LPCWSTR
*vector
, *temp_vector
;
4557 static const WCHAR separator
[] = {'[','~',']',0};
4560 sep_len
= sizeof(separator
) / sizeof(WCHAR
) - 1;
4565 vector
= msi_alloc(sizeof(LPWSTR
));
4573 vector
[*numargs
- 1] = p
;
4575 if ((q
= strstrW(p
, separator
)))
4579 temp_vector
= msi_realloc(vector
, (*numargs
+ 1) * sizeof(LPWSTR
));
4585 vector
= temp_vector
;
4594 static UINT
ITERATE_StartService(MSIRECORD
*rec
, LPVOID param
)
4596 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4598 SC_HANDLE scm
, service
= NULL
;
4599 LPCWSTR name
, *vector
= NULL
;
4601 DWORD event
, numargs
;
4602 UINT r
= ERROR_FUNCTION_FAILED
;
4604 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 6));
4605 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4606 return ERROR_SUCCESS
;
4608 name
= MSI_RecordGetString(rec
, 2);
4609 event
= MSI_RecordGetInteger(rec
, 3);
4610 args
= strdupW(MSI_RecordGetString(rec
, 4));
4612 if (!(event
& msidbServiceControlEventStart
))
4613 return ERROR_SUCCESS
;
4615 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_CONNECT
);
4618 ERR("Failed to open the service control manager\n");
4622 service
= OpenServiceW(scm
, name
, SERVICE_START
);
4625 ERR("Failed to open service %s\n", debugstr_w(name
));
4629 vector
= msi_service_args_to_vector(args
, &numargs
);
4631 if (!StartServiceW(service
, numargs
, vector
))
4633 ERR("Failed to start service %s\n", debugstr_w(name
));
4640 CloseServiceHandle(service
);
4641 CloseServiceHandle(scm
);
4648 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
4653 static const WCHAR query
[] = {
4654 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4655 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4657 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4658 if (rc
!= ERROR_SUCCESS
)
4659 return ERROR_SUCCESS
;
4661 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StartService
, package
);
4662 msiobj_release(&view
->hdr
);
4667 static BOOL
stop_service_dependents(SC_HANDLE scm
, SC_HANDLE service
)
4669 DWORD i
, needed
, count
;
4670 ENUM_SERVICE_STATUSW
*dependencies
;
4674 if (EnumDependentServicesW(service
, SERVICE_ACTIVE
, NULL
,
4675 0, &needed
, &count
))
4678 if (GetLastError() != ERROR_MORE_DATA
)
4681 dependencies
= msi_alloc(needed
);
4685 if (!EnumDependentServicesW(service
, SERVICE_ACTIVE
, dependencies
,
4686 needed
, &needed
, &count
))
4689 for (i
= 0; i
< count
; i
++)
4691 depserv
= OpenServiceW(scm
, dependencies
[i
].lpServiceName
,
4692 SERVICE_STOP
| SERVICE_QUERY_STATUS
);
4696 if (!ControlService(depserv
, SERVICE_CONTROL_STOP
, &ss
))
4703 msi_free(dependencies
);
4707 static UINT
ITERATE_StopService(MSIRECORD
*rec
, LPVOID param
)
4709 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4711 SERVICE_STATUS status
;
4712 SERVICE_STATUS_PROCESS ssp
;
4713 SC_HANDLE scm
= NULL
, service
= NULL
;
4715 DWORD event
, needed
;
4717 event
= MSI_RecordGetInteger(rec
, 3);
4718 if (!(event
& msidbServiceControlEventStop
))
4719 return ERROR_SUCCESS
;
4721 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 6));
4722 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4723 return ERROR_SUCCESS
;
4725 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
4726 deformat_string(package
, MSI_RecordGetString(rec
, 4), &args
);
4727 args
= strdupW(MSI_RecordGetString(rec
, 4));
4729 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
4732 WARN("Failed to open the SCM: %d\n", GetLastError());
4736 service
= OpenServiceW(scm
, name
,
4738 SERVICE_QUERY_STATUS
|
4739 SERVICE_ENUMERATE_DEPENDENTS
);
4742 WARN("Failed to open service (%s): %d\n",
4743 debugstr_w(name
), GetLastError());
4747 if (!QueryServiceStatusEx(service
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&ssp
,
4748 sizeof(SERVICE_STATUS_PROCESS
), &needed
))
4750 WARN("Failed to query service status (%s): %d\n",
4751 debugstr_w(name
), GetLastError());
4755 if (ssp
.dwCurrentState
== SERVICE_STOPPED
)
4758 stop_service_dependents(scm
, service
);
4760 if (!ControlService(service
, SERVICE_CONTROL_STOP
, &status
))
4761 WARN("Failed to stop service (%s): %d\n", debugstr_w(name
), GetLastError());
4764 CloseServiceHandle(service
);
4765 CloseServiceHandle(scm
);
4769 return ERROR_SUCCESS
;
4772 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
4777 static const WCHAR query
[] = {
4778 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4779 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4781 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4782 if (rc
!= ERROR_SUCCESS
)
4783 return ERROR_SUCCESS
;
4785 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StopService
, package
);
4786 msiobj_release(&view
->hdr
);
4791 static MSIFILE
*msi_find_file( MSIPACKAGE
*package
, LPCWSTR filename
)
4795 LIST_FOR_EACH_ENTRY(file
, &package
->files
, MSIFILE
, entry
)
4797 if (!lstrcmpW(file
->File
, filename
))
4804 static UINT
ITERATE_InstallODBCDriver( MSIRECORD
*rec
, LPVOID param
)
4806 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4807 LPWSTR driver
, driver_path
, ptr
;
4808 WCHAR outpath
[MAX_PATH
];
4809 MSIFILE
*driver_file
, *setup_file
;
4812 UINT r
= ERROR_SUCCESS
;
4814 static const WCHAR driver_fmt
[] = {
4815 'D','r','i','v','e','r','=','%','s',0};
4816 static const WCHAR setup_fmt
[] = {
4817 'S','e','t','u','p','=','%','s',0};
4818 static const WCHAR usage_fmt
[] = {
4819 'F','i','l','e','U','s','a','g','e','=','1',0};
4821 desc
= MSI_RecordGetString(rec
, 3);
4823 driver_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
4824 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
4826 if (!driver_file
|| !setup_file
)
4828 ERR("ODBC Driver entry not found!\n");
4829 return ERROR_FUNCTION_FAILED
;
4832 len
= lstrlenW(desc
) + lstrlenW(driver_fmt
) + lstrlenW(driver_file
->FileName
) +
4833 lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
) +
4834 lstrlenW(usage_fmt
) + 1;
4835 driver
= msi_alloc(len
* sizeof(WCHAR
));
4837 return ERROR_OUTOFMEMORY
;
4840 lstrcpyW(ptr
, desc
);
4841 ptr
+= lstrlenW(ptr
) + 1;
4843 sprintfW(ptr
, driver_fmt
, driver_file
->FileName
);
4844 ptr
+= lstrlenW(ptr
) + 1;
4846 sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
4847 ptr
+= lstrlenW(ptr
) + 1;
4849 lstrcpyW(ptr
, usage_fmt
);
4850 ptr
+= lstrlenW(ptr
) + 1;
4853 driver_path
= strdupW(driver_file
->TargetPath
);
4854 ptr
= strrchrW(driver_path
, '\\');
4855 if (ptr
) *ptr
= '\0';
4857 if (!SQLInstallDriverExW(driver
, driver_path
, outpath
, MAX_PATH
,
4858 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
4860 ERR("Failed to install SQL driver!\n");
4861 r
= ERROR_FUNCTION_FAILED
;
4865 msi_free(driver_path
);
4870 static UINT
ITERATE_InstallODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
4872 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4873 LPWSTR translator
, translator_path
, ptr
;
4874 WCHAR outpath
[MAX_PATH
];
4875 MSIFILE
*translator_file
, *setup_file
;
4878 UINT r
= ERROR_SUCCESS
;
4880 static const WCHAR translator_fmt
[] = {
4881 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4882 static const WCHAR setup_fmt
[] = {
4883 'S','e','t','u','p','=','%','s',0};
4885 desc
= MSI_RecordGetString(rec
, 3);
4887 translator_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
4888 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
4890 if (!translator_file
|| !setup_file
)
4892 ERR("ODBC Translator entry not found!\n");
4893 return ERROR_FUNCTION_FAILED
;
4896 len
= lstrlenW(desc
) + lstrlenW(translator_fmt
) + lstrlenW(translator_file
->FileName
) +
4897 lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
) + 1;
4898 translator
= msi_alloc(len
* sizeof(WCHAR
));
4900 return ERROR_OUTOFMEMORY
;
4903 lstrcpyW(ptr
, desc
);
4904 ptr
+= lstrlenW(ptr
) + 1;
4906 sprintfW(ptr
, translator_fmt
, translator_file
->FileName
);
4907 ptr
+= lstrlenW(ptr
) + 1;
4909 sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
4910 ptr
+= lstrlenW(ptr
) + 1;
4913 translator_path
= strdupW(translator_file
->TargetPath
);
4914 ptr
= strrchrW(translator_path
, '\\');
4915 if (ptr
) *ptr
= '\0';
4917 if (!SQLInstallTranslatorExW(translator
, translator_path
, outpath
, MAX_PATH
,
4918 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
4920 ERR("Failed to install SQL translator!\n");
4921 r
= ERROR_FUNCTION_FAILED
;
4924 msi_free(translator
);
4925 msi_free(translator_path
);
4930 static UINT
ITERATE_InstallODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
4933 LPCWSTR desc
, driver
;
4934 WORD request
= ODBC_ADD_SYS_DSN
;
4937 UINT r
= ERROR_SUCCESS
;
4939 static const WCHAR attrs_fmt
[] = {
4940 'D','S','N','=','%','s',0 };
4942 desc
= MSI_RecordGetString(rec
, 3);
4943 driver
= MSI_RecordGetString(rec
, 4);
4944 registration
= MSI_RecordGetInteger(rec
, 5);
4946 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_ADD_SYS_DSN
;
4947 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_ADD_DSN
;
4949 len
= lstrlenW(attrs_fmt
) + lstrlenW(desc
) + 1 + 1;
4950 attrs
= msi_alloc(len
* sizeof(WCHAR
));
4952 return ERROR_OUTOFMEMORY
;
4954 sprintfW(attrs
, attrs_fmt
, desc
);
4955 attrs
[len
- 1] = '\0';
4957 if (!SQLConfigDataSourceW(NULL
, request
, driver
, attrs
))
4959 ERR("Failed to install SQL data source!\n");
4960 r
= ERROR_FUNCTION_FAILED
;
4968 static UINT
ACTION_InstallODBC( MSIPACKAGE
*package
)
4973 static const WCHAR driver_query
[] = {
4974 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4975 'O','D','B','C','D','r','i','v','e','r',0 };
4977 static const WCHAR translator_query
[] = {
4978 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4979 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4981 static const WCHAR source_query
[] = {
4982 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4983 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4985 rc
= MSI_DatabaseOpenViewW(package
->db
, driver_query
, &view
);
4986 if (rc
!= ERROR_SUCCESS
)
4987 return ERROR_SUCCESS
;
4989 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDriver
, package
);
4990 msiobj_release(&view
->hdr
);
4992 rc
= MSI_DatabaseOpenViewW(package
->db
, translator_query
, &view
);
4993 if (rc
!= ERROR_SUCCESS
)
4994 return ERROR_SUCCESS
;
4996 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCTranslator
, package
);
4997 msiobj_release(&view
->hdr
);
4999 rc
= MSI_DatabaseOpenViewW(package
->db
, source_query
, &view
);
5000 if (rc
!= ERROR_SUCCESS
)
5001 return ERROR_SUCCESS
;
5003 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDataSource
, package
);
5004 msiobj_release(&view
->hdr
);
5009 #define ENV_ACT_SETALWAYS 0x1
5010 #define ENV_ACT_SETABSENT 0x2
5011 #define ENV_ACT_REMOVE 0x4
5012 #define ENV_ACT_REMOVEMATCH 0x8
5014 #define ENV_MOD_MACHINE 0x20000000
5015 #define ENV_MOD_APPEND 0x40000000
5016 #define ENV_MOD_PREFIX 0x80000000
5017 #define ENV_MOD_MASK 0xC0000000
5019 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5021 static LONG
env_set_flags( LPCWSTR
*name
, LPCWSTR
*value
, DWORD
*flags
)
5023 LPCWSTR cptr
= *name
;
5024 LPCWSTR ptr
= *value
;
5026 static const WCHAR prefix
[] = {'[','~',']',0};
5027 static const int prefix_len
= 3;
5033 *flags
|= ENV_ACT_SETALWAYS
;
5034 else if (*cptr
== '+')
5035 *flags
|= ENV_ACT_SETABSENT
;
5036 else if (*cptr
== '-')
5037 *flags
|= ENV_ACT_REMOVE
;
5038 else if (*cptr
== '!')
5039 *flags
|= ENV_ACT_REMOVEMATCH
;
5040 else if (*cptr
== '*')
5041 *flags
|= ENV_MOD_MACHINE
;
5051 ERR("Missing environment variable\n");
5052 return ERROR_FUNCTION_FAILED
;
5055 if (!strncmpW(ptr
, prefix
, prefix_len
))
5057 *flags
|= ENV_MOD_APPEND
;
5058 *value
+= lstrlenW(prefix
);
5060 else if (lstrlenW(*value
) >= prefix_len
)
5062 ptr
+= lstrlenW(ptr
) - prefix_len
;
5063 if (!lstrcmpW(ptr
, prefix
))
5065 *flags
|= ENV_MOD_PREFIX
;
5066 /* the "[~]" will be removed by deformat_string */;
5071 check_flag_combo(*flags
, ENV_ACT_SETALWAYS
| ENV_ACT_SETABSENT
) ||
5072 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETABSENT
) ||
5073 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETALWAYS
) ||
5074 check_flag_combo(*flags
, ENV_ACT_SETABSENT
| ENV_MOD_MASK
))
5076 ERR("Invalid flags: %08x\n", *flags
);
5077 return ERROR_FUNCTION_FAILED
;
5080 return ERROR_SUCCESS
;
5083 static UINT
ITERATE_WriteEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
5085 MSIPACKAGE
*package
= param
;
5086 LPCWSTR name
, value
;
5087 LPWSTR data
= NULL
, newval
= NULL
;
5088 LPWSTR deformatted
= NULL
, ptr
;
5089 DWORD flags
, type
, size
;
5091 HKEY env
= NULL
, root
;
5092 LPCWSTR environment
;
5094 static const WCHAR user_env
[] =
5095 {'E','n','v','i','r','o','n','m','e','n','t',0};
5096 static const WCHAR machine_env
[] =
5097 {'S','y','s','t','e','m','\\',
5098 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5099 'C','o','n','t','r','o','l','\\',
5100 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5101 'E','n','v','i','r','o','n','m','e','n','t',0};
5102 static const WCHAR semicolon
[] = {';',0};
5104 name
= MSI_RecordGetString(rec
, 2);
5105 value
= MSI_RecordGetString(rec
, 3);
5107 res
= env_set_flags(&name
, &value
, &flags
);
5108 if (res
!= ERROR_SUCCESS
)
5111 deformat_string(package
, value
, &deformatted
);
5114 res
= ERROR_OUTOFMEMORY
;
5118 value
= deformatted
;
5120 if (flags
& ENV_MOD_MACHINE
)
5122 environment
= machine_env
;
5123 root
= HKEY_LOCAL_MACHINE
;
5127 environment
= user_env
;
5128 root
= HKEY_CURRENT_USER
;
5131 res
= RegCreateKeyExW(root
, environment
, 0, NULL
, 0,
5132 KEY_ALL_ACCESS
, NULL
, &env
, NULL
);
5133 if (res
!= ERROR_SUCCESS
)
5136 if (flags
& ENV_ACT_REMOVE
)
5137 FIXME("Not removing environment variable on uninstall!\n");
5140 res
= RegQueryValueExW(env
, name
, NULL
, &type
, NULL
, &size
);
5141 if ((res
!= ERROR_SUCCESS
&& res
!= ERROR_FILE_NOT_FOUND
) ||
5142 (res
== ERROR_SUCCESS
&& type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
))
5145 if (res
!= ERROR_FILE_NOT_FOUND
)
5147 if (flags
& ENV_ACT_SETABSENT
)
5149 res
= ERROR_SUCCESS
;
5153 data
= msi_alloc(size
);
5157 return ERROR_OUTOFMEMORY
;
5160 res
= RegQueryValueExW(env
, name
, NULL
, &type
, (LPVOID
)data
, &size
);
5161 if (res
!= ERROR_SUCCESS
)
5164 if (flags
& ENV_ACT_REMOVEMATCH
&& (!value
|| !lstrcmpW(data
, value
)))
5166 res
= RegDeleteKeyW(env
, name
);
5170 size
= (lstrlenW(value
) + 1 + size
) * sizeof(WCHAR
);
5171 newval
= msi_alloc(size
);
5175 res
= ERROR_OUTOFMEMORY
;
5179 if (!(flags
& ENV_MOD_MASK
))
5180 lstrcpyW(newval
, value
);
5183 if (flags
& ENV_MOD_PREFIX
)
5185 lstrcpyW(newval
, value
);
5186 lstrcatW(newval
, semicolon
);
5187 ptr
= newval
+ lstrlenW(value
) + 1;
5190 lstrcpyW(ptr
, data
);
5192 if (flags
& ENV_MOD_APPEND
)
5194 lstrcatW(newval
, semicolon
);
5195 lstrcatW(newval
, value
);
5201 size
= (lstrlenW(value
) + 1) * sizeof(WCHAR
);
5202 newval
= msi_alloc(size
);
5205 res
= ERROR_OUTOFMEMORY
;
5209 lstrcpyW(newval
, value
);
5212 TRACE("setting %s to %s\n", debugstr_w(name
), debugstr_w(newval
));
5213 res
= RegSetValueExW(env
, name
, 0, type
, (LPVOID
)newval
, size
);
5216 if (env
) RegCloseKey(env
);
5217 msi_free(deformatted
);
5223 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
5227 static const WCHAR ExecSeqQuery
[] =
5228 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5229 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5230 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5231 if (rc
!= ERROR_SUCCESS
)
5232 return ERROR_SUCCESS
;
5234 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteEnvironmentString
, package
);
5235 msiobj_release(&view
->hdr
);
5240 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5251 static BOOL
msi_move_file(LPCWSTR source
, LPCWSTR dest
, int options
)
5255 if (GetFileAttributesW(source
) == FILE_ATTRIBUTE_DIRECTORY
||
5256 GetFileAttributesW(dest
) == FILE_ATTRIBUTE_DIRECTORY
)
5258 WARN("Source or dest is directory, not moving\n");
5262 if (options
== msidbMoveFileOptionsMove
)
5264 TRACE("moving %s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
5265 ret
= MoveFileExW(source
, dest
, MOVEFILE_REPLACE_EXISTING
);
5268 WARN("MoveFile failed: %d\n", GetLastError());
5274 TRACE("copying %s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
5275 ret
= CopyFileW(source
, dest
, FALSE
);
5278 WARN("CopyFile failed: %d\n", GetLastError());
5286 static LPWSTR
wildcard_to_file(LPWSTR wildcard
, LPWSTR filename
)
5289 DWORD dirlen
, pathlen
;
5291 ptr
= strrchrW(wildcard
, '\\');
5292 dirlen
= ptr
- wildcard
+ 1;
5294 pathlen
= dirlen
+ lstrlenW(filename
) + 1;
5295 path
= msi_alloc(pathlen
* sizeof(WCHAR
));
5297 lstrcpynW(path
, wildcard
, dirlen
+ 1);
5298 lstrcatW(path
, filename
);
5303 static void free_file_entry(FILE_LIST
*file
)
5305 msi_free(file
->source
);
5306 msi_free(file
->dest
);
5310 static void free_list(FILE_LIST
*list
)
5312 while (!list_empty(&list
->entry
))
5314 FILE_LIST
*file
= LIST_ENTRY(list_head(&list
->entry
), FILE_LIST
, entry
);
5316 list_remove(&file
->entry
);
5317 free_file_entry(file
);
5321 static BOOL
add_wildcard(FILE_LIST
*files
, LPWSTR source
, LPWSTR dest
)
5323 FILE_LIST
*new, *file
;
5324 LPWSTR ptr
, filename
;
5327 new = msi_alloc_zero(sizeof(FILE_LIST
));
5331 new->source
= strdupW(source
);
5332 ptr
= strrchrW(dest
, '\\') + 1;
5333 filename
= strrchrW(new->source
, '\\') + 1;
5335 new->sourcename
= filename
;
5338 new->destname
= ptr
;
5340 new->destname
= new->sourcename
;
5342 size
= (ptr
- dest
) + lstrlenW(filename
) + 1;
5343 new->dest
= msi_alloc(size
* sizeof(WCHAR
));
5346 free_file_entry(new);
5350 lstrcpynW(new->dest
, dest
, ptr
- dest
+ 1);
5351 lstrcatW(new->dest
, filename
);
5353 if (list_empty(&files
->entry
))
5355 list_add_head(&files
->entry
, &new->entry
);
5359 LIST_FOR_EACH_ENTRY(file
, &files
->entry
, FILE_LIST
, entry
)
5361 if (lstrcmpW(source
, file
->source
) < 0)
5363 list_add_before(&file
->entry
, &new->entry
);
5368 list_add_after(&file
->entry
, &new->entry
);
5372 static BOOL
move_files_wildcard(LPWSTR source
, LPWSTR dest
, int options
)
5374 WIN32_FIND_DATAW wfd
;
5378 FILE_LIST files
, *file
;
5381 hfile
= FindFirstFileW(source
, &wfd
);
5382 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
5384 list_init(&files
.entry
);
5386 for (res
= TRUE
; res
; res
= FindNextFileW(hfile
, &wfd
))
5388 if (is_dot_dir(wfd
.cFileName
)) continue;
5390 path
= wildcard_to_file(source
, wfd
.cFileName
);
5397 add_wildcard(&files
, path
, dest
);
5401 /* no files match the wildcard */
5402 if (list_empty(&files
.entry
))
5405 /* only the first wildcard match gets renamed to dest */
5406 file
= LIST_ENTRY(list_head(&files
.entry
), FILE_LIST
, entry
);
5407 size
= (strrchrW(file
->dest
, '\\') - file
->dest
) + lstrlenW(file
->destname
) + 2;
5408 file
->dest
= msi_realloc(file
->dest
, size
* sizeof(WCHAR
));
5415 lstrcpyW(strrchrW(file
->dest
, '\\') + 1, file
->destname
);
5417 while (!list_empty(&files
.entry
))
5419 file
= LIST_ENTRY(list_head(&files
.entry
), FILE_LIST
, entry
);
5421 msi_move_file((LPCWSTR
)file
->source
, (LPCWSTR
)file
->dest
, options
);
5423 list_remove(&file
->entry
);
5424 free_file_entry(file
);
5435 static UINT
ITERATE_MoveFiles( MSIRECORD
*rec
, LPVOID param
)
5437 MSIPACKAGE
*package
= param
;
5439 LPCWSTR sourcename
, destname
;
5440 LPWSTR sourcedir
= NULL
, destdir
= NULL
;
5441 LPWSTR source
= NULL
, dest
= NULL
;
5444 BOOL ret
, wildcards
;
5446 static const WCHAR backslash
[] = {'\\',0};
5448 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 2));
5449 if (!comp
|| !comp
->Enabled
||
5450 !(comp
->Action
& (INSTALLSTATE_LOCAL
| INSTALLSTATE_SOURCE
)))
5452 TRACE("Component not set for install, not moving file\n");
5453 return ERROR_SUCCESS
;
5456 sourcename
= MSI_RecordGetString(rec
, 3);
5457 destname
= MSI_RecordGetString(rec
, 4);
5458 options
= MSI_RecordGetInteger(rec
, 7);
5460 sourcedir
= msi_dup_property(package
, MSI_RecordGetString(rec
, 5));
5464 destdir
= msi_dup_property(package
, MSI_RecordGetString(rec
, 6));
5470 if (GetFileAttributesW(sourcedir
) == INVALID_FILE_ATTRIBUTES
)
5473 source
= strdupW(sourcedir
);
5479 size
= lstrlenW(sourcedir
) + lstrlenW(sourcename
) + 2;
5480 source
= msi_alloc(size
* sizeof(WCHAR
));
5484 lstrcpyW(source
, sourcedir
);
5485 if (source
[lstrlenW(source
) - 1] != '\\')
5486 lstrcatW(source
, backslash
);
5487 lstrcatW(source
, sourcename
);
5490 wildcards
= strchrW(source
, '*') || strchrW(source
, '?');
5492 if (!destname
&& !wildcards
)
5494 destname
= strdupW(sourcename
);
5501 size
= lstrlenW(destname
);
5503 size
+= lstrlenW(destdir
) + 2;
5504 dest
= msi_alloc(size
* sizeof(WCHAR
));
5508 lstrcpyW(dest
, destdir
);
5509 if (dest
[lstrlenW(dest
) - 1] != '\\')
5510 lstrcatW(dest
, backslash
);
5513 lstrcatW(dest
, destname
);
5515 if (GetFileAttributesW(destdir
) == INVALID_FILE_ATTRIBUTES
)
5517 ret
= CreateDirectoryW(destdir
, NULL
);
5520 WARN("CreateDirectory failed: %d\n", GetLastError());
5521 return ERROR_SUCCESS
;
5526 msi_move_file(source
, dest
, options
);
5528 move_files_wildcard(source
, dest
, options
);
5531 msi_free(sourcedir
);
5536 return ERROR_SUCCESS
;
5539 static UINT
ACTION_MoveFiles( MSIPACKAGE
*package
)
5544 static const WCHAR ExecSeqQuery
[] =
5545 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5546 '`','M','o','v','e','F','i','l','e','`',0};
5548 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5549 if (rc
!= ERROR_SUCCESS
)
5550 return ERROR_SUCCESS
;
5552 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_MoveFiles
, package
);
5553 msiobj_release(&view
->hdr
);
5558 static HRESULT (WINAPI
*pCreateAssemblyCache
)(IAssemblyCache
**ppAsmCache
,
5560 static HRESULT (WINAPI
*pLoadLibraryShim
)(LPCWSTR szDllName
, LPCWSTR szVersion
,
5561 LPVOID pvReserved
, HMODULE
*phModDll
);
5563 static BOOL
init_functionpointers(void)
5569 static const WCHAR szFusion
[] = {'f','u','s','i','o','n','.','d','l','l',0};
5571 hmscoree
= LoadLibraryA("mscoree.dll");
5574 WARN("mscoree.dll not available\n");
5578 pLoadLibraryShim
= (void *)GetProcAddress(hmscoree
, "LoadLibraryShim");
5579 if (!pLoadLibraryShim
)
5581 WARN("LoadLibraryShim not available\n");
5582 FreeLibrary(hmscoree
);
5586 hr
= pLoadLibraryShim(szFusion
, NULL
, NULL
, &hfusion
);
5589 WARN("fusion.dll not available\n");
5590 FreeLibrary(hmscoree
);
5594 pCreateAssemblyCache
= (void *)GetProcAddress(hfusion
, "CreateAssemblyCache");
5596 FreeLibrary(hmscoree
);
5600 static UINT
install_assembly(LPWSTR path
)
5602 IAssemblyCache
*cache
;
5604 UINT r
= ERROR_FUNCTION_FAILED
;
5606 if (!init_functionpointers() || !pCreateAssemblyCache
)
5607 return ERROR_FUNCTION_FAILED
;
5609 hr
= pCreateAssemblyCache(&cache
, 0);
5613 hr
= IAssemblyCache_InstallAssembly(cache
, 0, path
, NULL
);
5615 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path
), hr
);
5620 IAssemblyCache_Release(cache
);
5624 static UINT
ITERATE_PublishAssembly( MSIRECORD
*rec
, LPVOID param
)
5626 MSIPACKAGE
*package
= param
;
5628 MSIFEATURE
*feature
;
5630 WCHAR path
[MAX_PATH
];
5635 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 1));
5636 if (!comp
|| !comp
->Enabled
||
5637 !(comp
->Action
& (INSTALLSTATE_LOCAL
| INSTALLSTATE_SOURCE
)))
5639 ERR("Component not set for install, not publishing assembly\n");
5640 return ERROR_SUCCESS
;
5643 feature
= find_feature_by_name(package
, MSI_RecordGetString(rec
, 2));
5645 msi_feature_set_state(feature
, INSTALLSTATE_LOCAL
);
5647 if (MSI_RecordGetString(rec
, 3))
5648 FIXME("Manifest unhandled\n");
5650 app
= MSI_RecordGetString(rec
, 4);
5653 FIXME("Assembly should be privately installed\n");
5654 return ERROR_SUCCESS
;
5657 attr
= MSI_RecordGetInteger(rec
, 5);
5658 if (attr
== msidbAssemblyAttributesWin32
)
5660 FIXME("Win32 assemblies not handled\n");
5661 return ERROR_SUCCESS
;
5664 /* FIXME: extract all files belonging to this component */
5665 file
= msi_find_file(package
, comp
->KeyPath
);
5668 ERR("File %s not found\n", debugstr_w(comp
->KeyPath
));
5669 return ERROR_FUNCTION_FAILED
;
5672 GetTempPathW(MAX_PATH
, path
);
5674 if (file
->IsCompressed
)
5676 r
= msi_extract_file(package
, file
, path
);
5677 if (r
!= ERROR_SUCCESS
)
5679 ERR("Failed to extract temporary assembly\n");
5683 PathAddBackslashW(path
);
5684 lstrcatW(path
, file
->FileName
);
5688 PathAddBackslashW(path
);
5689 lstrcatW(path
, file
->FileName
);
5691 if (!CopyFileW(file
->SourcePath
, path
, FALSE
))
5693 ERR("Failed to copy temporary assembly: %d\n", GetLastError());
5694 return ERROR_FUNCTION_FAILED
;
5698 r
= install_assembly(path
);
5699 if (r
!= ERROR_SUCCESS
)
5700 ERR("Failed to install assembly\n");
5702 /* FIXME: write Installer assembly reg values */
5707 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
5712 static const WCHAR ExecSeqQuery
[] =
5713 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5714 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
5716 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5717 if (rc
!= ERROR_SUCCESS
)
5718 return ERROR_SUCCESS
;
5720 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishAssembly
, package
);
5721 msiobj_release(&view
->hdr
);
5726 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
5727 LPCSTR action
, LPCWSTR table
)
5729 static const WCHAR query
[] = {
5730 'S','E','L','E','C','T',' ','*',' ',
5731 'F','R','O','M',' ','`','%','s','`',0 };
5732 MSIQUERY
*view
= NULL
;
5736 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
5737 if (r
== ERROR_SUCCESS
)
5739 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
5740 msiobj_release(&view
->hdr
);
5744 FIXME("%s -> %u ignored %s table values\n",
5745 action
, count
, debugstr_w(table
));
5747 return ERROR_SUCCESS
;
5750 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
5752 TRACE("%p\n", package
);
5753 return ERROR_SUCCESS
;
5756 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
5758 static const WCHAR table
[] =
5759 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
5760 return msi_unimplemented_action_stub( package
, "RemoveIniValues", table
);
5763 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
5765 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
5766 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
5769 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
5771 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
5772 return msi_unimplemented_action_stub( package
, "BindImage", table
);
5775 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
5777 static const WCHAR table
[] = {
5778 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
5779 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
5782 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
5784 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
5785 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
5788 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
5790 static const WCHAR table
[] = { 'S','e','l','f','R','e','g',0 };
5791 return msi_unimplemented_action_stub( package
, "SelfUnregModules", table
);
5794 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
5796 static const WCHAR table
[] = {
5797 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5798 return msi_unimplemented_action_stub( package
, "DeleteServices", table
);
5800 static UINT
ACTION_ValidateProductID( MSIPACKAGE
*package
)
5802 static const WCHAR table
[] = {
5803 'P','r','o','d','u','c','t','I','D',0 };
5804 return msi_unimplemented_action_stub( package
, "ValidateProductID", table
);
5807 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
5809 static const WCHAR table
[] = {
5810 'E','n','v','i','r','o','n','m','e','n','t',0 };
5811 return msi_unimplemented_action_stub( package
, "RemoveEnvironmentStrings", table
);
5814 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
5816 static const WCHAR table
[] = {
5817 'M','s','i','A','s','s','e','m','b','l','y',0 };
5818 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
5821 static UINT
ACTION_UnregisterFonts( MSIPACKAGE
*package
)
5823 static const WCHAR table
[] = { 'F','o','n','t',0 };
5824 return msi_unimplemented_action_stub( package
, "UnregisterFonts", table
);
5827 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
5829 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
5830 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
5833 static UINT
ACTION_RegisterComPlus( MSIPACKAGE
*package
)
5835 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
5836 return msi_unimplemented_action_stub( package
, "RegisterComPlus", table
);
5839 static UINT
ACTION_UnregisterComPlus( MSIPACKAGE
*package
)
5841 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
5842 return msi_unimplemented_action_stub( package
, "UnregisterComPlus", table
);
5845 static UINT
ACTION_InstallSFPCatalogFile( MSIPACKAGE
*package
)
5847 static const WCHAR table
[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
5848 return msi_unimplemented_action_stub( package
, "InstallSFPCatalogFile", table
);
5851 static UINT
ACTION_RemoveDuplicateFiles( MSIPACKAGE
*package
)
5853 static const WCHAR table
[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
5854 return msi_unimplemented_action_stub( package
, "RemoveDuplicateFiles", table
);
5857 static UINT
ACTION_RemoveExistingProducts( MSIPACKAGE
*package
)
5859 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
5860 return msi_unimplemented_action_stub( package
, "RemoveExistingProducts", table
);
5863 static UINT
ACTION_RemoveFolders( MSIPACKAGE
*package
)
5865 static const WCHAR table
[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
5866 return msi_unimplemented_action_stub( package
, "RemoveFolders", table
);
5869 static UINT
ACTION_RemoveODBC( MSIPACKAGE
*package
)
5871 static const WCHAR table
[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
5872 return msi_unimplemented_action_stub( package
, "RemoveODBC", table
);
5875 static UINT
ACTION_RemoveRegistryValues( MSIPACKAGE
*package
)
5877 static const WCHAR table
[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
5878 return msi_unimplemented_action_stub( package
, "RemoveRegistryValues", table
);
5881 static UINT
ACTION_RemoveShortcuts( MSIPACKAGE
*package
)
5883 static const WCHAR table
[] = { 'S','h','o','r','t','c','u','t',0 };
5884 return msi_unimplemented_action_stub( package
, "RemoveShortcuts", table
);
5887 static UINT
ACTION_UnpublishComponents( MSIPACKAGE
*package
)
5889 static const WCHAR table
[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
5890 return msi_unimplemented_action_stub( package
, "UnpublishComponents", table
);
5893 static UINT
ACTION_UnregisterClassInfo( MSIPACKAGE
*package
)
5895 static const WCHAR table
[] = { 'A','p','p','I','d',0 };
5896 return msi_unimplemented_action_stub( package
, "UnregisterClassInfo", table
);
5899 static UINT
ACTION_UnregisterExtensionInfo( MSIPACKAGE
*package
)
5901 static const WCHAR table
[] = { 'E','x','t','e','n','s','i','o','n',0 };
5902 return msi_unimplemented_action_stub( package
, "UnregisterExtensionInfo", table
);
5905 static UINT
ACTION_UnregisterMIMEInfo( MSIPACKAGE
*package
)
5907 static const WCHAR table
[] = { 'M','I','M','E',0 };
5908 return msi_unimplemented_action_stub( package
, "UnregisterMIMEInfo", table
);
5911 static UINT
ACTION_UnregisterProgIdInfo( MSIPACKAGE
*package
)
5913 static const WCHAR table
[] = { 'P','r','o','g','I','d',0 };
5914 return msi_unimplemented_action_stub( package
, "UnregisterProgIdInfo", table
);
5917 static UINT
ACTION_UnregisterTypeLibraries( MSIPACKAGE
*package
)
5919 static const WCHAR table
[] = { 'T','y','p','e','L','i','b',0 };
5920 return msi_unimplemented_action_stub( package
, "UnregisterTypeLibraries", table
);
5923 static const struct _actions StandardActions
[] = {
5924 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
5925 { szAppSearch
, ACTION_AppSearch
},
5926 { szBindImage
, ACTION_BindImage
},
5927 { szCCPSearch
, ACTION_CCPSearch
},
5928 { szCostFinalize
, ACTION_CostFinalize
},
5929 { szCostInitialize
, ACTION_CostInitialize
},
5930 { szCreateFolders
, ACTION_CreateFolders
},
5931 { szCreateShortcuts
, ACTION_CreateShortcuts
},
5932 { szDeleteServices
, ACTION_DeleteServices
},
5933 { szDisableRollback
, NULL
},
5934 { szDuplicateFiles
, ACTION_DuplicateFiles
},
5935 { szExecuteAction
, ACTION_ExecuteAction
},
5936 { szFileCost
, ACTION_FileCost
},
5937 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
5938 { szForceReboot
, ACTION_ForceReboot
},
5939 { szInstallAdminPackage
, NULL
},
5940 { szInstallExecute
, ACTION_InstallExecute
},
5941 { szInstallExecuteAgain
, ACTION_InstallExecute
},
5942 { szInstallFiles
, ACTION_InstallFiles
},
5943 { szInstallFinalize
, ACTION_InstallFinalize
},
5944 { szInstallInitialize
, ACTION_InstallInitialize
},
5945 { szInstallSFPCatalogFile
, ACTION_InstallSFPCatalogFile
},
5946 { szInstallValidate
, ACTION_InstallValidate
},
5947 { szIsolateComponents
, ACTION_IsolateComponents
},
5948 { szLaunchConditions
, ACTION_LaunchConditions
},
5949 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
5950 { szMoveFiles
, ACTION_MoveFiles
},
5951 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
5952 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
5953 { szInstallODBC
, ACTION_InstallODBC
},
5954 { szInstallServices
, ACTION_InstallServices
},
5955 { szPatchFiles
, ACTION_PatchFiles
},
5956 { szProcessComponents
, ACTION_ProcessComponents
},
5957 { szPublishComponents
, ACTION_PublishComponents
},
5958 { szPublishFeatures
, ACTION_PublishFeatures
},
5959 { szPublishProduct
, ACTION_PublishProduct
},
5960 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
5961 { szRegisterComPlus
, ACTION_RegisterComPlus
},
5962 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
5963 { szRegisterFonts
, ACTION_RegisterFonts
},
5964 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
5965 { szRegisterProduct
, ACTION_RegisterProduct
},
5966 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
5967 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
5968 { szRegisterUser
, ACTION_RegisterUser
},
5969 { szRemoveDuplicateFiles
, ACTION_RemoveDuplicateFiles
},
5970 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
5971 { szRemoveExistingProducts
, ACTION_RemoveExistingProducts
},
5972 { szRemoveFiles
, ACTION_RemoveFiles
},
5973 { szRemoveFolders
, ACTION_RemoveFolders
},
5974 { szRemoveIniValues
, ACTION_RemoveIniValues
},
5975 { szRemoveODBC
, ACTION_RemoveODBC
},
5976 { szRemoveRegistryValues
, ACTION_RemoveRegistryValues
},
5977 { szRemoveShortcuts
, ACTION_RemoveShortcuts
},
5978 { szResolveSource
, ACTION_ResolveSource
},
5979 { szRMCCPSearch
, ACTION_RMCCPSearch
},
5980 { szScheduleReboot
, NULL
},
5981 { szSelfRegModules
, ACTION_SelfRegModules
},
5982 { szSelfUnregModules
, ACTION_SelfUnregModules
},
5983 { szSetODBCFolders
, NULL
},
5984 { szStartServices
, ACTION_StartServices
},
5985 { szStopServices
, ACTION_StopServices
},
5986 { szUnpublishComponents
, ACTION_UnpublishComponents
},
5987 { szUnpublishFeatures
, ACTION_UnpublishFeatures
},
5988 { szUnregisterClassInfo
, ACTION_UnregisterClassInfo
},
5989 { szUnregisterComPlus
, ACTION_UnregisterComPlus
},
5990 { szUnregisterExtensionInfo
, ACTION_UnregisterExtensionInfo
},
5991 { szUnregisterFonts
, ACTION_UnregisterFonts
},
5992 { szUnregisterMIMEInfo
, ACTION_UnregisterMIMEInfo
},
5993 { szUnregisterProgIdInfo
, ACTION_UnregisterProgIdInfo
},
5994 { szUnregisterTypeLibraries
, ACTION_UnregisterTypeLibraries
},
5995 { szValidateProductID
, ACTION_ValidateProductID
},
5996 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
5997 { szWriteIniValues
, ACTION_WriteIniValues
},
5998 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
6002 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
6003 UINT
* rc
, BOOL force
)
6009 if (!run
&& !package
->script
->CurrentlyScripting
)
6014 if (strcmpW(action
,szInstallFinalize
) == 0 ||
6015 strcmpW(action
,szInstallExecute
) == 0 ||
6016 strcmpW(action
,szInstallExecuteAgain
) == 0)
6021 while (StandardActions
[i
].action
!= NULL
)
6023 if (strcmpW(StandardActions
[i
].action
, action
)==0)
6027 ui_actioninfo(package
, action
, TRUE
, 0);
6028 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
6029 ui_actioninfo(package
, action
, FALSE
, *rc
);
6033 ui_actionstart(package
, action
);
6034 if (StandardActions
[i
].handler
)
6036 *rc
= StandardActions
[i
].handler(package
);
6040 FIXME("unhandled standard action %s\n",debugstr_w(action
));
6041 *rc
= ERROR_SUCCESS
;