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 static UINT
msi_set_context(MSIPACKAGE
*package
)
658 static const WCHAR szOne
[] = {'1',0};
659 static const WCHAR szAllUsers
[] = {'A','L','L','U','S','E','R','S',0};
661 package
->Context
= MSIINSTALLCONTEXT_USERUNMANAGED
;
663 r
= MSI_GetPropertyW(package
, szAllUsers
, val
, &sz
);
664 if (r
== ERROR_SUCCESS
)
667 if (num
== 1 || num
== 2)
668 package
->Context
= MSIINSTALLCONTEXT_MACHINE
;
671 MSI_SetPropertyW(package
, szAllUsers
, szOne
);
672 return ERROR_SUCCESS
;
675 /****************************************************
676 * TOP level entry points
677 *****************************************************/
679 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
680 LPCWSTR szCommandLine
)
683 BOOL ui
= FALSE
, ui_exists
;
684 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
685 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
686 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
688 MSI_SetPropertyW(package
, szAction
, szInstall
);
690 package
->script
= msi_alloc_zero(sizeof(MSISCRIPT
));
692 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
699 dir
= strdupW(szPackagePath
);
700 p
= strrchrW(dir
, '\\');
704 file
= szPackagePath
+ (p
- dir
);
709 dir
= msi_alloc(MAX_PATH
*sizeof(WCHAR
));
710 GetCurrentDirectoryW(MAX_PATH
, dir
);
711 lstrcatW(dir
, cszbs
);
712 file
= szPackagePath
;
715 msi_free( package
->PackagePath
);
716 package
->PackagePath
= msi_alloc((lstrlenW(dir
) + lstrlenW(file
) + 1) * sizeof(WCHAR
));
717 if (!package
->PackagePath
)
720 return ERROR_OUTOFMEMORY
;
723 lstrcpyW(package
->PackagePath
, dir
);
724 lstrcatW(package
->PackagePath
, file
);
727 msi_set_sourcedir_props(package
, FALSE
);
730 msi_parse_command_line( package
, szCommandLine
);
732 msi_apply_transforms( package
);
733 msi_apply_patches( package
);
735 /* properties may have been added by a transform */
736 msi_clone_properties( package
);
737 msi_set_context( package
);
739 if ( (msi_get_property_int(package
, szUILevel
, 0) & INSTALLUILEVEL_MASK
) >= INSTALLUILEVEL_REDUCED
)
741 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
742 rc
= ACTION_ProcessUISequence(package
);
744 ui_exists
= ui_sequence_exists(package
);
745 if (rc
== ERROR_SUCCESS
|| !ui_exists
)
747 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
748 rc
= ACTION_ProcessExecSequence(package
,ui_exists
);
752 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
754 package
->script
->CurrentlyScripting
= FALSE
;
756 /* process the ending type action */
757 if (rc
== ERROR_SUCCESS
)
758 ACTION_PerformActionSequence(package
,-1,ui
);
759 else if (rc
== ERROR_INSTALL_USEREXIT
)
760 ACTION_PerformActionSequence(package
,-2,ui
);
761 else if (rc
== ERROR_INSTALL_SUSPEND
)
762 ACTION_PerformActionSequence(package
,-4,ui
);
764 ACTION_PerformActionSequence(package
,-3,ui
);
766 /* finish up running custom actions */
767 ACTION_FinishCustomActions(package
);
772 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
)
774 UINT rc
= ERROR_SUCCESS
;
776 static const WCHAR ExecSeqQuery
[] =
777 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
778 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
779 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
780 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
782 static const WCHAR UISeqQuery
[] =
783 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
784 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
785 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
786 ' ', '=',' ','%','i',0};
789 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
791 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
795 LPCWSTR action
, cond
;
797 TRACE("Running the actions\n");
799 /* check conditions */
800 cond
= MSI_RecordGetString(row
,2);
802 /* this is a hack to skip errors in the condition code */
803 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
806 action
= MSI_RecordGetString(row
,1);
809 ERR("failed to fetch action\n");
810 rc
= ERROR_FUNCTION_FAILED
;
815 rc
= ACTION_PerformUIAction(package
,action
,-1);
817 rc
= ACTION_PerformAction(package
,action
,-1,FALSE
);
819 msiobj_release(&row
->hdr
);
830 } iterate_action_param
;
832 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
834 iterate_action_param
*iap
= (iterate_action_param
*)param
;
836 LPCWSTR cond
, action
;
838 action
= MSI_RecordGetString(row
,1);
841 ERR("Error is retrieving action name\n");
842 return ERROR_FUNCTION_FAILED
;
845 /* check conditions */
846 cond
= MSI_RecordGetString(row
,2);
848 /* this is a hack to skip errors in the condition code */
849 if (MSI_EvaluateConditionW(iap
->package
, cond
) == MSICONDITION_FALSE
)
851 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action
));
852 return ERROR_SUCCESS
;
856 rc
= ACTION_PerformUIAction(iap
->package
,action
,-1);
858 rc
= ACTION_PerformAction(iap
->package
,action
,-1,FALSE
);
860 msi_dialog_check_messages( NULL
);
862 if (iap
->package
->CurrentInstallState
!= ERROR_SUCCESS
)
863 rc
= iap
->package
->CurrentInstallState
;
865 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
868 if (rc
!= ERROR_SUCCESS
)
869 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
874 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
878 static const WCHAR query
[] =
879 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
881 ' ','W','H','E','R','E',' ',
882 '`','S','e','q','u','e','n','c','e','`',' ',
883 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
884 '`','S','e','q','u','e','n','c','e','`',0};
885 iterate_action_param iap
;
888 * FIXME: probably should be checking UILevel in the
889 * ACTION_PerformUIAction/ACTION_PerformAction
890 * rather than saving the UI level here. Those
891 * two functions can be merged too.
893 iap
.package
= package
;
896 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
898 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
899 if (r
== ERROR_SUCCESS
)
901 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, &iap
);
902 msiobj_release(&view
->hdr
);
908 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
912 static const WCHAR ExecSeqQuery
[] =
913 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
914 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
915 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
916 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
917 'O','R','D','E','R',' ', 'B','Y',' ',
918 '`','S','e','q','u','e','n','c','e','`',0 };
920 static const WCHAR IVQuery
[] =
921 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
922 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
923 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
924 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
925 ' ','\'', 'I','n','s','t','a','l','l',
926 'V','a','l','i','d','a','t','e','\'', 0};
928 iterate_action_param iap
;
930 iap
.package
= package
;
933 if (package
->script
->ExecuteSequenceRun
)
935 TRACE("Execute Sequence already Run\n");
936 return ERROR_SUCCESS
;
939 package
->script
->ExecuteSequenceRun
= TRUE
;
941 /* get the sequence number */
944 row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
946 return ERROR_FUNCTION_FAILED
;
947 seq
= MSI_RecordGetInteger(row
,1);
948 msiobj_release(&row
->hdr
);
951 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
952 if (rc
== ERROR_SUCCESS
)
954 TRACE("Running the actions\n");
956 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
957 msiobj_release(&view
->hdr
);
963 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
967 static const WCHAR ExecSeqQuery
[] =
968 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
969 '`','I','n','s','t','a','l','l',
970 'U','I','S','e','q','u','e','n','c','e','`',
971 ' ','W','H','E','R','E',' ',
972 '`','S','e','q','u','e','n','c','e','`',' ',
973 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
974 '`','S','e','q','u','e','n','c','e','`',0};
975 iterate_action_param iap
;
977 iap
.package
= package
;
980 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
982 if (rc
== ERROR_SUCCESS
)
984 TRACE("Running the actions\n");
986 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
987 msiobj_release(&view
->hdr
);
993 /********************************************************
994 * ACTION helper functions and functions that perform the actions
995 *******************************************************/
996 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
997 UINT
* rc
, UINT script
, BOOL force
)
1002 arc
= ACTION_CustomAction(package
, action
, script
, force
);
1004 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
1013 * A lot of actions are really important even if they don't do anything
1014 * explicit... Lots of properties are set at the beginning of the installation
1015 * CostFinalize does a bunch of work to translate the directories and such
1017 * But until I get write access to the database that is hard, so I am going to
1018 * hack it to see if I can get something to run.
1020 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
, BOOL force
)
1022 UINT rc
= ERROR_SUCCESS
;
1025 TRACE("Performing action (%s)\n",debugstr_w(action
));
1027 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
1030 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, force
);
1034 WARN("unhandled msi action %s\n",debugstr_w(action
));
1035 rc
= ERROR_FUNCTION_NOT_CALLED
;
1041 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
)
1043 UINT rc
= ERROR_SUCCESS
;
1044 BOOL handled
= FALSE
;
1046 TRACE("Performing action (%s)\n",debugstr_w(action
));
1048 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
1051 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, FALSE
);
1053 if( !handled
&& ACTION_DialogBox(package
,action
) == ERROR_SUCCESS
)
1058 WARN("unhandled msi action %s\n",debugstr_w(action
));
1059 rc
= ERROR_FUNCTION_NOT_CALLED
;
1067 * Actual Action Handlers
1070 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
1072 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1078 dir
= MSI_RecordGetString(row
,1);
1081 ERR("Unable to get folder id\n");
1082 return ERROR_SUCCESS
;
1085 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,TRUE
,&folder
);
1088 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
1089 return ERROR_SUCCESS
;
1092 TRACE("Folder is %s\n",debugstr_w(full_path
));
1095 uirow
= MSI_CreateRecord(1);
1096 MSI_RecordSetStringW(uirow
,1,full_path
);
1097 ui_actiondata(package
,szCreateFolders
,uirow
);
1098 msiobj_release( &uirow
->hdr
);
1100 if (folder
->State
== 0)
1101 create_full_pathW(full_path
);
1105 msi_free(full_path
);
1106 return ERROR_SUCCESS
;
1109 /* FIXME: probably should merge this with the above function */
1110 static UINT
msi_create_directory( MSIPACKAGE
* package
, LPCWSTR dir
)
1112 UINT rc
= ERROR_SUCCESS
;
1114 LPWSTR install_path
;
1116 install_path
= resolve_folder(package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
1118 return ERROR_FUNCTION_FAILED
;
1120 /* create the path */
1121 if (folder
->State
== 0)
1123 create_full_pathW(install_path
);
1126 msi_free(install_path
);
1131 UINT
msi_create_component_directories( MSIPACKAGE
*package
)
1135 /* create all the folders required by the components are going to install */
1136 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1138 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
1140 msi_create_directory( package
, comp
->Directory
);
1143 return ERROR_SUCCESS
;
1147 * Also we cannot enable/disable components either, so for now I am just going
1148 * to do all the directories for all the components.
1150 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1152 static const WCHAR ExecSeqQuery
[] =
1153 {'S','E','L','E','C','T',' ',
1154 '`','D','i','r','e','c','t','o','r','y','_','`',
1155 ' ','F','R','O','M',' ',
1156 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1160 /* create all the empty folders specified in the CreateFolder table */
1161 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1162 if (rc
!= ERROR_SUCCESS
)
1163 return ERROR_SUCCESS
;
1165 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
1166 msiobj_release(&view
->hdr
);
1168 msi_create_component_directories( package
);
1173 static UINT
load_component( MSIRECORD
*row
, LPVOID param
)
1175 MSIPACKAGE
*package
= param
;
1178 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1180 return ERROR_FUNCTION_FAILED
;
1182 list_add_tail( &package
->components
, &comp
->entry
);
1184 /* fill in the data */
1185 comp
->Component
= msi_dup_record_field( row
, 1 );
1187 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1189 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1190 comp
->Directory
= msi_dup_record_field( row
, 3 );
1191 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1192 comp
->Condition
= msi_dup_record_field( row
, 5 );
1193 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1195 comp
->Installed
= INSTALLSTATE_UNKNOWN
;
1196 msi_component_set_state(package
, comp
, INSTALLSTATE_UNKNOWN
);
1198 return ERROR_SUCCESS
;
1201 static UINT
load_all_components( MSIPACKAGE
*package
)
1203 static const WCHAR query
[] = {
1204 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1205 '`','C','o','m','p','o','n','e','n','t','`',0 };
1209 if (!list_empty(&package
->components
))
1210 return ERROR_SUCCESS
;
1212 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1213 if (r
!= ERROR_SUCCESS
)
1216 r
= MSI_IterateRecords(view
, NULL
, load_component
, package
);
1217 msiobj_release(&view
->hdr
);
1222 MSIPACKAGE
*package
;
1223 MSIFEATURE
*feature
;
1226 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1230 cl
= msi_alloc( sizeof (*cl
) );
1232 return ERROR_NOT_ENOUGH_MEMORY
;
1233 cl
->component
= comp
;
1234 list_add_tail( &feature
->Components
, &cl
->entry
);
1236 return ERROR_SUCCESS
;
1239 static UINT
add_feature_child( MSIFEATURE
*parent
, MSIFEATURE
*child
)
1243 fl
= msi_alloc( sizeof(*fl
) );
1245 return ERROR_NOT_ENOUGH_MEMORY
;
1246 fl
->feature
= child
;
1247 list_add_tail( &parent
->Children
, &fl
->entry
);
1249 return ERROR_SUCCESS
;
1252 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1254 _ilfs
* ilfs
= (_ilfs
*)param
;
1258 component
= MSI_RecordGetString(row
,1);
1260 /* check to see if the component is already loaded */
1261 comp
= get_loaded_component( ilfs
->package
, component
);
1264 ERR("unknown component %s\n", debugstr_w(component
));
1265 return ERROR_FUNCTION_FAILED
;
1268 add_feature_component( ilfs
->feature
, comp
);
1269 comp
->Enabled
= TRUE
;
1271 return ERROR_SUCCESS
;
1274 static MSIFEATURE
*find_feature_by_name( MSIPACKAGE
*package
, LPCWSTR name
)
1276 MSIFEATURE
*feature
;
1281 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1283 if ( !lstrcmpW( feature
->Feature
, name
) )
1290 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1292 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1293 MSIFEATURE
* feature
;
1294 static const WCHAR Query1
[] =
1295 {'S','E','L','E','C','T',' ',
1296 '`','C','o','m','p','o','n','e','n','t','_','`',
1297 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1298 'C','o','m','p','o','n','e','n','t','s','`',' ',
1299 'W','H','E','R','E',' ',
1300 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1305 /* fill in the data */
1307 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1309 return ERROR_NOT_ENOUGH_MEMORY
;
1311 list_init( &feature
->Children
);
1312 list_init( &feature
->Components
);
1314 feature
->Feature
= msi_dup_record_field( row
, 1 );
1316 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1318 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1319 feature
->Title
= msi_dup_record_field( row
, 3 );
1320 feature
->Description
= msi_dup_record_field( row
, 4 );
1322 if (!MSI_RecordIsNull(row
,5))
1323 feature
->Display
= MSI_RecordGetInteger(row
,5);
1325 feature
->Level
= MSI_RecordGetInteger(row
,6);
1326 feature
->Directory
= msi_dup_record_field( row
, 7 );
1327 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1329 feature
->Installed
= INSTALLSTATE_UNKNOWN
;
1330 msi_feature_set_state(package
, feature
, INSTALLSTATE_UNKNOWN
);
1332 list_add_tail( &package
->features
, &feature
->entry
);
1334 /* load feature components */
1336 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1337 if (rc
!= ERROR_SUCCESS
)
1338 return ERROR_SUCCESS
;
1340 ilfs
.package
= package
;
1341 ilfs
.feature
= feature
;
1343 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1344 msiobj_release(&view
->hdr
);
1346 return ERROR_SUCCESS
;
1349 static UINT
find_feature_children(MSIRECORD
* row
, LPVOID param
)
1351 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1352 MSIFEATURE
*parent
, *child
;
1354 child
= find_feature_by_name( package
, MSI_RecordGetString( row
, 1 ) );
1356 return ERROR_FUNCTION_FAILED
;
1358 if (!child
->Feature_Parent
)
1359 return ERROR_SUCCESS
;
1361 parent
= find_feature_by_name( package
, child
->Feature_Parent
);
1363 return ERROR_FUNCTION_FAILED
;
1365 add_feature_child( parent
, child
);
1366 return ERROR_SUCCESS
;
1369 static UINT
load_all_features( MSIPACKAGE
*package
)
1371 static const WCHAR query
[] = {
1372 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1373 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1374 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1378 if (!list_empty(&package
->features
))
1379 return ERROR_SUCCESS
;
1381 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1382 if (r
!= ERROR_SUCCESS
)
1385 r
= MSI_IterateRecords( view
, NULL
, load_feature
, package
);
1386 if (r
!= ERROR_SUCCESS
)
1389 r
= MSI_IterateRecords( view
, NULL
, find_feature_children
, package
);
1390 msiobj_release( &view
->hdr
);
1395 static LPWSTR
folder_split_path(LPWSTR p
, WCHAR ch
)
1406 static UINT
load_file_hash(MSIPACKAGE
*package
, MSIFILE
*file
)
1408 static const WCHAR query
[] = {
1409 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1410 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1411 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1412 MSIQUERY
*view
= NULL
;
1413 MSIRECORD
*row
= NULL
;
1416 TRACE("%s\n", debugstr_w(file
->File
));
1418 r
= MSI_OpenQuery(package
->db
, &view
, query
, file
->File
);
1419 if (r
!= ERROR_SUCCESS
)
1422 r
= MSI_ViewExecute(view
, NULL
);
1423 if (r
!= ERROR_SUCCESS
)
1426 r
= MSI_ViewFetch(view
, &row
);
1427 if (r
!= ERROR_SUCCESS
)
1430 file
->hash
.dwFileHashInfoSize
= sizeof(MSIFILEHASHINFO
);
1431 file
->hash
.dwData
[0] = MSI_RecordGetInteger(row
, 3);
1432 file
->hash
.dwData
[1] = MSI_RecordGetInteger(row
, 4);
1433 file
->hash
.dwData
[2] = MSI_RecordGetInteger(row
, 5);
1434 file
->hash
.dwData
[3] = MSI_RecordGetInteger(row
, 6);
1437 if (view
) msiobj_release(&view
->hdr
);
1438 if (row
) msiobj_release(&row
->hdr
);
1442 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1444 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1448 /* fill in the data */
1450 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1452 return ERROR_NOT_ENOUGH_MEMORY
;
1454 file
->File
= msi_dup_record_field( row
, 1 );
1456 component
= MSI_RecordGetString( row
, 2 );
1457 file
->Component
= get_loaded_component( package
, component
);
1459 if (!file
->Component
)
1461 WARN("Component not found: %s\n", debugstr_w(component
));
1462 msi_free(file
->File
);
1464 return ERROR_SUCCESS
;
1467 file
->FileName
= msi_dup_record_field( row
, 3 );
1468 reduce_to_longfilename( file
->FileName
);
1470 file
->ShortName
= msi_dup_record_field( row
, 3 );
1471 file
->LongName
= strdupW( folder_split_path(file
->ShortName
, '|'));
1473 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1474 file
->Version
= msi_dup_record_field( row
, 5 );
1475 file
->Language
= msi_dup_record_field( row
, 6 );
1476 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1477 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1479 file
->state
= msifs_invalid
;
1481 /* if the compressed bits are not set in the file attributes,
1482 * then read the information from the package word count property
1484 if (file
->Attributes
&
1485 (msidbFileAttributesCompressed
| msidbFileAttributesPatchAdded
))
1487 file
->IsCompressed
= TRUE
;
1489 else if (file
->Attributes
& msidbFileAttributesNoncompressed
)
1491 file
->IsCompressed
= FALSE
;
1495 file
->IsCompressed
= package
->WordCount
& msidbSumInfoSourceTypeCompressed
;
1498 if (!file
->IsCompressed
)
1502 p
= resolve_folder(package
, file
->Component
->Directory
,
1503 TRUE
, FALSE
, TRUE
, NULL
);
1504 path
= build_directory_name(2, p
, file
->ShortName
);
1506 if (file
->LongName
&&
1507 GetFileAttributesW(path
) == INVALID_FILE_ATTRIBUTES
)
1510 path
= build_directory_name(2, p
, file
->LongName
);
1513 file
->SourcePath
= path
;
1517 load_file_hash(package
, file
);
1519 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1521 list_add_tail( &package
->files
, &file
->entry
);
1523 return ERROR_SUCCESS
;
1526 static UINT
load_all_files(MSIPACKAGE
*package
)
1530 static const WCHAR Query
[] =
1531 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1532 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1533 '`','S','e','q','u','e','n','c','e','`', 0};
1535 if (!list_empty(&package
->files
))
1536 return ERROR_SUCCESS
;
1538 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1539 if (rc
!= ERROR_SUCCESS
)
1540 return ERROR_SUCCESS
;
1542 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1543 msiobj_release(&view
->hdr
);
1545 return ERROR_SUCCESS
;
1548 static UINT
load_folder( MSIRECORD
*row
, LPVOID param
)
1550 MSIPACKAGE
*package
= param
;
1551 static const WCHAR szDot
[] = { '.',0 };
1552 static WCHAR szEmpty
[] = { 0 };
1553 LPWSTR p
, tgt_short
, tgt_long
, src_short
, src_long
;
1556 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1558 return ERROR_NOT_ENOUGH_MEMORY
;
1560 folder
->Directory
= msi_dup_record_field( row
, 1 );
1562 TRACE("%s\n", debugstr_w(folder
->Directory
));
1564 p
= msi_dup_record_field(row
, 3);
1566 /* split src and target dir */
1568 src_short
= folder_split_path( p
, ':' );
1570 /* split the long and short paths */
1571 tgt_long
= folder_split_path( tgt_short
, '|' );
1572 src_long
= folder_split_path( src_short
, '|' );
1574 /* check for no-op dirs */
1575 if (!lstrcmpW(szDot
, tgt_short
))
1576 tgt_short
= szEmpty
;
1577 if (!lstrcmpW(szDot
, src_short
))
1578 src_short
= szEmpty
;
1581 tgt_long
= tgt_short
;
1584 src_short
= tgt_short
;
1585 src_long
= tgt_long
;
1589 src_long
= src_short
;
1591 /* FIXME: use the target short path too */
1592 folder
->TargetDefault
= strdupW(tgt_long
);
1593 folder
->SourceShortPath
= strdupW(src_short
);
1594 folder
->SourceLongPath
= strdupW(src_long
);
1597 TRACE("TargetDefault = %s\n",debugstr_w( folder
->TargetDefault
));
1598 TRACE("SourceLong = %s\n", debugstr_w( folder
->SourceLongPath
));
1599 TRACE("SourceShort = %s\n", debugstr_w( folder
->SourceShortPath
));
1601 folder
->Parent
= msi_dup_record_field( row
, 2 );
1603 folder
->Property
= msi_dup_property( package
, folder
->Directory
);
1605 list_add_tail( &package
->folders
, &folder
->entry
);
1607 TRACE("returning %p\n", folder
);
1609 return ERROR_SUCCESS
;
1612 static UINT
load_all_folders( MSIPACKAGE
*package
)
1614 static const WCHAR query
[] = {
1615 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1616 '`','D','i','r','e','c','t','o','r','y','`',0 };
1620 if (!list_empty(&package
->folders
))
1621 return ERROR_SUCCESS
;
1623 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1624 if (r
!= ERROR_SUCCESS
)
1627 r
= MSI_IterateRecords(view
, NULL
, load_folder
, package
);
1628 msiobj_release(&view
->hdr
);
1633 * I am not doing any of the costing functionality yet.
1634 * Mostly looking at doing the Component and Feature loading
1636 * The native MSI does A LOT of modification to tables here. Mostly adding
1637 * a lot of temporary columns to the Feature and Component tables.
1639 * note: Native msi also tracks the short filename. But I am only going to
1640 * track the long ones. Also looking at this directory table
1641 * it appears that the directory table does not get the parents
1642 * resolved base on property only based on their entries in the
1645 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1647 static const WCHAR szCosting
[] =
1648 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1649 static const WCHAR szZero
[] = { '0', 0 };
1651 MSI_SetPropertyW(package
, szCosting
, szZero
);
1652 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1654 load_all_folders( package
);
1655 load_all_components( package
);
1656 load_all_features( package
);
1657 load_all_files( package
);
1659 return ERROR_SUCCESS
;
1662 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1665 UINT rc
= ERROR_SUCCESS
;
1667 TRACE("Executing Script %i\n",script
);
1669 if (!package
->script
)
1671 ERR("no script!\n");
1672 return ERROR_FUNCTION_FAILED
;
1675 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1678 action
= package
->script
->Actions
[script
][i
];
1679 ui_actionstart(package
, action
);
1680 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1681 rc
= ACTION_PerformAction(package
, action
, script
, TRUE
);
1682 if (rc
!= ERROR_SUCCESS
)
1685 msi_free_action_script(package
, script
);
1689 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1691 return ERROR_SUCCESS
;
1694 static void ACTION_GetComponentInstallStates(MSIPACKAGE
*package
)
1700 state
= MsiQueryProductStateW(package
->ProductCode
);
1702 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
1704 if (!comp
->ComponentId
)
1707 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1708 comp
->Installed
= INSTALLSTATE_ABSENT
;
1711 r
= MsiQueryComponentStateW(package
->ProductCode
, NULL
,
1712 package
->Context
, comp
->ComponentId
,
1714 if (r
!= ERROR_SUCCESS
)
1715 comp
->Installed
= INSTALLSTATE_ABSENT
;
1720 static void ACTION_GetFeatureInstallStates(MSIPACKAGE
*package
)
1722 MSIFEATURE
*feature
;
1725 state
= MsiQueryProductStateW(package
->ProductCode
);
1727 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1729 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1730 feature
->Installed
= INSTALLSTATE_ABSENT
;
1733 feature
->Installed
= MsiQueryFeatureStateW(package
->ProductCode
,
1739 static BOOL
process_state_property(MSIPACKAGE
* package
, int level
,
1740 LPCWSTR property
, INSTALLSTATE state
)
1742 static const WCHAR all
[]={'A','L','L',0};
1743 static const WCHAR remove
[] = {'R','E','M','O','V','E',0};
1745 MSIFEATURE
*feature
;
1747 override
= msi_dup_property( package
, property
);
1751 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1753 if (lstrcmpW(property
, remove
) &&
1754 (feature
->Level
<= 0 || feature
->Level
> level
))
1757 if (strcmpiW(override
,all
)==0)
1758 msi_feature_set_state(package
, feature
, state
);
1761 LPWSTR ptr
= override
;
1762 LPWSTR ptr2
= strchrW(override
,',');
1766 if ((ptr2
&& strncmpW(ptr
,feature
->Feature
, ptr2
-ptr
)==0)
1767 || (!ptr2
&& strcmpW(ptr
,feature
->Feature
)==0))
1769 msi_feature_set_state(package
, feature
, state
);
1775 ptr2
= strchrW(ptr
,',');
1787 UINT
MSI_SetFeatureStates(MSIPACKAGE
*package
)
1790 static const WCHAR szlevel
[] =
1791 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1792 static const WCHAR szAddLocal
[] =
1793 {'A','D','D','L','O','C','A','L',0};
1794 static const WCHAR szAddSource
[] =
1795 {'A','D','D','S','O','U','R','C','E',0};
1796 static const WCHAR szRemove
[] =
1797 {'R','E','M','O','V','E',0};
1798 static const WCHAR szReinstall
[] =
1799 {'R','E','I','N','S','T','A','L','L',0};
1800 BOOL override
= FALSE
;
1801 MSICOMPONENT
* component
;
1802 MSIFEATURE
*feature
;
1805 /* I do not know if this is where it should happen.. but */
1807 TRACE("Checking Install Level\n");
1809 level
= msi_get_property_int(package
, szlevel
, 1);
1811 /* ok here is the _real_ rub
1812 * all these activation/deactivation things happen in order and things
1813 * later on the list override things earlier on the list.
1814 * 1) INSTALLLEVEL processing
1824 * 11) FILEADDDEFAULT
1826 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1827 * REMOVE are the big ones, since we don't handle administrative installs
1830 override
|= process_state_property(package
, level
, szAddLocal
, INSTALLSTATE_LOCAL
);
1831 override
|= process_state_property(package
, level
, szRemove
, INSTALLSTATE_ABSENT
);
1832 override
|= process_state_property(package
, level
, szAddSource
, INSTALLSTATE_SOURCE
);
1833 override
|= process_state_property(package
, level
, szReinstall
, INSTALLSTATE_LOCAL
);
1837 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1839 BOOL feature_state
= ((feature
->Level
> 0) &&
1840 (feature
->Level
<= level
));
1842 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1844 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1845 msi_feature_set_state(package
, feature
, INSTALLSTATE_SOURCE
);
1846 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1847 msi_feature_set_state(package
, feature
, INSTALLSTATE_ADVERTISED
);
1849 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1853 /* disable child features of unselected parent features */
1854 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1858 if (feature
->Level
> 0 && feature
->Level
<= level
)
1861 LIST_FOR_EACH_ENTRY( fl
, &feature
->Children
, FeatureList
, entry
)
1862 msi_feature_set_state(package
, fl
->feature
, INSTALLSTATE_UNKNOWN
);
1867 /* set the Preselected Property */
1868 static const WCHAR szPreselected
[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1869 static const WCHAR szOne
[] = { '1', 0 };
1871 MSI_SetPropertyW(package
,szPreselected
,szOne
);
1875 * now we want to enable or disable components base on feature
1878 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1882 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1883 debugstr_w(feature
->Feature
), feature
->Level
, feature
->Installed
, feature
->Action
);
1885 if (!feature
->Level
)
1888 /* features with components that have compressed files are made local */
1889 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1891 if (cl
->component
->Enabled
&&
1892 cl
->component
->ForceLocalState
&&
1893 feature
->Action
== INSTALLSTATE_SOURCE
)
1895 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1900 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1902 component
= cl
->component
;
1904 if (!component
->Enabled
)
1907 switch (feature
->Action
)
1909 case INSTALLSTATE_ABSENT
:
1910 component
->anyAbsent
= 1;
1912 case INSTALLSTATE_ADVERTISED
:
1913 component
->hasAdvertiseFeature
= 1;
1915 case INSTALLSTATE_SOURCE
:
1916 component
->hasSourceFeature
= 1;
1918 case INSTALLSTATE_LOCAL
:
1919 component
->hasLocalFeature
= 1;
1921 case INSTALLSTATE_DEFAULT
:
1922 if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1923 component
->hasAdvertiseFeature
= 1;
1924 else if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1925 component
->hasSourceFeature
= 1;
1927 component
->hasLocalFeature
= 1;
1935 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1937 /* if the component isn't enabled, leave it alone */
1938 if (!component
->Enabled
)
1941 /* check if it's local or source */
1942 if (!(component
->Attributes
& msidbComponentAttributesOptional
) &&
1943 (component
->hasLocalFeature
|| component
->hasSourceFeature
))
1945 if ((component
->Attributes
& msidbComponentAttributesSourceOnly
) &&
1946 !component
->ForceLocalState
)
1947 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1949 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1953 /* if any feature is local, the component must be local too */
1954 if (component
->hasLocalFeature
)
1956 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1960 if (component
->hasSourceFeature
)
1962 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1966 if (component
->hasAdvertiseFeature
)
1968 msi_component_set_state(package
, component
, INSTALLSTATE_ADVERTISED
);
1972 TRACE("nobody wants component %s\n", debugstr_w(component
->Component
));
1973 if (component
->anyAbsent
)
1974 msi_component_set_state(package
, component
, INSTALLSTATE_ABSENT
);
1977 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1979 if (component
->Action
== INSTALLSTATE_DEFAULT
)
1981 TRACE("%s was default, setting to local\n", debugstr_w(component
->Component
));
1982 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1985 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1986 debugstr_w(component
->Component
), component
->Installed
, component
->Action
);
1990 return ERROR_SUCCESS
;
1993 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1995 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2000 name
= MSI_RecordGetString(row
,1);
2002 f
= get_loaded_folder(package
, name
);
2003 if (!f
) return ERROR_SUCCESS
;
2005 /* reset the ResolvedTarget */
2006 msi_free(f
->ResolvedTarget
);
2007 f
->ResolvedTarget
= NULL
;
2009 /* This helper function now does ALL the work */
2010 TRACE("Dir %s ...\n",debugstr_w(name
));
2011 path
= resolve_folder(package
,name
,FALSE
,TRUE
,TRUE
,NULL
);
2012 TRACE("resolves to %s\n",debugstr_w(path
));
2015 return ERROR_SUCCESS
;
2018 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
2020 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2022 MSIFEATURE
*feature
;
2024 name
= MSI_RecordGetString( row
, 1 );
2026 feature
= get_loaded_feature( package
, name
);
2028 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
2032 Condition
= MSI_RecordGetString(row
,3);
2034 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
2036 int level
= MSI_RecordGetInteger(row
,2);
2037 TRACE("Resetting feature %s to level %i\n", debugstr_w(name
), level
);
2038 feature
->Level
= level
;
2041 return ERROR_SUCCESS
;
2044 static LPWSTR
msi_get_disk_file_version( LPCWSTR filename
)
2046 static const WCHAR name_fmt
[] =
2047 {'%','u','.','%','u','.','%','u','.','%','u',0};
2048 static const WCHAR name
[] = {'\\',0};
2049 VS_FIXEDFILEINFO
*lpVer
;
2050 WCHAR filever
[0x100];
2056 TRACE("%s\n", debugstr_w(filename
));
2058 versize
= GetFileVersionInfoSizeW( filename
, &handle
);
2062 version
= msi_alloc( versize
);
2063 GetFileVersionInfoW( filename
, 0, versize
, version
);
2065 if (!VerQueryValueW( version
, name
, (LPVOID
*)&lpVer
, &sz
))
2067 msi_free( version
);
2071 sprintfW( filever
, name_fmt
,
2072 HIWORD(lpVer
->dwFileVersionMS
),
2073 LOWORD(lpVer
->dwFileVersionMS
),
2074 HIWORD(lpVer
->dwFileVersionLS
),
2075 LOWORD(lpVer
->dwFileVersionLS
));
2077 msi_free( version
);
2079 return strdupW( filever
);
2082 static UINT
msi_check_file_install_states( MSIPACKAGE
*package
)
2084 LPWSTR file_version
;
2087 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2089 MSICOMPONENT
* comp
= file
->Component
;
2095 if (file
->IsCompressed
)
2096 comp
->ForceLocalState
= TRUE
;
2098 /* calculate target */
2099 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, TRUE
, NULL
);
2101 msi_free(file
->TargetPath
);
2103 TRACE("file %s is named %s\n",
2104 debugstr_w(file
->File
), debugstr_w(file
->FileName
));
2106 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
2110 TRACE("file %s resolves to %s\n",
2111 debugstr_w(file
->File
), debugstr_w(file
->TargetPath
));
2113 /* don't check files of components that aren't installed */
2114 if (comp
->Installed
== INSTALLSTATE_UNKNOWN
||
2115 comp
->Installed
== INSTALLSTATE_ABSENT
)
2117 file
->state
= msifs_missing
; /* assume files are missing */
2121 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
2123 file
->state
= msifs_missing
;
2124 comp
->Cost
+= file
->FileSize
;
2128 if (file
->Version
&&
2129 (file_version
= msi_get_disk_file_version( file
->TargetPath
)))
2131 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
2132 debugstr_w(file_version
));
2133 /* FIXME: seems like a bad way to compare version numbers */
2134 if (lstrcmpiW(file_version
, file
->Version
)<0)
2136 file
->state
= msifs_overwrite
;
2137 comp
->Cost
+= file
->FileSize
;
2140 file
->state
= msifs_present
;
2141 msi_free( file_version
);
2144 file
->state
= msifs_present
;
2147 return ERROR_SUCCESS
;
2151 * A lot is done in this function aside from just the costing.
2152 * The costing needs to be implemented at some point but for now I am going
2153 * to focus on the directory building
2156 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2158 static const WCHAR ExecSeqQuery
[] =
2159 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2160 '`','D','i','r','e','c','t','o','r','y','`',0};
2161 static const WCHAR ConditionQuery
[] =
2162 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2163 '`','C','o','n','d','i','t','i','o','n','`',0};
2164 static const WCHAR szCosting
[] =
2165 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2166 static const WCHAR szlevel
[] =
2167 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2168 static const WCHAR szOutOfDiskSpace
[] =
2169 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2170 static const WCHAR szOne
[] = { '1', 0 };
2171 static const WCHAR szZero
[] = { '0', 0 };
2177 TRACE("Building Directory properties\n");
2179 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2180 if (rc
== ERROR_SUCCESS
)
2182 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
2184 msiobj_release(&view
->hdr
);
2187 /* read components states from the registry */
2188 ACTION_GetComponentInstallStates(package
);
2189 ACTION_GetFeatureInstallStates(package
);
2191 TRACE("File calculations\n");
2192 msi_check_file_install_states( package
);
2194 TRACE("Evaluating Condition Table\n");
2196 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
2197 if (rc
== ERROR_SUCCESS
)
2199 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeConditions
,
2201 msiobj_release(&view
->hdr
);
2204 TRACE("Enabling or Disabling Components\n");
2205 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2207 if (MSI_EvaluateConditionW(package
, comp
->Condition
) == MSICONDITION_FALSE
)
2209 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
2210 comp
->Enabled
= FALSE
;
2213 comp
->Enabled
= TRUE
;
2216 MSI_SetPropertyW(package
,szCosting
,szOne
);
2217 /* set default run level if not set */
2218 level
= msi_dup_property( package
, szlevel
);
2220 MSI_SetPropertyW(package
,szlevel
, szOne
);
2223 /* FIXME: check volume disk space */
2224 MSI_SetPropertyW(package
, szOutOfDiskSpace
, szZero
);
2226 return MSI_SetFeatureStates(package
);
2229 /* OK this value is "interpreted" and then formatted based on the
2230 first few characters */
2231 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
2236 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2242 LPWSTR deformated
= NULL
;
2245 deformat_string(package
, &value
[2], &deformated
);
2247 /* binary value type */
2251 *size
= (strlenW(ptr
)/2)+1;
2253 *size
= strlenW(ptr
)/2;
2255 data
= msi_alloc(*size
);
2261 /* if uneven pad with a zero in front */
2267 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2269 TRACE("Uneven byte count\n");
2277 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2280 msi_free(deformated
);
2282 TRACE("Data %i bytes(%i)\n",*size
,count
);
2289 deformat_string(package
, &value
[1], &deformated
);
2292 *size
= sizeof(DWORD
);
2293 data
= msi_alloc(*size
);
2299 if ( (*p
< '0') || (*p
> '9') )
2305 if (deformated
[0] == '-')
2308 TRACE("DWORD %i\n",*(LPDWORD
)data
);
2310 msi_free(deformated
);
2315 static const WCHAR szMulti
[] = {'[','~',']',0};
2324 *type
=REG_EXPAND_SZ
;
2332 if (strstrW(value
,szMulti
))
2333 *type
= REG_MULTI_SZ
;
2335 /* remove initial delimiter */
2336 if (!strncmpW(value
, szMulti
, 3))
2339 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2341 /* add double NULL terminator */
2342 if (*type
== REG_MULTI_SZ
)
2344 *size
+= 2 * sizeof(WCHAR
); /* two NULL terminators */
2345 data
= msi_realloc_zero(data
, *size
);
2351 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2353 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2354 static const WCHAR szHCR
[] =
2355 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2356 'R','O','O','T','\\',0};
2357 static const WCHAR szHCU
[] =
2358 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2359 'U','S','E','R','\\',0};
2360 static const WCHAR szHLM
[] =
2361 {'H','K','E','Y','_','L','O','C','A','L','_',
2362 'M','A','C','H','I','N','E','\\',0};
2363 static const WCHAR szHU
[] =
2364 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2366 LPSTR value_data
= NULL
;
2367 HKEY root_key
, hkey
;
2370 LPCWSTR szRoot
, component
, name
, key
, value
;
2375 BOOL check_first
= FALSE
;
2378 ui_progress(package
,2,0,0,0);
2385 component
= MSI_RecordGetString(row
, 6);
2386 comp
= get_loaded_component(package
,component
);
2388 return ERROR_SUCCESS
;
2390 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2392 TRACE("Skipping write due to disabled component %s\n",
2393 debugstr_w(component
));
2395 comp
->Action
= comp
->Installed
;
2397 return ERROR_SUCCESS
;
2400 comp
->Action
= INSTALLSTATE_LOCAL
;
2402 name
= MSI_RecordGetString(row
, 4);
2403 if( MSI_RecordIsNull(row
,5) && name
)
2405 /* null values can have special meanings */
2406 if (name
[0]=='-' && name
[1] == 0)
2407 return ERROR_SUCCESS
;
2408 else if ((name
[0]=='+' && name
[1] == 0) ||
2409 (name
[0] == '*' && name
[1] == 0))
2414 root
= MSI_RecordGetInteger(row
,2);
2415 key
= MSI_RecordGetString(row
, 3);
2417 /* get the root key */
2422 static const WCHAR szALLUSER
[] = {'A','L','L','U','S','E','R','S',0};
2423 LPWSTR all_users
= msi_dup_property( package
, szALLUSER
);
2424 if (all_users
&& all_users
[0] == '1')
2426 root_key
= HKEY_LOCAL_MACHINE
;
2431 root_key
= HKEY_CURRENT_USER
;
2434 msi_free(all_users
);
2437 case 0: root_key
= HKEY_CLASSES_ROOT
;
2440 case 1: root_key
= HKEY_CURRENT_USER
;
2443 case 2: root_key
= HKEY_LOCAL_MACHINE
;
2446 case 3: root_key
= HKEY_USERS
;
2450 ERR("Unknown root %i\n",root
);
2456 return ERROR_SUCCESS
;
2458 deformat_string(package
, key
, &deformated
);
2459 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2460 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2461 strcpyW(uikey
,szRoot
);
2462 strcatW(uikey
,deformated
);
2464 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2466 ERR("Could not create key %s\n",debugstr_w(deformated
));
2467 msi_free(deformated
);
2469 return ERROR_SUCCESS
;
2471 msi_free(deformated
);
2473 value
= MSI_RecordGetString(row
,5);
2475 value_data
= parse_value(package
, value
, &type
, &size
);
2478 static const WCHAR szEmpty
[] = {0};
2479 value_data
= (LPSTR
)strdupW(szEmpty
);
2480 size
= sizeof(szEmpty
);
2484 deformat_string(package
, name
, &deformated
);
2488 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2490 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2495 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2496 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2498 TRACE("value %s of %s checked already exists\n",
2499 debugstr_w(deformated
), debugstr_w(uikey
));
2503 TRACE("Checked and setting value %s of %s\n",
2504 debugstr_w(deformated
), debugstr_w(uikey
));
2505 if (deformated
|| size
)
2506 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2511 uirow
= MSI_CreateRecord(3);
2512 MSI_RecordSetStringW(uirow
,2,deformated
);
2513 MSI_RecordSetStringW(uirow
,1,uikey
);
2516 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2518 MSI_RecordSetStringW(uirow
,3,value
);
2520 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2521 msiobj_release( &uirow
->hdr
);
2523 msi_free(value_data
);
2524 msi_free(deformated
);
2527 return ERROR_SUCCESS
;
2530 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2534 static const WCHAR ExecSeqQuery
[] =
2535 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2536 '`','R','e','g','i','s','t','r','y','`',0 };
2538 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2539 if (rc
!= ERROR_SUCCESS
)
2540 return ERROR_SUCCESS
;
2542 /* increment progress bar each time action data is sent */
2543 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2545 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2547 msiobj_release(&view
->hdr
);
2551 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2553 package
->script
->CurrentlyScripting
= TRUE
;
2555 return ERROR_SUCCESS
;
2559 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2564 static const WCHAR q1
[]=
2565 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2566 '`','R','e','g','i','s','t','r','y','`',0};
2569 MSIFEATURE
*feature
;
2572 TRACE("InstallValidate\n");
2574 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2575 if (rc
== ERROR_SUCCESS
)
2577 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2578 msiobj_release( &view
->hdr
);
2579 total
+= progress
* REG_PROGRESS_VALUE
;
2582 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2583 total
+= COMPONENT_PROGRESS_VALUE
;
2585 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2586 total
+= file
->FileSize
;
2588 ui_progress(package
,0,total
,0,0);
2590 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2592 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2593 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2594 feature
->ActionRequest
);
2597 return ERROR_SUCCESS
;
2600 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2602 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2603 LPCWSTR cond
= NULL
;
2604 LPCWSTR message
= NULL
;
2607 static const WCHAR title
[]=
2608 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2610 cond
= MSI_RecordGetString(row
,1);
2612 r
= MSI_EvaluateConditionW(package
,cond
);
2613 if (r
== MSICONDITION_FALSE
)
2615 if ((gUILevel
& INSTALLUILEVEL_MASK
) != INSTALLUILEVEL_NONE
)
2618 message
= MSI_RecordGetString(row
,2);
2619 deformat_string(package
,message
,&deformated
);
2620 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2621 msi_free(deformated
);
2624 return ERROR_INSTALL_FAILURE
;
2627 return ERROR_SUCCESS
;
2630 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2633 MSIQUERY
* view
= NULL
;
2634 static const WCHAR ExecSeqQuery
[] =
2635 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2636 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2638 TRACE("Checking launch conditions\n");
2640 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2641 if (rc
!= ERROR_SUCCESS
)
2642 return ERROR_SUCCESS
;
2644 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2645 msiobj_release(&view
->hdr
);
2650 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2654 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,TRUE
,NULL
);
2656 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2658 MSIRECORD
* row
= 0;
2660 LPWSTR deformated
,buffer
,deformated_name
;
2662 static const WCHAR ExecSeqQuery
[] =
2663 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2664 '`','R','e','g','i','s','t','r','y','`',' ',
2665 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2666 ' ','=',' ' ,'\'','%','s','\'',0 };
2667 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2668 static const WCHAR fmt2
[]=
2669 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2671 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2675 root
= MSI_RecordGetInteger(row
,2);
2676 key
= MSI_RecordGetString(row
, 3);
2677 name
= MSI_RecordGetString(row
, 4);
2678 deformat_string(package
, key
, &deformated
);
2679 deformat_string(package
, name
, &deformated_name
);
2681 len
= strlenW(deformated
) + 6;
2682 if (deformated_name
)
2683 len
+=strlenW(deformated_name
);
2685 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2687 if (deformated_name
)
2688 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2690 sprintfW(buffer
,fmt
,root
,deformated
);
2692 msi_free(deformated
);
2693 msi_free(deformated_name
);
2694 msiobj_release(&row
->hdr
);
2698 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2700 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2705 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2708 return strdupW( file
->TargetPath
);
2713 static HKEY
openSharedDLLsKey(void)
2716 static const WCHAR path
[] =
2717 {'S','o','f','t','w','a','r','e','\\',
2718 'M','i','c','r','o','s','o','f','t','\\',
2719 'W','i','n','d','o','w','s','\\',
2720 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2721 'S','h','a','r','e','d','D','L','L','s',0};
2723 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2727 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2732 DWORD sz
= sizeof(count
);
2735 hkey
= openSharedDLLsKey();
2736 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2737 if (rc
!= ERROR_SUCCESS
)
2743 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2747 hkey
= openSharedDLLsKey();
2749 msi_reg_set_val_dword( hkey
, path
, count
);
2751 RegDeleteValueW(hkey
,path
);
2757 * Return TRUE if the count should be written out and FALSE if not
2759 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2761 MSIFEATURE
*feature
;
2765 /* only refcount DLLs */
2766 if (comp
->KeyPath
== NULL
||
2767 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2768 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2772 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2773 write
= (count
> 0);
2775 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2779 /* increment counts */
2780 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2784 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
))
2787 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2789 if ( cl
->component
== comp
)
2794 /* decrement counts */
2795 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2799 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ABSENT
))
2802 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2804 if ( cl
->component
== comp
)
2809 /* ref count all the files in the component */
2814 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2816 if (file
->Component
== comp
)
2817 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2821 /* add a count for permanent */
2822 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2825 comp
->RefCount
= count
;
2828 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2831 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2833 WCHAR squished_pc
[GUID_SIZE
];
2834 WCHAR squished_cc
[GUID_SIZE
];
2841 squash_guid(package
->ProductCode
,squished_pc
);
2842 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2844 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2848 ui_progress(package
,2,0,0,0);
2849 if (!comp
->ComponentId
)
2852 squash_guid(comp
->ComponentId
,squished_cc
);
2854 msi_free(comp
->FullKeypath
);
2855 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2857 ACTION_RefCountComponent( package
, comp
);
2859 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2860 debugstr_w(comp
->Component
),
2861 debugstr_w(squished_cc
),
2862 debugstr_w(comp
->FullKeypath
),
2865 if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) ||
2866 ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
))
2868 if (!comp
->FullKeypath
)
2871 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2872 rc
= MSIREG_OpenLocalUserDataComponentKey(comp
->ComponentId
, &hkey
, TRUE
);
2874 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, &hkey
, TRUE
);
2876 if (rc
!= ERROR_SUCCESS
)
2879 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2881 static const WCHAR szPermKey
[] =
2882 { '0','0','0','0','0','0','0','0','0','0','0','0',
2883 '0','0','0','0','0','0','0','0','0','0','0','0',
2884 '0','0','0','0','0','0','0','0',0 };
2886 msi_reg_set_val_str(hkey
, szPermKey
, comp
->FullKeypath
);
2889 if (comp
->Action
== INSTALLSTATE_LOCAL
)
2890 msi_reg_set_val_str(hkey
, squished_pc
, comp
->FullKeypath
);
2896 WCHAR source
[MAX_PATH
];
2897 WCHAR base
[MAX_PATH
];
2899 static const WCHAR fmt
[] = {'%','0','2','d','\\',0};
2900 static const WCHAR query
[] = {
2901 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2902 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2903 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2904 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2905 '`','D','i','s','k','I','d','`',0};
2907 file
= get_loaded_file(package
, comp
->KeyPath
);
2911 row
= MSI_QueryGetRecord(package
->db
, query
, file
->Sequence
);
2912 sprintfW(source
, fmt
, MSI_RecordGetInteger(row
, 1));
2913 ptr2
= strrchrW(source
, '\\') + 1;
2914 msiobj_release(&row
->hdr
);
2916 lstrcpyW(base
, package
->PackagePath
);
2917 ptr
= strrchrW(base
, '\\');
2920 ptr
= file
->SourcePath
+ lstrlenW(base
);
2921 lstrcpyW(ptr2
, ptr
);
2923 msi_reg_set_val_str(hkey
, squished_pc
, source
);
2927 else if (ACTION_VerifyComponentForAction(comp
, INSTALLSTATE_ABSENT
))
2929 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2930 MSIREG_DeleteLocalUserDataComponentKey(comp
->ComponentId
);
2932 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
);
2936 uirow
= MSI_CreateRecord(3);
2937 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2938 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2939 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
2940 ui_actiondata(package
,szProcessComponents
,uirow
);
2941 msiobj_release( &uirow
->hdr
);
2944 return ERROR_SUCCESS
;
2955 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
2956 LPWSTR lpszName
, LONG_PTR lParam
)
2959 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
2960 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
2964 if (!IS_INTRESOURCE(lpszName
))
2966 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
2970 sz
= strlenW(tl_struct
->source
)+4;
2971 sz
*= sizeof(WCHAR
);
2973 if ((INT_PTR
)lpszName
== 1)
2974 tl_struct
->path
= strdupW(tl_struct
->source
);
2977 tl_struct
->path
= msi_alloc(sz
);
2978 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
2981 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
2982 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
2983 if (!SUCCEEDED(res
))
2985 msi_free(tl_struct
->path
);
2986 tl_struct
->path
= NULL
;
2991 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
2992 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
2994 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2998 msi_free(tl_struct
->path
);
2999 tl_struct
->path
= NULL
;
3001 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
3002 ITypeLib_Release(tl_struct
->ptLib
);
3007 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
3009 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
3013 typelib_struct tl_struct
;
3018 static const WCHAR szTYPELIB
[] = {'T','Y','P','E','L','I','B',0};
3020 component
= MSI_RecordGetString(row
,3);
3021 comp
= get_loaded_component(package
,component
);
3023 return ERROR_SUCCESS
;
3025 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3027 TRACE("Skipping typelib reg due to disabled component\n");
3029 comp
->Action
= comp
->Installed
;
3031 return ERROR_SUCCESS
;
3034 comp
->Action
= INSTALLSTATE_LOCAL
;
3036 file
= get_loaded_file( package
, comp
->KeyPath
);
3038 return ERROR_SUCCESS
;
3040 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
3044 guid
= MSI_RecordGetString(row
,1);
3045 CLSIDFromString((LPWSTR
)guid
, &tl_struct
.clsid
);
3046 tl_struct
.source
= strdupW( file
->TargetPath
);
3047 tl_struct
.path
= NULL
;
3049 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
3050 (LONG_PTR
)&tl_struct
);
3058 helpid
= MSI_RecordGetString(row
,6);
3061 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,TRUE
,NULL
);
3062 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
3065 if (!SUCCEEDED(res
))
3066 ERR("Failed to register type library %s\n",
3067 debugstr_w(tl_struct
.path
));
3070 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
3072 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
3075 ITypeLib_Release(tl_struct
.ptLib
);
3076 msi_free(tl_struct
.path
);
3079 ERR("Failed to load type library %s\n",
3080 debugstr_w(tl_struct
.source
));
3082 FreeLibrary(module
);
3083 msi_free(tl_struct
.source
);
3087 hr
= LoadTypeLibEx(file
->TargetPath
, REGKIND_REGISTER
, &tlib
);
3090 ERR("Failed to load type library: %08x\n", hr
);
3091 return ERROR_FUNCTION_FAILED
;
3094 ITypeLib_Release(tlib
);
3097 return ERROR_SUCCESS
;
3100 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
3103 * OK this is a bit confusing.. I am given a _Component key and I believe
3104 * that the file that is being registered as a type library is the "key file
3105 * of that component" which I interpret to mean "The file in the KeyPath of
3110 static const WCHAR Query
[] =
3111 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3112 '`','T','y','p','e','L','i','b','`',0};
3114 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3115 if (rc
!= ERROR_SUCCESS
)
3116 return ERROR_SUCCESS
;
3118 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
3119 msiobj_release(&view
->hdr
);
3123 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
3125 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3126 LPWSTR target_file
, target_folder
, filename
;
3127 LPCWSTR buffer
, extension
;
3129 static const WCHAR szlnk
[]={'.','l','n','k',0};
3130 IShellLinkW
*sl
= NULL
;
3131 IPersistFile
*pf
= NULL
;
3134 buffer
= MSI_RecordGetString(row
,4);
3135 comp
= get_loaded_component(package
,buffer
);
3137 return ERROR_SUCCESS
;
3139 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3141 TRACE("Skipping shortcut creation due to disabled component\n");
3143 comp
->Action
= comp
->Installed
;
3145 return ERROR_SUCCESS
;
3148 comp
->Action
= INSTALLSTATE_LOCAL
;
3150 ui_actiondata(package
,szCreateShortcuts
,row
);
3152 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
3153 &IID_IShellLinkW
, (LPVOID
*) &sl
);
3157 ERR("CLSID_ShellLink not available\n");
3161 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
3164 ERR("QueryInterface(IID_IPersistFile) failed\n");
3168 buffer
= MSI_RecordGetString(row
,2);
3169 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,TRUE
,NULL
);
3171 /* may be needed because of a bug somewhere else */
3172 create_full_pathW(target_folder
);
3174 filename
= msi_dup_record_field( row
, 3 );
3175 reduce_to_longfilename(filename
);
3177 extension
= strchrW(filename
,'.');
3178 if (!extension
|| strcmpiW(extension
,szlnk
))
3180 int len
= strlenW(filename
);
3181 filename
= msi_realloc(filename
, len
* sizeof(WCHAR
) + sizeof(szlnk
));
3182 memcpy(filename
+ len
, szlnk
, sizeof(szlnk
));
3184 target_file
= build_directory_name(2, target_folder
, filename
);
3185 msi_free(target_folder
);
3188 buffer
= MSI_RecordGetString(row
,5);
3189 if (strchrW(buffer
,'['))
3192 deformat_string(package
,buffer
,&deformated
);
3193 IShellLinkW_SetPath(sl
,deformated
);
3194 msi_free(deformated
);
3198 FIXME("poorly handled shortcut format, advertised shortcut\n");
3199 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
3202 if (!MSI_RecordIsNull(row
,6))
3205 buffer
= MSI_RecordGetString(row
,6);
3206 deformat_string(package
,buffer
,&deformated
);
3207 IShellLinkW_SetArguments(sl
,deformated
);
3208 msi_free(deformated
);
3211 if (!MSI_RecordIsNull(row
,7))
3213 buffer
= MSI_RecordGetString(row
,7);
3214 IShellLinkW_SetDescription(sl
,buffer
);
3217 if (!MSI_RecordIsNull(row
,8))
3218 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
3220 if (!MSI_RecordIsNull(row
,9))
3225 buffer
= MSI_RecordGetString(row
,9);
3227 Path
= build_icon_path(package
,buffer
);
3228 index
= MSI_RecordGetInteger(row
,10);
3230 /* no value means 0 */
3231 if (index
== MSI_NULL_INTEGER
)
3234 IShellLinkW_SetIconLocation(sl
,Path
,index
);
3238 if (!MSI_RecordIsNull(row
,11))
3239 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
3241 if (!MSI_RecordIsNull(row
,12))
3244 buffer
= MSI_RecordGetString(row
,12);
3245 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, TRUE
, NULL
);
3247 IShellLinkW_SetWorkingDirectory(sl
,Path
);
3251 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
3252 IPersistFile_Save(pf
,target_file
,FALSE
);
3254 msi_free(target_file
);
3258 IPersistFile_Release( pf
);
3260 IShellLinkW_Release( sl
);
3262 return ERROR_SUCCESS
;
3265 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
3270 static const WCHAR Query
[] =
3271 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3272 '`','S','h','o','r','t','c','u','t','`',0};
3274 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3275 if (rc
!= ERROR_SUCCESS
)
3276 return ERROR_SUCCESS
;
3278 res
= CoInitialize( NULL
);
3281 ERR("CoInitialize failed\n");
3282 return ERROR_FUNCTION_FAILED
;
3285 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
3286 msiobj_release(&view
->hdr
);
3293 static UINT
ITERATE_PublishIcon(MSIRECORD
*row
, LPVOID param
)
3295 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
3304 FileName
= MSI_RecordGetString(row
,1);
3307 ERR("Unable to get FileName\n");
3308 return ERROR_SUCCESS
;
3311 FilePath
= build_icon_path(package
,FileName
);
3313 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
3315 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
3316 FILE_ATTRIBUTE_NORMAL
, NULL
);
3318 if (the_file
== INVALID_HANDLE_VALUE
)
3320 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3322 return ERROR_SUCCESS
;
3329 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3330 if (rc
!= ERROR_SUCCESS
)
3332 ERR("Failed to get stream\n");
3333 CloseHandle(the_file
);
3334 DeleteFileW(FilePath
);
3337 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3338 } while (sz
== 1024);
3342 CloseHandle(the_file
);
3344 uirow
= MSI_CreateRecord(1);
3345 MSI_RecordSetStringW(uirow
,1,FileName
);
3346 ui_actiondata(package
,szPublishProduct
,uirow
);
3347 msiobj_release( &uirow
->hdr
);
3349 return ERROR_SUCCESS
;
3352 static UINT
msi_publish_icons(MSIPACKAGE
*package
)
3357 static const WCHAR query
[]= {
3358 'S','E','L','E','C','T',' ','*',' ',
3359 'F','R','O','M',' ','`','I','c','o','n','`',0};
3361 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
3362 if (r
== ERROR_SUCCESS
)
3364 MSI_IterateRecords(view
, NULL
, ITERATE_PublishIcon
, package
);
3365 msiobj_release(&view
->hdr
);
3368 return ERROR_SUCCESS
;
3371 static UINT
msi_publish_sourcelist(MSIPACKAGE
*package
, HKEY hkey
)
3377 MSISOURCELISTINFO
*info
;
3379 static const WCHAR szEmpty
[] = {0};
3380 static const WCHAR szSourceList
[] = {'S','o','u','r','c','e','L','i','s','t',0};
3382 r
= RegCreateKeyW(hkey
, szSourceList
, &source
);
3383 if (r
!= ERROR_SUCCESS
)
3386 RegCloseKey(source
);
3388 buffer
= strrchrW(package
->PackagePath
, '\\') + 1;
3389 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3390 package
->Context
, MSICODE_PRODUCT
,
3391 INSTALLPROPERTY_PACKAGENAMEW
, buffer
);
3392 if (r
!= ERROR_SUCCESS
)
3395 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3396 package
->Context
, MSICODE_PRODUCT
,
3397 INSTALLPROPERTY_MEDIAPACKAGEPATHW
, szEmpty
);
3398 if (r
!= ERROR_SUCCESS
)
3401 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3402 package
->Context
, MSICODE_PRODUCT
,
3403 INSTALLPROPERTY_DISKPROMPTW
, szEmpty
);
3404 if (r
!= ERROR_SUCCESS
)
3407 LIST_FOR_EACH_ENTRY(info
, &package
->sourcelist_info
, MSISOURCELISTINFO
, entry
)
3409 if (!lstrcmpW(info
->property
, INSTALLPROPERTY_LASTUSEDSOURCEW
))
3410 msi_set_last_used_source(package
->ProductCode
, NULL
, info
->context
,
3411 info
->options
, info
->value
);
3413 MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3414 info
->context
, info
->options
,
3415 info
->property
, info
->value
);
3418 LIST_FOR_EACH_ENTRY(disk
, &package
->sourcelist_media
, MSIMEDIADISK
, entry
)
3420 MsiSourceListAddMediaDiskW(package
->ProductCode
, NULL
,
3421 disk
->context
, disk
->options
,
3422 disk
->disk_id
, disk
->volume_label
, disk
->disk_prompt
);
3425 return ERROR_SUCCESS
;
3428 static UINT
msi_publish_product_properties(MSIPACKAGE
*package
, HKEY hkey
)
3430 MSIHANDLE hdb
, suminfo
;
3431 WCHAR guids
[MAX_PATH
];
3432 WCHAR packcode
[SQUISH_GUID_SIZE
];
3439 static const WCHAR szProductLanguage
[] =
3440 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3441 static const WCHAR szARPProductIcon
[] =
3442 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3443 static const WCHAR szProductVersion
[] =
3444 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3445 static const WCHAR szAssignment
[] =
3446 {'A','s','s','i','g','n','m','e','n','t',0};
3447 static const WCHAR szAdvertiseFlags
[] =
3448 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3449 static const WCHAR szClients
[] =
3450 {'C','l','i','e','n','t','s',0};
3451 static const WCHAR szColon
[] = {':',0};
3453 buffer
= msi_dup_property(package
, INSTALLPROPERTY_PRODUCTNAMEW
);
3454 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3457 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
3458 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3460 ptr
= strrchrW(package
->PackagePath
, '\\' ) + 1;
3461 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PACKAGENAMEW
, ptr
);
3464 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_AUTHORIZED_LUA_APPW
, 0);
3466 buffer
= msi_dup_property(package
, szARPProductIcon
);
3469 LPWSTR path
= build_icon_path(package
,buffer
);
3470 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3475 buffer
= msi_dup_property(package
, szProductVersion
);
3478 DWORD verdword
= msi_version_str_to_dword(buffer
);
3479 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3483 msi_reg_set_val_dword(hkey
, szAssignment
, 0);
3484 msi_reg_set_val_dword(hkey
, szAdvertiseFlags
, 0x184);
3485 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_INSTANCETYPEW
, 0);
3486 msi_reg_set_val_str(hkey
, szClients
, szColon
);
3488 hdb
= alloc_msihandle(&package
->db
->hdr
);
3490 return ERROR_NOT_ENOUGH_MEMORY
;
3492 r
= MsiGetSummaryInformationW(hdb
, NULL
, 0, &suminfo
);
3493 MsiCloseHandle(hdb
);
3494 if (r
!= ERROR_SUCCESS
)
3498 r
= MsiSummaryInfoGetPropertyW(suminfo
, PID_REVNUMBER
, NULL
, NULL
,
3499 NULL
, guids
, &size
);
3500 if (r
!= ERROR_SUCCESS
)
3503 ptr
= strchrW(guids
, ';');
3505 squash_guid(guids
, packcode
);
3506 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PACKAGECODEW
, packcode
);
3509 MsiCloseHandle(suminfo
);
3510 return ERROR_SUCCESS
;
3513 static UINT
msi_publish_upgrade_code(MSIPACKAGE
*package
)
3518 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
3520 static const WCHAR szUpgradeCode
[] =
3521 {'U','p','g','r','a','d','e','C','o','d','e',0};
3523 upgrade
= msi_dup_property(package
, szUpgradeCode
);
3525 return ERROR_SUCCESS
;
3527 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3529 r
= MSIREG_OpenClassesUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3530 if (r
!= ERROR_SUCCESS
)
3535 r
= MSIREG_OpenUserUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3536 if (r
!= ERROR_SUCCESS
)
3540 squash_guid(package
->ProductCode
, squashed_pc
);
3541 msi_reg_set_val_str(hkey
, squashed_pc
, NULL
);
3550 static BOOL
msi_check_publish(MSIPACKAGE
*package
)
3552 MSIFEATURE
*feature
;
3554 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3556 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
3563 static BOOL
msi_check_unpublish(MSIPACKAGE
*package
)
3565 MSIFEATURE
*feature
;
3567 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3569 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3577 * 99% of the work done here is only done for
3578 * advertised installs. However this is where the
3579 * Icon table is processed and written out
3580 * so that is what I am going to do here.
3582 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3588 /* FIXME: also need to publish if the product is in advertise mode */
3589 if (!msi_check_publish(package
))
3590 return ERROR_SUCCESS
;
3592 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3594 rc
= MSIREG_OpenLocalClassesProductKey(package
->ProductCode
, &hukey
, TRUE
);
3595 if (rc
!= ERROR_SUCCESS
)
3598 rc
= MSIREG_OpenLocalUserDataProductKey(package
->ProductCode
, &hudkey
, TRUE
);
3599 if (rc
!= ERROR_SUCCESS
)
3604 rc
= MSIREG_OpenUserProductsKey(package
->ProductCode
, &hukey
, TRUE
);
3605 if (rc
!= ERROR_SUCCESS
)
3608 rc
= MSIREG_OpenUserDataProductKey(package
->ProductCode
, &hudkey
, TRUE
);
3609 if (rc
!= ERROR_SUCCESS
)
3613 rc
= msi_publish_upgrade_code(package
);
3614 if (rc
!= ERROR_SUCCESS
)
3617 rc
= msi_publish_product_properties(package
, hukey
);
3618 if (rc
!= ERROR_SUCCESS
)
3621 rc
= msi_publish_sourcelist(package
, hukey
);
3622 if (rc
!= ERROR_SUCCESS
)
3625 rc
= msi_publish_icons(package
);
3629 RegCloseKey(hudkey
);
3634 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3636 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3637 LPCWSTR component
,section
,key
,value
,identifier
,filename
,dirproperty
;
3638 LPWSTR deformated_section
, deformated_key
, deformated_value
;
3639 LPWSTR folder
, fullname
= NULL
;
3643 static const WCHAR szWindowsFolder
[] =
3644 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3646 component
= MSI_RecordGetString(row
, 8);
3647 comp
= get_loaded_component(package
,component
);
3649 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3651 TRACE("Skipping ini file due to disabled component %s\n",
3652 debugstr_w(component
));
3654 comp
->Action
= comp
->Installed
;
3656 return ERROR_SUCCESS
;
3659 comp
->Action
= INSTALLSTATE_LOCAL
;
3661 identifier
= MSI_RecordGetString(row
,1);
3662 filename
= MSI_RecordGetString(row
,2);
3663 dirproperty
= MSI_RecordGetString(row
,3);
3664 section
= MSI_RecordGetString(row
,4);
3665 key
= MSI_RecordGetString(row
,5);
3666 value
= MSI_RecordGetString(row
,6);
3667 action
= MSI_RecordGetInteger(row
,7);
3669 deformat_string(package
,section
,&deformated_section
);
3670 deformat_string(package
,key
,&deformated_key
);
3671 deformat_string(package
,value
,&deformated_value
);
3675 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, TRUE
, NULL
);
3677 folder
= msi_dup_property( package
, dirproperty
);
3680 folder
= msi_dup_property( package
, szWindowsFolder
);
3684 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
3688 fullname
= build_directory_name(2, folder
, filename
);
3692 TRACE("Adding value %s to section %s in %s\n",
3693 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3694 debugstr_w(fullname
));
3695 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3696 deformated_value
, fullname
);
3698 else if (action
== 1)
3701 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3702 returned
, 10, fullname
);
3703 if (returned
[0] == 0)
3705 TRACE("Adding value %s to section %s in %s\n",
3706 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3707 debugstr_w(fullname
));
3709 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3710 deformated_value
, fullname
);
3713 else if (action
== 3)
3714 FIXME("Append to existing section not yet implemented\n");
3716 uirow
= MSI_CreateRecord(4);
3717 MSI_RecordSetStringW(uirow
,1,identifier
);
3718 MSI_RecordSetStringW(uirow
,2,deformated_section
);
3719 MSI_RecordSetStringW(uirow
,3,deformated_key
);
3720 MSI_RecordSetStringW(uirow
,4,deformated_value
);
3721 ui_actiondata(package
,szWriteIniValues
,uirow
);
3722 msiobj_release( &uirow
->hdr
);
3726 msi_free(deformated_key
);
3727 msi_free(deformated_value
);
3728 msi_free(deformated_section
);
3729 return ERROR_SUCCESS
;
3732 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
3736 static const WCHAR ExecSeqQuery
[] =
3737 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3738 '`','I','n','i','F','i','l','e','`',0};
3740 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3741 if (rc
!= ERROR_SUCCESS
)
3743 TRACE("no IniFile table\n");
3744 return ERROR_SUCCESS
;
3747 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
3748 msiobj_release(&view
->hdr
);
3752 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
3754 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3759 static const WCHAR ExeStr
[] =
3760 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3761 static const WCHAR close
[] = {'\"',0};
3763 PROCESS_INFORMATION info
;
3768 memset(&si
,0,sizeof(STARTUPINFOW
));
3770 filename
= MSI_RecordGetString(row
,1);
3771 file
= get_loaded_file( package
, filename
);
3775 ERR("Unable to find file id %s\n",debugstr_w(filename
));
3776 return ERROR_SUCCESS
;
3779 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
3781 FullName
= msi_alloc(len
*sizeof(WCHAR
));
3782 strcpyW(FullName
,ExeStr
);
3783 strcatW( FullName
, file
->TargetPath
);
3784 strcatW(FullName
,close
);
3786 TRACE("Registering %s\n",debugstr_w(FullName
));
3787 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
3792 CloseHandle(info
.hThread
);
3793 msi_dialog_check_messages(info
.hProcess
);
3794 CloseHandle(info
.hProcess
);
3800 uirow
= MSI_CreateRecord( 2 );
3801 uipath
= strdupW( file
->TargetPath
);
3802 p
= strrchrW(uipath
,'\\');
3805 MSI_RecordSetStringW( uirow
, 1, &p
[1] );
3806 MSI_RecordSetStringW( uirow
, 2, uipath
);
3807 ui_actiondata( package
, szSelfRegModules
, uirow
);
3808 msiobj_release( &uirow
->hdr
);
3810 /* FIXME: call ui_progress? */
3812 return ERROR_SUCCESS
;
3815 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
3819 static const WCHAR ExecSeqQuery
[] =
3820 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3821 '`','S','e','l','f','R','e','g','`',0};
3823 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3824 if (rc
!= ERROR_SUCCESS
)
3826 TRACE("no SelfReg table\n");
3827 return ERROR_SUCCESS
;
3830 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
3831 msiobj_release(&view
->hdr
);
3833 return ERROR_SUCCESS
;
3836 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
3838 MSIFEATURE
*feature
;
3843 if (!msi_check_publish(package
))
3844 return ERROR_SUCCESS
;
3846 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3848 rc
= MSIREG_OpenLocalClassesFeaturesKey(package
->ProductCode
,
3850 if (rc
!= ERROR_SUCCESS
)
3853 rc
= MSIREG_OpenLocalUserDataFeaturesKey(package
->ProductCode
,
3855 if (rc
!= ERROR_SUCCESS
)
3860 rc
= MSIREG_OpenUserFeaturesKey(package
->ProductCode
, &hkey
, TRUE
);
3861 if (rc
!= ERROR_SUCCESS
)
3864 rc
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
,
3866 if (rc
!= ERROR_SUCCESS
)
3870 /* here the guids are base 85 encoded */
3871 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
3877 BOOL absent
= FALSE
;
3880 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
) &&
3881 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_SOURCE
) &&
3882 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ADVERTISED
))
3886 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3890 if (feature
->Feature_Parent
)
3891 size
+= strlenW( feature
->Feature_Parent
)+2;
3893 data
= msi_alloc(size
* sizeof(WCHAR
));
3896 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3898 MSICOMPONENT
* component
= cl
->component
;
3902 if (component
->ComponentId
)
3904 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
3905 CLSIDFromString(component
->ComponentId
, &clsid
);
3906 encode_base85_guid(&clsid
,buf
);
3907 TRACE("to %s\n",debugstr_w(buf
));
3912 if (feature
->Feature_Parent
)
3914 static const WCHAR sep
[] = {'\2',0};
3916 strcatW(data
,feature
->Feature_Parent
);
3919 msi_reg_set_val_str( userdata
, feature
->Feature
, data
);
3923 if (feature
->Feature_Parent
)
3924 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
3927 static const WCHAR emptyW
[] = {0};
3928 size
+= sizeof(WCHAR
);
3929 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
3930 (LPBYTE
)(feature
->Feature_Parent
? feature
->Feature_Parent
: emptyW
),size
);
3934 size
+= 2*sizeof(WCHAR
);
3935 data
= msi_alloc(size
);
3938 if (feature
->Feature_Parent
)
3939 strcpyW( &data
[1], feature
->Feature_Parent
);
3940 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
3946 uirow
= MSI_CreateRecord( 1 );
3947 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
3948 ui_actiondata( package
, szPublishFeatures
, uirow
);
3949 msiobj_release( &uirow
->hdr
);
3950 /* FIXME: call ui_progress? */
3955 RegCloseKey(userdata
);
3959 static UINT
msi_unpublish_feature(MSIPACKAGE
*package
, MSIFEATURE
*feature
)
3964 TRACE("unpublishing feature %s\n", debugstr_w(feature
->Feature
));
3966 r
= MSIREG_OpenUserFeaturesKey(package
->ProductCode
, &hkey
, FALSE
);
3967 if (r
== ERROR_SUCCESS
)
3969 RegDeleteValueW(hkey
, feature
->Feature
);
3973 r
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, &hkey
, FALSE
);
3974 if (r
== ERROR_SUCCESS
)
3976 RegDeleteValueW(hkey
, feature
->Feature
);
3980 return ERROR_SUCCESS
;
3983 static UINT
ACTION_UnpublishFeatures(MSIPACKAGE
*package
)
3985 MSIFEATURE
*feature
;
3987 if (!msi_check_unpublish(package
))
3988 return ERROR_SUCCESS
;
3990 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3992 msi_unpublish_feature(package
, feature
);
3995 return ERROR_SUCCESS
;
3998 static UINT
msi_get_local_package_name( LPWSTR path
)
4000 static const WCHAR szInstaller
[] = {
4001 '\\','I','n','s','t','a','l','l','e','r','\\',0};
4002 static const WCHAR fmt
[] = { '%','x','.','m','s','i',0};
4006 time
= GetTickCount();
4007 GetWindowsDirectoryW( path
, MAX_PATH
);
4008 lstrcatW( path
, szInstaller
);
4009 CreateDirectoryW( path
, NULL
);
4011 len
= lstrlenW(path
);
4012 for (i
=0; i
<0x10000; i
++)
4014 snprintfW( &path
[len
], MAX_PATH
- len
, fmt
, (time
+i
)&0xffff );
4015 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
,
4016 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
4017 if (handle
!= INVALID_HANDLE_VALUE
)
4019 CloseHandle(handle
);
4022 if (GetLastError() != ERROR_FILE_EXISTS
&&
4023 GetLastError() != ERROR_SHARING_VIOLATION
)
4024 return ERROR_FUNCTION_FAILED
;
4027 return ERROR_SUCCESS
;
4030 static UINT
msi_make_package_local( MSIPACKAGE
*package
, HKEY hkey
)
4032 WCHAR packagefile
[MAX_PATH
];
4035 r
= msi_get_local_package_name( packagefile
);
4036 if (r
!= ERROR_SUCCESS
)
4039 TRACE("Copying to local package %s\n",debugstr_w(packagefile
));
4041 r
= CopyFileW( package
->db
->path
, packagefile
, FALSE
);
4045 ERR("Unable to copy package (%s -> %s) (error %d)\n",
4046 debugstr_w(package
->db
->path
), debugstr_w(packagefile
), GetLastError());
4047 return ERROR_FUNCTION_FAILED
;
4050 msi_reg_set_val_str( hkey
, INSTALLPROPERTY_LOCALPACKAGEW
, packagefile
);
4052 return ERROR_SUCCESS
;
4055 static UINT
msi_publish_install_properties(MSIPACKAGE
*package
, HKEY hkey
)
4057 LPWSTR prop
, val
, key
;
4063 static const WCHAR date_fmt
[] = {'%','i','%','0','2','i','%','0','2','i',0};
4064 static const WCHAR szWindowsInstaller
[] =
4065 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4066 static const WCHAR modpath_fmt
[] =
4067 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4068 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4069 static const WCHAR szModifyPath
[] =
4070 {'M','o','d','i','f','y','P','a','t','h',0};
4071 static const WCHAR szUninstallString
[] =
4072 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4073 static const WCHAR szEstimatedSize
[] =
4074 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4075 static const WCHAR szProductLanguage
[] =
4076 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4077 static const WCHAR szProductVersion
[] =
4078 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4079 static const WCHAR szProductName
[] =
4080 {'P','r','o','d','u','c','t','N','a','m','e',0};
4081 static const WCHAR szDisplayName
[] =
4082 {'D','i','s','p','l','a','y','N','a','m','e',0};
4083 static const WCHAR szDisplayVersion
[] =
4084 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4085 static const WCHAR szManufacturer
[] =
4086 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4088 static const LPCSTR propval
[] = {
4089 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4090 "ARPCONTACT", "Contact",
4091 "ARPCOMMENTS", "Comments",
4092 "ProductName", "DisplayName",
4093 "ProductVersion", "DisplayVersion",
4094 "ARPHELPLINK", "HelpLink",
4095 "ARPHELPTELEPHONE", "HelpTelephone",
4096 "ARPINSTALLLOCATION", "InstallLocation",
4097 "SourceDir", "InstallSource",
4098 "Manufacturer", "Publisher",
4099 "ARPREADME", "Readme",
4101 "ARPURLINFOABOUT", "URLInfoAbout",
4102 "ARPURLUPDATEINFO", "URLUpdateInfo",
4105 const LPCSTR
*p
= propval
;
4109 prop
= strdupAtoW(*p
++);
4110 key
= strdupAtoW(*p
++);
4111 val
= msi_dup_property(package
, prop
);
4112 msi_reg_set_val_str(hkey
, key
, val
);
4118 msi_reg_set_val_dword(hkey
, szWindowsInstaller
, 1);
4120 size
= deformat_string(package
, modpath_fmt
, &buffer
);
4121 RegSetValueExW(hkey
, szModifyPath
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4122 RegSetValueExW(hkey
, szUninstallString
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4125 /* FIXME: Write real Estimated Size when we have it */
4126 msi_reg_set_val_dword(hkey
, szEstimatedSize
, 0);
4128 buffer
= msi_dup_property(package
, szProductName
);
4129 msi_reg_set_val_str(hkey
, szDisplayName
, buffer
);
4132 buffer
= msi_dup_property(package
, cszSourceDir
);
4133 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLSOURCEW
, buffer
);
4136 buffer
= msi_dup_property(package
, szManufacturer
);
4137 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PUBLISHERW
, buffer
);
4140 GetLocalTime(&systime
);
4141 sprintfW(date
, date_fmt
, systime
.wYear
, systime
.wMonth
, systime
.wDay
);
4142 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLDATEW
, date
);
4144 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
4145 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
4147 buffer
= msi_dup_property(package
, szProductVersion
);
4148 msi_reg_set_val_str(hkey
, szDisplayVersion
, buffer
);
4151 DWORD verdword
= msi_version_str_to_dword(buffer
);
4153 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
4154 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>> 24);
4155 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>> 16) & 0xFF);
4159 return ERROR_SUCCESS
;
4162 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
4164 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
4165 LPWSTR upgrade_code
;
4170 static const WCHAR szUpgradeCode
[] = {
4171 'U','p','g','r','a','d','e','C','o','d','e',0};
4173 /* FIXME: also need to publish if the product is in advertise mode */
4174 if (!msi_check_publish(package
))
4175 return ERROR_SUCCESS
;
4177 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
, &hkey
, TRUE
);
4178 if (rc
!= ERROR_SUCCESS
)
4181 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4183 rc
= MSIREG_OpenLocalSystemInstallProps(package
->ProductCode
, &props
, TRUE
);
4184 if (rc
!= ERROR_SUCCESS
)
4189 rc
= MSIREG_OpenCurrentUserInstallProps(package
->ProductCode
, &props
, TRUE
);
4190 if (rc
!= ERROR_SUCCESS
)
4194 msi_make_package_local(package
, props
);
4196 rc
= msi_publish_install_properties(package
, hkey
);
4197 if (rc
!= ERROR_SUCCESS
)
4200 rc
= msi_publish_install_properties(package
, props
);
4201 if (rc
!= ERROR_SUCCESS
)
4204 upgrade_code
= msi_dup_property(package
, szUpgradeCode
);
4207 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &upgrade
, TRUE
);
4208 squash_guid(package
->ProductCode
, squashed_pc
);
4209 msi_reg_set_val_str(upgrade
, squashed_pc
, NULL
);
4210 RegCloseKey(upgrade
);
4211 msi_free(upgrade_code
);
4217 return ERROR_SUCCESS
;
4220 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
4222 return execute_script(package
,INSTALL_SCRIPT
);
4225 static UINT
msi_unpublish_product(MSIPACKAGE
*package
)
4228 LPWSTR remove
= NULL
;
4229 LPWSTR
*features
= NULL
;
4230 BOOL full_uninstall
= TRUE
;
4231 MSIFEATURE
*feature
;
4233 static const WCHAR szRemove
[] = {'R','E','M','O','V','E',0};
4234 static const WCHAR szAll
[] = {'A','L','L',0};
4235 static const WCHAR szUpgradeCode
[] =
4236 {'U','p','g','r','a','d','e','C','o','d','e',0};
4238 remove
= msi_dup_property(package
, szRemove
);
4240 return ERROR_SUCCESS
;
4242 features
= msi_split_string(remove
, ',');
4246 ERR("REMOVE feature list is empty!\n");
4247 return ERROR_FUNCTION_FAILED
;
4250 if (!lstrcmpW(features
[0], szAll
))
4251 full_uninstall
= TRUE
;
4254 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4256 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
4257 full_uninstall
= FALSE
;
4261 if (!full_uninstall
)
4264 MSIREG_DeleteProductKey(package
->ProductCode
);
4265 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4266 MSIREG_DeleteUninstallKey(package
->ProductCode
);
4268 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4270 MSIREG_DeleteLocalClassesProductKey(package
->ProductCode
);
4271 MSIREG_DeleteLocalClassesFeaturesKey(package
->ProductCode
);
4275 MSIREG_DeleteUserProductKey(package
->ProductCode
);
4276 MSIREG_DeleteUserFeaturesKey(package
->ProductCode
);
4279 upgrade
= msi_dup_property(package
, szUpgradeCode
);
4282 MSIREG_DeleteUserUpgradeCodesKey(upgrade
);
4289 return ERROR_SUCCESS
;
4292 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
4296 rc
= msi_unpublish_product(package
);
4297 if (rc
!= ERROR_SUCCESS
)
4300 /* turn off scheduling */
4301 package
->script
->CurrentlyScripting
= FALSE
;
4303 /* first do the same as an InstallExecute */
4304 rc
= ACTION_InstallExecute(package
);
4305 if (rc
!= ERROR_SUCCESS
)
4308 /* then handle Commit Actions */
4309 rc
= execute_script(package
,COMMIT_SCRIPT
);
4314 UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
4316 static const WCHAR RunOnce
[] = {
4317 'S','o','f','t','w','a','r','e','\\',
4318 'M','i','c','r','o','s','o','f','t','\\',
4319 'W','i','n','d','o','w','s','\\',
4320 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4321 'R','u','n','O','n','c','e',0};
4322 static const WCHAR InstallRunOnce
[] = {
4323 'S','o','f','t','w','a','r','e','\\',
4324 'M','i','c','r','o','s','o','f','t','\\',
4325 'W','i','n','d','o','w','s','\\',
4326 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4327 'I','n','s','t','a','l','l','e','r','\\',
4328 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4330 static const WCHAR msiexec_fmt
[] = {
4332 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4333 '\"','%','s','\"',0};
4334 static const WCHAR install_fmt
[] = {
4335 '/','I',' ','\"','%','s','\"',' ',
4336 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4337 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4338 WCHAR buffer
[256], sysdir
[MAX_PATH
];
4340 WCHAR squished_pc
[100];
4342 squash_guid(package
->ProductCode
,squished_pc
);
4344 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
4345 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
4346 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
4349 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4352 TRACE("Reboot command %s\n",debugstr_w(buffer
));
4354 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
4355 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
4357 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4360 return ERROR_INSTALL_SUSPEND
;
4363 static UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
4369 * We are currently doing what should be done here in the top level Install
4370 * however for Administrative and uninstalls this step will be needed
4372 if (!package
->PackagePath
)
4373 return ERROR_SUCCESS
;
4375 msi_set_sourcedir_props(package
, TRUE
);
4377 attrib
= GetFileAttributesW(package
->db
->path
);
4378 if (attrib
== INVALID_FILE_ATTRIBUTES
)
4384 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4385 package
->Context
, MSICODE_PRODUCT
,
4386 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
4387 if (rc
== ERROR_MORE_DATA
)
4389 prompt
= msi_alloc(size
* sizeof(WCHAR
));
4390 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4391 package
->Context
, MSICODE_PRODUCT
,
4392 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
4395 prompt
= strdupW(package
->db
->path
);
4397 msg
= generate_error_string(package
,1302,1,prompt
);
4398 while(attrib
== INVALID_FILE_ATTRIBUTES
)
4400 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
4403 rc
= ERROR_INSTALL_USEREXIT
;
4406 attrib
= GetFileAttributesW(package
->db
->path
);
4412 return ERROR_SUCCESS
;
4417 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
4424 static const WCHAR szPropKeys
[][80] =
4426 {'P','r','o','d','u','c','t','I','D',0},
4427 {'U','S','E','R','N','A','M','E',0},
4428 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4432 static const WCHAR szRegKeys
[][80] =
4434 {'P','r','o','d','u','c','t','I','D',0},
4435 {'R','e','g','O','w','n','e','r',0},
4436 {'R','e','g','C','o','m','p','a','n','y',0},
4440 if (msi_check_unpublish(package
))
4442 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4443 return ERROR_SUCCESS
;
4446 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
4448 return ERROR_SUCCESS
;
4450 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4451 rc
= MSIREG_OpenLocalSystemInstallProps(package
->ProductCode
, &hkey
, TRUE
);
4453 rc
= MSIREG_OpenCurrentUserInstallProps(package
->ProductCode
, &hkey
, TRUE
);
4455 if (rc
!= ERROR_SUCCESS
)
4458 for( i
= 0; szPropKeys
[i
][0]; i
++ )
4460 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
4461 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
4466 msi_free(productid
);
4469 /* FIXME: call ui_actiondata */
4475 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
4479 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
4480 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
4485 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4487 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4488 LPCWSTR compgroupid
=NULL
;
4489 LPCWSTR feature
=NULL
;
4490 LPCWSTR text
= NULL
;
4491 LPCWSTR qualifier
= NULL
;
4492 LPCWSTR component
= NULL
;
4493 LPWSTR advertise
= NULL
;
4494 LPWSTR output
= NULL
;
4496 UINT rc
= ERROR_SUCCESS
;
4501 component
= MSI_RecordGetString(rec
,3);
4502 comp
= get_loaded_component(package
,component
);
4504 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) &&
4505 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
) &&
4506 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ADVERTISED
))
4508 TRACE("Skipping: Component %s not scheduled for install\n",
4509 debugstr_w(component
));
4511 return ERROR_SUCCESS
;
4514 compgroupid
= MSI_RecordGetString(rec
,1);
4515 qualifier
= MSI_RecordGetString(rec
,2);
4517 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
4518 if (rc
!= ERROR_SUCCESS
)
4521 text
= MSI_RecordGetString(rec
,4);
4522 feature
= MSI_RecordGetString(rec
,5);
4524 advertise
= create_component_advertise_string(package
, comp
, feature
);
4526 sz
= strlenW(advertise
);
4529 sz
+= lstrlenW(text
);
4532 sz
*= sizeof(WCHAR
);
4534 output
= msi_alloc_zero(sz
);
4535 strcpyW(output
,advertise
);
4536 msi_free(advertise
);
4539 strcatW(output
,text
);
4541 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
4548 uirow
= MSI_CreateRecord( 2 );
4549 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4550 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4551 ui_actiondata( package
, szPublishComponents
, uirow
);
4552 msiobj_release( &uirow
->hdr
);
4553 /* FIXME: call ui_progress? */
4559 * At present I am ignorning the advertised components part of this and only
4560 * focusing on the qualified component sets
4562 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
4566 static const WCHAR ExecSeqQuery
[] =
4567 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4568 '`','P','u','b','l','i','s','h',
4569 'C','o','m','p','o','n','e','n','t','`',0};
4571 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4572 if (rc
!= ERROR_SUCCESS
)
4573 return ERROR_SUCCESS
;
4575 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
4576 msiobj_release(&view
->hdr
);
4581 static UINT
ITERATE_InstallService(MSIRECORD
*rec
, LPVOID param
)
4583 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4586 SC_HANDLE hscm
, service
= NULL
;
4587 LPCWSTR comp
, depends
, pass
;
4588 LPWSTR name
= NULL
, disp
= NULL
;
4589 LPCWSTR load_order
, serv_name
, key
;
4590 DWORD serv_type
, start_type
;
4593 static const WCHAR query
[] =
4594 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4595 '`','C','o','m','p','o','n','e','n','t','`',' ',
4596 'W','H','E','R','E',' ',
4597 '`','C','o','m','p','o','n','e','n','t','`',' ',
4598 '=','\'','%','s','\'',0};
4600 hscm
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASEW
, GENERIC_WRITE
);
4603 ERR("Failed to open the SC Manager!\n");
4607 start_type
= MSI_RecordGetInteger(rec
, 5);
4608 if (start_type
== SERVICE_BOOT_START
|| start_type
== SERVICE_SYSTEM_START
)
4611 depends
= MSI_RecordGetString(rec
, 8);
4612 if (depends
&& *depends
)
4613 FIXME("Dependency list unhandled!\n");
4615 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
4616 deformat_string(package
, MSI_RecordGetString(rec
, 3), &disp
);
4617 serv_type
= MSI_RecordGetInteger(rec
, 4);
4618 err_control
= MSI_RecordGetInteger(rec
, 6);
4619 load_order
= MSI_RecordGetString(rec
, 7);
4620 serv_name
= MSI_RecordGetString(rec
, 9);
4621 pass
= MSI_RecordGetString(rec
, 10);
4622 comp
= MSI_RecordGetString(rec
, 12);
4624 /* fetch the service path */
4625 row
= MSI_QueryGetRecord(package
->db
, query
, comp
);
4628 ERR("Control query failed!\n");
4632 key
= MSI_RecordGetString(row
, 6);
4634 file
= get_loaded_file(package
, key
);
4635 msiobj_release(&row
->hdr
);
4638 ERR("Failed to load the service file\n");
4642 service
= CreateServiceW(hscm
, name
, disp
, GENERIC_ALL
, serv_type
,
4643 start_type
, err_control
, file
->TargetPath
,
4644 load_order
, NULL
, NULL
, serv_name
, pass
);
4647 if (GetLastError() != ERROR_SERVICE_EXISTS
)
4648 ERR("Failed to create service %s: %d\n", debugstr_w(name
), GetLastError());
4652 CloseServiceHandle(service
);
4653 CloseServiceHandle(hscm
);
4657 return ERROR_SUCCESS
;
4660 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
4664 static const WCHAR ExecSeqQuery
[] =
4665 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4666 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4668 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4669 if (rc
!= ERROR_SUCCESS
)
4670 return ERROR_SUCCESS
;
4672 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallService
, package
);
4673 msiobj_release(&view
->hdr
);
4678 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4679 static LPCWSTR
*msi_service_args_to_vector(LPWSTR args
, DWORD
*numargs
)
4681 LPCWSTR
*vector
, *temp_vector
;
4685 static const WCHAR separator
[] = {'[','~',']',0};
4688 sep_len
= sizeof(separator
) / sizeof(WCHAR
) - 1;
4693 vector
= msi_alloc(sizeof(LPWSTR
));
4701 vector
[*numargs
- 1] = p
;
4703 if ((q
= strstrW(p
, separator
)))
4707 temp_vector
= msi_realloc(vector
, (*numargs
+ 1) * sizeof(LPWSTR
));
4713 vector
= temp_vector
;
4722 static UINT
ITERATE_StartService(MSIRECORD
*rec
, LPVOID param
)
4724 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4726 SC_HANDLE scm
, service
= NULL
;
4727 LPCWSTR name
, *vector
= NULL
;
4729 DWORD event
, numargs
;
4730 UINT r
= ERROR_FUNCTION_FAILED
;
4732 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 6));
4733 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4734 return ERROR_SUCCESS
;
4736 name
= MSI_RecordGetString(rec
, 2);
4737 event
= MSI_RecordGetInteger(rec
, 3);
4738 args
= strdupW(MSI_RecordGetString(rec
, 4));
4740 if (!(event
& msidbServiceControlEventStart
))
4741 return ERROR_SUCCESS
;
4743 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_CONNECT
);
4746 ERR("Failed to open the service control manager\n");
4750 service
= OpenServiceW(scm
, name
, SERVICE_START
);
4753 ERR("Failed to open service %s\n", debugstr_w(name
));
4757 vector
= msi_service_args_to_vector(args
, &numargs
);
4759 if (!StartServiceW(service
, numargs
, vector
))
4761 ERR("Failed to start service %s\n", debugstr_w(name
));
4768 CloseServiceHandle(service
);
4769 CloseServiceHandle(scm
);
4776 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
4781 static const WCHAR query
[] = {
4782 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4783 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4785 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4786 if (rc
!= ERROR_SUCCESS
)
4787 return ERROR_SUCCESS
;
4789 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StartService
, package
);
4790 msiobj_release(&view
->hdr
);
4795 static BOOL
stop_service_dependents(SC_HANDLE scm
, SC_HANDLE service
)
4797 DWORD i
, needed
, count
;
4798 ENUM_SERVICE_STATUSW
*dependencies
;
4802 if (EnumDependentServicesW(service
, SERVICE_ACTIVE
, NULL
,
4803 0, &needed
, &count
))
4806 if (GetLastError() != ERROR_MORE_DATA
)
4809 dependencies
= msi_alloc(needed
);
4813 if (!EnumDependentServicesW(service
, SERVICE_ACTIVE
, dependencies
,
4814 needed
, &needed
, &count
))
4817 for (i
= 0; i
< count
; i
++)
4819 depserv
= OpenServiceW(scm
, dependencies
[i
].lpServiceName
,
4820 SERVICE_STOP
| SERVICE_QUERY_STATUS
);
4824 if (!ControlService(depserv
, SERVICE_CONTROL_STOP
, &ss
))
4831 msi_free(dependencies
);
4835 static UINT
ITERATE_StopService(MSIRECORD
*rec
, LPVOID param
)
4837 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4839 SERVICE_STATUS status
;
4840 SERVICE_STATUS_PROCESS ssp
;
4841 SC_HANDLE scm
= NULL
, service
= NULL
;
4843 DWORD event
, needed
;
4845 event
= MSI_RecordGetInteger(rec
, 3);
4846 if (!(event
& msidbServiceControlEventStop
))
4847 return ERROR_SUCCESS
;
4849 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 6));
4850 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4851 return ERROR_SUCCESS
;
4853 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
4854 deformat_string(package
, MSI_RecordGetString(rec
, 4), &args
);
4855 args
= strdupW(MSI_RecordGetString(rec
, 4));
4857 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
4860 WARN("Failed to open the SCM: %d\n", GetLastError());
4864 service
= OpenServiceW(scm
, name
,
4866 SERVICE_QUERY_STATUS
|
4867 SERVICE_ENUMERATE_DEPENDENTS
);
4870 WARN("Failed to open service (%s): %d\n",
4871 debugstr_w(name
), GetLastError());
4875 if (!QueryServiceStatusEx(service
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&ssp
,
4876 sizeof(SERVICE_STATUS_PROCESS
), &needed
))
4878 WARN("Failed to query service status (%s): %d\n",
4879 debugstr_w(name
), GetLastError());
4883 if (ssp
.dwCurrentState
== SERVICE_STOPPED
)
4886 stop_service_dependents(scm
, service
);
4888 if (!ControlService(service
, SERVICE_CONTROL_STOP
, &status
))
4889 WARN("Failed to stop service (%s): %d\n", debugstr_w(name
), GetLastError());
4892 CloseServiceHandle(service
);
4893 CloseServiceHandle(scm
);
4897 return ERROR_SUCCESS
;
4900 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
4905 static const WCHAR query
[] = {
4906 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4907 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4909 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4910 if (rc
!= ERROR_SUCCESS
)
4911 return ERROR_SUCCESS
;
4913 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StopService
, package
);
4914 msiobj_release(&view
->hdr
);
4919 static MSIFILE
*msi_find_file( MSIPACKAGE
*package
, LPCWSTR filename
)
4923 LIST_FOR_EACH_ENTRY(file
, &package
->files
, MSIFILE
, entry
)
4925 if (!lstrcmpW(file
->File
, filename
))
4932 static UINT
ITERATE_InstallODBCDriver( MSIRECORD
*rec
, LPVOID param
)
4934 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4935 LPWSTR driver
, driver_path
, ptr
;
4936 WCHAR outpath
[MAX_PATH
];
4937 MSIFILE
*driver_file
, *setup_file
;
4940 UINT r
= ERROR_SUCCESS
;
4942 static const WCHAR driver_fmt
[] = {
4943 'D','r','i','v','e','r','=','%','s',0};
4944 static const WCHAR setup_fmt
[] = {
4945 'S','e','t','u','p','=','%','s',0};
4946 static const WCHAR usage_fmt
[] = {
4947 'F','i','l','e','U','s','a','g','e','=','1',0};
4949 desc
= MSI_RecordGetString(rec
, 3);
4951 driver_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
4952 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
4954 if (!driver_file
|| !setup_file
)
4956 ERR("ODBC Driver entry not found!\n");
4957 return ERROR_FUNCTION_FAILED
;
4960 len
= lstrlenW(desc
) + lstrlenW(driver_fmt
) + lstrlenW(driver_file
->FileName
) +
4961 lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
) +
4962 lstrlenW(usage_fmt
) + 1;
4963 driver
= msi_alloc(len
* sizeof(WCHAR
));
4965 return ERROR_OUTOFMEMORY
;
4968 lstrcpyW(ptr
, desc
);
4969 ptr
+= lstrlenW(ptr
) + 1;
4971 sprintfW(ptr
, driver_fmt
, driver_file
->FileName
);
4972 ptr
+= lstrlenW(ptr
) + 1;
4974 sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
4975 ptr
+= lstrlenW(ptr
) + 1;
4977 lstrcpyW(ptr
, usage_fmt
);
4978 ptr
+= lstrlenW(ptr
) + 1;
4981 driver_path
= strdupW(driver_file
->TargetPath
);
4982 ptr
= strrchrW(driver_path
, '\\');
4983 if (ptr
) *ptr
= '\0';
4985 if (!SQLInstallDriverExW(driver
, driver_path
, outpath
, MAX_PATH
,
4986 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
4988 ERR("Failed to install SQL driver!\n");
4989 r
= ERROR_FUNCTION_FAILED
;
4993 msi_free(driver_path
);
4998 static UINT
ITERATE_InstallODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5000 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
5001 LPWSTR translator
, translator_path
, ptr
;
5002 WCHAR outpath
[MAX_PATH
];
5003 MSIFILE
*translator_file
, *setup_file
;
5006 UINT r
= ERROR_SUCCESS
;
5008 static const WCHAR translator_fmt
[] = {
5009 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5010 static const WCHAR setup_fmt
[] = {
5011 'S','e','t','u','p','=','%','s',0};
5013 desc
= MSI_RecordGetString(rec
, 3);
5015 translator_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5016 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5018 if (!translator_file
|| !setup_file
)
5020 ERR("ODBC Translator entry not found!\n");
5021 return ERROR_FUNCTION_FAILED
;
5024 len
= lstrlenW(desc
) + lstrlenW(translator_fmt
) + lstrlenW(translator_file
->FileName
) +
5025 lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
) + 1;
5026 translator
= msi_alloc(len
* sizeof(WCHAR
));
5028 return ERROR_OUTOFMEMORY
;
5031 lstrcpyW(ptr
, desc
);
5032 ptr
+= lstrlenW(ptr
) + 1;
5034 sprintfW(ptr
, translator_fmt
, translator_file
->FileName
);
5035 ptr
+= lstrlenW(ptr
) + 1;
5037 sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5038 ptr
+= lstrlenW(ptr
) + 1;
5041 translator_path
= strdupW(translator_file
->TargetPath
);
5042 ptr
= strrchrW(translator_path
, '\\');
5043 if (ptr
) *ptr
= '\0';
5045 if (!SQLInstallTranslatorExW(translator
, translator_path
, outpath
, MAX_PATH
,
5046 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5048 ERR("Failed to install SQL translator!\n");
5049 r
= ERROR_FUNCTION_FAILED
;
5052 msi_free(translator
);
5053 msi_free(translator_path
);
5058 static UINT
ITERATE_InstallODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5061 LPCWSTR desc
, driver
;
5062 WORD request
= ODBC_ADD_SYS_DSN
;
5065 UINT r
= ERROR_SUCCESS
;
5067 static const WCHAR attrs_fmt
[] = {
5068 'D','S','N','=','%','s',0 };
5070 desc
= MSI_RecordGetString(rec
, 3);
5071 driver
= MSI_RecordGetString(rec
, 4);
5072 registration
= MSI_RecordGetInteger(rec
, 5);
5074 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_ADD_SYS_DSN
;
5075 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_ADD_DSN
;
5077 len
= lstrlenW(attrs_fmt
) + lstrlenW(desc
) + 1 + 1;
5078 attrs
= msi_alloc(len
* sizeof(WCHAR
));
5080 return ERROR_OUTOFMEMORY
;
5082 sprintfW(attrs
, attrs_fmt
, desc
);
5083 attrs
[len
- 1] = '\0';
5085 if (!SQLConfigDataSourceW(NULL
, request
, driver
, attrs
))
5087 ERR("Failed to install SQL data source!\n");
5088 r
= ERROR_FUNCTION_FAILED
;
5096 static UINT
ACTION_InstallODBC( MSIPACKAGE
*package
)
5101 static const WCHAR driver_query
[] = {
5102 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5103 'O','D','B','C','D','r','i','v','e','r',0 };
5105 static const WCHAR translator_query
[] = {
5106 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5107 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5109 static const WCHAR source_query
[] = {
5110 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5111 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5113 rc
= MSI_DatabaseOpenViewW(package
->db
, driver_query
, &view
);
5114 if (rc
!= ERROR_SUCCESS
)
5115 return ERROR_SUCCESS
;
5117 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDriver
, package
);
5118 msiobj_release(&view
->hdr
);
5120 rc
= MSI_DatabaseOpenViewW(package
->db
, translator_query
, &view
);
5121 if (rc
!= ERROR_SUCCESS
)
5122 return ERROR_SUCCESS
;
5124 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCTranslator
, package
);
5125 msiobj_release(&view
->hdr
);
5127 rc
= MSI_DatabaseOpenViewW(package
->db
, source_query
, &view
);
5128 if (rc
!= ERROR_SUCCESS
)
5129 return ERROR_SUCCESS
;
5131 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDataSource
, package
);
5132 msiobj_release(&view
->hdr
);
5137 #define ENV_ACT_SETALWAYS 0x1
5138 #define ENV_ACT_SETABSENT 0x2
5139 #define ENV_ACT_REMOVE 0x4
5140 #define ENV_ACT_REMOVEMATCH 0x8
5142 #define ENV_MOD_MACHINE 0x20000000
5143 #define ENV_MOD_APPEND 0x40000000
5144 #define ENV_MOD_PREFIX 0x80000000
5145 #define ENV_MOD_MASK 0xC0000000
5147 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5149 static LONG
env_set_flags( LPCWSTR
*name
, LPCWSTR
*value
, DWORD
*flags
)
5151 LPCWSTR cptr
= *name
;
5152 LPCWSTR ptr
= *value
;
5154 static const WCHAR prefix
[] = {'[','~',']',0};
5155 static const int prefix_len
= 3;
5161 *flags
|= ENV_ACT_SETALWAYS
;
5162 else if (*cptr
== '+')
5163 *flags
|= ENV_ACT_SETABSENT
;
5164 else if (*cptr
== '-')
5165 *flags
|= ENV_ACT_REMOVE
;
5166 else if (*cptr
== '!')
5167 *flags
|= ENV_ACT_REMOVEMATCH
;
5168 else if (*cptr
== '*')
5169 *flags
|= ENV_MOD_MACHINE
;
5179 ERR("Missing environment variable\n");
5180 return ERROR_FUNCTION_FAILED
;
5183 if (!strncmpW(ptr
, prefix
, prefix_len
))
5185 *flags
|= ENV_MOD_APPEND
;
5186 *value
+= lstrlenW(prefix
);
5188 else if (lstrlenW(*value
) >= prefix_len
)
5190 ptr
+= lstrlenW(ptr
) - prefix_len
;
5191 if (!lstrcmpW(ptr
, prefix
))
5193 *flags
|= ENV_MOD_PREFIX
;
5194 /* the "[~]" will be removed by deformat_string */;
5199 check_flag_combo(*flags
, ENV_ACT_SETALWAYS
| ENV_ACT_SETABSENT
) ||
5200 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETABSENT
) ||
5201 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETALWAYS
) ||
5202 check_flag_combo(*flags
, ENV_ACT_SETABSENT
| ENV_MOD_MASK
))
5204 ERR("Invalid flags: %08x\n", *flags
);
5205 return ERROR_FUNCTION_FAILED
;
5208 return ERROR_SUCCESS
;
5211 static UINT
ITERATE_WriteEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
5213 MSIPACKAGE
*package
= param
;
5214 LPCWSTR name
, value
;
5215 LPWSTR data
= NULL
, newval
= NULL
;
5216 LPWSTR deformatted
= NULL
, ptr
;
5217 DWORD flags
, type
, size
;
5219 HKEY env
= NULL
, root
;
5220 LPCWSTR environment
;
5222 static const WCHAR user_env
[] =
5223 {'E','n','v','i','r','o','n','m','e','n','t',0};
5224 static const WCHAR machine_env
[] =
5225 {'S','y','s','t','e','m','\\',
5226 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5227 'C','o','n','t','r','o','l','\\',
5228 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5229 'E','n','v','i','r','o','n','m','e','n','t',0};
5230 static const WCHAR semicolon
[] = {';',0};
5232 name
= MSI_RecordGetString(rec
, 2);
5233 value
= MSI_RecordGetString(rec
, 3);
5235 res
= env_set_flags(&name
, &value
, &flags
);
5236 if (res
!= ERROR_SUCCESS
)
5239 deformat_string(package
, value
, &deformatted
);
5242 res
= ERROR_OUTOFMEMORY
;
5246 value
= deformatted
;
5248 if (flags
& ENV_MOD_MACHINE
)
5250 environment
= machine_env
;
5251 root
= HKEY_LOCAL_MACHINE
;
5255 environment
= user_env
;
5256 root
= HKEY_CURRENT_USER
;
5259 res
= RegCreateKeyExW(root
, environment
, 0, NULL
, 0,
5260 KEY_ALL_ACCESS
, NULL
, &env
, NULL
);
5261 if (res
!= ERROR_SUCCESS
)
5264 if (flags
& ENV_ACT_REMOVE
)
5265 FIXME("Not removing environment variable on uninstall!\n");
5268 res
= RegQueryValueExW(env
, name
, NULL
, &type
, NULL
, &size
);
5269 if ((res
!= ERROR_SUCCESS
&& res
!= ERROR_FILE_NOT_FOUND
) ||
5270 (res
== ERROR_SUCCESS
&& type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
))
5273 if (res
!= ERROR_FILE_NOT_FOUND
)
5275 if (flags
& ENV_ACT_SETABSENT
)
5277 res
= ERROR_SUCCESS
;
5281 data
= msi_alloc(size
);
5285 return ERROR_OUTOFMEMORY
;
5288 res
= RegQueryValueExW(env
, name
, NULL
, &type
, (LPVOID
)data
, &size
);
5289 if (res
!= ERROR_SUCCESS
)
5292 if (flags
& ENV_ACT_REMOVEMATCH
&& (!value
|| !lstrcmpW(data
, value
)))
5294 res
= RegDeleteKeyW(env
, name
);
5298 size
= (lstrlenW(value
) + 1 + size
) * sizeof(WCHAR
);
5299 newval
= msi_alloc(size
);
5303 res
= ERROR_OUTOFMEMORY
;
5307 if (!(flags
& ENV_MOD_MASK
))
5308 lstrcpyW(newval
, value
);
5311 if (flags
& ENV_MOD_PREFIX
)
5313 lstrcpyW(newval
, value
);
5314 lstrcatW(newval
, semicolon
);
5315 ptr
= newval
+ lstrlenW(value
) + 1;
5318 lstrcpyW(ptr
, data
);
5320 if (flags
& ENV_MOD_APPEND
)
5322 lstrcatW(newval
, semicolon
);
5323 lstrcatW(newval
, value
);
5329 size
= (lstrlenW(value
) + 1) * sizeof(WCHAR
);
5330 newval
= msi_alloc(size
);
5333 res
= ERROR_OUTOFMEMORY
;
5337 lstrcpyW(newval
, value
);
5340 TRACE("setting %s to %s\n", debugstr_w(name
), debugstr_w(newval
));
5341 res
= RegSetValueExW(env
, name
, 0, type
, (LPVOID
)newval
, size
);
5344 if (env
) RegCloseKey(env
);
5345 msi_free(deformatted
);
5351 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
5355 static const WCHAR ExecSeqQuery
[] =
5356 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5357 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5358 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5359 if (rc
!= ERROR_SUCCESS
)
5360 return ERROR_SUCCESS
;
5362 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteEnvironmentString
, package
);
5363 msiobj_release(&view
->hdr
);
5368 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5379 static BOOL
msi_move_file(LPCWSTR source
, LPCWSTR dest
, int options
)
5383 if (GetFileAttributesW(source
) == FILE_ATTRIBUTE_DIRECTORY
||
5384 GetFileAttributesW(dest
) == FILE_ATTRIBUTE_DIRECTORY
)
5386 WARN("Source or dest is directory, not moving\n");
5390 if (options
== msidbMoveFileOptionsMove
)
5392 TRACE("moving %s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
5393 ret
= MoveFileExW(source
, dest
, MOVEFILE_REPLACE_EXISTING
);
5396 WARN("MoveFile failed: %d\n", GetLastError());
5402 TRACE("copying %s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
5403 ret
= CopyFileW(source
, dest
, FALSE
);
5406 WARN("CopyFile failed: %d\n", GetLastError());
5414 static LPWSTR
wildcard_to_file(LPWSTR wildcard
, LPWSTR filename
)
5417 DWORD dirlen
, pathlen
;
5419 ptr
= strrchrW(wildcard
, '\\');
5420 dirlen
= ptr
- wildcard
+ 1;
5422 pathlen
= dirlen
+ lstrlenW(filename
) + 1;
5423 path
= msi_alloc(pathlen
* sizeof(WCHAR
));
5425 lstrcpynW(path
, wildcard
, dirlen
+ 1);
5426 lstrcatW(path
, filename
);
5431 static void free_file_entry(FILE_LIST
*file
)
5433 msi_free(file
->source
);
5434 msi_free(file
->dest
);
5438 static void free_list(FILE_LIST
*list
)
5440 while (!list_empty(&list
->entry
))
5442 FILE_LIST
*file
= LIST_ENTRY(list_head(&list
->entry
), FILE_LIST
, entry
);
5444 list_remove(&file
->entry
);
5445 free_file_entry(file
);
5449 static BOOL
add_wildcard(FILE_LIST
*files
, LPWSTR source
, LPWSTR dest
)
5451 FILE_LIST
*new, *file
;
5452 LPWSTR ptr
, filename
;
5455 new = msi_alloc_zero(sizeof(FILE_LIST
));
5459 new->source
= strdupW(source
);
5460 ptr
= strrchrW(dest
, '\\') + 1;
5461 filename
= strrchrW(new->source
, '\\') + 1;
5463 new->sourcename
= filename
;
5466 new->destname
= ptr
;
5468 new->destname
= new->sourcename
;
5470 size
= (ptr
- dest
) + lstrlenW(filename
) + 1;
5471 new->dest
= msi_alloc(size
* sizeof(WCHAR
));
5474 free_file_entry(new);
5478 lstrcpynW(new->dest
, dest
, ptr
- dest
+ 1);
5479 lstrcatW(new->dest
, filename
);
5481 if (list_empty(&files
->entry
))
5483 list_add_head(&files
->entry
, &new->entry
);
5487 LIST_FOR_EACH_ENTRY(file
, &files
->entry
, FILE_LIST
, entry
)
5489 if (lstrcmpW(source
, file
->source
) < 0)
5491 list_add_before(&file
->entry
, &new->entry
);
5496 list_add_after(&file
->entry
, &new->entry
);
5500 static BOOL
move_files_wildcard(LPWSTR source
, LPWSTR dest
, int options
)
5502 WIN32_FIND_DATAW wfd
;
5506 FILE_LIST files
, *file
;
5509 hfile
= FindFirstFileW(source
, &wfd
);
5510 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
5512 list_init(&files
.entry
);
5514 for (res
= TRUE
; res
; res
= FindNextFileW(hfile
, &wfd
))
5516 if (is_dot_dir(wfd
.cFileName
)) continue;
5518 path
= wildcard_to_file(source
, wfd
.cFileName
);
5525 add_wildcard(&files
, path
, dest
);
5529 /* no files match the wildcard */
5530 if (list_empty(&files
.entry
))
5533 /* only the first wildcard match gets renamed to dest */
5534 file
= LIST_ENTRY(list_head(&files
.entry
), FILE_LIST
, entry
);
5535 size
= (strrchrW(file
->dest
, '\\') - file
->dest
) + lstrlenW(file
->destname
) + 2;
5536 file
->dest
= msi_realloc(file
->dest
, size
* sizeof(WCHAR
));
5543 lstrcpyW(strrchrW(file
->dest
, '\\') + 1, file
->destname
);
5545 while (!list_empty(&files
.entry
))
5547 file
= LIST_ENTRY(list_head(&files
.entry
), FILE_LIST
, entry
);
5549 msi_move_file((LPCWSTR
)file
->source
, (LPCWSTR
)file
->dest
, options
);
5551 list_remove(&file
->entry
);
5552 free_file_entry(file
);
5563 static UINT
ITERATE_MoveFiles( MSIRECORD
*rec
, LPVOID param
)
5565 MSIPACKAGE
*package
= param
;
5567 LPCWSTR sourcename
, destname
;
5568 LPWSTR sourcedir
= NULL
, destdir
= NULL
;
5569 LPWSTR source
= NULL
, dest
= NULL
;
5572 BOOL ret
, wildcards
;
5574 static const WCHAR backslash
[] = {'\\',0};
5576 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 2));
5577 if (!comp
|| !comp
->Enabled
||
5578 !(comp
->Action
& (INSTALLSTATE_LOCAL
| INSTALLSTATE_SOURCE
)))
5580 TRACE("Component not set for install, not moving file\n");
5581 return ERROR_SUCCESS
;
5584 sourcename
= MSI_RecordGetString(rec
, 3);
5585 destname
= MSI_RecordGetString(rec
, 4);
5586 options
= MSI_RecordGetInteger(rec
, 7);
5588 sourcedir
= msi_dup_property(package
, MSI_RecordGetString(rec
, 5));
5592 destdir
= msi_dup_property(package
, MSI_RecordGetString(rec
, 6));
5598 if (GetFileAttributesW(sourcedir
) == INVALID_FILE_ATTRIBUTES
)
5601 source
= strdupW(sourcedir
);
5607 size
= lstrlenW(sourcedir
) + lstrlenW(sourcename
) + 2;
5608 source
= msi_alloc(size
* sizeof(WCHAR
));
5612 lstrcpyW(source
, sourcedir
);
5613 if (source
[lstrlenW(source
) - 1] != '\\')
5614 lstrcatW(source
, backslash
);
5615 lstrcatW(source
, sourcename
);
5618 wildcards
= strchrW(source
, '*') || strchrW(source
, '?');
5620 if (!destname
&& !wildcards
)
5622 destname
= strdupW(sourcename
);
5629 size
= lstrlenW(destname
);
5631 size
+= lstrlenW(destdir
) + 2;
5632 dest
= msi_alloc(size
* sizeof(WCHAR
));
5636 lstrcpyW(dest
, destdir
);
5637 if (dest
[lstrlenW(dest
) - 1] != '\\')
5638 lstrcatW(dest
, backslash
);
5641 lstrcatW(dest
, destname
);
5643 if (GetFileAttributesW(destdir
) == INVALID_FILE_ATTRIBUTES
)
5645 ret
= CreateDirectoryW(destdir
, NULL
);
5648 WARN("CreateDirectory failed: %d\n", GetLastError());
5649 return ERROR_SUCCESS
;
5654 msi_move_file(source
, dest
, options
);
5656 move_files_wildcard(source
, dest
, options
);
5659 msi_free(sourcedir
);
5664 return ERROR_SUCCESS
;
5667 static UINT
ACTION_MoveFiles( MSIPACKAGE
*package
)
5672 static const WCHAR ExecSeqQuery
[] =
5673 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5674 '`','M','o','v','e','F','i','l','e','`',0};
5676 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5677 if (rc
!= ERROR_SUCCESS
)
5678 return ERROR_SUCCESS
;
5680 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_MoveFiles
, package
);
5681 msiobj_release(&view
->hdr
);
5686 typedef struct tagMSIASSEMBLY
5689 MSICOMPONENT
*component
;
5690 MSIFEATURE
*feature
;
5698 static HRESULT (WINAPI
*pCreateAssemblyCache
)(IAssemblyCache
**ppAsmCache
,
5700 static HRESULT (WINAPI
*pLoadLibraryShim
)(LPCWSTR szDllName
, LPCWSTR szVersion
,
5701 LPVOID pvReserved
, HMODULE
*phModDll
);
5703 static BOOL
init_functionpointers(void)
5709 static const WCHAR szFusion
[] = {'f','u','s','i','o','n','.','d','l','l',0};
5711 hmscoree
= LoadLibraryA("mscoree.dll");
5714 WARN("mscoree.dll not available\n");
5718 pLoadLibraryShim
= (void *)GetProcAddress(hmscoree
, "LoadLibraryShim");
5719 if (!pLoadLibraryShim
)
5721 WARN("LoadLibraryShim not available\n");
5722 FreeLibrary(hmscoree
);
5726 hr
= pLoadLibraryShim(szFusion
, NULL
, NULL
, &hfusion
);
5729 WARN("fusion.dll not available\n");
5730 FreeLibrary(hmscoree
);
5734 pCreateAssemblyCache
= (void *)GetProcAddress(hfusion
, "CreateAssemblyCache");
5736 FreeLibrary(hmscoree
);
5740 static UINT
install_assembly(MSIPACKAGE
*package
, MSIASSEMBLY
*assembly
,
5743 IAssemblyCache
*cache
;
5745 UINT r
= ERROR_FUNCTION_FAILED
;
5747 TRACE("installing assembly: %s\n", debugstr_w(path
));
5749 if (assembly
->feature
)
5750 msi_feature_set_state(package
, assembly
->feature
, INSTALLSTATE_LOCAL
);
5752 if (assembly
->manifest
)
5753 FIXME("Manifest unhandled\n");
5755 if (assembly
->application
)
5757 FIXME("Assembly should be privately installed\n");
5758 return ERROR_SUCCESS
;
5761 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
5763 FIXME("Win32 assemblies not handled\n");
5764 return ERROR_SUCCESS
;
5767 if (!init_functionpointers() || !pCreateAssemblyCache
)
5768 return ERROR_FUNCTION_FAILED
;
5770 hr
= pCreateAssemblyCache(&cache
, 0);
5774 hr
= IAssemblyCache_InstallAssembly(cache
, 0, path
, NULL
);
5776 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path
), hr
);
5781 IAssemblyCache_Release(cache
);
5785 typedef struct tagASSEMBLY_LIST
5787 MSIPACKAGE
*package
;
5788 struct list
*assemblies
;
5791 static UINT
load_assembly(MSIRECORD
*rec
, LPVOID param
)
5793 ASSEMBLY_LIST
*list
= (ASSEMBLY_LIST
*)param
;
5794 MSIASSEMBLY
*assembly
;
5796 assembly
= msi_alloc_zero(sizeof(MSIASSEMBLY
));
5798 return ERROR_OUTOFMEMORY
;
5800 assembly
->component
= get_loaded_component(list
->package
, MSI_RecordGetString(rec
, 1));
5802 if (!assembly
->component
|| !assembly
->component
->Enabled
||
5803 !(assembly
->component
->Action
& (INSTALLSTATE_LOCAL
| INSTALLSTATE_SOURCE
)))
5805 TRACE("Component not set for install, not publishing assembly\n");
5807 return ERROR_SUCCESS
;
5810 assembly
->feature
= find_feature_by_name(list
->package
, MSI_RecordGetString(rec
, 2));
5811 assembly
->file
= msi_find_file(list
->package
, assembly
->component
->KeyPath
);
5813 if (!assembly
->file
)
5815 ERR("File %s not found\n", debugstr_w(assembly
->component
->KeyPath
));
5816 return ERROR_FUNCTION_FAILED
;
5819 assembly
->manifest
= strdupW(MSI_RecordGetString(rec
, 3));
5820 assembly
->application
= strdupW(MSI_RecordGetString(rec
, 4));
5821 assembly
->attributes
= MSI_RecordGetInteger(rec
, 5);
5822 assembly
->installed
= FALSE
;
5824 list_add_head(list
->assemblies
, &assembly
->entry
);
5826 return ERROR_SUCCESS
;
5829 static UINT
load_assemblies(MSIPACKAGE
*package
, struct list
*assemblies
)
5835 static const WCHAR query
[] =
5836 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5837 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
5839 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5840 if (r
!= ERROR_SUCCESS
)
5841 return ERROR_SUCCESS
;
5843 list
.package
= package
;
5844 list
.assemblies
= assemblies
;
5846 r
= MSI_IterateRecords(view
, NULL
, load_assembly
, &list
);
5847 msiobj_release(&view
->hdr
);
5852 static void free_assemblies(struct list
*assemblies
)
5854 struct list
*item
, *cursor
;
5856 LIST_FOR_EACH_SAFE(item
, cursor
, assemblies
)
5858 MSIASSEMBLY
*assembly
= LIST_ENTRY(item
, MSIASSEMBLY
, entry
);
5860 list_remove(&assembly
->entry
);
5861 msi_free(assembly
->application
);
5862 msi_free(assembly
->manifest
);
5867 static BOOL
find_assembly(struct list
*assemblies
, LPCWSTR file
, MSIASSEMBLY
**out
)
5869 MSIASSEMBLY
*assembly
;
5871 LIST_FOR_EACH_ENTRY(assembly
, assemblies
, MSIASSEMBLY
, entry
)
5873 if (!lstrcmpW(assembly
->file
->File
, file
))
5883 static BOOL
installassembly_cb(MSIPACKAGE
*package
, LPCWSTR file
, DWORD action
,
5884 LPWSTR
*path
, DWORD
*attrs
, PVOID user
)
5886 MSIASSEMBLY
*assembly
;
5887 WCHAR temppath
[MAX_PATH
];
5888 struct list
*assemblies
= (struct list
*)user
;
5891 if (!find_assembly(assemblies
, file
, &assembly
))
5894 GetTempPathW(MAX_PATH
, temppath
);
5895 PathAddBackslashW(temppath
);
5896 lstrcatW(temppath
, assembly
->file
->FileName
);
5898 if (action
== MSICABEXTRACT_BEGINEXTRACT
)
5900 if (assembly
->installed
)
5903 *path
= strdupW(temppath
);
5904 *attrs
= assembly
->file
->Attributes
;
5906 else if (action
== MSICABEXTRACT_FILEEXTRACTED
)
5908 assembly
->installed
= TRUE
;
5910 r
= install_assembly(package
, assembly
, temppath
);
5911 if (r
!= ERROR_SUCCESS
)
5912 ERR("Failed to install assembly\n");
5918 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
5921 struct list assemblies
= LIST_INIT(assemblies
);
5922 MSIASSEMBLY
*assembly
;
5924 WCHAR path
[MAX_PATH
];
5926 r
= load_assemblies(package
, &assemblies
);
5927 if (r
!= ERROR_SUCCESS
)
5930 if (list_empty(&assemblies
))
5933 mi
= msi_alloc_zero(sizeof(MSIMEDIAINFO
));
5936 r
= ERROR_OUTOFMEMORY
;
5940 LIST_FOR_EACH_ENTRY(assembly
, &assemblies
, MSIASSEMBLY
, entry
)
5942 if (assembly
->installed
&& !mi
->is_continuous
)
5945 if (assembly
->file
->Sequence
> mi
->last_sequence
|| mi
->is_continuous
||
5946 (assembly
->file
->IsCompressed
&& !mi
->is_extracted
))
5950 r
= ready_media(package
, assembly
->file
, mi
);
5951 if (r
!= ERROR_SUCCESS
)
5953 ERR("Failed to ready media\n");
5958 data
.package
= package
;
5959 data
.cb
= installassembly_cb
;
5960 data
.user
= &assemblies
;
5962 if (assembly
->file
->IsCompressed
&&
5963 !msi_cabextract(package
, mi
, &data
))
5965 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi
->cabinet
));
5966 r
= ERROR_FUNCTION_FAILED
;
5971 if (!assembly
->file
->IsCompressed
)
5973 lstrcpyW(path
, assembly
->file
->SourcePath
);
5975 r
= install_assembly(package
, assembly
, path
);
5976 if (r
!= ERROR_SUCCESS
)
5977 ERR("Failed to install assembly\n");
5980 /* FIXME: write Installer assembly reg values */
5984 free_assemblies(&assemblies
);
5988 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
5989 LPCSTR action
, LPCWSTR table
)
5991 static const WCHAR query
[] = {
5992 'S','E','L','E','C','T',' ','*',' ',
5993 'F','R','O','M',' ','`','%','s','`',0 };
5994 MSIQUERY
*view
= NULL
;
5998 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
5999 if (r
== ERROR_SUCCESS
)
6001 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
6002 msiobj_release(&view
->hdr
);
6006 FIXME("%s -> %u ignored %s table values\n",
6007 action
, count
, debugstr_w(table
));
6009 return ERROR_SUCCESS
;
6012 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
6014 TRACE("%p\n", package
);
6015 return ERROR_SUCCESS
;
6018 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
6020 static const WCHAR table
[] =
6021 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
6022 return msi_unimplemented_action_stub( package
, "RemoveIniValues", table
);
6025 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
6027 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
6028 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
6031 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
6033 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
6034 return msi_unimplemented_action_stub( package
, "BindImage", table
);
6037 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
6039 static const WCHAR table
[] = {
6040 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
6041 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
6044 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
6046 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6047 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
6050 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
6052 static const WCHAR table
[] = { 'S','e','l','f','R','e','g',0 };
6053 return msi_unimplemented_action_stub( package
, "SelfUnregModules", table
);
6056 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
6058 static const WCHAR table
[] = {
6059 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6060 return msi_unimplemented_action_stub( package
, "DeleteServices", table
);
6062 static UINT
ACTION_ValidateProductID( MSIPACKAGE
*package
)
6064 static const WCHAR table
[] = {
6065 'P','r','o','d','u','c','t','I','D',0 };
6066 return msi_unimplemented_action_stub( package
, "ValidateProductID", table
);
6069 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
6071 static const WCHAR table
[] = {
6072 'E','n','v','i','r','o','n','m','e','n','t',0 };
6073 return msi_unimplemented_action_stub( package
, "RemoveEnvironmentStrings", table
);
6076 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
6078 static const WCHAR table
[] = {
6079 'M','s','i','A','s','s','e','m','b','l','y',0 };
6080 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
6083 static UINT
ACTION_UnregisterFonts( MSIPACKAGE
*package
)
6085 static const WCHAR table
[] = { 'F','o','n','t',0 };
6086 return msi_unimplemented_action_stub( package
, "UnregisterFonts", table
);
6089 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
6091 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
6092 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
6095 static UINT
ACTION_RegisterComPlus( MSIPACKAGE
*package
)
6097 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6098 return msi_unimplemented_action_stub( package
, "RegisterComPlus", table
);
6101 static UINT
ACTION_UnregisterComPlus( MSIPACKAGE
*package
)
6103 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6104 return msi_unimplemented_action_stub( package
, "UnregisterComPlus", table
);
6107 static UINT
ACTION_InstallSFPCatalogFile( MSIPACKAGE
*package
)
6109 static const WCHAR table
[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6110 return msi_unimplemented_action_stub( package
, "InstallSFPCatalogFile", table
);
6113 static UINT
ACTION_RemoveDuplicateFiles( MSIPACKAGE
*package
)
6115 static const WCHAR table
[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6116 return msi_unimplemented_action_stub( package
, "RemoveDuplicateFiles", table
);
6119 static UINT
ACTION_RemoveExistingProducts( MSIPACKAGE
*package
)
6121 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6122 return msi_unimplemented_action_stub( package
, "RemoveExistingProducts", table
);
6125 static UINT
ACTION_RemoveFolders( MSIPACKAGE
*package
)
6127 static const WCHAR table
[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6128 return msi_unimplemented_action_stub( package
, "RemoveFolders", table
);
6131 static UINT
ACTION_RemoveODBC( MSIPACKAGE
*package
)
6133 static const WCHAR table
[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6134 return msi_unimplemented_action_stub( package
, "RemoveODBC", table
);
6137 static UINT
ACTION_RemoveRegistryValues( MSIPACKAGE
*package
)
6139 static const WCHAR table
[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6140 return msi_unimplemented_action_stub( package
, "RemoveRegistryValues", table
);
6143 static UINT
ACTION_RemoveShortcuts( MSIPACKAGE
*package
)
6145 static const WCHAR table
[] = { 'S','h','o','r','t','c','u','t',0 };
6146 return msi_unimplemented_action_stub( package
, "RemoveShortcuts", table
);
6149 static UINT
ACTION_UnpublishComponents( MSIPACKAGE
*package
)
6151 static const WCHAR table
[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6152 return msi_unimplemented_action_stub( package
, "UnpublishComponents", table
);
6155 static UINT
ACTION_UnregisterClassInfo( MSIPACKAGE
*package
)
6157 static const WCHAR table
[] = { 'A','p','p','I','d',0 };
6158 return msi_unimplemented_action_stub( package
, "UnregisterClassInfo", table
);
6161 static UINT
ACTION_UnregisterExtensionInfo( MSIPACKAGE
*package
)
6163 static const WCHAR table
[] = { 'E','x','t','e','n','s','i','o','n',0 };
6164 return msi_unimplemented_action_stub( package
, "UnregisterExtensionInfo", table
);
6167 static UINT
ACTION_UnregisterMIMEInfo( MSIPACKAGE
*package
)
6169 static const WCHAR table
[] = { 'M','I','M','E',0 };
6170 return msi_unimplemented_action_stub( package
, "UnregisterMIMEInfo", table
);
6173 static UINT
ACTION_UnregisterProgIdInfo( MSIPACKAGE
*package
)
6175 static const WCHAR table
[] = { 'P','r','o','g','I','d',0 };
6176 return msi_unimplemented_action_stub( package
, "UnregisterProgIdInfo", table
);
6179 static UINT
ACTION_UnregisterTypeLibraries( MSIPACKAGE
*package
)
6181 static const WCHAR table
[] = { 'T','y','p','e','L','i','b',0 };
6182 return msi_unimplemented_action_stub( package
, "UnregisterTypeLibraries", table
);
6185 static const struct _actions StandardActions
[] = {
6186 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
6187 { szAppSearch
, ACTION_AppSearch
},
6188 { szBindImage
, ACTION_BindImage
},
6189 { szCCPSearch
, ACTION_CCPSearch
},
6190 { szCostFinalize
, ACTION_CostFinalize
},
6191 { szCostInitialize
, ACTION_CostInitialize
},
6192 { szCreateFolders
, ACTION_CreateFolders
},
6193 { szCreateShortcuts
, ACTION_CreateShortcuts
},
6194 { szDeleteServices
, ACTION_DeleteServices
},
6195 { szDisableRollback
, NULL
},
6196 { szDuplicateFiles
, ACTION_DuplicateFiles
},
6197 { szExecuteAction
, ACTION_ExecuteAction
},
6198 { szFileCost
, ACTION_FileCost
},
6199 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
6200 { szForceReboot
, ACTION_ForceReboot
},
6201 { szInstallAdminPackage
, NULL
},
6202 { szInstallExecute
, ACTION_InstallExecute
},
6203 { szInstallExecuteAgain
, ACTION_InstallExecute
},
6204 { szInstallFiles
, ACTION_InstallFiles
},
6205 { szInstallFinalize
, ACTION_InstallFinalize
},
6206 { szInstallInitialize
, ACTION_InstallInitialize
},
6207 { szInstallSFPCatalogFile
, ACTION_InstallSFPCatalogFile
},
6208 { szInstallValidate
, ACTION_InstallValidate
},
6209 { szIsolateComponents
, ACTION_IsolateComponents
},
6210 { szLaunchConditions
, ACTION_LaunchConditions
},
6211 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
6212 { szMoveFiles
, ACTION_MoveFiles
},
6213 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
6214 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
6215 { szInstallODBC
, ACTION_InstallODBC
},
6216 { szInstallServices
, ACTION_InstallServices
},
6217 { szPatchFiles
, ACTION_PatchFiles
},
6218 { szProcessComponents
, ACTION_ProcessComponents
},
6219 { szPublishComponents
, ACTION_PublishComponents
},
6220 { szPublishFeatures
, ACTION_PublishFeatures
},
6221 { szPublishProduct
, ACTION_PublishProduct
},
6222 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
6223 { szRegisterComPlus
, ACTION_RegisterComPlus
},
6224 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
6225 { szRegisterFonts
, ACTION_RegisterFonts
},
6226 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
6227 { szRegisterProduct
, ACTION_RegisterProduct
},
6228 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
6229 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
6230 { szRegisterUser
, ACTION_RegisterUser
},
6231 { szRemoveDuplicateFiles
, ACTION_RemoveDuplicateFiles
},
6232 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
6233 { szRemoveExistingProducts
, ACTION_RemoveExistingProducts
},
6234 { szRemoveFiles
, ACTION_RemoveFiles
},
6235 { szRemoveFolders
, ACTION_RemoveFolders
},
6236 { szRemoveIniValues
, ACTION_RemoveIniValues
},
6237 { szRemoveODBC
, ACTION_RemoveODBC
},
6238 { szRemoveRegistryValues
, ACTION_RemoveRegistryValues
},
6239 { szRemoveShortcuts
, ACTION_RemoveShortcuts
},
6240 { szResolveSource
, ACTION_ResolveSource
},
6241 { szRMCCPSearch
, ACTION_RMCCPSearch
},
6242 { szScheduleReboot
, NULL
},
6243 { szSelfRegModules
, ACTION_SelfRegModules
},
6244 { szSelfUnregModules
, ACTION_SelfUnregModules
},
6245 { szSetODBCFolders
, NULL
},
6246 { szStartServices
, ACTION_StartServices
},
6247 { szStopServices
, ACTION_StopServices
},
6248 { szUnpublishComponents
, ACTION_UnpublishComponents
},
6249 { szUnpublishFeatures
, ACTION_UnpublishFeatures
},
6250 { szUnregisterClassInfo
, ACTION_UnregisterClassInfo
},
6251 { szUnregisterComPlus
, ACTION_UnregisterComPlus
},
6252 { szUnregisterExtensionInfo
, ACTION_UnregisterExtensionInfo
},
6253 { szUnregisterFonts
, ACTION_UnregisterFonts
},
6254 { szUnregisterMIMEInfo
, ACTION_UnregisterMIMEInfo
},
6255 { szUnregisterProgIdInfo
, ACTION_UnregisterProgIdInfo
},
6256 { szUnregisterTypeLibraries
, ACTION_UnregisterTypeLibraries
},
6257 { szValidateProductID
, ACTION_ValidateProductID
},
6258 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
6259 { szWriteIniValues
, ACTION_WriteIniValues
},
6260 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
6264 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
6265 UINT
* rc
, BOOL force
)
6271 if (!run
&& !package
->script
->CurrentlyScripting
)
6276 if (strcmpW(action
,szInstallFinalize
) == 0 ||
6277 strcmpW(action
,szInstallExecute
) == 0 ||
6278 strcmpW(action
,szInstallExecuteAgain
) == 0)
6283 while (StandardActions
[i
].action
!= NULL
)
6285 if (strcmpW(StandardActions
[i
].action
, action
)==0)
6289 ui_actioninfo(package
, action
, TRUE
, 0);
6290 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
6291 ui_actioninfo(package
, action
, FALSE
, *rc
);
6295 ui_actionstart(package
, action
);
6296 if (StandardActions
[i
].handler
)
6298 *rc
= StandardActions
[i
].handler(package
);
6302 FIXME("unhandled standard action %s\n",debugstr_w(action
));
6303 *rc
= ERROR_SUCCESS
;