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
));
331 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
344 val
= msi_alloc((len
+1)*sizeof(WCHAR
));
345 memcpy(val
,ptr2
,len
*sizeof(WCHAR
));
348 if (lstrlenW(prop
) > 0)
350 TRACE("Found commandline property (%s) = (%s)\n",
351 debugstr_w(prop
), debugstr_w(val
));
352 MSI_SetPropertyW(package
,prop
,val
);
358 return ERROR_SUCCESS
;
362 static LPWSTR
* msi_split_string( LPCWSTR str
, WCHAR sep
)
365 LPWSTR p
, *ret
= NULL
;
371 /* count the number of substrings */
372 for ( pc
= str
, count
= 0; pc
; count
++ )
374 pc
= strchrW( pc
, sep
);
379 /* allocate space for an array of substring pointers and the substrings */
380 ret
= msi_alloc( (count
+1) * sizeof (LPWSTR
) +
381 (lstrlenW(str
)+1) * sizeof(WCHAR
) );
385 /* copy the string and set the pointers */
386 p
= (LPWSTR
) &ret
[count
+1];
388 for( count
= 0; (ret
[count
] = p
); count
++ )
390 p
= strchrW( p
, sep
);
398 static UINT
msi_check_transform_applicable( MSIPACKAGE
*package
, IStorage
*patch
)
400 WCHAR szProductCode
[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
401 LPWSTR prod_code
, patch_product
;
404 prod_code
= msi_dup_property( package
, szProductCode
);
405 patch_product
= msi_get_suminfo_product( patch
);
407 TRACE("db = %s patch = %s\n", debugstr_w(prod_code
), debugstr_w(patch_product
));
409 if ( strstrW( patch_product
, prod_code
) )
412 ret
= ERROR_FUNCTION_FAILED
;
414 msi_free( patch_product
);
415 msi_free( prod_code
);
420 static UINT
msi_apply_substorage_transform( MSIPACKAGE
*package
,
421 MSIDATABASE
*patch_db
, LPCWSTR name
)
423 UINT ret
= ERROR_FUNCTION_FAILED
;
424 IStorage
*stg
= NULL
;
427 TRACE("%p %s\n", package
, debugstr_w(name
) );
431 ERR("expected a colon in %s\n", debugstr_w(name
));
432 return ERROR_FUNCTION_FAILED
;
435 r
= IStorage_OpenStorage( patch_db
->storage
, name
, NULL
, STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
438 ret
= msi_check_transform_applicable( package
, stg
);
439 if (ret
== ERROR_SUCCESS
)
440 msi_table_apply_transform( package
->db
, stg
);
442 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name
));
443 IStorage_Release( stg
);
446 ERR("failed to open substorage %s\n", debugstr_w(name
));
448 return ERROR_SUCCESS
;
451 static UINT
msi_check_patch_applicable( MSIPACKAGE
*package
, MSISUMMARYINFO
*si
)
453 static const WCHAR szProdCode
[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
454 LPWSTR guid_list
, *guids
, product_code
;
455 UINT i
, ret
= ERROR_FUNCTION_FAILED
;
457 product_code
= msi_dup_property( package
, szProdCode
);
460 /* FIXME: the property ProductCode should be written into the DB somewhere */
461 ERR("no product code to check\n");
462 return ERROR_SUCCESS
;
465 guid_list
= msi_suminfo_dup_string( si
, PID_TEMPLATE
);
466 guids
= msi_split_string( guid_list
, ';' );
467 for ( i
= 0; guids
[i
] && ret
!= ERROR_SUCCESS
; i
++ )
469 if (!lstrcmpW( guids
[i
], product_code
))
473 msi_free( guid_list
);
474 msi_free( product_code
);
479 static UINT
msi_parse_patch_summary( MSIPACKAGE
*package
, MSIDATABASE
*patch_db
)
482 LPWSTR str
, *substorage
;
483 UINT i
, r
= ERROR_SUCCESS
;
485 si
= MSI_GetSummaryInformationW( patch_db
->storage
, 0 );
487 return ERROR_FUNCTION_FAILED
;
489 msi_check_patch_applicable( package
, si
);
491 /* enumerate the substorage */
492 str
= msi_suminfo_dup_string( si
, PID_LASTAUTHOR
);
493 substorage
= msi_split_string( str
, ';' );
494 for ( i
= 0; substorage
&& substorage
[i
] && r
== ERROR_SUCCESS
; i
++ )
495 r
= msi_apply_substorage_transform( package
, patch_db
, substorage
[i
] );
496 msi_free( substorage
);
499 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
501 msiobj_release( &si
->hdr
);
506 static UINT
msi_apply_patch_package( MSIPACKAGE
*package
, LPCWSTR file
)
508 MSIDATABASE
*patch_db
= NULL
;
511 TRACE("%p %s\n", package
, debugstr_w( file
) );
514 * We probably want to make sure we only open a patch collection here.
515 * Patch collections (.msp) and databases (.msi) have different GUIDs
516 * but currently MSI_OpenDatabaseW will accept both.
518 r
= MSI_OpenDatabaseW( file
, MSIDBOPEN_READONLY
, &patch_db
);
519 if ( r
!= ERROR_SUCCESS
)
521 ERR("failed to open patch collection %s\n", debugstr_w( file
) );
525 msi_parse_patch_summary( package
, patch_db
);
528 * There might be a CAB file in the patch package,
529 * so append it to the list of storage to search for streams.
531 append_storage_to_db( package
->db
, patch_db
->storage
);
533 msiobj_release( &patch_db
->hdr
);
535 return ERROR_SUCCESS
;
538 /* get the PATCH property, and apply all the patches it specifies */
539 static UINT
msi_apply_patches( MSIPACKAGE
*package
)
541 static const WCHAR szPatch
[] = { 'P','A','T','C','H',0 };
542 LPWSTR patch_list
, *patches
;
543 UINT i
, r
= ERROR_SUCCESS
;
545 patch_list
= msi_dup_property( package
, szPatch
);
547 TRACE("patches to be applied: %s\n", debugstr_w( patch_list
) );
549 patches
= msi_split_string( patch_list
, ';' );
550 for( i
=0; patches
&& patches
[i
] && r
== ERROR_SUCCESS
; i
++ )
551 r
= msi_apply_patch_package( package
, patches
[i
] );
554 msi_free( patch_list
);
559 static UINT
msi_apply_transforms( MSIPACKAGE
*package
)
561 static const WCHAR szTransforms
[] = {
562 'T','R','A','N','S','F','O','R','M','S',0 };
563 LPWSTR xform_list
, *xforms
;
564 UINT i
, r
= ERROR_SUCCESS
;
566 xform_list
= msi_dup_property( package
, szTransforms
);
567 xforms
= msi_split_string( xform_list
, ';' );
569 for( i
=0; xforms
&& xforms
[i
] && r
== ERROR_SUCCESS
; i
++ )
571 if (xforms
[i
][0] == ':')
572 r
= msi_apply_substorage_transform( package
, package
->db
, xforms
[i
] );
574 r
= MSI_DatabaseApplyTransformW( package
->db
, xforms
[i
], 0 );
578 msi_free( xform_list
);
583 static BOOL
ui_sequence_exists( MSIPACKAGE
*package
)
588 static const WCHAR ExecSeqQuery
[] =
589 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
590 '`','I','n','s','t','a','l','l',
591 'U','I','S','e','q','u','e','n','c','e','`',
592 ' ','W','H','E','R','E',' ',
593 '`','S','e','q','u','e','n','c','e','`',' ',
594 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
595 '`','S','e','q','u','e','n','c','e','`',0};
597 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
598 if (rc
== ERROR_SUCCESS
)
600 msiobj_release(&view
->hdr
);
607 static UINT
msi_set_sourcedir_props(MSIPACKAGE
*package
, BOOL replace
)
610 LPWSTR source
, check
;
613 static const WCHAR szOriginalDatabase
[] =
614 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
616 db
= msi_dup_property( package
, szOriginalDatabase
);
618 return ERROR_OUTOFMEMORY
;
620 p
= strrchrW( db
, '\\' );
623 p
= strrchrW( db
, '/' );
627 return ERROR_SUCCESS
;
632 source
= msi_alloc( len
* sizeof(WCHAR
) );
633 lstrcpynW( source
, db
, len
);
635 check
= msi_dup_property( package
, cszSourceDir
);
636 if (!check
|| replace
)
637 MSI_SetPropertyW( package
, cszSourceDir
, source
);
641 check
= msi_dup_property( package
, cszSOURCEDIR
);
642 if (!check
|| replace
)
643 MSI_SetPropertyW( package
, cszSOURCEDIR
, source
);
649 return ERROR_SUCCESS
;
652 static UINT
msi_set_context(MSIPACKAGE
*package
)
659 static const WCHAR szOne
[] = {'1',0};
660 static const WCHAR szAllUsers
[] = {'A','L','L','U','S','E','R','S',0};
662 package
->Context
= MSIINSTALLCONTEXT_USERUNMANAGED
;
664 r
= MSI_GetPropertyW(package
, szAllUsers
, val
, &sz
);
665 if (r
== ERROR_SUCCESS
)
668 if (num
== 1 || num
== 2)
669 package
->Context
= MSIINSTALLCONTEXT_MACHINE
;
672 MSI_SetPropertyW(package
, szAllUsers
, szOne
);
673 return ERROR_SUCCESS
;
676 /****************************************************
677 * TOP level entry points
678 *****************************************************/
680 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
681 LPCWSTR szCommandLine
)
684 BOOL ui
= FALSE
, ui_exists
;
685 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
686 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
687 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
689 MSI_SetPropertyW(package
, szAction
, szInstall
);
691 package
->script
= msi_alloc_zero(sizeof(MSISCRIPT
));
693 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
700 dir
= strdupW(szPackagePath
);
701 p
= strrchrW(dir
, '\\');
705 file
= szPackagePath
+ (p
- dir
);
710 dir
= msi_alloc(MAX_PATH
*sizeof(WCHAR
));
711 GetCurrentDirectoryW(MAX_PATH
, dir
);
712 lstrcatW(dir
, cszbs
);
713 file
= szPackagePath
;
716 msi_free( package
->PackagePath
);
717 package
->PackagePath
= msi_alloc((lstrlenW(dir
) + lstrlenW(file
) + 1) * sizeof(WCHAR
));
718 if (!package
->PackagePath
)
721 return ERROR_OUTOFMEMORY
;
724 lstrcpyW(package
->PackagePath
, dir
);
725 lstrcatW(package
->PackagePath
, file
);
728 msi_set_sourcedir_props(package
, FALSE
);
731 msi_parse_command_line( package
, szCommandLine
);
733 msi_apply_transforms( package
);
734 msi_apply_patches( package
);
736 /* properties may have been added by a transform */
737 msi_clone_properties( package
);
738 msi_set_context( package
);
740 if ( (msi_get_property_int(package
, szUILevel
, 0) & INSTALLUILEVEL_MASK
) >= INSTALLUILEVEL_REDUCED
)
742 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
743 rc
= ACTION_ProcessUISequence(package
);
745 ui_exists
= ui_sequence_exists(package
);
746 if (rc
== ERROR_SUCCESS
|| !ui_exists
)
748 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
749 rc
= ACTION_ProcessExecSequence(package
,ui_exists
);
753 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
755 package
->script
->CurrentlyScripting
= FALSE
;
757 /* process the ending type action */
758 if (rc
== ERROR_SUCCESS
)
759 ACTION_PerformActionSequence(package
,-1,ui
);
760 else if (rc
== ERROR_INSTALL_USEREXIT
)
761 ACTION_PerformActionSequence(package
,-2,ui
);
762 else if (rc
== ERROR_INSTALL_SUSPEND
)
763 ACTION_PerformActionSequence(package
,-4,ui
);
765 ACTION_PerformActionSequence(package
,-3,ui
);
767 /* finish up running custom actions */
768 ACTION_FinishCustomActions(package
);
773 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
)
775 UINT rc
= ERROR_SUCCESS
;
777 static const WCHAR ExecSeqQuery
[] =
778 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
779 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
780 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
781 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
783 static const WCHAR UISeqQuery
[] =
784 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
785 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
786 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
787 ' ', '=',' ','%','i',0};
790 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
792 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
796 LPCWSTR action
, cond
;
798 TRACE("Running the actions\n");
800 /* check conditions */
801 cond
= MSI_RecordGetString(row
,2);
803 /* this is a hack to skip errors in the condition code */
804 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
807 action
= MSI_RecordGetString(row
,1);
810 ERR("failed to fetch action\n");
811 rc
= ERROR_FUNCTION_FAILED
;
816 rc
= ACTION_PerformUIAction(package
,action
,-1);
818 rc
= ACTION_PerformAction(package
,action
,-1,FALSE
);
820 msiobj_release(&row
->hdr
);
831 } iterate_action_param
;
833 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
835 iterate_action_param
*iap
= (iterate_action_param
*)param
;
837 LPCWSTR cond
, action
;
839 action
= MSI_RecordGetString(row
,1);
842 ERR("Error is retrieving action name\n");
843 return ERROR_FUNCTION_FAILED
;
846 /* check conditions */
847 cond
= MSI_RecordGetString(row
,2);
849 /* this is a hack to skip errors in the condition code */
850 if (MSI_EvaluateConditionW(iap
->package
, cond
) == MSICONDITION_FALSE
)
852 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action
));
853 return ERROR_SUCCESS
;
857 rc
= ACTION_PerformUIAction(iap
->package
,action
,-1);
859 rc
= ACTION_PerformAction(iap
->package
,action
,-1,FALSE
);
861 msi_dialog_check_messages( NULL
);
863 if (iap
->package
->CurrentInstallState
!= ERROR_SUCCESS
)
864 rc
= iap
->package
->CurrentInstallState
;
866 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
869 if (rc
!= ERROR_SUCCESS
)
870 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
875 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
879 static const WCHAR query
[] =
880 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
882 ' ','W','H','E','R','E',' ',
883 '`','S','e','q','u','e','n','c','e','`',' ',
884 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
885 '`','S','e','q','u','e','n','c','e','`',0};
886 iterate_action_param iap
;
889 * FIXME: probably should be checking UILevel in the
890 * ACTION_PerformUIAction/ACTION_PerformAction
891 * rather than saving the UI level here. Those
892 * two functions can be merged too.
894 iap
.package
= package
;
897 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
899 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
900 if (r
== ERROR_SUCCESS
)
902 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, &iap
);
903 msiobj_release(&view
->hdr
);
909 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
913 static const WCHAR ExecSeqQuery
[] =
914 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
915 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
916 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
917 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
918 'O','R','D','E','R',' ', 'B','Y',' ',
919 '`','S','e','q','u','e','n','c','e','`',0 };
921 static const WCHAR IVQuery
[] =
922 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
923 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
924 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
925 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
926 ' ','\'', 'I','n','s','t','a','l','l',
927 'V','a','l','i','d','a','t','e','\'', 0};
929 iterate_action_param iap
;
931 iap
.package
= package
;
934 if (package
->script
->ExecuteSequenceRun
)
936 TRACE("Execute Sequence already Run\n");
937 return ERROR_SUCCESS
;
940 package
->script
->ExecuteSequenceRun
= TRUE
;
942 /* get the sequence number */
945 row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
947 return ERROR_FUNCTION_FAILED
;
948 seq
= MSI_RecordGetInteger(row
,1);
949 msiobj_release(&row
->hdr
);
952 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
953 if (rc
== ERROR_SUCCESS
)
955 TRACE("Running the actions\n");
957 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
958 msiobj_release(&view
->hdr
);
964 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
968 static const WCHAR ExecSeqQuery
[] =
969 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
970 '`','I','n','s','t','a','l','l',
971 'U','I','S','e','q','u','e','n','c','e','`',
972 ' ','W','H','E','R','E',' ',
973 '`','S','e','q','u','e','n','c','e','`',' ',
974 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
975 '`','S','e','q','u','e','n','c','e','`',0};
976 iterate_action_param iap
;
978 iap
.package
= package
;
981 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
983 if (rc
== ERROR_SUCCESS
)
985 TRACE("Running the actions\n");
987 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
988 msiobj_release(&view
->hdr
);
994 /********************************************************
995 * ACTION helper functions and functions that perform the actions
996 *******************************************************/
997 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
998 UINT
* rc
, UINT script
, BOOL force
)
1003 arc
= ACTION_CustomAction(package
, action
, script
, force
);
1005 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
1014 * A lot of actions are really important even if they don't do anything
1015 * explicit... Lots of properties are set at the beginning of the installation
1016 * CostFinalize does a bunch of work to translate the directories and such
1018 * But until I get write access to the database that is hard, so I am going to
1019 * hack it to see if I can get something to run.
1021 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
, BOOL force
)
1023 UINT rc
= ERROR_SUCCESS
;
1026 TRACE("Performing action (%s)\n",debugstr_w(action
));
1028 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
1031 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, force
);
1035 WARN("unhandled msi action %s\n",debugstr_w(action
));
1036 rc
= ERROR_FUNCTION_NOT_CALLED
;
1042 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
)
1044 UINT rc
= ERROR_SUCCESS
;
1045 BOOL handled
= FALSE
;
1047 TRACE("Performing action (%s)\n",debugstr_w(action
));
1049 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
1052 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, FALSE
);
1054 if( !handled
&& ACTION_DialogBox(package
,action
) == ERROR_SUCCESS
)
1059 WARN("unhandled msi action %s\n",debugstr_w(action
));
1060 rc
= ERROR_FUNCTION_NOT_CALLED
;
1068 * Actual Action Handlers
1071 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
1073 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1079 dir
= MSI_RecordGetString(row
,1);
1082 ERR("Unable to get folder id\n");
1083 return ERROR_SUCCESS
;
1086 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,TRUE
,&folder
);
1089 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
1090 return ERROR_SUCCESS
;
1093 TRACE("Folder is %s\n",debugstr_w(full_path
));
1096 uirow
= MSI_CreateRecord(1);
1097 MSI_RecordSetStringW(uirow
,1,full_path
);
1098 ui_actiondata(package
,szCreateFolders
,uirow
);
1099 msiobj_release( &uirow
->hdr
);
1101 if (folder
->State
== 0)
1102 create_full_pathW(full_path
);
1106 msi_free(full_path
);
1107 return ERROR_SUCCESS
;
1110 /* FIXME: probably should merge this with the above function */
1111 static UINT
msi_create_directory( MSIPACKAGE
* package
, LPCWSTR dir
)
1113 UINT rc
= ERROR_SUCCESS
;
1115 LPWSTR install_path
;
1117 install_path
= resolve_folder(package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
1119 return ERROR_FUNCTION_FAILED
;
1121 /* create the path */
1122 if (folder
->State
== 0)
1124 create_full_pathW(install_path
);
1127 msi_free(install_path
);
1132 UINT
msi_create_component_directories( MSIPACKAGE
*package
)
1136 /* create all the folders required by the components are going to install */
1137 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1139 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
1141 msi_create_directory( package
, comp
->Directory
);
1144 return ERROR_SUCCESS
;
1148 * Also we cannot enable/disable components either, so for now I am just going
1149 * to do all the directories for all the components.
1151 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1153 static const WCHAR ExecSeqQuery
[] =
1154 {'S','E','L','E','C','T',' ',
1155 '`','D','i','r','e','c','t','o','r','y','_','`',
1156 ' ','F','R','O','M',' ',
1157 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1161 /* create all the empty folders specified in the CreateFolder table */
1162 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1163 if (rc
!= ERROR_SUCCESS
)
1164 return ERROR_SUCCESS
;
1166 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
1167 msiobj_release(&view
->hdr
);
1169 msi_create_component_directories( package
);
1174 static UINT
load_component( MSIRECORD
*row
, LPVOID param
)
1176 MSIPACKAGE
*package
= param
;
1179 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1181 return ERROR_FUNCTION_FAILED
;
1183 list_add_tail( &package
->components
, &comp
->entry
);
1185 /* fill in the data */
1186 comp
->Component
= msi_dup_record_field( row
, 1 );
1188 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1190 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1191 comp
->Directory
= msi_dup_record_field( row
, 3 );
1192 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1193 comp
->Condition
= msi_dup_record_field( row
, 5 );
1194 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1196 comp
->Installed
= INSTALLSTATE_UNKNOWN
;
1197 msi_component_set_state(package
, comp
, INSTALLSTATE_UNKNOWN
);
1199 return ERROR_SUCCESS
;
1202 static UINT
load_all_components( MSIPACKAGE
*package
)
1204 static const WCHAR query
[] = {
1205 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1206 '`','C','o','m','p','o','n','e','n','t','`',0 };
1210 if (!list_empty(&package
->components
))
1211 return ERROR_SUCCESS
;
1213 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1214 if (r
!= ERROR_SUCCESS
)
1217 r
= MSI_IterateRecords(view
, NULL
, load_component
, package
);
1218 msiobj_release(&view
->hdr
);
1223 MSIPACKAGE
*package
;
1224 MSIFEATURE
*feature
;
1227 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1231 cl
= msi_alloc( sizeof (*cl
) );
1233 return ERROR_NOT_ENOUGH_MEMORY
;
1234 cl
->component
= comp
;
1235 list_add_tail( &feature
->Components
, &cl
->entry
);
1237 return ERROR_SUCCESS
;
1240 static UINT
add_feature_child( MSIFEATURE
*parent
, MSIFEATURE
*child
)
1244 fl
= msi_alloc( sizeof(*fl
) );
1246 return ERROR_NOT_ENOUGH_MEMORY
;
1247 fl
->feature
= child
;
1248 list_add_tail( &parent
->Children
, &fl
->entry
);
1250 return ERROR_SUCCESS
;
1253 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1255 _ilfs
* ilfs
= (_ilfs
*)param
;
1259 component
= MSI_RecordGetString(row
,1);
1261 /* check to see if the component is already loaded */
1262 comp
= get_loaded_component( ilfs
->package
, component
);
1265 ERR("unknown component %s\n", debugstr_w(component
));
1266 return ERROR_FUNCTION_FAILED
;
1269 add_feature_component( ilfs
->feature
, comp
);
1270 comp
->Enabled
= TRUE
;
1272 return ERROR_SUCCESS
;
1275 static MSIFEATURE
*find_feature_by_name( MSIPACKAGE
*package
, LPCWSTR name
)
1277 MSIFEATURE
*feature
;
1282 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1284 if ( !lstrcmpW( feature
->Feature
, name
) )
1291 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1293 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1294 MSIFEATURE
* feature
;
1295 static const WCHAR Query1
[] =
1296 {'S','E','L','E','C','T',' ',
1297 '`','C','o','m','p','o','n','e','n','t','_','`',
1298 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1299 'C','o','m','p','o','n','e','n','t','s','`',' ',
1300 'W','H','E','R','E',' ',
1301 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1306 /* fill in the data */
1308 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1310 return ERROR_NOT_ENOUGH_MEMORY
;
1312 list_init( &feature
->Children
);
1313 list_init( &feature
->Components
);
1315 feature
->Feature
= msi_dup_record_field( row
, 1 );
1317 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1319 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1320 feature
->Title
= msi_dup_record_field( row
, 3 );
1321 feature
->Description
= msi_dup_record_field( row
, 4 );
1323 if (!MSI_RecordIsNull(row
,5))
1324 feature
->Display
= MSI_RecordGetInteger(row
,5);
1326 feature
->Level
= MSI_RecordGetInteger(row
,6);
1327 feature
->Directory
= msi_dup_record_field( row
, 7 );
1328 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1330 feature
->Installed
= INSTALLSTATE_UNKNOWN
;
1331 msi_feature_set_state(package
, feature
, INSTALLSTATE_UNKNOWN
);
1333 list_add_tail( &package
->features
, &feature
->entry
);
1335 /* load feature components */
1337 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1338 if (rc
!= ERROR_SUCCESS
)
1339 return ERROR_SUCCESS
;
1341 ilfs
.package
= package
;
1342 ilfs
.feature
= feature
;
1344 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1345 msiobj_release(&view
->hdr
);
1347 return ERROR_SUCCESS
;
1350 static UINT
find_feature_children(MSIRECORD
* row
, LPVOID param
)
1352 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1353 MSIFEATURE
*parent
, *child
;
1355 child
= find_feature_by_name( package
, MSI_RecordGetString( row
, 1 ) );
1357 return ERROR_FUNCTION_FAILED
;
1359 if (!child
->Feature_Parent
)
1360 return ERROR_SUCCESS
;
1362 parent
= find_feature_by_name( package
, child
->Feature_Parent
);
1364 return ERROR_FUNCTION_FAILED
;
1366 add_feature_child( parent
, child
);
1367 return ERROR_SUCCESS
;
1370 static UINT
load_all_features( MSIPACKAGE
*package
)
1372 static const WCHAR query
[] = {
1373 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1374 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1375 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1379 if (!list_empty(&package
->features
))
1380 return ERROR_SUCCESS
;
1382 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1383 if (r
!= ERROR_SUCCESS
)
1386 r
= MSI_IterateRecords( view
, NULL
, load_feature
, package
);
1387 if (r
!= ERROR_SUCCESS
)
1390 r
= MSI_IterateRecords( view
, NULL
, find_feature_children
, package
);
1391 msiobj_release( &view
->hdr
);
1396 static LPWSTR
folder_split_path(LPWSTR p
, WCHAR ch
)
1407 static UINT
load_file_hash(MSIPACKAGE
*package
, MSIFILE
*file
)
1409 static const WCHAR query
[] = {
1410 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1411 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1412 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1413 MSIQUERY
*view
= NULL
;
1414 MSIRECORD
*row
= NULL
;
1417 TRACE("%s\n", debugstr_w(file
->File
));
1419 r
= MSI_OpenQuery(package
->db
, &view
, query
, file
->File
);
1420 if (r
!= ERROR_SUCCESS
)
1423 r
= MSI_ViewExecute(view
, NULL
);
1424 if (r
!= ERROR_SUCCESS
)
1427 r
= MSI_ViewFetch(view
, &row
);
1428 if (r
!= ERROR_SUCCESS
)
1431 file
->hash
.dwFileHashInfoSize
= sizeof(MSIFILEHASHINFO
);
1432 file
->hash
.dwData
[0] = MSI_RecordGetInteger(row
, 3);
1433 file
->hash
.dwData
[1] = MSI_RecordGetInteger(row
, 4);
1434 file
->hash
.dwData
[2] = MSI_RecordGetInteger(row
, 5);
1435 file
->hash
.dwData
[3] = MSI_RecordGetInteger(row
, 6);
1438 if (view
) msiobj_release(&view
->hdr
);
1439 if (row
) msiobj_release(&row
->hdr
);
1443 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1445 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1449 /* fill in the data */
1451 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1453 return ERROR_NOT_ENOUGH_MEMORY
;
1455 file
->File
= msi_dup_record_field( row
, 1 );
1457 component
= MSI_RecordGetString( row
, 2 );
1458 file
->Component
= get_loaded_component( package
, component
);
1460 if (!file
->Component
)
1462 WARN("Component not found: %s\n", debugstr_w(component
));
1463 msi_free(file
->File
);
1465 return ERROR_SUCCESS
;
1468 file
->FileName
= msi_dup_record_field( row
, 3 );
1469 reduce_to_longfilename( file
->FileName
);
1471 file
->ShortName
= msi_dup_record_field( row
, 3 );
1472 file
->LongName
= strdupW( folder_split_path(file
->ShortName
, '|'));
1474 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1475 file
->Version
= msi_dup_record_field( row
, 5 );
1476 file
->Language
= msi_dup_record_field( row
, 6 );
1477 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1478 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1480 file
->state
= msifs_invalid
;
1482 /* if the compressed bits are not set in the file attributes,
1483 * then read the information from the package word count property
1485 if (package
->WordCount
& msidbSumInfoSourceTypeAdminImage
)
1487 file
->IsCompressed
= FALSE
;
1489 else if (file
->Attributes
&
1490 (msidbFileAttributesCompressed
| msidbFileAttributesPatchAdded
))
1492 file
->IsCompressed
= TRUE
;
1494 else if (file
->Attributes
& msidbFileAttributesNoncompressed
)
1496 file
->IsCompressed
= FALSE
;
1500 file
->IsCompressed
= package
->WordCount
& msidbSumInfoSourceTypeCompressed
;
1503 load_file_hash(package
, file
);
1505 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1507 list_add_tail( &package
->files
, &file
->entry
);
1509 return ERROR_SUCCESS
;
1512 static UINT
load_all_files(MSIPACKAGE
*package
)
1516 static const WCHAR Query
[] =
1517 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1518 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1519 '`','S','e','q','u','e','n','c','e','`', 0};
1521 if (!list_empty(&package
->files
))
1522 return ERROR_SUCCESS
;
1524 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1525 if (rc
!= ERROR_SUCCESS
)
1526 return ERROR_SUCCESS
;
1528 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1529 msiobj_release(&view
->hdr
);
1531 return ERROR_SUCCESS
;
1534 static UINT
load_folder( MSIRECORD
*row
, LPVOID param
)
1536 MSIPACKAGE
*package
= param
;
1537 static const WCHAR szDot
[] = { '.',0 };
1538 static WCHAR szEmpty
[] = { 0 };
1539 LPWSTR p
, tgt_short
, tgt_long
, src_short
, src_long
;
1542 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1544 return ERROR_NOT_ENOUGH_MEMORY
;
1546 folder
->Directory
= msi_dup_record_field( row
, 1 );
1548 TRACE("%s\n", debugstr_w(folder
->Directory
));
1550 p
= msi_dup_record_field(row
, 3);
1552 /* split src and target dir */
1554 src_short
= folder_split_path( p
, ':' );
1556 /* split the long and short paths */
1557 tgt_long
= folder_split_path( tgt_short
, '|' );
1558 src_long
= folder_split_path( src_short
, '|' );
1560 /* check for no-op dirs */
1561 if (!lstrcmpW(szDot
, tgt_short
))
1562 tgt_short
= szEmpty
;
1563 if (!lstrcmpW(szDot
, src_short
))
1564 src_short
= szEmpty
;
1567 tgt_long
= tgt_short
;
1570 src_short
= tgt_short
;
1571 src_long
= tgt_long
;
1575 src_long
= src_short
;
1577 /* FIXME: use the target short path too */
1578 folder
->TargetDefault
= strdupW(tgt_long
);
1579 folder
->SourceShortPath
= strdupW(src_short
);
1580 folder
->SourceLongPath
= strdupW(src_long
);
1583 TRACE("TargetDefault = %s\n",debugstr_w( folder
->TargetDefault
));
1584 TRACE("SourceLong = %s\n", debugstr_w( folder
->SourceLongPath
));
1585 TRACE("SourceShort = %s\n", debugstr_w( folder
->SourceShortPath
));
1587 folder
->Parent
= msi_dup_record_field( row
, 2 );
1589 folder
->Property
= msi_dup_property( package
, folder
->Directory
);
1591 list_add_tail( &package
->folders
, &folder
->entry
);
1593 TRACE("returning %p\n", folder
);
1595 return ERROR_SUCCESS
;
1598 static UINT
load_all_folders( MSIPACKAGE
*package
)
1600 static const WCHAR query
[] = {
1601 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1602 '`','D','i','r','e','c','t','o','r','y','`',0 };
1606 if (!list_empty(&package
->folders
))
1607 return ERROR_SUCCESS
;
1609 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1610 if (r
!= ERROR_SUCCESS
)
1613 r
= MSI_IterateRecords(view
, NULL
, load_folder
, package
);
1614 msiobj_release(&view
->hdr
);
1619 * I am not doing any of the costing functionality yet.
1620 * Mostly looking at doing the Component and Feature loading
1622 * The native MSI does A LOT of modification to tables here. Mostly adding
1623 * a lot of temporary columns to the Feature and Component tables.
1625 * note: Native msi also tracks the short filename. But I am only going to
1626 * track the long ones. Also looking at this directory table
1627 * it appears that the directory table does not get the parents
1628 * resolved base on property only based on their entries in the
1631 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1633 static const WCHAR szCosting
[] =
1634 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1635 static const WCHAR szZero
[] = { '0', 0 };
1637 MSI_SetPropertyW(package
, szCosting
, szZero
);
1638 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1640 load_all_folders( package
);
1641 load_all_components( package
);
1642 load_all_features( package
);
1643 load_all_files( package
);
1645 return ERROR_SUCCESS
;
1648 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1651 UINT rc
= ERROR_SUCCESS
;
1653 TRACE("Executing Script %i\n",script
);
1655 if (!package
->script
)
1657 ERR("no script!\n");
1658 return ERROR_FUNCTION_FAILED
;
1661 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1664 action
= package
->script
->Actions
[script
][i
];
1665 ui_actionstart(package
, action
);
1666 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1667 rc
= ACTION_PerformAction(package
, action
, script
, TRUE
);
1668 if (rc
!= ERROR_SUCCESS
)
1671 msi_free_action_script(package
, script
);
1675 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1677 return ERROR_SUCCESS
;
1680 static void ACTION_GetComponentInstallStates(MSIPACKAGE
*package
)
1686 state
= MsiQueryProductStateW(package
->ProductCode
);
1688 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
1690 if (!comp
->ComponentId
)
1693 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1694 comp
->Installed
= INSTALLSTATE_ABSENT
;
1697 r
= MsiQueryComponentStateW(package
->ProductCode
, NULL
,
1698 package
->Context
, comp
->ComponentId
,
1700 if (r
!= ERROR_SUCCESS
)
1701 comp
->Installed
= INSTALLSTATE_ABSENT
;
1706 static void ACTION_GetFeatureInstallStates(MSIPACKAGE
*package
)
1708 MSIFEATURE
*feature
;
1711 state
= MsiQueryProductStateW(package
->ProductCode
);
1713 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1715 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1716 feature
->Installed
= INSTALLSTATE_ABSENT
;
1719 feature
->Installed
= MsiQueryFeatureStateW(package
->ProductCode
,
1725 static BOOL
process_state_property(MSIPACKAGE
* package
, int level
,
1726 LPCWSTR property
, INSTALLSTATE state
)
1728 static const WCHAR all
[]={'A','L','L',0};
1729 static const WCHAR remove
[] = {'R','E','M','O','V','E',0};
1731 MSIFEATURE
*feature
;
1733 override
= msi_dup_property( package
, property
);
1737 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1739 if (lstrcmpW(property
, remove
) &&
1740 (feature
->Level
<= 0 || feature
->Level
> level
))
1743 if (strcmpiW(override
,all
)==0)
1744 msi_feature_set_state(package
, feature
, state
);
1747 LPWSTR ptr
= override
;
1748 LPWSTR ptr2
= strchrW(override
,',');
1752 if ((ptr2
&& strncmpW(ptr
,feature
->Feature
, ptr2
-ptr
)==0)
1753 || (!ptr2
&& strcmpW(ptr
,feature
->Feature
)==0))
1755 msi_feature_set_state(package
, feature
, state
);
1761 ptr2
= strchrW(ptr
,',');
1773 UINT
MSI_SetFeatureStates(MSIPACKAGE
*package
)
1776 static const WCHAR szlevel
[] =
1777 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1778 static const WCHAR szAddLocal
[] =
1779 {'A','D','D','L','O','C','A','L',0};
1780 static const WCHAR szAddSource
[] =
1781 {'A','D','D','S','O','U','R','C','E',0};
1782 static const WCHAR szRemove
[] =
1783 {'R','E','M','O','V','E',0};
1784 static const WCHAR szReinstall
[] =
1785 {'R','E','I','N','S','T','A','L','L',0};
1786 BOOL override
= FALSE
;
1787 MSICOMPONENT
* component
;
1788 MSIFEATURE
*feature
;
1791 /* I do not know if this is where it should happen.. but */
1793 TRACE("Checking Install Level\n");
1795 level
= msi_get_property_int(package
, szlevel
, 1);
1797 /* ok here is the _real_ rub
1798 * all these activation/deactivation things happen in order and things
1799 * later on the list override things earlier on the list.
1800 * 1) INSTALLLEVEL processing
1810 * 11) FILEADDDEFAULT
1812 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1813 * REMOVE are the big ones, since we don't handle administrative installs
1816 override
|= process_state_property(package
, level
, szAddLocal
, INSTALLSTATE_LOCAL
);
1817 override
|= process_state_property(package
, level
, szRemove
, INSTALLSTATE_ABSENT
);
1818 override
|= process_state_property(package
, level
, szAddSource
, INSTALLSTATE_SOURCE
);
1819 override
|= process_state_property(package
, level
, szReinstall
, INSTALLSTATE_LOCAL
);
1823 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1825 BOOL feature_state
= ((feature
->Level
> 0) &&
1826 (feature
->Level
<= level
));
1828 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1830 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1831 msi_feature_set_state(package
, feature
, INSTALLSTATE_SOURCE
);
1832 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1833 msi_feature_set_state(package
, feature
, INSTALLSTATE_ADVERTISED
);
1835 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1839 /* disable child features of unselected parent features */
1840 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1844 if (feature
->Level
> 0 && feature
->Level
<= level
)
1847 LIST_FOR_EACH_ENTRY( fl
, &feature
->Children
, FeatureList
, entry
)
1848 msi_feature_set_state(package
, fl
->feature
, INSTALLSTATE_UNKNOWN
);
1853 /* set the Preselected Property */
1854 static const WCHAR szPreselected
[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1855 static const WCHAR szOne
[] = { '1', 0 };
1857 MSI_SetPropertyW(package
,szPreselected
,szOne
);
1861 * now we want to enable or disable components base on feature
1864 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1868 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1869 debugstr_w(feature
->Feature
), feature
->Level
, feature
->Installed
, feature
->Action
);
1871 if (!feature
->Level
)
1874 /* features with components that have compressed files are made local */
1875 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1877 if (cl
->component
->Enabled
&&
1878 cl
->component
->ForceLocalState
&&
1879 feature
->Action
== INSTALLSTATE_SOURCE
)
1881 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1886 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1888 component
= cl
->component
;
1890 if (!component
->Enabled
)
1893 switch (feature
->Action
)
1895 case INSTALLSTATE_ABSENT
:
1896 component
->anyAbsent
= 1;
1898 case INSTALLSTATE_ADVERTISED
:
1899 component
->hasAdvertiseFeature
= 1;
1901 case INSTALLSTATE_SOURCE
:
1902 component
->hasSourceFeature
= 1;
1904 case INSTALLSTATE_LOCAL
:
1905 component
->hasLocalFeature
= 1;
1907 case INSTALLSTATE_DEFAULT
:
1908 if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1909 component
->hasAdvertiseFeature
= 1;
1910 else if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1911 component
->hasSourceFeature
= 1;
1913 component
->hasLocalFeature
= 1;
1921 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1923 /* if the component isn't enabled, leave it alone */
1924 if (!component
->Enabled
)
1927 /* check if it's local or source */
1928 if (!(component
->Attributes
& msidbComponentAttributesOptional
) &&
1929 (component
->hasLocalFeature
|| component
->hasSourceFeature
))
1931 if ((component
->Attributes
& msidbComponentAttributesSourceOnly
) &&
1932 !component
->ForceLocalState
)
1933 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1935 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1939 /* if any feature is local, the component must be local too */
1940 if (component
->hasLocalFeature
)
1942 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1946 if (component
->hasSourceFeature
)
1948 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1952 if (component
->hasAdvertiseFeature
)
1954 msi_component_set_state(package
, component
, INSTALLSTATE_ADVERTISED
);
1958 TRACE("nobody wants component %s\n", debugstr_w(component
->Component
));
1959 if (component
->anyAbsent
)
1960 msi_component_set_state(package
, component
, INSTALLSTATE_ABSENT
);
1963 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1965 if (component
->Action
== INSTALLSTATE_DEFAULT
)
1967 TRACE("%s was default, setting to local\n", debugstr_w(component
->Component
));
1968 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1971 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1972 debugstr_w(component
->Component
), component
->Installed
, component
->Action
);
1976 return ERROR_SUCCESS
;
1979 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1981 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1986 name
= MSI_RecordGetString(row
,1);
1988 f
= get_loaded_folder(package
, name
);
1989 if (!f
) return ERROR_SUCCESS
;
1991 /* reset the ResolvedTarget */
1992 msi_free(f
->ResolvedTarget
);
1993 f
->ResolvedTarget
= NULL
;
1995 /* This helper function now does ALL the work */
1996 TRACE("Dir %s ...\n",debugstr_w(name
));
1997 path
= resolve_folder(package
,name
,FALSE
,TRUE
,TRUE
,NULL
);
1998 TRACE("resolves to %s\n",debugstr_w(path
));
2001 return ERROR_SUCCESS
;
2004 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
2006 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2008 MSIFEATURE
*feature
;
2010 name
= MSI_RecordGetString( row
, 1 );
2012 feature
= get_loaded_feature( package
, name
);
2014 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
2018 Condition
= MSI_RecordGetString(row
,3);
2020 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
2022 int level
= MSI_RecordGetInteger(row
,2);
2023 TRACE("Resetting feature %s to level %i\n", debugstr_w(name
), level
);
2024 feature
->Level
= level
;
2027 return ERROR_SUCCESS
;
2030 static LPWSTR
msi_get_disk_file_version( LPCWSTR filename
)
2032 static const WCHAR name_fmt
[] =
2033 {'%','u','.','%','u','.','%','u','.','%','u',0};
2034 static const WCHAR name
[] = {'\\',0};
2035 VS_FIXEDFILEINFO
*lpVer
;
2036 WCHAR filever
[0x100];
2042 TRACE("%s\n", debugstr_w(filename
));
2044 versize
= GetFileVersionInfoSizeW( filename
, &handle
);
2048 version
= msi_alloc( versize
);
2049 GetFileVersionInfoW( filename
, 0, versize
, version
);
2051 if (!VerQueryValueW( version
, name
, (LPVOID
*)&lpVer
, &sz
))
2053 msi_free( version
);
2057 sprintfW( filever
, name_fmt
,
2058 HIWORD(lpVer
->dwFileVersionMS
),
2059 LOWORD(lpVer
->dwFileVersionMS
),
2060 HIWORD(lpVer
->dwFileVersionLS
),
2061 LOWORD(lpVer
->dwFileVersionLS
));
2063 msi_free( version
);
2065 return strdupW( filever
);
2068 static UINT
msi_check_file_install_states( MSIPACKAGE
*package
)
2070 LPWSTR file_version
;
2073 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2075 MSICOMPONENT
* comp
= file
->Component
;
2081 if (file
->IsCompressed
)
2082 comp
->ForceLocalState
= TRUE
;
2084 /* calculate target */
2085 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, TRUE
, NULL
);
2087 msi_free(file
->TargetPath
);
2089 TRACE("file %s is named %s\n",
2090 debugstr_w(file
->File
), debugstr_w(file
->FileName
));
2092 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
2096 TRACE("file %s resolves to %s\n",
2097 debugstr_w(file
->File
), debugstr_w(file
->TargetPath
));
2099 /* don't check files of components that aren't installed */
2100 if (comp
->Installed
== INSTALLSTATE_UNKNOWN
||
2101 comp
->Installed
== INSTALLSTATE_ABSENT
)
2103 file
->state
= msifs_missing
; /* assume files are missing */
2107 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
2109 file
->state
= msifs_missing
;
2110 comp
->Cost
+= file
->FileSize
;
2114 if (file
->Version
&&
2115 (file_version
= msi_get_disk_file_version( file
->TargetPath
)))
2117 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
2118 debugstr_w(file_version
));
2119 /* FIXME: seems like a bad way to compare version numbers */
2120 if (lstrcmpiW(file_version
, file
->Version
)<0)
2122 file
->state
= msifs_overwrite
;
2123 comp
->Cost
+= file
->FileSize
;
2126 file
->state
= msifs_present
;
2127 msi_free( file_version
);
2130 file
->state
= msifs_present
;
2133 return ERROR_SUCCESS
;
2137 * A lot is done in this function aside from just the costing.
2138 * The costing needs to be implemented at some point but for now I am going
2139 * to focus on the directory building
2142 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2144 static const WCHAR ExecSeqQuery
[] =
2145 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2146 '`','D','i','r','e','c','t','o','r','y','`',0};
2147 static const WCHAR ConditionQuery
[] =
2148 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2149 '`','C','o','n','d','i','t','i','o','n','`',0};
2150 static const WCHAR szCosting
[] =
2151 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2152 static const WCHAR szlevel
[] =
2153 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2154 static const WCHAR szOutOfDiskSpace
[] =
2155 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2156 static const WCHAR szOne
[] = { '1', 0 };
2157 static const WCHAR szZero
[] = { '0', 0 };
2163 TRACE("Building Directory properties\n");
2165 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2166 if (rc
== ERROR_SUCCESS
)
2168 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
2170 msiobj_release(&view
->hdr
);
2173 /* read components states from the registry */
2174 ACTION_GetComponentInstallStates(package
);
2175 ACTION_GetFeatureInstallStates(package
);
2177 TRACE("File calculations\n");
2178 msi_check_file_install_states( package
);
2180 TRACE("Evaluating Condition Table\n");
2182 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
2183 if (rc
== ERROR_SUCCESS
)
2185 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeConditions
,
2187 msiobj_release(&view
->hdr
);
2190 TRACE("Enabling or Disabling Components\n");
2191 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2193 if (MSI_EvaluateConditionW(package
, comp
->Condition
) == MSICONDITION_FALSE
)
2195 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
2196 comp
->Enabled
= FALSE
;
2199 comp
->Enabled
= TRUE
;
2202 MSI_SetPropertyW(package
,szCosting
,szOne
);
2203 /* set default run level if not set */
2204 level
= msi_dup_property( package
, szlevel
);
2206 MSI_SetPropertyW(package
,szlevel
, szOne
);
2209 /* FIXME: check volume disk space */
2210 MSI_SetPropertyW(package
, szOutOfDiskSpace
, szZero
);
2212 return MSI_SetFeatureStates(package
);
2215 /* OK this value is "interpreted" and then formatted based on the
2216 first few characters */
2217 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
2222 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2228 LPWSTR deformated
= NULL
;
2231 deformat_string(package
, &value
[2], &deformated
);
2233 /* binary value type */
2237 *size
= (strlenW(ptr
)/2)+1;
2239 *size
= strlenW(ptr
)/2;
2241 data
= msi_alloc(*size
);
2247 /* if uneven pad with a zero in front */
2253 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2255 TRACE("Uneven byte count\n");
2263 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2266 msi_free(deformated
);
2268 TRACE("Data %i bytes(%i)\n",*size
,count
);
2275 deformat_string(package
, &value
[1], &deformated
);
2278 *size
= sizeof(DWORD
);
2279 data
= msi_alloc(*size
);
2285 if ( (*p
< '0') || (*p
> '9') )
2291 if (deformated
[0] == '-')
2294 TRACE("DWORD %i\n",*(LPDWORD
)data
);
2296 msi_free(deformated
);
2301 static const WCHAR szMulti
[] = {'[','~',']',0};
2310 *type
=REG_EXPAND_SZ
;
2318 if (strstrW(value
,szMulti
))
2319 *type
= REG_MULTI_SZ
;
2321 /* remove initial delimiter */
2322 if (!strncmpW(value
, szMulti
, 3))
2325 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2327 /* add double NULL terminator */
2328 if (*type
== REG_MULTI_SZ
)
2330 *size
+= 2 * sizeof(WCHAR
); /* two NULL terminators */
2331 data
= msi_realloc_zero(data
, *size
);
2337 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2339 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2340 static const WCHAR szHCR
[] =
2341 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2342 'R','O','O','T','\\',0};
2343 static const WCHAR szHCU
[] =
2344 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2345 'U','S','E','R','\\',0};
2346 static const WCHAR szHLM
[] =
2347 {'H','K','E','Y','_','L','O','C','A','L','_',
2348 'M','A','C','H','I','N','E','\\',0};
2349 static const WCHAR szHU
[] =
2350 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2352 LPSTR value_data
= NULL
;
2353 HKEY root_key
, hkey
;
2356 LPCWSTR szRoot
, component
, name
, key
, value
;
2361 BOOL check_first
= FALSE
;
2364 ui_progress(package
,2,0,0,0);
2371 component
= MSI_RecordGetString(row
, 6);
2372 comp
= get_loaded_component(package
,component
);
2374 return ERROR_SUCCESS
;
2376 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2378 TRACE("Skipping write due to disabled component %s\n",
2379 debugstr_w(component
));
2381 comp
->Action
= comp
->Installed
;
2383 return ERROR_SUCCESS
;
2386 comp
->Action
= INSTALLSTATE_LOCAL
;
2388 name
= MSI_RecordGetString(row
, 4);
2389 if( MSI_RecordIsNull(row
,5) && name
)
2391 /* null values can have special meanings */
2392 if (name
[0]=='-' && name
[1] == 0)
2393 return ERROR_SUCCESS
;
2394 else if ((name
[0]=='+' && name
[1] == 0) ||
2395 (name
[0] == '*' && name
[1] == 0))
2400 root
= MSI_RecordGetInteger(row
,2);
2401 key
= MSI_RecordGetString(row
, 3);
2403 /* get the root key */
2408 static const WCHAR szALLUSER
[] = {'A','L','L','U','S','E','R','S',0};
2409 LPWSTR all_users
= msi_dup_property( package
, szALLUSER
);
2410 if (all_users
&& all_users
[0] == '1')
2412 root_key
= HKEY_LOCAL_MACHINE
;
2417 root_key
= HKEY_CURRENT_USER
;
2420 msi_free(all_users
);
2423 case 0: root_key
= HKEY_CLASSES_ROOT
;
2426 case 1: root_key
= HKEY_CURRENT_USER
;
2429 case 2: root_key
= HKEY_LOCAL_MACHINE
;
2432 case 3: root_key
= HKEY_USERS
;
2436 ERR("Unknown root %i\n",root
);
2442 return ERROR_SUCCESS
;
2444 deformat_string(package
, key
, &deformated
);
2445 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2446 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2447 strcpyW(uikey
,szRoot
);
2448 strcatW(uikey
,deformated
);
2450 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2452 ERR("Could not create key %s\n",debugstr_w(deformated
));
2453 msi_free(deformated
);
2455 return ERROR_SUCCESS
;
2457 msi_free(deformated
);
2459 value
= MSI_RecordGetString(row
,5);
2461 value_data
= parse_value(package
, value
, &type
, &size
);
2464 static const WCHAR szEmpty
[] = {0};
2465 value_data
= (LPSTR
)strdupW(szEmpty
);
2466 size
= sizeof(szEmpty
);
2470 deformat_string(package
, name
, &deformated
);
2474 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2476 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2481 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2482 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2484 TRACE("value %s of %s checked already exists\n",
2485 debugstr_w(deformated
), debugstr_w(uikey
));
2489 TRACE("Checked and setting value %s of %s\n",
2490 debugstr_w(deformated
), debugstr_w(uikey
));
2491 if (deformated
|| size
)
2492 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2497 uirow
= MSI_CreateRecord(3);
2498 MSI_RecordSetStringW(uirow
,2,deformated
);
2499 MSI_RecordSetStringW(uirow
,1,uikey
);
2502 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2504 MSI_RecordSetStringW(uirow
,3,value
);
2506 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2507 msiobj_release( &uirow
->hdr
);
2509 msi_free(value_data
);
2510 msi_free(deformated
);
2513 return ERROR_SUCCESS
;
2516 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2520 static const WCHAR ExecSeqQuery
[] =
2521 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2522 '`','R','e','g','i','s','t','r','y','`',0 };
2524 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2525 if (rc
!= ERROR_SUCCESS
)
2526 return ERROR_SUCCESS
;
2528 /* increment progress bar each time action data is sent */
2529 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2531 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2533 msiobj_release(&view
->hdr
);
2537 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2539 package
->script
->CurrentlyScripting
= TRUE
;
2541 return ERROR_SUCCESS
;
2545 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2550 static const WCHAR q1
[]=
2551 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2552 '`','R','e','g','i','s','t','r','y','`',0};
2555 MSIFEATURE
*feature
;
2558 TRACE("InstallValidate\n");
2560 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2561 if (rc
== ERROR_SUCCESS
)
2563 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2564 msiobj_release( &view
->hdr
);
2565 total
+= progress
* REG_PROGRESS_VALUE
;
2568 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2569 total
+= COMPONENT_PROGRESS_VALUE
;
2571 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2572 total
+= file
->FileSize
;
2574 ui_progress(package
,0,total
,0,0);
2576 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2578 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2579 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2580 feature
->ActionRequest
);
2583 return ERROR_SUCCESS
;
2586 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2588 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2589 LPCWSTR cond
= NULL
;
2590 LPCWSTR message
= NULL
;
2593 static const WCHAR title
[]=
2594 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2596 cond
= MSI_RecordGetString(row
,1);
2598 r
= MSI_EvaluateConditionW(package
,cond
);
2599 if (r
== MSICONDITION_FALSE
)
2601 if ((gUILevel
& INSTALLUILEVEL_MASK
) != INSTALLUILEVEL_NONE
)
2604 message
= MSI_RecordGetString(row
,2);
2605 deformat_string(package
,message
,&deformated
);
2606 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2607 msi_free(deformated
);
2610 return ERROR_INSTALL_FAILURE
;
2613 return ERROR_SUCCESS
;
2616 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2619 MSIQUERY
* view
= NULL
;
2620 static const WCHAR ExecSeqQuery
[] =
2621 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2622 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2624 TRACE("Checking launch conditions\n");
2626 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2627 if (rc
!= ERROR_SUCCESS
)
2628 return ERROR_SUCCESS
;
2630 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2631 msiobj_release(&view
->hdr
);
2636 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2640 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,TRUE
,NULL
);
2642 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2644 MSIRECORD
* row
= 0;
2646 LPWSTR deformated
,buffer
,deformated_name
;
2648 static const WCHAR ExecSeqQuery
[] =
2649 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2650 '`','R','e','g','i','s','t','r','y','`',' ',
2651 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2652 ' ','=',' ' ,'\'','%','s','\'',0 };
2653 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2654 static const WCHAR fmt2
[]=
2655 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2657 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2661 root
= MSI_RecordGetInteger(row
,2);
2662 key
= MSI_RecordGetString(row
, 3);
2663 name
= MSI_RecordGetString(row
, 4);
2664 deformat_string(package
, key
, &deformated
);
2665 deformat_string(package
, name
, &deformated_name
);
2667 len
= strlenW(deformated
) + 6;
2668 if (deformated_name
)
2669 len
+=strlenW(deformated_name
);
2671 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2673 if (deformated_name
)
2674 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2676 sprintfW(buffer
,fmt
,root
,deformated
);
2678 msi_free(deformated
);
2679 msi_free(deformated_name
);
2680 msiobj_release(&row
->hdr
);
2684 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2686 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2691 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2694 return strdupW( file
->TargetPath
);
2699 static HKEY
openSharedDLLsKey(void)
2702 static const WCHAR path
[] =
2703 {'S','o','f','t','w','a','r','e','\\',
2704 'M','i','c','r','o','s','o','f','t','\\',
2705 'W','i','n','d','o','w','s','\\',
2706 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2707 'S','h','a','r','e','d','D','L','L','s',0};
2709 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2713 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2718 DWORD sz
= sizeof(count
);
2721 hkey
= openSharedDLLsKey();
2722 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2723 if (rc
!= ERROR_SUCCESS
)
2729 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2733 hkey
= openSharedDLLsKey();
2735 msi_reg_set_val_dword( hkey
, path
, count
);
2737 RegDeleteValueW(hkey
,path
);
2743 * Return TRUE if the count should be written out and FALSE if not
2745 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2747 MSIFEATURE
*feature
;
2751 /* only refcount DLLs */
2752 if (comp
->KeyPath
== NULL
||
2753 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2754 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2758 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2759 write
= (count
> 0);
2761 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2765 /* increment counts */
2766 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2770 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
))
2773 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2775 if ( cl
->component
== comp
)
2780 /* decrement counts */
2781 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2785 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ABSENT
))
2788 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2790 if ( cl
->component
== comp
)
2795 /* ref count all the files in the component */
2800 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2802 if (file
->Component
== comp
)
2803 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2807 /* add a count for permanent */
2808 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2811 comp
->RefCount
= count
;
2814 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2817 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2819 WCHAR squished_pc
[GUID_SIZE
];
2820 WCHAR squished_cc
[GUID_SIZE
];
2827 squash_guid(package
->ProductCode
,squished_pc
);
2828 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2830 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2834 ui_progress(package
,2,0,0,0);
2835 if (!comp
->ComponentId
)
2838 squash_guid(comp
->ComponentId
,squished_cc
);
2840 msi_free(comp
->FullKeypath
);
2841 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2843 ACTION_RefCountComponent( package
, comp
);
2845 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2846 debugstr_w(comp
->Component
),
2847 debugstr_w(squished_cc
),
2848 debugstr_w(comp
->FullKeypath
),
2851 if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) ||
2852 ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
))
2854 if (!comp
->FullKeypath
)
2857 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2858 rc
= MSIREG_OpenLocalUserDataComponentKey(comp
->ComponentId
, &hkey
, TRUE
);
2860 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, &hkey
, TRUE
);
2862 if (rc
!= ERROR_SUCCESS
)
2865 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2867 static const WCHAR szPermKey
[] =
2868 { '0','0','0','0','0','0','0','0','0','0','0','0',
2869 '0','0','0','0','0','0','0','0','0','0','0','0',
2870 '0','0','0','0','0','0','0','0',0 };
2872 msi_reg_set_val_str(hkey
, szPermKey
, comp
->FullKeypath
);
2875 if (comp
->Action
== INSTALLSTATE_LOCAL
)
2876 msi_reg_set_val_str(hkey
, squished_pc
, comp
->FullKeypath
);
2882 WCHAR source
[MAX_PATH
];
2883 WCHAR base
[MAX_PATH
];
2886 static const WCHAR fmt
[] = {'%','0','2','d','\\',0};
2887 static const WCHAR query
[] = {
2888 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2889 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2890 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2891 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2892 '`','D','i','s','k','I','d','`',0};
2894 file
= get_loaded_file(package
, comp
->KeyPath
);
2898 row
= MSI_QueryGetRecord(package
->db
, query
, file
->Sequence
);
2899 sprintfW(source
, fmt
, MSI_RecordGetInteger(row
, 1));
2900 ptr2
= strrchrW(source
, '\\') + 1;
2901 msiobj_release(&row
->hdr
);
2903 lstrcpyW(base
, package
->PackagePath
);
2904 ptr
= strrchrW(base
, '\\');
2907 sourcepath
= resolve_file_source(package
, file
);
2908 ptr
= sourcepath
+ lstrlenW(base
);
2909 lstrcpyW(ptr2
, ptr
);
2910 msi_free(sourcepath
);
2912 msi_reg_set_val_str(hkey
, squished_pc
, source
);
2916 else if (ACTION_VerifyComponentForAction(comp
, INSTALLSTATE_ABSENT
))
2918 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2919 MSIREG_DeleteLocalUserDataComponentKey(comp
->ComponentId
);
2921 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
);
2925 uirow
= MSI_CreateRecord(3);
2926 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2927 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2928 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
2929 ui_actiondata(package
,szProcessComponents
,uirow
);
2930 msiobj_release( &uirow
->hdr
);
2933 return ERROR_SUCCESS
;
2944 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
2945 LPWSTR lpszName
, LONG_PTR lParam
)
2948 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
2949 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
2953 if (!IS_INTRESOURCE(lpszName
))
2955 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
2959 sz
= strlenW(tl_struct
->source
)+4;
2960 sz
*= sizeof(WCHAR
);
2962 if ((INT_PTR
)lpszName
== 1)
2963 tl_struct
->path
= strdupW(tl_struct
->source
);
2966 tl_struct
->path
= msi_alloc(sz
);
2967 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
2970 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
2971 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
2974 msi_free(tl_struct
->path
);
2975 tl_struct
->path
= NULL
;
2980 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
2981 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
2983 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2987 msi_free(tl_struct
->path
);
2988 tl_struct
->path
= NULL
;
2990 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2991 ITypeLib_Release(tl_struct
->ptLib
);
2996 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
2998 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
3002 typelib_struct tl_struct
;
3007 static const WCHAR szTYPELIB
[] = {'T','Y','P','E','L','I','B',0};
3009 component
= MSI_RecordGetString(row
,3);
3010 comp
= get_loaded_component(package
,component
);
3012 return ERROR_SUCCESS
;
3014 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3016 TRACE("Skipping typelib reg due to disabled component\n");
3018 comp
->Action
= comp
->Installed
;
3020 return ERROR_SUCCESS
;
3023 comp
->Action
= INSTALLSTATE_LOCAL
;
3025 file
= get_loaded_file( package
, comp
->KeyPath
);
3027 return ERROR_SUCCESS
;
3029 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
3033 guid
= MSI_RecordGetString(row
,1);
3034 CLSIDFromString((LPWSTR
)guid
, &tl_struct
.clsid
);
3035 tl_struct
.source
= strdupW( file
->TargetPath
);
3036 tl_struct
.path
= NULL
;
3038 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
3039 (LONG_PTR
)&tl_struct
);
3047 helpid
= MSI_RecordGetString(row
,6);
3050 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,TRUE
,NULL
);
3051 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
3055 ERR("Failed to register type library %s\n",
3056 debugstr_w(tl_struct
.path
));
3059 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
3061 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
3064 ITypeLib_Release(tl_struct
.ptLib
);
3065 msi_free(tl_struct
.path
);
3068 ERR("Failed to load type library %s\n",
3069 debugstr_w(tl_struct
.source
));
3071 FreeLibrary(module
);
3072 msi_free(tl_struct
.source
);
3076 hr
= LoadTypeLibEx(file
->TargetPath
, REGKIND_REGISTER
, &tlib
);
3079 ERR("Failed to load type library: %08x\n", hr
);
3080 return ERROR_FUNCTION_FAILED
;
3083 ITypeLib_Release(tlib
);
3086 return ERROR_SUCCESS
;
3089 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
3092 * OK this is a bit confusing.. I am given a _Component key and I believe
3093 * that the file that is being registered as a type library is the "key file
3094 * of that component" which I interpret to mean "The file in the KeyPath of
3099 static const WCHAR Query
[] =
3100 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3101 '`','T','y','p','e','L','i','b','`',0};
3103 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3104 if (rc
!= ERROR_SUCCESS
)
3105 return ERROR_SUCCESS
;
3107 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
3108 msiobj_release(&view
->hdr
);
3112 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
3114 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3115 LPWSTR target_file
, target_folder
, filename
;
3116 LPCWSTR buffer
, extension
;
3118 static const WCHAR szlnk
[]={'.','l','n','k',0};
3119 IShellLinkW
*sl
= NULL
;
3120 IPersistFile
*pf
= NULL
;
3123 buffer
= MSI_RecordGetString(row
,4);
3124 comp
= get_loaded_component(package
,buffer
);
3126 return ERROR_SUCCESS
;
3128 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3130 TRACE("Skipping shortcut creation due to disabled component\n");
3132 comp
->Action
= comp
->Installed
;
3134 return ERROR_SUCCESS
;
3137 comp
->Action
= INSTALLSTATE_LOCAL
;
3139 ui_actiondata(package
,szCreateShortcuts
,row
);
3141 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
3142 &IID_IShellLinkW
, (LPVOID
*) &sl
);
3146 ERR("CLSID_ShellLink not available\n");
3150 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
3153 ERR("QueryInterface(IID_IPersistFile) failed\n");
3157 buffer
= MSI_RecordGetString(row
,2);
3158 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,TRUE
,NULL
);
3160 /* may be needed because of a bug somewhere else */
3161 create_full_pathW(target_folder
);
3163 filename
= msi_dup_record_field( row
, 3 );
3164 reduce_to_longfilename(filename
);
3166 extension
= strchrW(filename
,'.');
3167 if (!extension
|| strcmpiW(extension
,szlnk
))
3169 int len
= strlenW(filename
);
3170 filename
= msi_realloc(filename
, len
* sizeof(WCHAR
) + sizeof(szlnk
));
3171 memcpy(filename
+ len
, szlnk
, sizeof(szlnk
));
3173 target_file
= build_directory_name(2, target_folder
, filename
);
3174 msi_free(target_folder
);
3177 buffer
= MSI_RecordGetString(row
,5);
3178 if (strchrW(buffer
,'['))
3181 deformat_string(package
,buffer
,&deformated
);
3182 IShellLinkW_SetPath(sl
,deformated
);
3183 msi_free(deformated
);
3187 FIXME("poorly handled shortcut format, advertised shortcut\n");
3188 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
3191 if (!MSI_RecordIsNull(row
,6))
3194 buffer
= MSI_RecordGetString(row
,6);
3195 deformat_string(package
,buffer
,&deformated
);
3196 IShellLinkW_SetArguments(sl
,deformated
);
3197 msi_free(deformated
);
3200 if (!MSI_RecordIsNull(row
,7))
3202 buffer
= MSI_RecordGetString(row
,7);
3203 IShellLinkW_SetDescription(sl
,buffer
);
3206 if (!MSI_RecordIsNull(row
,8))
3207 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
3209 if (!MSI_RecordIsNull(row
,9))
3214 buffer
= MSI_RecordGetString(row
,9);
3216 Path
= build_icon_path(package
,buffer
);
3217 index
= MSI_RecordGetInteger(row
,10);
3219 /* no value means 0 */
3220 if (index
== MSI_NULL_INTEGER
)
3223 IShellLinkW_SetIconLocation(sl
,Path
,index
);
3227 if (!MSI_RecordIsNull(row
,11))
3228 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
3230 if (!MSI_RecordIsNull(row
,12))
3233 buffer
= MSI_RecordGetString(row
,12);
3234 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, TRUE
, NULL
);
3236 IShellLinkW_SetWorkingDirectory(sl
,Path
);
3240 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
3241 IPersistFile_Save(pf
,target_file
,FALSE
);
3243 msi_free(target_file
);
3247 IPersistFile_Release( pf
);
3249 IShellLinkW_Release( sl
);
3251 return ERROR_SUCCESS
;
3254 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
3259 static const WCHAR Query
[] =
3260 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3261 '`','S','h','o','r','t','c','u','t','`',0};
3263 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3264 if (rc
!= ERROR_SUCCESS
)
3265 return ERROR_SUCCESS
;
3267 res
= CoInitialize( NULL
);
3270 ERR("CoInitialize failed\n");
3271 return ERROR_FUNCTION_FAILED
;
3274 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
3275 msiobj_release(&view
->hdr
);
3282 static UINT
ITERATE_PublishIcon(MSIRECORD
*row
, LPVOID param
)
3284 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
3293 FileName
= MSI_RecordGetString(row
,1);
3296 ERR("Unable to get FileName\n");
3297 return ERROR_SUCCESS
;
3300 FilePath
= build_icon_path(package
,FileName
);
3302 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
3304 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
3305 FILE_ATTRIBUTE_NORMAL
, NULL
);
3307 if (the_file
== INVALID_HANDLE_VALUE
)
3309 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3311 return ERROR_SUCCESS
;
3318 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3319 if (rc
!= ERROR_SUCCESS
)
3321 ERR("Failed to get stream\n");
3322 CloseHandle(the_file
);
3323 DeleteFileW(FilePath
);
3326 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3327 } while (sz
== 1024);
3331 CloseHandle(the_file
);
3333 uirow
= MSI_CreateRecord(1);
3334 MSI_RecordSetStringW(uirow
,1,FileName
);
3335 ui_actiondata(package
,szPublishProduct
,uirow
);
3336 msiobj_release( &uirow
->hdr
);
3338 return ERROR_SUCCESS
;
3341 static UINT
msi_publish_icons(MSIPACKAGE
*package
)
3346 static const WCHAR query
[]= {
3347 'S','E','L','E','C','T',' ','*',' ',
3348 'F','R','O','M',' ','`','I','c','o','n','`',0};
3350 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
3351 if (r
== ERROR_SUCCESS
)
3353 MSI_IterateRecords(view
, NULL
, ITERATE_PublishIcon
, package
);
3354 msiobj_release(&view
->hdr
);
3357 return ERROR_SUCCESS
;
3360 static UINT
msi_publish_sourcelist(MSIPACKAGE
*package
, HKEY hkey
)
3366 MSISOURCELISTINFO
*info
;
3368 static const WCHAR szEmpty
[] = {0};
3369 static const WCHAR szSourceList
[] = {'S','o','u','r','c','e','L','i','s','t',0};
3371 r
= RegCreateKeyW(hkey
, szSourceList
, &source
);
3372 if (r
!= ERROR_SUCCESS
)
3375 RegCloseKey(source
);
3377 buffer
= strrchrW(package
->PackagePath
, '\\') + 1;
3378 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3379 package
->Context
, MSICODE_PRODUCT
,
3380 INSTALLPROPERTY_PACKAGENAMEW
, buffer
);
3381 if (r
!= ERROR_SUCCESS
)
3384 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3385 package
->Context
, MSICODE_PRODUCT
,
3386 INSTALLPROPERTY_MEDIAPACKAGEPATHW
, szEmpty
);
3387 if (r
!= ERROR_SUCCESS
)
3390 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3391 package
->Context
, MSICODE_PRODUCT
,
3392 INSTALLPROPERTY_DISKPROMPTW
, szEmpty
);
3393 if (r
!= ERROR_SUCCESS
)
3396 LIST_FOR_EACH_ENTRY(info
, &package
->sourcelist_info
, MSISOURCELISTINFO
, entry
)
3398 if (!lstrcmpW(info
->property
, INSTALLPROPERTY_LASTUSEDSOURCEW
))
3399 msi_set_last_used_source(package
->ProductCode
, NULL
, info
->context
,
3400 info
->options
, info
->value
);
3402 MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3403 info
->context
, info
->options
,
3404 info
->property
, info
->value
);
3407 LIST_FOR_EACH_ENTRY(disk
, &package
->sourcelist_media
, MSIMEDIADISK
, entry
)
3409 MsiSourceListAddMediaDiskW(package
->ProductCode
, NULL
,
3410 disk
->context
, disk
->options
,
3411 disk
->disk_id
, disk
->volume_label
, disk
->disk_prompt
);
3414 return ERROR_SUCCESS
;
3417 static UINT
msi_publish_product_properties(MSIPACKAGE
*package
, HKEY hkey
)
3419 MSIHANDLE hdb
, suminfo
;
3420 WCHAR guids
[MAX_PATH
];
3421 WCHAR packcode
[SQUISH_GUID_SIZE
];
3428 static const WCHAR szProductLanguage
[] =
3429 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3430 static const WCHAR szARPProductIcon
[] =
3431 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3432 static const WCHAR szProductVersion
[] =
3433 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3434 static const WCHAR szAssignment
[] =
3435 {'A','s','s','i','g','n','m','e','n','t',0};
3436 static const WCHAR szAdvertiseFlags
[] =
3437 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3438 static const WCHAR szClients
[] =
3439 {'C','l','i','e','n','t','s',0};
3440 static const WCHAR szColon
[] = {':',0};
3442 buffer
= msi_dup_property(package
, INSTALLPROPERTY_PRODUCTNAMEW
);
3443 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3446 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
3447 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3449 ptr
= strrchrW(package
->PackagePath
, '\\' ) + 1;
3450 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PACKAGENAMEW
, ptr
);
3453 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_AUTHORIZED_LUA_APPW
, 0);
3455 buffer
= msi_dup_property(package
, szARPProductIcon
);
3458 LPWSTR path
= build_icon_path(package
,buffer
);
3459 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3464 buffer
= msi_dup_property(package
, szProductVersion
);
3467 DWORD verdword
= msi_version_str_to_dword(buffer
);
3468 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3472 msi_reg_set_val_dword(hkey
, szAssignment
, 0);
3473 msi_reg_set_val_dword(hkey
, szAdvertiseFlags
, 0x184);
3474 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_INSTANCETYPEW
, 0);
3475 msi_reg_set_val_str(hkey
, szClients
, szColon
);
3477 hdb
= alloc_msihandle(&package
->db
->hdr
);
3479 return ERROR_NOT_ENOUGH_MEMORY
;
3481 r
= MsiGetSummaryInformationW(hdb
, NULL
, 0, &suminfo
);
3482 MsiCloseHandle(hdb
);
3483 if (r
!= ERROR_SUCCESS
)
3487 r
= MsiSummaryInfoGetPropertyW(suminfo
, PID_REVNUMBER
, NULL
, NULL
,
3488 NULL
, guids
, &size
);
3489 if (r
!= ERROR_SUCCESS
)
3492 ptr
= strchrW(guids
, ';');
3494 squash_guid(guids
, packcode
);
3495 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PACKAGECODEW
, packcode
);
3498 MsiCloseHandle(suminfo
);
3499 return ERROR_SUCCESS
;
3502 static UINT
msi_publish_upgrade_code(MSIPACKAGE
*package
)
3507 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
3509 static const WCHAR szUpgradeCode
[] =
3510 {'U','p','g','r','a','d','e','C','o','d','e',0};
3512 upgrade
= msi_dup_property(package
, szUpgradeCode
);
3514 return ERROR_SUCCESS
;
3516 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3518 r
= MSIREG_OpenClassesUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3519 if (r
!= ERROR_SUCCESS
)
3524 r
= MSIREG_OpenUserUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3525 if (r
!= ERROR_SUCCESS
)
3529 squash_guid(package
->ProductCode
, squashed_pc
);
3530 msi_reg_set_val_str(hkey
, squashed_pc
, NULL
);
3539 static BOOL
msi_check_publish(MSIPACKAGE
*package
)
3541 MSIFEATURE
*feature
;
3543 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3545 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
3552 static BOOL
msi_check_unpublish(MSIPACKAGE
*package
)
3554 MSIFEATURE
*feature
;
3556 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3558 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3566 * 99% of the work done here is only done for
3567 * advertised installs. However this is where the
3568 * Icon table is processed and written out
3569 * so that is what I am going to do here.
3571 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3577 /* FIXME: also need to publish if the product is in advertise mode */
3578 if (!msi_check_publish(package
))
3579 return ERROR_SUCCESS
;
3581 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3583 rc
= MSIREG_OpenLocalClassesProductKey(package
->ProductCode
, &hukey
, TRUE
);
3584 if (rc
!= ERROR_SUCCESS
)
3587 rc
= MSIREG_OpenLocalUserDataProductKey(package
->ProductCode
, &hudkey
, TRUE
);
3588 if (rc
!= ERROR_SUCCESS
)
3593 rc
= MSIREG_OpenUserProductsKey(package
->ProductCode
, &hukey
, TRUE
);
3594 if (rc
!= ERROR_SUCCESS
)
3597 rc
= MSIREG_OpenUserDataProductKey(package
->ProductCode
, &hudkey
, TRUE
);
3598 if (rc
!= ERROR_SUCCESS
)
3602 rc
= msi_publish_upgrade_code(package
);
3603 if (rc
!= ERROR_SUCCESS
)
3606 rc
= msi_publish_product_properties(package
, hukey
);
3607 if (rc
!= ERROR_SUCCESS
)
3610 rc
= msi_publish_sourcelist(package
, hukey
);
3611 if (rc
!= ERROR_SUCCESS
)
3614 rc
= msi_publish_icons(package
);
3618 RegCloseKey(hudkey
);
3623 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3625 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3626 LPCWSTR component
, section
, key
, value
, identifier
, dirproperty
;
3627 LPWSTR deformated_section
, deformated_key
, deformated_value
;
3628 LPWSTR folder
, filename
, fullname
= NULL
;
3629 LPCWSTR filenameptr
;
3633 static const WCHAR szWindowsFolder
[] =
3634 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3636 component
= MSI_RecordGetString(row
, 8);
3637 comp
= get_loaded_component(package
,component
);
3639 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3641 TRACE("Skipping ini file due to disabled component %s\n",
3642 debugstr_w(component
));
3644 comp
->Action
= comp
->Installed
;
3646 return ERROR_SUCCESS
;
3649 comp
->Action
= INSTALLSTATE_LOCAL
;
3651 identifier
= MSI_RecordGetString(row
,1);
3652 dirproperty
= MSI_RecordGetString(row
,3);
3653 section
= MSI_RecordGetString(row
,4);
3654 key
= MSI_RecordGetString(row
,5);
3655 value
= MSI_RecordGetString(row
,6);
3656 action
= MSI_RecordGetInteger(row
,7);
3658 deformat_string(package
,section
,&deformated_section
);
3659 deformat_string(package
,key
,&deformated_key
);
3660 deformat_string(package
,value
,&deformated_value
);
3662 filename
= msi_dup_record_field(row
, 2);
3663 if (filename
&& (filenameptr
= strchrW(filename
, '|')))
3666 filenameptr
= filename
;
3670 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, TRUE
, NULL
);
3672 folder
= msi_dup_property( package
, dirproperty
);
3675 folder
= msi_dup_property( package
, szWindowsFolder
);
3679 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
3683 fullname
= build_directory_name(2, folder
, filenameptr
);
3687 TRACE("Adding value %s to section %s in %s\n",
3688 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3689 debugstr_w(fullname
));
3690 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3691 deformated_value
, fullname
);
3693 else if (action
== 1)
3696 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3697 returned
, 10, fullname
);
3698 if (returned
[0] == 0)
3700 TRACE("Adding value %s to section %s in %s\n",
3701 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3702 debugstr_w(fullname
));
3704 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3705 deformated_value
, fullname
);
3708 else if (action
== 3)
3709 FIXME("Append to existing section not yet implemented\n");
3711 uirow
= MSI_CreateRecord(4);
3712 MSI_RecordSetStringW(uirow
,1,identifier
);
3713 MSI_RecordSetStringW(uirow
,2,deformated_section
);
3714 MSI_RecordSetStringW(uirow
,3,deformated_key
);
3715 MSI_RecordSetStringW(uirow
,4,deformated_value
);
3716 ui_actiondata(package
,szWriteIniValues
,uirow
);
3717 msiobj_release( &uirow
->hdr
);
3723 msi_free(deformated_key
);
3724 msi_free(deformated_value
);
3725 msi_free(deformated_section
);
3726 return ERROR_SUCCESS
;
3729 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
3733 static const WCHAR ExecSeqQuery
[] =
3734 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3735 '`','I','n','i','F','i','l','e','`',0};
3737 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3738 if (rc
!= ERROR_SUCCESS
)
3740 TRACE("no IniFile table\n");
3741 return ERROR_SUCCESS
;
3744 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
3745 msiobj_release(&view
->hdr
);
3749 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
3751 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3756 static const WCHAR ExeStr
[] =
3757 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3758 static const WCHAR close
[] = {'\"',0};
3760 PROCESS_INFORMATION info
;
3765 memset(&si
,0,sizeof(STARTUPINFOW
));
3767 filename
= MSI_RecordGetString(row
,1);
3768 file
= get_loaded_file( package
, filename
);
3772 ERR("Unable to find file id %s\n",debugstr_w(filename
));
3773 return ERROR_SUCCESS
;
3776 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
3778 FullName
= msi_alloc(len
*sizeof(WCHAR
));
3779 strcpyW(FullName
,ExeStr
);
3780 strcatW( FullName
, file
->TargetPath
);
3781 strcatW(FullName
,close
);
3783 TRACE("Registering %s\n",debugstr_w(FullName
));
3784 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
3789 CloseHandle(info
.hThread
);
3790 msi_dialog_check_messages(info
.hProcess
);
3791 CloseHandle(info
.hProcess
);
3797 uirow
= MSI_CreateRecord( 2 );
3798 uipath
= strdupW( file
->TargetPath
);
3799 p
= strrchrW(uipath
,'\\');
3802 MSI_RecordSetStringW( uirow
, 1, &p
[1] );
3803 MSI_RecordSetStringW( uirow
, 2, uipath
);
3804 ui_actiondata( package
, szSelfRegModules
, uirow
);
3805 msiobj_release( &uirow
->hdr
);
3807 /* FIXME: call ui_progress? */
3809 return ERROR_SUCCESS
;
3812 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
3816 static const WCHAR ExecSeqQuery
[] =
3817 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3818 '`','S','e','l','f','R','e','g','`',0};
3820 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3821 if (rc
!= ERROR_SUCCESS
)
3823 TRACE("no SelfReg table\n");
3824 return ERROR_SUCCESS
;
3827 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
3828 msiobj_release(&view
->hdr
);
3830 return ERROR_SUCCESS
;
3833 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
3835 MSIFEATURE
*feature
;
3838 HKEY userdata
= NULL
;
3840 if (!msi_check_publish(package
))
3841 return ERROR_SUCCESS
;
3843 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3845 rc
= MSIREG_OpenLocalClassesFeaturesKey(package
->ProductCode
,
3847 if (rc
!= ERROR_SUCCESS
)
3850 rc
= MSIREG_OpenLocalUserDataFeaturesKey(package
->ProductCode
,
3852 if (rc
!= ERROR_SUCCESS
)
3857 rc
= MSIREG_OpenUserFeaturesKey(package
->ProductCode
, &hkey
, TRUE
);
3858 if (rc
!= ERROR_SUCCESS
)
3861 rc
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
,
3863 if (rc
!= ERROR_SUCCESS
)
3867 /* here the guids are base 85 encoded */
3868 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
3874 BOOL absent
= FALSE
;
3877 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
) &&
3878 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_SOURCE
) &&
3879 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ADVERTISED
))
3883 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3887 if (feature
->Feature_Parent
)
3888 size
+= strlenW( feature
->Feature_Parent
)+2;
3890 data
= msi_alloc(size
* sizeof(WCHAR
));
3893 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3895 MSICOMPONENT
* component
= cl
->component
;
3899 if (component
->ComponentId
)
3901 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
3902 CLSIDFromString(component
->ComponentId
, &clsid
);
3903 encode_base85_guid(&clsid
,buf
);
3904 TRACE("to %s\n",debugstr_w(buf
));
3909 if (feature
->Feature_Parent
)
3911 static const WCHAR sep
[] = {'\2',0};
3913 strcatW(data
,feature
->Feature_Parent
);
3916 msi_reg_set_val_str( userdata
, feature
->Feature
, data
);
3920 if (feature
->Feature_Parent
)
3921 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
3924 static const WCHAR emptyW
[] = {0};
3925 size
+= sizeof(WCHAR
);
3926 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
3927 (LPBYTE
)(feature
->Feature_Parent
? feature
->Feature_Parent
: emptyW
),size
);
3931 size
+= 2*sizeof(WCHAR
);
3932 data
= msi_alloc(size
);
3935 if (feature
->Feature_Parent
)
3936 strcpyW( &data
[1], feature
->Feature_Parent
);
3937 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
3943 uirow
= MSI_CreateRecord( 1 );
3944 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
3945 ui_actiondata( package
, szPublishFeatures
, uirow
);
3946 msiobj_release( &uirow
->hdr
);
3947 /* FIXME: call ui_progress? */
3952 RegCloseKey(userdata
);
3956 static UINT
msi_unpublish_feature(MSIPACKAGE
*package
, MSIFEATURE
*feature
)
3961 TRACE("unpublishing feature %s\n", debugstr_w(feature
->Feature
));
3963 r
= MSIREG_OpenUserFeaturesKey(package
->ProductCode
, &hkey
, FALSE
);
3964 if (r
== ERROR_SUCCESS
)
3966 RegDeleteValueW(hkey
, feature
->Feature
);
3970 r
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, &hkey
, FALSE
);
3971 if (r
== ERROR_SUCCESS
)
3973 RegDeleteValueW(hkey
, feature
->Feature
);
3977 return ERROR_SUCCESS
;
3980 static UINT
ACTION_UnpublishFeatures(MSIPACKAGE
*package
)
3982 MSIFEATURE
*feature
;
3984 if (!msi_check_unpublish(package
))
3985 return ERROR_SUCCESS
;
3987 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3989 msi_unpublish_feature(package
, feature
);
3992 return ERROR_SUCCESS
;
3995 static UINT
msi_get_local_package_name( LPWSTR path
)
3997 static const WCHAR szInstaller
[] = {
3998 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3999 static const WCHAR fmt
[] = { '%','x','.','m','s','i',0};
4003 time
= GetTickCount();
4004 GetWindowsDirectoryW( path
, MAX_PATH
);
4005 lstrcatW( path
, szInstaller
);
4006 CreateDirectoryW( path
, NULL
);
4008 len
= lstrlenW(path
);
4009 for (i
=0; i
<0x10000; i
++)
4011 snprintfW( &path
[len
], MAX_PATH
- len
, fmt
, (time
+i
)&0xffff );
4012 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
,
4013 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
4014 if (handle
!= INVALID_HANDLE_VALUE
)
4016 CloseHandle(handle
);
4019 if (GetLastError() != ERROR_FILE_EXISTS
&&
4020 GetLastError() != ERROR_SHARING_VIOLATION
)
4021 return ERROR_FUNCTION_FAILED
;
4024 return ERROR_SUCCESS
;
4027 static UINT
msi_make_package_local( MSIPACKAGE
*package
, HKEY hkey
)
4029 WCHAR packagefile
[MAX_PATH
];
4032 r
= msi_get_local_package_name( packagefile
);
4033 if (r
!= ERROR_SUCCESS
)
4036 TRACE("Copying to local package %s\n",debugstr_w(packagefile
));
4038 r
= CopyFileW( package
->db
->path
, packagefile
, FALSE
);
4042 ERR("Unable to copy package (%s -> %s) (error %d)\n",
4043 debugstr_w(package
->db
->path
), debugstr_w(packagefile
), GetLastError());
4044 return ERROR_FUNCTION_FAILED
;
4047 msi_reg_set_val_str( hkey
, INSTALLPROPERTY_LOCALPACKAGEW
, packagefile
);
4049 return ERROR_SUCCESS
;
4052 static UINT
msi_publish_install_properties(MSIPACKAGE
*package
, HKEY hkey
)
4054 LPWSTR prop
, val
, key
;
4060 static const WCHAR date_fmt
[] = {'%','i','%','0','2','i','%','0','2','i',0};
4061 static const WCHAR szWindowsInstaller
[] =
4062 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4063 static const WCHAR modpath_fmt
[] =
4064 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4065 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4066 static const WCHAR szModifyPath
[] =
4067 {'M','o','d','i','f','y','P','a','t','h',0};
4068 static const WCHAR szUninstallString
[] =
4069 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4070 static const WCHAR szEstimatedSize
[] =
4071 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4072 static const WCHAR szProductLanguage
[] =
4073 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4074 static const WCHAR szProductVersion
[] =
4075 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4076 static const WCHAR szProductName
[] =
4077 {'P','r','o','d','u','c','t','N','a','m','e',0};
4078 static const WCHAR szDisplayName
[] =
4079 {'D','i','s','p','l','a','y','N','a','m','e',0};
4080 static const WCHAR szDisplayVersion
[] =
4081 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4082 static const WCHAR szManufacturer
[] =
4083 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4085 static const LPCSTR propval
[] = {
4086 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4087 "ARPCONTACT", "Contact",
4088 "ARPCOMMENTS", "Comments",
4089 "ProductName", "DisplayName",
4090 "ProductVersion", "DisplayVersion",
4091 "ARPHELPLINK", "HelpLink",
4092 "ARPHELPTELEPHONE", "HelpTelephone",
4093 "ARPINSTALLLOCATION", "InstallLocation",
4094 "SourceDir", "InstallSource",
4095 "Manufacturer", "Publisher",
4096 "ARPREADME", "Readme",
4098 "ARPURLINFOABOUT", "URLInfoAbout",
4099 "ARPURLUPDATEINFO", "URLUpdateInfo",
4102 const LPCSTR
*p
= propval
;
4106 prop
= strdupAtoW(*p
++);
4107 key
= strdupAtoW(*p
++);
4108 val
= msi_dup_property(package
, prop
);
4109 msi_reg_set_val_str(hkey
, key
, val
);
4115 msi_reg_set_val_dword(hkey
, szWindowsInstaller
, 1);
4117 size
= deformat_string(package
, modpath_fmt
, &buffer
);
4118 RegSetValueExW(hkey
, szModifyPath
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4119 RegSetValueExW(hkey
, szUninstallString
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4122 /* FIXME: Write real Estimated Size when we have it */
4123 msi_reg_set_val_dword(hkey
, szEstimatedSize
, 0);
4125 buffer
= msi_dup_property(package
, szProductName
);
4126 msi_reg_set_val_str(hkey
, szDisplayName
, buffer
);
4129 buffer
= msi_dup_property(package
, cszSourceDir
);
4130 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLSOURCEW
, buffer
);
4133 buffer
= msi_dup_property(package
, szManufacturer
);
4134 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PUBLISHERW
, buffer
);
4137 GetLocalTime(&systime
);
4138 sprintfW(date
, date_fmt
, systime
.wYear
, systime
.wMonth
, systime
.wDay
);
4139 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLDATEW
, date
);
4141 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
4142 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
4144 buffer
= msi_dup_property(package
, szProductVersion
);
4145 msi_reg_set_val_str(hkey
, szDisplayVersion
, buffer
);
4148 DWORD verdword
= msi_version_str_to_dword(buffer
);
4150 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
4151 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>> 24);
4152 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>> 16) & 0xFF);
4156 return ERROR_SUCCESS
;
4159 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
4161 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
4162 LPWSTR upgrade_code
;
4167 static const WCHAR szUpgradeCode
[] = {
4168 'U','p','g','r','a','d','e','C','o','d','e',0};
4170 /* FIXME: also need to publish if the product is in advertise mode */
4171 if (!msi_check_publish(package
))
4172 return ERROR_SUCCESS
;
4174 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
, &hkey
, TRUE
);
4175 if (rc
!= ERROR_SUCCESS
)
4178 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4180 rc
= MSIREG_OpenLocalSystemInstallProps(package
->ProductCode
, &props
, TRUE
);
4181 if (rc
!= ERROR_SUCCESS
)
4186 rc
= MSIREG_OpenCurrentUserInstallProps(package
->ProductCode
, &props
, TRUE
);
4187 if (rc
!= ERROR_SUCCESS
)
4191 msi_make_package_local(package
, props
);
4193 rc
= msi_publish_install_properties(package
, hkey
);
4194 if (rc
!= ERROR_SUCCESS
)
4197 rc
= msi_publish_install_properties(package
, props
);
4198 if (rc
!= ERROR_SUCCESS
)
4201 upgrade_code
= msi_dup_property(package
, szUpgradeCode
);
4204 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &upgrade
, TRUE
);
4205 squash_guid(package
->ProductCode
, squashed_pc
);
4206 msi_reg_set_val_str(upgrade
, squashed_pc
, NULL
);
4207 RegCloseKey(upgrade
);
4208 msi_free(upgrade_code
);
4214 return ERROR_SUCCESS
;
4217 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
4219 return execute_script(package
,INSTALL_SCRIPT
);
4222 static UINT
msi_unpublish_product(MSIPACKAGE
*package
)
4225 LPWSTR remove
= NULL
;
4226 LPWSTR
*features
= NULL
;
4227 BOOL full_uninstall
= TRUE
;
4228 MSIFEATURE
*feature
;
4230 static const WCHAR szRemove
[] = {'R','E','M','O','V','E',0};
4231 static const WCHAR szAll
[] = {'A','L','L',0};
4232 static const WCHAR szUpgradeCode
[] =
4233 {'U','p','g','r','a','d','e','C','o','d','e',0};
4235 remove
= msi_dup_property(package
, szRemove
);
4237 return ERROR_SUCCESS
;
4239 features
= msi_split_string(remove
, ',');
4243 ERR("REMOVE feature list is empty!\n");
4244 return ERROR_FUNCTION_FAILED
;
4247 if (!lstrcmpW(features
[0], szAll
))
4248 full_uninstall
= TRUE
;
4251 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4253 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
4254 full_uninstall
= FALSE
;
4258 if (!full_uninstall
)
4261 MSIREG_DeleteProductKey(package
->ProductCode
);
4262 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4263 MSIREG_DeleteUninstallKey(package
->ProductCode
);
4265 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4267 MSIREG_DeleteLocalClassesProductKey(package
->ProductCode
);
4268 MSIREG_DeleteLocalClassesFeaturesKey(package
->ProductCode
);
4272 MSIREG_DeleteUserProductKey(package
->ProductCode
);
4273 MSIREG_DeleteUserFeaturesKey(package
->ProductCode
);
4276 upgrade
= msi_dup_property(package
, szUpgradeCode
);
4279 MSIREG_DeleteUserUpgradeCodesKey(upgrade
);
4286 return ERROR_SUCCESS
;
4289 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
4293 rc
= msi_unpublish_product(package
);
4294 if (rc
!= ERROR_SUCCESS
)
4297 /* turn off scheduling */
4298 package
->script
->CurrentlyScripting
= FALSE
;
4300 /* first do the same as an InstallExecute */
4301 rc
= ACTION_InstallExecute(package
);
4302 if (rc
!= ERROR_SUCCESS
)
4305 /* then handle Commit Actions */
4306 rc
= execute_script(package
,COMMIT_SCRIPT
);
4311 UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
4313 static const WCHAR RunOnce
[] = {
4314 'S','o','f','t','w','a','r','e','\\',
4315 'M','i','c','r','o','s','o','f','t','\\',
4316 'W','i','n','d','o','w','s','\\',
4317 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4318 'R','u','n','O','n','c','e',0};
4319 static const WCHAR InstallRunOnce
[] = {
4320 'S','o','f','t','w','a','r','e','\\',
4321 'M','i','c','r','o','s','o','f','t','\\',
4322 'W','i','n','d','o','w','s','\\',
4323 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4324 'I','n','s','t','a','l','l','e','r','\\',
4325 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4327 static const WCHAR msiexec_fmt
[] = {
4329 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4330 '\"','%','s','\"',0};
4331 static const WCHAR install_fmt
[] = {
4332 '/','I',' ','\"','%','s','\"',' ',
4333 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4334 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4335 WCHAR buffer
[256], sysdir
[MAX_PATH
];
4337 WCHAR squished_pc
[100];
4339 squash_guid(package
->ProductCode
,squished_pc
);
4341 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
4342 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
4343 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
4346 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4349 TRACE("Reboot command %s\n",debugstr_w(buffer
));
4351 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
4352 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
4354 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4357 return ERROR_INSTALL_SUSPEND
;
4360 static UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
4366 * We are currently doing what should be done here in the top level Install
4367 * however for Administrative and uninstalls this step will be needed
4369 if (!package
->PackagePath
)
4370 return ERROR_SUCCESS
;
4372 msi_set_sourcedir_props(package
, TRUE
);
4374 attrib
= GetFileAttributesW(package
->db
->path
);
4375 if (attrib
== INVALID_FILE_ATTRIBUTES
)
4381 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4382 package
->Context
, MSICODE_PRODUCT
,
4383 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
4384 if (rc
== ERROR_MORE_DATA
)
4386 prompt
= msi_alloc(size
* sizeof(WCHAR
));
4387 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4388 package
->Context
, MSICODE_PRODUCT
,
4389 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
4392 prompt
= strdupW(package
->db
->path
);
4394 msg
= generate_error_string(package
,1302,1,prompt
);
4395 while(attrib
== INVALID_FILE_ATTRIBUTES
)
4397 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
4400 rc
= ERROR_INSTALL_USEREXIT
;
4403 attrib
= GetFileAttributesW(package
->db
->path
);
4409 return ERROR_SUCCESS
;
4414 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
4421 static const WCHAR szPropKeys
[][80] =
4423 {'P','r','o','d','u','c','t','I','D',0},
4424 {'U','S','E','R','N','A','M','E',0},
4425 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4429 static const WCHAR szRegKeys
[][80] =
4431 {'P','r','o','d','u','c','t','I','D',0},
4432 {'R','e','g','O','w','n','e','r',0},
4433 {'R','e','g','C','o','m','p','a','n','y',0},
4437 if (msi_check_unpublish(package
))
4439 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4440 return ERROR_SUCCESS
;
4443 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
4445 return ERROR_SUCCESS
;
4447 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4448 rc
= MSIREG_OpenLocalSystemInstallProps(package
->ProductCode
, &hkey
, TRUE
);
4450 rc
= MSIREG_OpenCurrentUserInstallProps(package
->ProductCode
, &hkey
, TRUE
);
4452 if (rc
!= ERROR_SUCCESS
)
4455 for( i
= 0; szPropKeys
[i
][0]; i
++ )
4457 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
4458 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
4463 msi_free(productid
);
4466 /* FIXME: call ui_actiondata */
4472 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
4476 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
4477 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
4482 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4484 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4485 LPCWSTR compgroupid
=NULL
;
4486 LPCWSTR feature
=NULL
;
4487 LPCWSTR text
= NULL
;
4488 LPCWSTR qualifier
= NULL
;
4489 LPCWSTR component
= NULL
;
4490 LPWSTR advertise
= NULL
;
4491 LPWSTR output
= NULL
;
4493 UINT rc
= ERROR_SUCCESS
;
4498 component
= MSI_RecordGetString(rec
,3);
4499 comp
= get_loaded_component(package
,component
);
4501 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) &&
4502 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
) &&
4503 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ADVERTISED
))
4505 TRACE("Skipping: Component %s not scheduled for install\n",
4506 debugstr_w(component
));
4508 return ERROR_SUCCESS
;
4511 compgroupid
= MSI_RecordGetString(rec
,1);
4512 qualifier
= MSI_RecordGetString(rec
,2);
4514 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
4515 if (rc
!= ERROR_SUCCESS
)
4518 text
= MSI_RecordGetString(rec
,4);
4519 feature
= MSI_RecordGetString(rec
,5);
4521 advertise
= create_component_advertise_string(package
, comp
, feature
);
4523 sz
= strlenW(advertise
);
4526 sz
+= lstrlenW(text
);
4529 sz
*= sizeof(WCHAR
);
4531 output
= msi_alloc_zero(sz
);
4532 strcpyW(output
,advertise
);
4533 msi_free(advertise
);
4536 strcatW(output
,text
);
4538 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
4545 uirow
= MSI_CreateRecord( 2 );
4546 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4547 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4548 ui_actiondata( package
, szPublishComponents
, uirow
);
4549 msiobj_release( &uirow
->hdr
);
4550 /* FIXME: call ui_progress? */
4556 * At present I am ignorning the advertised components part of this and only
4557 * focusing on the qualified component sets
4559 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
4563 static const WCHAR ExecSeqQuery
[] =
4564 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4565 '`','P','u','b','l','i','s','h',
4566 'C','o','m','p','o','n','e','n','t','`',0};
4568 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4569 if (rc
!= ERROR_SUCCESS
)
4570 return ERROR_SUCCESS
;
4572 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
4573 msiobj_release(&view
->hdr
);
4578 static UINT
ITERATE_InstallService(MSIRECORD
*rec
, LPVOID param
)
4580 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4583 SC_HANDLE hscm
, service
= NULL
;
4584 LPCWSTR comp
, depends
, pass
;
4585 LPWSTR name
= NULL
, disp
= NULL
;
4586 LPCWSTR load_order
, serv_name
, key
;
4587 DWORD serv_type
, start_type
;
4590 static const WCHAR query
[] =
4591 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4592 '`','C','o','m','p','o','n','e','n','t','`',' ',
4593 'W','H','E','R','E',' ',
4594 '`','C','o','m','p','o','n','e','n','t','`',' ',
4595 '=','\'','%','s','\'',0};
4597 hscm
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASEW
, GENERIC_WRITE
);
4600 ERR("Failed to open the SC Manager!\n");
4604 start_type
= MSI_RecordGetInteger(rec
, 5);
4605 if (start_type
== SERVICE_BOOT_START
|| start_type
== SERVICE_SYSTEM_START
)
4608 depends
= MSI_RecordGetString(rec
, 8);
4609 if (depends
&& *depends
)
4610 FIXME("Dependency list unhandled!\n");
4612 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
4613 deformat_string(package
, MSI_RecordGetString(rec
, 3), &disp
);
4614 serv_type
= MSI_RecordGetInteger(rec
, 4);
4615 err_control
= MSI_RecordGetInteger(rec
, 6);
4616 load_order
= MSI_RecordGetString(rec
, 7);
4617 serv_name
= MSI_RecordGetString(rec
, 9);
4618 pass
= MSI_RecordGetString(rec
, 10);
4619 comp
= MSI_RecordGetString(rec
, 12);
4621 /* fetch the service path */
4622 row
= MSI_QueryGetRecord(package
->db
, query
, comp
);
4625 ERR("Control query failed!\n");
4629 key
= MSI_RecordGetString(row
, 6);
4631 file
= get_loaded_file(package
, key
);
4632 msiobj_release(&row
->hdr
);
4635 ERR("Failed to load the service file\n");
4639 service
= CreateServiceW(hscm
, name
, disp
, GENERIC_ALL
, serv_type
,
4640 start_type
, err_control
, file
->TargetPath
,
4641 load_order
, NULL
, NULL
, serv_name
, pass
);
4644 if (GetLastError() != ERROR_SERVICE_EXISTS
)
4645 ERR("Failed to create service %s: %d\n", debugstr_w(name
), GetLastError());
4649 CloseServiceHandle(service
);
4650 CloseServiceHandle(hscm
);
4654 return ERROR_SUCCESS
;
4657 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
4661 static const WCHAR ExecSeqQuery
[] =
4662 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4663 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4665 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4666 if (rc
!= ERROR_SUCCESS
)
4667 return ERROR_SUCCESS
;
4669 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallService
, package
);
4670 msiobj_release(&view
->hdr
);
4675 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4676 static LPCWSTR
*msi_service_args_to_vector(LPWSTR args
, DWORD
*numargs
)
4678 LPCWSTR
*vector
, *temp_vector
;
4682 static const WCHAR separator
[] = {'[','~',']',0};
4685 sep_len
= sizeof(separator
) / sizeof(WCHAR
) - 1;
4690 vector
= msi_alloc(sizeof(LPWSTR
));
4698 vector
[*numargs
- 1] = p
;
4700 if ((q
= strstrW(p
, separator
)))
4704 temp_vector
= msi_realloc(vector
, (*numargs
+ 1) * sizeof(LPWSTR
));
4710 vector
= temp_vector
;
4719 static UINT
ITERATE_StartService(MSIRECORD
*rec
, LPVOID param
)
4721 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4723 SC_HANDLE scm
, service
= NULL
;
4724 LPCWSTR name
, *vector
= NULL
;
4726 DWORD event
, numargs
;
4727 UINT r
= ERROR_FUNCTION_FAILED
;
4729 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 6));
4730 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4731 return ERROR_SUCCESS
;
4733 name
= MSI_RecordGetString(rec
, 2);
4734 event
= MSI_RecordGetInteger(rec
, 3);
4735 args
= strdupW(MSI_RecordGetString(rec
, 4));
4737 if (!(event
& msidbServiceControlEventStart
))
4738 return ERROR_SUCCESS
;
4740 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_CONNECT
);
4743 ERR("Failed to open the service control manager\n");
4747 service
= OpenServiceW(scm
, name
, SERVICE_START
);
4750 ERR("Failed to open service %s\n", debugstr_w(name
));
4754 vector
= msi_service_args_to_vector(args
, &numargs
);
4756 if (!StartServiceW(service
, numargs
, vector
))
4758 ERR("Failed to start service %s\n", debugstr_w(name
));
4765 CloseServiceHandle(service
);
4766 CloseServiceHandle(scm
);
4773 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
4778 static const WCHAR query
[] = {
4779 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4780 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4782 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4783 if (rc
!= ERROR_SUCCESS
)
4784 return ERROR_SUCCESS
;
4786 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StartService
, package
);
4787 msiobj_release(&view
->hdr
);
4792 static BOOL
stop_service_dependents(SC_HANDLE scm
, SC_HANDLE service
)
4794 DWORD i
, needed
, count
;
4795 ENUM_SERVICE_STATUSW
*dependencies
;
4799 if (EnumDependentServicesW(service
, SERVICE_ACTIVE
, NULL
,
4800 0, &needed
, &count
))
4803 if (GetLastError() != ERROR_MORE_DATA
)
4806 dependencies
= msi_alloc(needed
);
4810 if (!EnumDependentServicesW(service
, SERVICE_ACTIVE
, dependencies
,
4811 needed
, &needed
, &count
))
4814 for (i
= 0; i
< count
; i
++)
4816 depserv
= OpenServiceW(scm
, dependencies
[i
].lpServiceName
,
4817 SERVICE_STOP
| SERVICE_QUERY_STATUS
);
4821 if (!ControlService(depserv
, SERVICE_CONTROL_STOP
, &ss
))
4828 msi_free(dependencies
);
4832 static UINT
ITERATE_StopService(MSIRECORD
*rec
, LPVOID param
)
4834 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4836 SERVICE_STATUS status
;
4837 SERVICE_STATUS_PROCESS ssp
;
4838 SC_HANDLE scm
= NULL
, service
= NULL
;
4840 DWORD event
, needed
;
4842 event
= MSI_RecordGetInteger(rec
, 3);
4843 if (!(event
& msidbServiceControlEventStop
))
4844 return ERROR_SUCCESS
;
4846 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 6));
4847 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4848 return ERROR_SUCCESS
;
4850 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
4851 deformat_string(package
, MSI_RecordGetString(rec
, 4), &args
);
4852 args
= strdupW(MSI_RecordGetString(rec
, 4));
4854 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
4857 WARN("Failed to open the SCM: %d\n", GetLastError());
4861 service
= OpenServiceW(scm
, name
,
4863 SERVICE_QUERY_STATUS
|
4864 SERVICE_ENUMERATE_DEPENDENTS
);
4867 WARN("Failed to open service (%s): %d\n",
4868 debugstr_w(name
), GetLastError());
4872 if (!QueryServiceStatusEx(service
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&ssp
,
4873 sizeof(SERVICE_STATUS_PROCESS
), &needed
))
4875 WARN("Failed to query service status (%s): %d\n",
4876 debugstr_w(name
), GetLastError());
4880 if (ssp
.dwCurrentState
== SERVICE_STOPPED
)
4883 stop_service_dependents(scm
, service
);
4885 if (!ControlService(service
, SERVICE_CONTROL_STOP
, &status
))
4886 WARN("Failed to stop service (%s): %d\n", debugstr_w(name
), GetLastError());
4889 CloseServiceHandle(service
);
4890 CloseServiceHandle(scm
);
4894 return ERROR_SUCCESS
;
4897 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
4902 static const WCHAR query
[] = {
4903 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4904 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4906 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4907 if (rc
!= ERROR_SUCCESS
)
4908 return ERROR_SUCCESS
;
4910 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StopService
, package
);
4911 msiobj_release(&view
->hdr
);
4916 static MSIFILE
*msi_find_file( MSIPACKAGE
*package
, LPCWSTR filename
)
4920 LIST_FOR_EACH_ENTRY(file
, &package
->files
, MSIFILE
, entry
)
4922 if (!lstrcmpW(file
->File
, filename
))
4929 static UINT
ITERATE_InstallODBCDriver( MSIRECORD
*rec
, LPVOID param
)
4931 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4932 LPWSTR driver
, driver_path
, ptr
;
4933 WCHAR outpath
[MAX_PATH
];
4934 MSIFILE
*driver_file
, *setup_file
;
4937 UINT r
= ERROR_SUCCESS
;
4939 static const WCHAR driver_fmt
[] = {
4940 'D','r','i','v','e','r','=','%','s',0};
4941 static const WCHAR setup_fmt
[] = {
4942 'S','e','t','u','p','=','%','s',0};
4943 static const WCHAR usage_fmt
[] = {
4944 'F','i','l','e','U','s','a','g','e','=','1',0};
4946 desc
= MSI_RecordGetString(rec
, 3);
4948 driver_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
4949 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
4951 if (!driver_file
|| !setup_file
)
4953 ERR("ODBC Driver entry not found!\n");
4954 return ERROR_FUNCTION_FAILED
;
4957 len
= lstrlenW(desc
) + lstrlenW(driver_fmt
) + lstrlenW(driver_file
->FileName
) +
4958 lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
) +
4959 lstrlenW(usage_fmt
) + 1;
4960 driver
= msi_alloc(len
* sizeof(WCHAR
));
4962 return ERROR_OUTOFMEMORY
;
4965 lstrcpyW(ptr
, desc
);
4966 ptr
+= lstrlenW(ptr
) + 1;
4968 sprintfW(ptr
, driver_fmt
, driver_file
->FileName
);
4969 ptr
+= lstrlenW(ptr
) + 1;
4971 sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
4972 ptr
+= lstrlenW(ptr
) + 1;
4974 lstrcpyW(ptr
, usage_fmt
);
4975 ptr
+= lstrlenW(ptr
) + 1;
4978 driver_path
= strdupW(driver_file
->TargetPath
);
4979 ptr
= strrchrW(driver_path
, '\\');
4980 if (ptr
) *ptr
= '\0';
4982 if (!SQLInstallDriverExW(driver
, driver_path
, outpath
, MAX_PATH
,
4983 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
4985 ERR("Failed to install SQL driver!\n");
4986 r
= ERROR_FUNCTION_FAILED
;
4990 msi_free(driver_path
);
4995 static UINT
ITERATE_InstallODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
4997 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4998 LPWSTR translator
, translator_path
, ptr
;
4999 WCHAR outpath
[MAX_PATH
];
5000 MSIFILE
*translator_file
, *setup_file
;
5003 UINT r
= ERROR_SUCCESS
;
5005 static const WCHAR translator_fmt
[] = {
5006 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5007 static const WCHAR setup_fmt
[] = {
5008 'S','e','t','u','p','=','%','s',0};
5010 desc
= MSI_RecordGetString(rec
, 3);
5012 translator_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5013 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5015 if (!translator_file
|| !setup_file
)
5017 ERR("ODBC Translator entry not found!\n");
5018 return ERROR_FUNCTION_FAILED
;
5021 len
= lstrlenW(desc
) + lstrlenW(translator_fmt
) + lstrlenW(translator_file
->FileName
) +
5022 lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
) + 1;
5023 translator
= msi_alloc(len
* sizeof(WCHAR
));
5025 return ERROR_OUTOFMEMORY
;
5028 lstrcpyW(ptr
, desc
);
5029 ptr
+= lstrlenW(ptr
) + 1;
5031 sprintfW(ptr
, translator_fmt
, translator_file
->FileName
);
5032 ptr
+= lstrlenW(ptr
) + 1;
5034 sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5035 ptr
+= lstrlenW(ptr
) + 1;
5038 translator_path
= strdupW(translator_file
->TargetPath
);
5039 ptr
= strrchrW(translator_path
, '\\');
5040 if (ptr
) *ptr
= '\0';
5042 if (!SQLInstallTranslatorExW(translator
, translator_path
, outpath
, MAX_PATH
,
5043 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5045 ERR("Failed to install SQL translator!\n");
5046 r
= ERROR_FUNCTION_FAILED
;
5049 msi_free(translator
);
5050 msi_free(translator_path
);
5055 static UINT
ITERATE_InstallODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5058 LPCWSTR desc
, driver
;
5059 WORD request
= ODBC_ADD_SYS_DSN
;
5062 UINT r
= ERROR_SUCCESS
;
5064 static const WCHAR attrs_fmt
[] = {
5065 'D','S','N','=','%','s',0 };
5067 desc
= MSI_RecordGetString(rec
, 3);
5068 driver
= MSI_RecordGetString(rec
, 4);
5069 registration
= MSI_RecordGetInteger(rec
, 5);
5071 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_ADD_SYS_DSN
;
5072 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_ADD_DSN
;
5074 len
= lstrlenW(attrs_fmt
) + lstrlenW(desc
) + 1 + 1;
5075 attrs
= msi_alloc(len
* sizeof(WCHAR
));
5077 return ERROR_OUTOFMEMORY
;
5079 sprintfW(attrs
, attrs_fmt
, desc
);
5080 attrs
[len
- 1] = '\0';
5082 if (!SQLConfigDataSourceW(NULL
, request
, driver
, attrs
))
5084 ERR("Failed to install SQL data source!\n");
5085 r
= ERROR_FUNCTION_FAILED
;
5093 static UINT
ACTION_InstallODBC( MSIPACKAGE
*package
)
5098 static const WCHAR driver_query
[] = {
5099 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5100 'O','D','B','C','D','r','i','v','e','r',0 };
5102 static const WCHAR translator_query
[] = {
5103 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5104 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5106 static const WCHAR source_query
[] = {
5107 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5108 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5110 rc
= MSI_DatabaseOpenViewW(package
->db
, driver_query
, &view
);
5111 if (rc
!= ERROR_SUCCESS
)
5112 return ERROR_SUCCESS
;
5114 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDriver
, package
);
5115 msiobj_release(&view
->hdr
);
5117 rc
= MSI_DatabaseOpenViewW(package
->db
, translator_query
, &view
);
5118 if (rc
!= ERROR_SUCCESS
)
5119 return ERROR_SUCCESS
;
5121 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCTranslator
, package
);
5122 msiobj_release(&view
->hdr
);
5124 rc
= MSI_DatabaseOpenViewW(package
->db
, source_query
, &view
);
5125 if (rc
!= ERROR_SUCCESS
)
5126 return ERROR_SUCCESS
;
5128 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDataSource
, package
);
5129 msiobj_release(&view
->hdr
);
5134 #define ENV_ACT_SETALWAYS 0x1
5135 #define ENV_ACT_SETABSENT 0x2
5136 #define ENV_ACT_REMOVE 0x4
5137 #define ENV_ACT_REMOVEMATCH 0x8
5139 #define ENV_MOD_MACHINE 0x20000000
5140 #define ENV_MOD_APPEND 0x40000000
5141 #define ENV_MOD_PREFIX 0x80000000
5142 #define ENV_MOD_MASK 0xC0000000
5144 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5146 static LONG
env_set_flags( LPCWSTR
*name
, LPCWSTR
*value
, DWORD
*flags
)
5148 LPCWSTR cptr
= *name
;
5149 LPCWSTR ptr
= *value
;
5151 static const WCHAR prefix
[] = {'[','~',']',0};
5152 static const int prefix_len
= 3;
5158 *flags
|= ENV_ACT_SETALWAYS
;
5159 else if (*cptr
== '+')
5160 *flags
|= ENV_ACT_SETABSENT
;
5161 else if (*cptr
== '-')
5162 *flags
|= ENV_ACT_REMOVE
;
5163 else if (*cptr
== '!')
5164 *flags
|= ENV_ACT_REMOVEMATCH
;
5165 else if (*cptr
== '*')
5166 *flags
|= ENV_MOD_MACHINE
;
5176 ERR("Missing environment variable\n");
5177 return ERROR_FUNCTION_FAILED
;
5180 if (!strncmpW(ptr
, prefix
, prefix_len
))
5182 *flags
|= ENV_MOD_APPEND
;
5183 *value
+= lstrlenW(prefix
);
5185 else if (lstrlenW(*value
) >= prefix_len
)
5187 ptr
+= lstrlenW(ptr
) - prefix_len
;
5188 if (!lstrcmpW(ptr
, prefix
))
5190 *flags
|= ENV_MOD_PREFIX
;
5191 /* the "[~]" will be removed by deformat_string */;
5196 check_flag_combo(*flags
, ENV_ACT_SETALWAYS
| ENV_ACT_SETABSENT
) ||
5197 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETABSENT
) ||
5198 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETALWAYS
) ||
5199 check_flag_combo(*flags
, ENV_ACT_SETABSENT
| ENV_MOD_MASK
))
5201 ERR("Invalid flags: %08x\n", *flags
);
5202 return ERROR_FUNCTION_FAILED
;
5205 return ERROR_SUCCESS
;
5208 static UINT
ITERATE_WriteEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
5210 MSIPACKAGE
*package
= param
;
5211 LPCWSTR name
, value
;
5212 LPWSTR data
= NULL
, newval
= NULL
;
5213 LPWSTR deformatted
= NULL
, ptr
;
5214 DWORD flags
, type
, size
;
5216 HKEY env
= NULL
, root
;
5217 LPCWSTR environment
;
5219 static const WCHAR user_env
[] =
5220 {'E','n','v','i','r','o','n','m','e','n','t',0};
5221 static const WCHAR machine_env
[] =
5222 {'S','y','s','t','e','m','\\',
5223 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5224 'C','o','n','t','r','o','l','\\',
5225 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5226 'E','n','v','i','r','o','n','m','e','n','t',0};
5227 static const WCHAR semicolon
[] = {';',0};
5229 name
= MSI_RecordGetString(rec
, 2);
5230 value
= MSI_RecordGetString(rec
, 3);
5232 res
= env_set_flags(&name
, &value
, &flags
);
5233 if (res
!= ERROR_SUCCESS
)
5236 deformat_string(package
, value
, &deformatted
);
5239 res
= ERROR_OUTOFMEMORY
;
5243 value
= deformatted
;
5245 if (flags
& ENV_MOD_MACHINE
)
5247 environment
= machine_env
;
5248 root
= HKEY_LOCAL_MACHINE
;
5252 environment
= user_env
;
5253 root
= HKEY_CURRENT_USER
;
5256 res
= RegCreateKeyExW(root
, environment
, 0, NULL
, 0,
5257 KEY_ALL_ACCESS
, NULL
, &env
, NULL
);
5258 if (res
!= ERROR_SUCCESS
)
5261 if (flags
& ENV_ACT_REMOVE
)
5262 FIXME("Not removing environment variable on uninstall!\n");
5265 res
= RegQueryValueExW(env
, name
, NULL
, &type
, NULL
, &size
);
5266 if ((res
!= ERROR_SUCCESS
&& res
!= ERROR_FILE_NOT_FOUND
) ||
5267 (res
== ERROR_SUCCESS
&& type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
))
5270 if (res
!= ERROR_FILE_NOT_FOUND
)
5272 if (flags
& ENV_ACT_SETABSENT
)
5274 res
= ERROR_SUCCESS
;
5278 data
= msi_alloc(size
);
5282 return ERROR_OUTOFMEMORY
;
5285 res
= RegQueryValueExW(env
, name
, NULL
, &type
, (LPVOID
)data
, &size
);
5286 if (res
!= ERROR_SUCCESS
)
5289 if (flags
& ENV_ACT_REMOVEMATCH
&& (!value
|| !lstrcmpW(data
, value
)))
5291 res
= RegDeleteKeyW(env
, name
);
5295 size
= (lstrlenW(value
) + 1 + size
) * sizeof(WCHAR
);
5296 newval
= msi_alloc(size
);
5300 res
= ERROR_OUTOFMEMORY
;
5304 if (!(flags
& ENV_MOD_MASK
))
5305 lstrcpyW(newval
, value
);
5308 if (flags
& ENV_MOD_PREFIX
)
5310 lstrcpyW(newval
, value
);
5311 lstrcatW(newval
, semicolon
);
5312 ptr
= newval
+ lstrlenW(value
) + 1;
5315 lstrcpyW(ptr
, data
);
5317 if (flags
& ENV_MOD_APPEND
)
5319 lstrcatW(newval
, semicolon
);
5320 lstrcatW(newval
, value
);
5326 size
= (lstrlenW(value
) + 1) * sizeof(WCHAR
);
5327 newval
= msi_alloc(size
);
5330 res
= ERROR_OUTOFMEMORY
;
5334 lstrcpyW(newval
, value
);
5337 TRACE("setting %s to %s\n", debugstr_w(name
), debugstr_w(newval
));
5338 res
= RegSetValueExW(env
, name
, 0, type
, (LPVOID
)newval
, size
);
5341 if (env
) RegCloseKey(env
);
5342 msi_free(deformatted
);
5348 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
5352 static const WCHAR ExecSeqQuery
[] =
5353 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5354 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5355 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5356 if (rc
!= ERROR_SUCCESS
)
5357 return ERROR_SUCCESS
;
5359 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteEnvironmentString
, package
);
5360 msiobj_release(&view
->hdr
);
5365 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5376 static BOOL
msi_move_file(LPCWSTR source
, LPCWSTR dest
, int options
)
5380 if (GetFileAttributesW(source
) == FILE_ATTRIBUTE_DIRECTORY
||
5381 GetFileAttributesW(dest
) == FILE_ATTRIBUTE_DIRECTORY
)
5383 WARN("Source or dest is directory, not moving\n");
5387 if (options
== msidbMoveFileOptionsMove
)
5389 TRACE("moving %s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
5390 ret
= MoveFileExW(source
, dest
, MOVEFILE_REPLACE_EXISTING
);
5393 WARN("MoveFile failed: %d\n", GetLastError());
5399 TRACE("copying %s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
5400 ret
= CopyFileW(source
, dest
, FALSE
);
5403 WARN("CopyFile failed: %d\n", GetLastError());
5411 static LPWSTR
wildcard_to_file(LPWSTR wildcard
, LPWSTR filename
)
5414 DWORD dirlen
, pathlen
;
5416 ptr
= strrchrW(wildcard
, '\\');
5417 dirlen
= ptr
- wildcard
+ 1;
5419 pathlen
= dirlen
+ lstrlenW(filename
) + 1;
5420 path
= msi_alloc(pathlen
* sizeof(WCHAR
));
5422 lstrcpynW(path
, wildcard
, dirlen
+ 1);
5423 lstrcatW(path
, filename
);
5428 static void free_file_entry(FILE_LIST
*file
)
5430 msi_free(file
->source
);
5431 msi_free(file
->dest
);
5435 static void free_list(FILE_LIST
*list
)
5437 while (!list_empty(&list
->entry
))
5439 FILE_LIST
*file
= LIST_ENTRY(list_head(&list
->entry
), FILE_LIST
, entry
);
5441 list_remove(&file
->entry
);
5442 free_file_entry(file
);
5446 static BOOL
add_wildcard(FILE_LIST
*files
, LPWSTR source
, LPWSTR dest
)
5448 FILE_LIST
*new, *file
;
5449 LPWSTR ptr
, filename
;
5452 new = msi_alloc_zero(sizeof(FILE_LIST
));
5456 new->source
= strdupW(source
);
5457 ptr
= strrchrW(dest
, '\\') + 1;
5458 filename
= strrchrW(new->source
, '\\') + 1;
5460 new->sourcename
= filename
;
5463 new->destname
= ptr
;
5465 new->destname
= new->sourcename
;
5467 size
= (ptr
- dest
) + lstrlenW(filename
) + 1;
5468 new->dest
= msi_alloc(size
* sizeof(WCHAR
));
5471 free_file_entry(new);
5475 lstrcpynW(new->dest
, dest
, ptr
- dest
+ 1);
5476 lstrcatW(new->dest
, filename
);
5478 if (list_empty(&files
->entry
))
5480 list_add_head(&files
->entry
, &new->entry
);
5484 LIST_FOR_EACH_ENTRY(file
, &files
->entry
, FILE_LIST
, entry
)
5486 if (lstrcmpW(source
, file
->source
) < 0)
5488 list_add_before(&file
->entry
, &new->entry
);
5493 list_add_after(&file
->entry
, &new->entry
);
5497 static BOOL
move_files_wildcard(LPWSTR source
, LPWSTR dest
, int options
)
5499 WIN32_FIND_DATAW wfd
;
5503 FILE_LIST files
, *file
;
5506 hfile
= FindFirstFileW(source
, &wfd
);
5507 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
5509 list_init(&files
.entry
);
5511 for (res
= TRUE
; res
; res
= FindNextFileW(hfile
, &wfd
))
5513 if (is_dot_dir(wfd
.cFileName
)) continue;
5515 path
= wildcard_to_file(source
, wfd
.cFileName
);
5522 add_wildcard(&files
, path
, dest
);
5526 /* no files match the wildcard */
5527 if (list_empty(&files
.entry
))
5530 /* only the first wildcard match gets renamed to dest */
5531 file
= LIST_ENTRY(list_head(&files
.entry
), FILE_LIST
, entry
);
5532 size
= (strrchrW(file
->dest
, '\\') - file
->dest
) + lstrlenW(file
->destname
) + 2;
5533 file
->dest
= msi_realloc(file
->dest
, size
* sizeof(WCHAR
));
5540 lstrcpyW(strrchrW(file
->dest
, '\\') + 1, file
->destname
);
5542 while (!list_empty(&files
.entry
))
5544 file
= LIST_ENTRY(list_head(&files
.entry
), FILE_LIST
, entry
);
5546 msi_move_file((LPCWSTR
)file
->source
, (LPCWSTR
)file
->dest
, options
);
5548 list_remove(&file
->entry
);
5549 free_file_entry(file
);
5560 static UINT
ITERATE_MoveFiles( MSIRECORD
*rec
, LPVOID param
)
5562 MSIPACKAGE
*package
= param
;
5565 LPWSTR destname
= NULL
;
5566 LPWSTR sourcedir
= NULL
, destdir
= NULL
;
5567 LPWSTR source
= NULL
, dest
= NULL
;
5570 BOOL ret
, wildcards
;
5572 static const WCHAR backslash
[] = {'\\',0};
5574 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 2));
5575 if (!comp
|| !comp
->Enabled
||
5576 !(comp
->Action
& (INSTALLSTATE_LOCAL
| INSTALLSTATE_SOURCE
)))
5578 TRACE("Component not set for install, not moving file\n");
5579 return ERROR_SUCCESS
;
5582 sourcename
= MSI_RecordGetString(rec
, 3);
5583 options
= MSI_RecordGetInteger(rec
, 7);
5585 sourcedir
= msi_dup_property(package
, MSI_RecordGetString(rec
, 5));
5589 destdir
= msi_dup_property(package
, MSI_RecordGetString(rec
, 6));
5595 if (GetFileAttributesW(sourcedir
) == INVALID_FILE_ATTRIBUTES
)
5598 source
= strdupW(sourcedir
);
5604 size
= lstrlenW(sourcedir
) + lstrlenW(sourcename
) + 2;
5605 source
= msi_alloc(size
* sizeof(WCHAR
));
5609 lstrcpyW(source
, sourcedir
);
5610 if (source
[lstrlenW(source
) - 1] != '\\')
5611 lstrcatW(source
, backslash
);
5612 lstrcatW(source
, sourcename
);
5615 wildcards
= strchrW(source
, '*') || strchrW(source
, '?');
5617 if (MSI_RecordIsNull(rec
, 4))
5621 destname
= strdupW(sourcename
);
5628 destname
= strdupW(MSI_RecordGetString(rec
, 4));
5630 reduce_to_longfilename(destname
);
5635 size
= lstrlenW(destname
);
5637 size
+= lstrlenW(destdir
) + 2;
5638 dest
= msi_alloc(size
* sizeof(WCHAR
));
5642 lstrcpyW(dest
, destdir
);
5643 if (dest
[lstrlenW(dest
) - 1] != '\\')
5644 lstrcatW(dest
, backslash
);
5647 lstrcatW(dest
, destname
);
5649 if (GetFileAttributesW(destdir
) == INVALID_FILE_ATTRIBUTES
)
5651 ret
= CreateDirectoryW(destdir
, NULL
);
5654 WARN("CreateDirectory failed: %d\n", GetLastError());
5655 return ERROR_SUCCESS
;
5660 msi_move_file(source
, dest
, options
);
5662 move_files_wildcard(source
, dest
, options
);
5665 msi_free(sourcedir
);
5671 return ERROR_SUCCESS
;
5674 static UINT
ACTION_MoveFiles( MSIPACKAGE
*package
)
5679 static const WCHAR ExecSeqQuery
[] =
5680 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5681 '`','M','o','v','e','F','i','l','e','`',0};
5683 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5684 if (rc
!= ERROR_SUCCESS
)
5685 return ERROR_SUCCESS
;
5687 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_MoveFiles
, package
);
5688 msiobj_release(&view
->hdr
);
5693 typedef struct tagMSIASSEMBLY
5696 MSICOMPONENT
*component
;
5697 MSIFEATURE
*feature
;
5705 static HRESULT (WINAPI
*pCreateAssemblyCache
)(IAssemblyCache
**ppAsmCache
,
5707 static HRESULT (WINAPI
*pLoadLibraryShim
)(LPCWSTR szDllName
, LPCWSTR szVersion
,
5708 LPVOID pvReserved
, HMODULE
*phModDll
);
5710 static BOOL
init_functionpointers(void)
5716 static const WCHAR szFusion
[] = {'f','u','s','i','o','n','.','d','l','l',0};
5718 hmscoree
= LoadLibraryA("mscoree.dll");
5721 WARN("mscoree.dll not available\n");
5725 pLoadLibraryShim
= (void *)GetProcAddress(hmscoree
, "LoadLibraryShim");
5726 if (!pLoadLibraryShim
)
5728 WARN("LoadLibraryShim not available\n");
5729 FreeLibrary(hmscoree
);
5733 hr
= pLoadLibraryShim(szFusion
, NULL
, NULL
, &hfusion
);
5736 WARN("fusion.dll not available\n");
5737 FreeLibrary(hmscoree
);
5741 pCreateAssemblyCache
= (void *)GetProcAddress(hfusion
, "CreateAssemblyCache");
5743 FreeLibrary(hmscoree
);
5747 static UINT
install_assembly(MSIPACKAGE
*package
, MSIASSEMBLY
*assembly
,
5750 IAssemblyCache
*cache
;
5752 UINT r
= ERROR_FUNCTION_FAILED
;
5754 TRACE("installing assembly: %s\n", debugstr_w(path
));
5756 if (assembly
->feature
)
5757 msi_feature_set_state(package
, assembly
->feature
, INSTALLSTATE_LOCAL
);
5759 if (assembly
->manifest
)
5760 FIXME("Manifest unhandled\n");
5762 if (assembly
->application
)
5764 FIXME("Assembly should be privately installed\n");
5765 return ERROR_SUCCESS
;
5768 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
5770 FIXME("Win32 assemblies not handled\n");
5771 return ERROR_SUCCESS
;
5774 if (!init_functionpointers() || !pCreateAssemblyCache
)
5775 return ERROR_FUNCTION_FAILED
;
5777 hr
= pCreateAssemblyCache(&cache
, 0);
5781 hr
= IAssemblyCache_InstallAssembly(cache
, 0, path
, NULL
);
5783 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path
), hr
);
5788 IAssemblyCache_Release(cache
);
5792 typedef struct tagASSEMBLY_LIST
5794 MSIPACKAGE
*package
;
5795 struct list
*assemblies
;
5798 static UINT
load_assembly(MSIRECORD
*rec
, LPVOID param
)
5800 ASSEMBLY_LIST
*list
= (ASSEMBLY_LIST
*)param
;
5801 MSIASSEMBLY
*assembly
;
5803 assembly
= msi_alloc_zero(sizeof(MSIASSEMBLY
));
5805 return ERROR_OUTOFMEMORY
;
5807 assembly
->component
= get_loaded_component(list
->package
, MSI_RecordGetString(rec
, 1));
5809 if (!assembly
->component
|| !assembly
->component
->Enabled
||
5810 !(assembly
->component
->Action
& (INSTALLSTATE_LOCAL
| INSTALLSTATE_SOURCE
)))
5812 TRACE("Component not set for install, not publishing assembly\n");
5814 return ERROR_SUCCESS
;
5817 assembly
->feature
= find_feature_by_name(list
->package
, MSI_RecordGetString(rec
, 2));
5818 assembly
->file
= msi_find_file(list
->package
, assembly
->component
->KeyPath
);
5820 if (!assembly
->file
)
5822 ERR("File %s not found\n", debugstr_w(assembly
->component
->KeyPath
));
5823 return ERROR_FUNCTION_FAILED
;
5826 assembly
->manifest
= strdupW(MSI_RecordGetString(rec
, 3));
5827 assembly
->application
= strdupW(MSI_RecordGetString(rec
, 4));
5828 assembly
->attributes
= MSI_RecordGetInteger(rec
, 5);
5829 assembly
->installed
= FALSE
;
5831 list_add_head(list
->assemblies
, &assembly
->entry
);
5833 return ERROR_SUCCESS
;
5836 static UINT
load_assemblies(MSIPACKAGE
*package
, struct list
*assemblies
)
5842 static const WCHAR query
[] =
5843 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5844 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
5846 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5847 if (r
!= ERROR_SUCCESS
)
5848 return ERROR_SUCCESS
;
5850 list
.package
= package
;
5851 list
.assemblies
= assemblies
;
5853 r
= MSI_IterateRecords(view
, NULL
, load_assembly
, &list
);
5854 msiobj_release(&view
->hdr
);
5859 static void free_assemblies(struct list
*assemblies
)
5861 struct list
*item
, *cursor
;
5863 LIST_FOR_EACH_SAFE(item
, cursor
, assemblies
)
5865 MSIASSEMBLY
*assembly
= LIST_ENTRY(item
, MSIASSEMBLY
, entry
);
5867 list_remove(&assembly
->entry
);
5868 msi_free(assembly
->application
);
5869 msi_free(assembly
->manifest
);
5874 static BOOL
find_assembly(struct list
*assemblies
, LPCWSTR file
, MSIASSEMBLY
**out
)
5876 MSIASSEMBLY
*assembly
;
5878 LIST_FOR_EACH_ENTRY(assembly
, assemblies
, MSIASSEMBLY
, entry
)
5880 if (!lstrcmpW(assembly
->file
->File
, file
))
5890 static BOOL
installassembly_cb(MSIPACKAGE
*package
, LPCWSTR file
, DWORD action
,
5891 LPWSTR
*path
, DWORD
*attrs
, PVOID user
)
5893 MSIASSEMBLY
*assembly
;
5894 WCHAR temppath
[MAX_PATH
];
5895 struct list
*assemblies
= (struct list
*)user
;
5898 if (!find_assembly(assemblies
, file
, &assembly
))
5901 GetTempPathW(MAX_PATH
, temppath
);
5902 PathAddBackslashW(temppath
);
5903 lstrcatW(temppath
, assembly
->file
->FileName
);
5905 if (action
== MSICABEXTRACT_BEGINEXTRACT
)
5907 if (assembly
->installed
)
5910 *path
= strdupW(temppath
);
5911 *attrs
= assembly
->file
->Attributes
;
5913 else if (action
== MSICABEXTRACT_FILEEXTRACTED
)
5915 assembly
->installed
= TRUE
;
5917 r
= install_assembly(package
, assembly
, temppath
);
5918 if (r
!= ERROR_SUCCESS
)
5919 ERR("Failed to install assembly\n");
5925 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
5928 struct list assemblies
= LIST_INIT(assemblies
);
5929 MSIASSEMBLY
*assembly
;
5932 r
= load_assemblies(package
, &assemblies
);
5933 if (r
!= ERROR_SUCCESS
)
5936 if (list_empty(&assemblies
))
5939 mi
= msi_alloc_zero(sizeof(MSIMEDIAINFO
));
5942 r
= ERROR_OUTOFMEMORY
;
5946 LIST_FOR_EACH_ENTRY(assembly
, &assemblies
, MSIASSEMBLY
, entry
)
5948 if (assembly
->installed
&& !mi
->is_continuous
)
5951 if (assembly
->file
->Sequence
> mi
->last_sequence
|| mi
->is_continuous
||
5952 (assembly
->file
->IsCompressed
&& !mi
->is_extracted
))
5956 r
= ready_media(package
, assembly
->file
, mi
);
5957 if (r
!= ERROR_SUCCESS
)
5959 ERR("Failed to ready media\n");
5964 data
.package
= package
;
5965 data
.cb
= installassembly_cb
;
5966 data
.user
= &assemblies
;
5968 if (assembly
->file
->IsCompressed
&&
5969 !msi_cabextract(package
, mi
, &data
))
5971 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi
->cabinet
));
5972 r
= ERROR_FUNCTION_FAILED
;
5977 if (!assembly
->file
->IsCompressed
)
5979 LPWSTR source
= resolve_file_source(package
, assembly
->file
);
5981 r
= install_assembly(package
, assembly
, source
);
5982 if (r
!= ERROR_SUCCESS
)
5983 ERR("Failed to install assembly\n");
5988 /* FIXME: write Installer assembly reg values */
5992 free_assemblies(&assemblies
);
5996 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
5997 LPCSTR action
, LPCWSTR table
)
5999 static const WCHAR query
[] = {
6000 'S','E','L','E','C','T',' ','*',' ',
6001 'F','R','O','M',' ','`','%','s','`',0 };
6002 MSIQUERY
*view
= NULL
;
6006 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
6007 if (r
== ERROR_SUCCESS
)
6009 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
6010 msiobj_release(&view
->hdr
);
6014 FIXME("%s -> %u ignored %s table values\n",
6015 action
, count
, debugstr_w(table
));
6017 return ERROR_SUCCESS
;
6020 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
6022 TRACE("%p\n", package
);
6023 return ERROR_SUCCESS
;
6026 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
6028 static const WCHAR table
[] =
6029 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
6030 return msi_unimplemented_action_stub( package
, "RemoveIniValues", table
);
6033 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
6035 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
6036 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
6039 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
6041 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
6042 return msi_unimplemented_action_stub( package
, "BindImage", table
);
6045 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
6047 static const WCHAR table
[] = {
6048 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
6049 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
6052 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
6054 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6055 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
6058 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
6060 static const WCHAR table
[] = { 'S','e','l','f','R','e','g',0 };
6061 return msi_unimplemented_action_stub( package
, "SelfUnregModules", table
);
6064 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
6066 static const WCHAR table
[] = {
6067 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6068 return msi_unimplemented_action_stub( package
, "DeleteServices", table
);
6070 static UINT
ACTION_ValidateProductID( MSIPACKAGE
*package
)
6072 static const WCHAR table
[] = {
6073 'P','r','o','d','u','c','t','I','D',0 };
6074 return msi_unimplemented_action_stub( package
, "ValidateProductID", table
);
6077 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
6079 static const WCHAR table
[] = {
6080 'E','n','v','i','r','o','n','m','e','n','t',0 };
6081 return msi_unimplemented_action_stub( package
, "RemoveEnvironmentStrings", table
);
6084 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
6086 static const WCHAR table
[] = {
6087 'M','s','i','A','s','s','e','m','b','l','y',0 };
6088 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
6091 static UINT
ACTION_UnregisterFonts( MSIPACKAGE
*package
)
6093 static const WCHAR table
[] = { 'F','o','n','t',0 };
6094 return msi_unimplemented_action_stub( package
, "UnregisterFonts", table
);
6097 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
6099 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
6100 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
6103 static UINT
ACTION_RegisterComPlus( MSIPACKAGE
*package
)
6105 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6106 return msi_unimplemented_action_stub( package
, "RegisterComPlus", table
);
6109 static UINT
ACTION_UnregisterComPlus( MSIPACKAGE
*package
)
6111 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6112 return msi_unimplemented_action_stub( package
, "UnregisterComPlus", table
);
6115 static UINT
ACTION_InstallSFPCatalogFile( MSIPACKAGE
*package
)
6117 static const WCHAR table
[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6118 return msi_unimplemented_action_stub( package
, "InstallSFPCatalogFile", table
);
6121 static UINT
ACTION_RemoveDuplicateFiles( MSIPACKAGE
*package
)
6123 static const WCHAR table
[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6124 return msi_unimplemented_action_stub( package
, "RemoveDuplicateFiles", table
);
6127 static UINT
ACTION_RemoveExistingProducts( MSIPACKAGE
*package
)
6129 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6130 return msi_unimplemented_action_stub( package
, "RemoveExistingProducts", table
);
6133 static UINT
ACTION_RemoveFolders( MSIPACKAGE
*package
)
6135 static const WCHAR table
[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6136 return msi_unimplemented_action_stub( package
, "RemoveFolders", table
);
6139 static UINT
ACTION_RemoveODBC( MSIPACKAGE
*package
)
6141 static const WCHAR table
[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6142 return msi_unimplemented_action_stub( package
, "RemoveODBC", table
);
6145 static UINT
ACTION_RemoveRegistryValues( MSIPACKAGE
*package
)
6147 static const WCHAR table
[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6148 return msi_unimplemented_action_stub( package
, "RemoveRegistryValues", table
);
6151 static UINT
ACTION_RemoveShortcuts( MSIPACKAGE
*package
)
6153 static const WCHAR table
[] = { 'S','h','o','r','t','c','u','t',0 };
6154 return msi_unimplemented_action_stub( package
, "RemoveShortcuts", table
);
6157 static UINT
ACTION_UnpublishComponents( MSIPACKAGE
*package
)
6159 static const WCHAR table
[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6160 return msi_unimplemented_action_stub( package
, "UnpublishComponents", table
);
6163 static UINT
ACTION_UnregisterClassInfo( MSIPACKAGE
*package
)
6165 static const WCHAR table
[] = { 'A','p','p','I','d',0 };
6166 return msi_unimplemented_action_stub( package
, "UnregisterClassInfo", table
);
6169 static UINT
ACTION_UnregisterExtensionInfo( MSIPACKAGE
*package
)
6171 static const WCHAR table
[] = { 'E','x','t','e','n','s','i','o','n',0 };
6172 return msi_unimplemented_action_stub( package
, "UnregisterExtensionInfo", table
);
6175 static UINT
ACTION_UnregisterMIMEInfo( MSIPACKAGE
*package
)
6177 static const WCHAR table
[] = { 'M','I','M','E',0 };
6178 return msi_unimplemented_action_stub( package
, "UnregisterMIMEInfo", table
);
6181 static UINT
ACTION_UnregisterProgIdInfo( MSIPACKAGE
*package
)
6183 static const WCHAR table
[] = { 'P','r','o','g','I','d',0 };
6184 return msi_unimplemented_action_stub( package
, "UnregisterProgIdInfo", table
);
6187 static UINT
ACTION_UnregisterTypeLibraries( MSIPACKAGE
*package
)
6189 static const WCHAR table
[] = { 'T','y','p','e','L','i','b',0 };
6190 return msi_unimplemented_action_stub( package
, "UnregisterTypeLibraries", table
);
6193 static const struct _actions StandardActions
[] = {
6194 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
6195 { szAppSearch
, ACTION_AppSearch
},
6196 { szBindImage
, ACTION_BindImage
},
6197 { szCCPSearch
, ACTION_CCPSearch
},
6198 { szCostFinalize
, ACTION_CostFinalize
},
6199 { szCostInitialize
, ACTION_CostInitialize
},
6200 { szCreateFolders
, ACTION_CreateFolders
},
6201 { szCreateShortcuts
, ACTION_CreateShortcuts
},
6202 { szDeleteServices
, ACTION_DeleteServices
},
6203 { szDisableRollback
, NULL
},
6204 { szDuplicateFiles
, ACTION_DuplicateFiles
},
6205 { szExecuteAction
, ACTION_ExecuteAction
},
6206 { szFileCost
, ACTION_FileCost
},
6207 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
6208 { szForceReboot
, ACTION_ForceReboot
},
6209 { szInstallAdminPackage
, NULL
},
6210 { szInstallExecute
, ACTION_InstallExecute
},
6211 { szInstallExecuteAgain
, ACTION_InstallExecute
},
6212 { szInstallFiles
, ACTION_InstallFiles
},
6213 { szInstallFinalize
, ACTION_InstallFinalize
},
6214 { szInstallInitialize
, ACTION_InstallInitialize
},
6215 { szInstallSFPCatalogFile
, ACTION_InstallSFPCatalogFile
},
6216 { szInstallValidate
, ACTION_InstallValidate
},
6217 { szIsolateComponents
, ACTION_IsolateComponents
},
6218 { szLaunchConditions
, ACTION_LaunchConditions
},
6219 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
6220 { szMoveFiles
, ACTION_MoveFiles
},
6221 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
6222 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
6223 { szInstallODBC
, ACTION_InstallODBC
},
6224 { szInstallServices
, ACTION_InstallServices
},
6225 { szPatchFiles
, ACTION_PatchFiles
},
6226 { szProcessComponents
, ACTION_ProcessComponents
},
6227 { szPublishComponents
, ACTION_PublishComponents
},
6228 { szPublishFeatures
, ACTION_PublishFeatures
},
6229 { szPublishProduct
, ACTION_PublishProduct
},
6230 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
6231 { szRegisterComPlus
, ACTION_RegisterComPlus
},
6232 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
6233 { szRegisterFonts
, ACTION_RegisterFonts
},
6234 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
6235 { szRegisterProduct
, ACTION_RegisterProduct
},
6236 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
6237 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
6238 { szRegisterUser
, ACTION_RegisterUser
},
6239 { szRemoveDuplicateFiles
, ACTION_RemoveDuplicateFiles
},
6240 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
6241 { szRemoveExistingProducts
, ACTION_RemoveExistingProducts
},
6242 { szRemoveFiles
, ACTION_RemoveFiles
},
6243 { szRemoveFolders
, ACTION_RemoveFolders
},
6244 { szRemoveIniValues
, ACTION_RemoveIniValues
},
6245 { szRemoveODBC
, ACTION_RemoveODBC
},
6246 { szRemoveRegistryValues
, ACTION_RemoveRegistryValues
},
6247 { szRemoveShortcuts
, ACTION_RemoveShortcuts
},
6248 { szResolveSource
, ACTION_ResolveSource
},
6249 { szRMCCPSearch
, ACTION_RMCCPSearch
},
6250 { szScheduleReboot
, NULL
},
6251 { szSelfRegModules
, ACTION_SelfRegModules
},
6252 { szSelfUnregModules
, ACTION_SelfUnregModules
},
6253 { szSetODBCFolders
, NULL
},
6254 { szStartServices
, ACTION_StartServices
},
6255 { szStopServices
, ACTION_StopServices
},
6256 { szUnpublishComponents
, ACTION_UnpublishComponents
},
6257 { szUnpublishFeatures
, ACTION_UnpublishFeatures
},
6258 { szUnregisterClassInfo
, ACTION_UnregisterClassInfo
},
6259 { szUnregisterComPlus
, ACTION_UnregisterComPlus
},
6260 { szUnregisterExtensionInfo
, ACTION_UnregisterExtensionInfo
},
6261 { szUnregisterFonts
, ACTION_UnregisterFonts
},
6262 { szUnregisterMIMEInfo
, ACTION_UnregisterMIMEInfo
},
6263 { szUnregisterProgIdInfo
, ACTION_UnregisterProgIdInfo
},
6264 { szUnregisterTypeLibraries
, ACTION_UnregisterTypeLibraries
},
6265 { szValidateProductID
, ACTION_ValidateProductID
},
6266 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
6267 { szWriteIniValues
, ACTION_WriteIniValues
},
6268 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
6272 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
6273 UINT
* rc
, BOOL force
)
6279 if (!run
&& !package
->script
->CurrentlyScripting
)
6284 if (strcmpW(action
,szInstallFinalize
) == 0 ||
6285 strcmpW(action
,szInstallExecute
) == 0 ||
6286 strcmpW(action
,szInstallExecuteAgain
) == 0)
6291 while (StandardActions
[i
].action
!= NULL
)
6293 if (strcmpW(StandardActions
[i
].action
, action
)==0)
6297 ui_actioninfo(package
, action
, TRUE
, 0);
6298 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
6299 ui_actioninfo(package
, action
, FALSE
, *rc
);
6303 ui_actionstart(package
, action
);
6304 if (StandardActions
[i
].handler
)
6306 *rc
= StandardActions
[i
].handler(package
);
6310 FIXME("unhandled standard action %s\n",debugstr_w(action
));
6311 *rc
= ERROR_SUCCESS
;