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
,
297 LPWSTR prop
= NULL
, val
= NULL
;
300 return ERROR_SUCCESS
;
312 TRACE("Looking at %s\n",debugstr_w(ptr
));
314 ptr2
= strchrW(ptr
,'=');
317 ERR("command line contains unknown string : %s\n", debugstr_w(ptr
));
324 prop
= msi_alloc((len
+1)*sizeof(WCHAR
));
325 memcpy(prop
,ptr
,len
*sizeof(WCHAR
));
335 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
348 val
= msi_alloc((len
+1)*sizeof(WCHAR
));
349 memcpy(val
,ptr2
,len
*sizeof(WCHAR
));
352 if (lstrlenW(prop
) > 0)
354 TRACE("Found commandline property (%s) = (%s)\n",
355 debugstr_w(prop
), debugstr_w(val
));
356 MSI_SetPropertyW(package
,prop
,val
);
362 return ERROR_SUCCESS
;
366 static LPWSTR
* msi_split_string( LPCWSTR str
, WCHAR sep
)
369 LPWSTR p
, *ret
= NULL
;
375 /* count the number of substrings */
376 for ( pc
= str
, count
= 0; pc
; count
++ )
378 pc
= strchrW( pc
, sep
);
383 /* allocate space for an array of substring pointers and the substrings */
384 ret
= msi_alloc( (count
+1) * sizeof (LPWSTR
) +
385 (lstrlenW(str
)+1) * sizeof(WCHAR
) );
389 /* copy the string and set the pointers */
390 p
= (LPWSTR
) &ret
[count
+1];
392 for( count
= 0; (ret
[count
] = p
); count
++ )
394 p
= strchrW( p
, sep
);
402 static UINT
msi_check_transform_applicable( MSIPACKAGE
*package
, IStorage
*patch
)
404 WCHAR szProductCode
[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
405 LPWSTR prod_code
, patch_product
;
408 prod_code
= msi_dup_property( package
, szProductCode
);
409 patch_product
= msi_get_suminfo_product( patch
);
411 TRACE("db = %s patch = %s\n", debugstr_w(prod_code
), debugstr_w(patch_product
));
413 if ( strstrW( patch_product
, prod_code
) )
416 ret
= ERROR_FUNCTION_FAILED
;
418 msi_free( patch_product
);
419 msi_free( prod_code
);
424 static UINT
msi_apply_substorage_transform( MSIPACKAGE
*package
,
425 MSIDATABASE
*patch_db
, LPCWSTR name
)
427 UINT ret
= ERROR_FUNCTION_FAILED
;
428 IStorage
*stg
= NULL
;
431 TRACE("%p %s\n", package
, debugstr_w(name
) );
435 ERR("expected a colon in %s\n", debugstr_w(name
));
436 return ERROR_FUNCTION_FAILED
;
439 r
= IStorage_OpenStorage( patch_db
->storage
, name
, NULL
, STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
442 ret
= msi_check_transform_applicable( package
, stg
);
443 if (ret
== ERROR_SUCCESS
)
444 msi_table_apply_transform( package
->db
, stg
);
446 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name
));
447 IStorage_Release( stg
);
450 ERR("failed to open substorage %s\n", debugstr_w(name
));
452 return ERROR_SUCCESS
;
455 static UINT
msi_check_patch_applicable( MSIPACKAGE
*package
, MSISUMMARYINFO
*si
)
457 static const WCHAR szProdCode
[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
458 LPWSTR guid_list
, *guids
, product_code
;
459 UINT i
, ret
= ERROR_FUNCTION_FAILED
;
461 product_code
= msi_dup_property( package
, szProdCode
);
464 /* FIXME: the property ProductCode should be written into the DB somewhere */
465 ERR("no product code to check\n");
466 return ERROR_SUCCESS
;
469 guid_list
= msi_suminfo_dup_string( si
, PID_TEMPLATE
);
470 guids
= msi_split_string( guid_list
, ';' );
471 for ( i
= 0; guids
[i
] && ret
!= ERROR_SUCCESS
; i
++ )
473 if (!lstrcmpW( guids
[i
], product_code
))
477 msi_free( guid_list
);
478 msi_free( product_code
);
483 static UINT
msi_parse_patch_summary( MSIPACKAGE
*package
, MSIDATABASE
*patch_db
)
486 LPWSTR str
, *substorage
;
487 UINT i
, r
= ERROR_SUCCESS
;
489 si
= MSI_GetSummaryInformationW( patch_db
->storage
, 0 );
491 return ERROR_FUNCTION_FAILED
;
493 msi_check_patch_applicable( package
, si
);
495 /* enumerate the substorage */
496 str
= msi_suminfo_dup_string( si
, PID_LASTAUTHOR
);
497 substorage
= msi_split_string( str
, ';' );
498 for ( i
= 0; substorage
&& substorage
[i
] && r
== ERROR_SUCCESS
; i
++ )
499 r
= msi_apply_substorage_transform( package
, patch_db
, substorage
[i
] );
500 msi_free( substorage
);
503 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
505 msiobj_release( &si
->hdr
);
510 static UINT
msi_apply_patch_package( MSIPACKAGE
*package
, LPCWSTR file
)
512 MSIDATABASE
*patch_db
= NULL
;
515 TRACE("%p %s\n", package
, debugstr_w( file
) );
518 * We probably want to make sure we only open a patch collection here.
519 * Patch collections (.msp) and databases (.msi) have different GUIDs
520 * but currently MSI_OpenDatabaseW will accept both.
522 r
= MSI_OpenDatabaseW( file
, MSIDBOPEN_READONLY
, &patch_db
);
523 if ( r
!= ERROR_SUCCESS
)
525 ERR("failed to open patch collection %s\n", debugstr_w( file
) );
529 msi_parse_patch_summary( package
, patch_db
);
532 * There might be a CAB file in the patch package,
533 * so append it to the list of storage to search for streams.
535 append_storage_to_db( package
->db
, patch_db
->storage
);
537 msiobj_release( &patch_db
->hdr
);
539 return ERROR_SUCCESS
;
542 /* get the PATCH property, and apply all the patches it specifies */
543 static UINT
msi_apply_patches( MSIPACKAGE
*package
)
545 static const WCHAR szPatch
[] = { 'P','A','T','C','H',0 };
546 LPWSTR patch_list
, *patches
;
547 UINT i
, r
= ERROR_SUCCESS
;
549 patch_list
= msi_dup_property( package
, szPatch
);
551 TRACE("patches to be applied: %s\n", debugstr_w( patch_list
) );
553 patches
= msi_split_string( patch_list
, ';' );
554 for( i
=0; patches
&& patches
[i
] && r
== ERROR_SUCCESS
; i
++ )
555 r
= msi_apply_patch_package( package
, patches
[i
] );
558 msi_free( patch_list
);
563 static UINT
msi_apply_transforms( MSIPACKAGE
*package
)
565 static const WCHAR szTransforms
[] = {
566 'T','R','A','N','S','F','O','R','M','S',0 };
567 LPWSTR xform_list
, *xforms
;
568 UINT i
, r
= ERROR_SUCCESS
;
570 xform_list
= msi_dup_property( package
, szTransforms
);
571 xforms
= msi_split_string( xform_list
, ';' );
573 for( i
=0; xforms
&& xforms
[i
] && r
== ERROR_SUCCESS
; i
++ )
575 if (xforms
[i
][0] == ':')
576 r
= msi_apply_substorage_transform( package
, package
->db
, xforms
[i
] );
578 r
= MSI_DatabaseApplyTransformW( package
->db
, xforms
[i
], 0 );
582 msi_free( xform_list
);
587 static BOOL
ui_sequence_exists( MSIPACKAGE
*package
)
592 static const WCHAR ExecSeqQuery
[] =
593 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
594 '`','I','n','s','t','a','l','l',
595 'U','I','S','e','q','u','e','n','c','e','`',
596 ' ','W','H','E','R','E',' ',
597 '`','S','e','q','u','e','n','c','e','`',' ',
598 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
599 '`','S','e','q','u','e','n','c','e','`',0};
601 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
602 if (rc
== ERROR_SUCCESS
)
604 msiobj_release(&view
->hdr
);
611 static UINT
msi_set_sourcedir_props(MSIPACKAGE
*package
, BOOL replace
)
614 LPWSTR source
, check
;
617 static const WCHAR szOriginalDatabase
[] =
618 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
620 db
= msi_dup_property( package
, szOriginalDatabase
);
622 return ERROR_OUTOFMEMORY
;
624 p
= strrchrW( db
, '\\' );
627 p
= strrchrW( db
, '/' );
631 return ERROR_SUCCESS
;
636 source
= msi_alloc( len
* sizeof(WCHAR
) );
637 lstrcpynW( source
, db
, len
);
639 check
= msi_dup_property( package
, cszSourceDir
);
640 if (!check
|| replace
)
641 MSI_SetPropertyW( package
, cszSourceDir
, source
);
645 check
= msi_dup_property( package
, cszSOURCEDIR
);
646 if (!check
|| replace
)
647 MSI_SetPropertyW( package
, cszSOURCEDIR
, source
);
653 return ERROR_SUCCESS
;
656 static UINT
msi_set_context(MSIPACKAGE
*package
)
663 static const WCHAR szOne
[] = {'1',0};
664 static const WCHAR szAllUsers
[] = {'A','L','L','U','S','E','R','S',0};
666 package
->Context
= MSIINSTALLCONTEXT_USERUNMANAGED
;
668 r
= MSI_GetPropertyW(package
, szAllUsers
, val
, &sz
);
669 if (r
== ERROR_SUCCESS
)
672 if (num
== 1 || num
== 2)
673 package
->Context
= MSIINSTALLCONTEXT_MACHINE
;
676 MSI_SetPropertyW(package
, szAllUsers
, szOne
);
677 return ERROR_SUCCESS
;
680 /****************************************************
681 * TOP level entry points
682 *****************************************************/
684 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
685 LPCWSTR szCommandLine
)
688 BOOL ui
= FALSE
, ui_exists
;
689 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
690 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
691 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
693 MSI_SetPropertyW(package
, szAction
, szInstall
);
695 package
->script
= msi_alloc_zero(sizeof(MSISCRIPT
));
697 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
704 dir
= strdupW(szPackagePath
);
705 p
= strrchrW(dir
, '\\');
709 file
= szPackagePath
+ (p
- dir
);
714 dir
= msi_alloc(MAX_PATH
*sizeof(WCHAR
));
715 GetCurrentDirectoryW(MAX_PATH
, dir
);
716 lstrcatW(dir
, cszbs
);
717 file
= szPackagePath
;
720 msi_free( package
->PackagePath
);
721 package
->PackagePath
= msi_alloc((lstrlenW(dir
) + lstrlenW(file
) + 1) * sizeof(WCHAR
));
722 if (!package
->PackagePath
)
725 return ERROR_OUTOFMEMORY
;
728 lstrcpyW(package
->PackagePath
, dir
);
729 lstrcatW(package
->PackagePath
, file
);
732 msi_set_sourcedir_props(package
, FALSE
);
735 msi_parse_command_line( package
, szCommandLine
, FALSE
);
737 msi_apply_transforms( package
);
738 msi_apply_patches( package
);
740 /* properties may have been added by a transform */
741 msi_clone_properties( package
);
742 msi_set_context( package
);
744 if ( (msi_get_property_int(package
, szUILevel
, 0) & INSTALLUILEVEL_MASK
) >= INSTALLUILEVEL_REDUCED
)
746 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
747 rc
= ACTION_ProcessUISequence(package
);
749 ui_exists
= ui_sequence_exists(package
);
750 if (rc
== ERROR_SUCCESS
|| !ui_exists
)
752 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
753 rc
= ACTION_ProcessExecSequence(package
,ui_exists
);
757 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
759 package
->script
->CurrentlyScripting
= FALSE
;
761 /* process the ending type action */
762 if (rc
== ERROR_SUCCESS
)
763 ACTION_PerformActionSequence(package
,-1,ui
);
764 else if (rc
== ERROR_INSTALL_USEREXIT
)
765 ACTION_PerformActionSequence(package
,-2,ui
);
766 else if (rc
== ERROR_INSTALL_SUSPEND
)
767 ACTION_PerformActionSequence(package
,-4,ui
);
769 ACTION_PerformActionSequence(package
,-3,ui
);
771 /* finish up running custom actions */
772 ACTION_FinishCustomActions(package
);
777 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
)
779 UINT rc
= ERROR_SUCCESS
;
781 static const WCHAR ExecSeqQuery
[] =
782 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
783 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
784 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
785 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
787 static const WCHAR UISeqQuery
[] =
788 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
789 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
790 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
791 ' ', '=',' ','%','i',0};
794 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
796 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
800 LPCWSTR action
, cond
;
802 TRACE("Running the actions\n");
804 /* check conditions */
805 cond
= MSI_RecordGetString(row
,2);
807 /* this is a hack to skip errors in the condition code */
808 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
811 action
= MSI_RecordGetString(row
,1);
814 ERR("failed to fetch action\n");
815 rc
= ERROR_FUNCTION_FAILED
;
820 rc
= ACTION_PerformUIAction(package
,action
,-1);
822 rc
= ACTION_PerformAction(package
,action
,-1,FALSE
);
824 msiobj_release(&row
->hdr
);
835 } iterate_action_param
;
837 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
839 iterate_action_param
*iap
= (iterate_action_param
*)param
;
841 LPCWSTR cond
, action
;
843 action
= MSI_RecordGetString(row
,1);
846 ERR("Error is retrieving action name\n");
847 return ERROR_FUNCTION_FAILED
;
850 /* check conditions */
851 cond
= MSI_RecordGetString(row
,2);
853 /* this is a hack to skip errors in the condition code */
854 if (MSI_EvaluateConditionW(iap
->package
, cond
) == MSICONDITION_FALSE
)
856 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action
));
857 return ERROR_SUCCESS
;
861 rc
= ACTION_PerformUIAction(iap
->package
,action
,-1);
863 rc
= ACTION_PerformAction(iap
->package
,action
,-1,FALSE
);
865 msi_dialog_check_messages( NULL
);
867 if (iap
->package
->CurrentInstallState
!= ERROR_SUCCESS
)
868 rc
= iap
->package
->CurrentInstallState
;
870 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
873 if (rc
!= ERROR_SUCCESS
)
874 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
879 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
883 static const WCHAR query
[] =
884 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
886 ' ','W','H','E','R','E',' ',
887 '`','S','e','q','u','e','n','c','e','`',' ',
888 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
889 '`','S','e','q','u','e','n','c','e','`',0};
890 iterate_action_param iap
;
893 * FIXME: probably should be checking UILevel in the
894 * ACTION_PerformUIAction/ACTION_PerformAction
895 * rather than saving the UI level here. Those
896 * two functions can be merged too.
898 iap
.package
= package
;
901 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
903 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
904 if (r
== ERROR_SUCCESS
)
906 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, &iap
);
907 msiobj_release(&view
->hdr
);
913 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
917 static const WCHAR ExecSeqQuery
[] =
918 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
919 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
920 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
921 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
922 'O','R','D','E','R',' ', 'B','Y',' ',
923 '`','S','e','q','u','e','n','c','e','`',0 };
925 static const WCHAR IVQuery
[] =
926 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
927 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
928 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
929 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
930 ' ','\'', 'I','n','s','t','a','l','l',
931 'V','a','l','i','d','a','t','e','\'', 0};
933 iterate_action_param iap
;
935 iap
.package
= package
;
938 if (package
->script
->ExecuteSequenceRun
)
940 TRACE("Execute Sequence already Run\n");
941 return ERROR_SUCCESS
;
944 package
->script
->ExecuteSequenceRun
= TRUE
;
946 /* get the sequence number */
949 row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
951 return ERROR_FUNCTION_FAILED
;
952 seq
= MSI_RecordGetInteger(row
,1);
953 msiobj_release(&row
->hdr
);
956 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
957 if (rc
== ERROR_SUCCESS
)
959 TRACE("Running the actions\n");
961 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
962 msiobj_release(&view
->hdr
);
968 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
972 static const WCHAR ExecSeqQuery
[] =
973 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
974 '`','I','n','s','t','a','l','l',
975 'U','I','S','e','q','u','e','n','c','e','`',
976 ' ','W','H','E','R','E',' ',
977 '`','S','e','q','u','e','n','c','e','`',' ',
978 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
979 '`','S','e','q','u','e','n','c','e','`',0};
980 iterate_action_param iap
;
982 iap
.package
= package
;
985 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
987 if (rc
== ERROR_SUCCESS
)
989 TRACE("Running the actions\n");
991 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
992 msiobj_release(&view
->hdr
);
998 /********************************************************
999 * ACTION helper functions and functions that perform the actions
1000 *******************************************************/
1001 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
1002 UINT
* rc
, UINT script
, BOOL force
)
1007 arc
= ACTION_CustomAction(package
, action
, script
, force
);
1009 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
1018 * A lot of actions are really important even if they don't do anything
1019 * explicit... Lots of properties are set at the beginning of the installation
1020 * CostFinalize does a bunch of work to translate the directories and such
1022 * But until I get write access to the database that is hard, so I am going to
1023 * hack it to see if I can get something to run.
1025 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
, BOOL force
)
1027 UINT rc
= ERROR_SUCCESS
;
1030 TRACE("Performing action (%s)\n",debugstr_w(action
));
1032 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
1035 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, force
);
1039 WARN("unhandled msi action %s\n",debugstr_w(action
));
1040 rc
= ERROR_FUNCTION_NOT_CALLED
;
1046 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
)
1048 UINT rc
= ERROR_SUCCESS
;
1049 BOOL handled
= FALSE
;
1051 TRACE("Performing action (%s)\n",debugstr_w(action
));
1053 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
1056 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, FALSE
);
1058 if( !handled
&& ACTION_DialogBox(package
,action
) == ERROR_SUCCESS
)
1063 WARN("unhandled msi action %s\n",debugstr_w(action
));
1064 rc
= ERROR_FUNCTION_NOT_CALLED
;
1072 * Actual Action Handlers
1075 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
1077 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1083 dir
= MSI_RecordGetString(row
,1);
1086 ERR("Unable to get folder id\n");
1087 return ERROR_SUCCESS
;
1090 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,TRUE
,&folder
);
1093 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
1094 return ERROR_SUCCESS
;
1097 TRACE("Folder is %s\n",debugstr_w(full_path
));
1100 uirow
= MSI_CreateRecord(1);
1101 MSI_RecordSetStringW(uirow
,1,full_path
);
1102 ui_actiondata(package
,szCreateFolders
,uirow
);
1103 msiobj_release( &uirow
->hdr
);
1105 if (folder
->State
== 0)
1106 create_full_pathW(full_path
);
1110 msi_free(full_path
);
1111 return ERROR_SUCCESS
;
1114 /* FIXME: probably should merge this with the above function */
1115 static UINT
msi_create_directory( MSIPACKAGE
* package
, LPCWSTR dir
)
1117 UINT rc
= ERROR_SUCCESS
;
1119 LPWSTR install_path
;
1121 install_path
= resolve_folder(package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
1123 return ERROR_FUNCTION_FAILED
;
1125 /* create the path */
1126 if (folder
->State
== 0)
1128 create_full_pathW(install_path
);
1131 msi_free(install_path
);
1136 UINT
msi_create_component_directories( MSIPACKAGE
*package
)
1140 /* create all the folders required by the components are going to install */
1141 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1143 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
1145 msi_create_directory( package
, comp
->Directory
);
1148 return ERROR_SUCCESS
;
1152 * Also we cannot enable/disable components either, so for now I am just going
1153 * to do all the directories for all the components.
1155 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1157 static const WCHAR ExecSeqQuery
[] =
1158 {'S','E','L','E','C','T',' ',
1159 '`','D','i','r','e','c','t','o','r','y','_','`',
1160 ' ','F','R','O','M',' ',
1161 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1165 /* create all the empty folders specified in the CreateFolder table */
1166 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1167 if (rc
!= ERROR_SUCCESS
)
1168 return ERROR_SUCCESS
;
1170 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
1171 msiobj_release(&view
->hdr
);
1173 msi_create_component_directories( package
);
1178 static UINT
load_component( MSIRECORD
*row
, LPVOID param
)
1180 MSIPACKAGE
*package
= param
;
1183 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1185 return ERROR_FUNCTION_FAILED
;
1187 list_add_tail( &package
->components
, &comp
->entry
);
1189 /* fill in the data */
1190 comp
->Component
= msi_dup_record_field( row
, 1 );
1192 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1194 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1195 comp
->Directory
= msi_dup_record_field( row
, 3 );
1196 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1197 comp
->Condition
= msi_dup_record_field( row
, 5 );
1198 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1200 comp
->Installed
= INSTALLSTATE_UNKNOWN
;
1201 msi_component_set_state(package
, comp
, INSTALLSTATE_UNKNOWN
);
1203 return ERROR_SUCCESS
;
1206 static UINT
load_all_components( MSIPACKAGE
*package
)
1208 static const WCHAR query
[] = {
1209 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1210 '`','C','o','m','p','o','n','e','n','t','`',0 };
1214 if (!list_empty(&package
->components
))
1215 return ERROR_SUCCESS
;
1217 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1218 if (r
!= ERROR_SUCCESS
)
1221 r
= MSI_IterateRecords(view
, NULL
, load_component
, package
);
1222 msiobj_release(&view
->hdr
);
1227 MSIPACKAGE
*package
;
1228 MSIFEATURE
*feature
;
1231 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1235 cl
= msi_alloc( sizeof (*cl
) );
1237 return ERROR_NOT_ENOUGH_MEMORY
;
1238 cl
->component
= comp
;
1239 list_add_tail( &feature
->Components
, &cl
->entry
);
1241 return ERROR_SUCCESS
;
1244 static UINT
add_feature_child( MSIFEATURE
*parent
, MSIFEATURE
*child
)
1248 fl
= msi_alloc( sizeof(*fl
) );
1250 return ERROR_NOT_ENOUGH_MEMORY
;
1251 fl
->feature
= child
;
1252 list_add_tail( &parent
->Children
, &fl
->entry
);
1254 return ERROR_SUCCESS
;
1257 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1259 _ilfs
* ilfs
= (_ilfs
*)param
;
1263 component
= MSI_RecordGetString(row
,1);
1265 /* check to see if the component is already loaded */
1266 comp
= get_loaded_component( ilfs
->package
, component
);
1269 ERR("unknown component %s\n", debugstr_w(component
));
1270 return ERROR_FUNCTION_FAILED
;
1273 add_feature_component( ilfs
->feature
, comp
);
1274 comp
->Enabled
= TRUE
;
1276 return ERROR_SUCCESS
;
1279 static MSIFEATURE
*find_feature_by_name( MSIPACKAGE
*package
, LPCWSTR name
)
1281 MSIFEATURE
*feature
;
1286 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1288 if ( !lstrcmpW( feature
->Feature
, name
) )
1295 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1297 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1298 MSIFEATURE
* feature
;
1299 static const WCHAR Query1
[] =
1300 {'S','E','L','E','C','T',' ',
1301 '`','C','o','m','p','o','n','e','n','t','_','`',
1302 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1303 'C','o','m','p','o','n','e','n','t','s','`',' ',
1304 'W','H','E','R','E',' ',
1305 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1310 /* fill in the data */
1312 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1314 return ERROR_NOT_ENOUGH_MEMORY
;
1316 list_init( &feature
->Children
);
1317 list_init( &feature
->Components
);
1319 feature
->Feature
= msi_dup_record_field( row
, 1 );
1321 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1323 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1324 feature
->Title
= msi_dup_record_field( row
, 3 );
1325 feature
->Description
= msi_dup_record_field( row
, 4 );
1327 if (!MSI_RecordIsNull(row
,5))
1328 feature
->Display
= MSI_RecordGetInteger(row
,5);
1330 feature
->Level
= MSI_RecordGetInteger(row
,6);
1331 feature
->Directory
= msi_dup_record_field( row
, 7 );
1332 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1334 feature
->Installed
= INSTALLSTATE_UNKNOWN
;
1335 msi_feature_set_state(package
, feature
, INSTALLSTATE_UNKNOWN
);
1337 list_add_tail( &package
->features
, &feature
->entry
);
1339 /* load feature components */
1341 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1342 if (rc
!= ERROR_SUCCESS
)
1343 return ERROR_SUCCESS
;
1345 ilfs
.package
= package
;
1346 ilfs
.feature
= feature
;
1348 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1349 msiobj_release(&view
->hdr
);
1351 return ERROR_SUCCESS
;
1354 static UINT
find_feature_children(MSIRECORD
* row
, LPVOID param
)
1356 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1357 MSIFEATURE
*parent
, *child
;
1359 child
= find_feature_by_name( package
, MSI_RecordGetString( row
, 1 ) );
1361 return ERROR_FUNCTION_FAILED
;
1363 if (!child
->Feature_Parent
)
1364 return ERROR_SUCCESS
;
1366 parent
= find_feature_by_name( package
, child
->Feature_Parent
);
1368 return ERROR_FUNCTION_FAILED
;
1370 add_feature_child( parent
, child
);
1371 return ERROR_SUCCESS
;
1374 static UINT
load_all_features( MSIPACKAGE
*package
)
1376 static const WCHAR query
[] = {
1377 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1378 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1379 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1383 if (!list_empty(&package
->features
))
1384 return ERROR_SUCCESS
;
1386 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1387 if (r
!= ERROR_SUCCESS
)
1390 r
= MSI_IterateRecords( view
, NULL
, load_feature
, package
);
1391 if (r
!= ERROR_SUCCESS
)
1394 r
= MSI_IterateRecords( view
, NULL
, find_feature_children
, package
);
1395 msiobj_release( &view
->hdr
);
1400 static LPWSTR
folder_split_path(LPWSTR p
, WCHAR ch
)
1411 static UINT
load_file_hash(MSIPACKAGE
*package
, MSIFILE
*file
)
1413 static const WCHAR query
[] = {
1414 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1415 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1416 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1417 MSIQUERY
*view
= NULL
;
1418 MSIRECORD
*row
= NULL
;
1421 TRACE("%s\n", debugstr_w(file
->File
));
1423 r
= MSI_OpenQuery(package
->db
, &view
, query
, file
->File
);
1424 if (r
!= ERROR_SUCCESS
)
1427 r
= MSI_ViewExecute(view
, NULL
);
1428 if (r
!= ERROR_SUCCESS
)
1431 r
= MSI_ViewFetch(view
, &row
);
1432 if (r
!= ERROR_SUCCESS
)
1435 file
->hash
.dwFileHashInfoSize
= sizeof(MSIFILEHASHINFO
);
1436 file
->hash
.dwData
[0] = MSI_RecordGetInteger(row
, 3);
1437 file
->hash
.dwData
[1] = MSI_RecordGetInteger(row
, 4);
1438 file
->hash
.dwData
[2] = MSI_RecordGetInteger(row
, 5);
1439 file
->hash
.dwData
[3] = MSI_RecordGetInteger(row
, 6);
1442 if (view
) msiobj_release(&view
->hdr
);
1443 if (row
) msiobj_release(&row
->hdr
);
1447 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1449 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1453 /* fill in the data */
1455 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1457 return ERROR_NOT_ENOUGH_MEMORY
;
1459 file
->File
= msi_dup_record_field( row
, 1 );
1461 component
= MSI_RecordGetString( row
, 2 );
1462 file
->Component
= get_loaded_component( package
, component
);
1464 if (!file
->Component
)
1466 WARN("Component not found: %s\n", debugstr_w(component
));
1467 msi_free(file
->File
);
1469 return ERROR_SUCCESS
;
1472 file
->FileName
= msi_dup_record_field( row
, 3 );
1473 reduce_to_longfilename( file
->FileName
);
1475 file
->ShortName
= msi_dup_record_field( row
, 3 );
1476 file
->LongName
= strdupW( folder_split_path(file
->ShortName
, '|'));
1478 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1479 file
->Version
= msi_dup_record_field( row
, 5 );
1480 file
->Language
= msi_dup_record_field( row
, 6 );
1481 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1482 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1484 file
->state
= msifs_invalid
;
1486 /* if the compressed bits are not set in the file attributes,
1487 * then read the information from the package word count property
1489 if (package
->WordCount
& msidbSumInfoSourceTypeAdminImage
)
1491 file
->IsCompressed
= FALSE
;
1493 else if (file
->Attributes
&
1494 (msidbFileAttributesCompressed
| msidbFileAttributesPatchAdded
))
1496 file
->IsCompressed
= TRUE
;
1498 else if (file
->Attributes
& msidbFileAttributesNoncompressed
)
1500 file
->IsCompressed
= FALSE
;
1504 file
->IsCompressed
= package
->WordCount
& msidbSumInfoSourceTypeCompressed
;
1507 load_file_hash(package
, file
);
1509 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1511 list_add_tail( &package
->files
, &file
->entry
);
1513 return ERROR_SUCCESS
;
1516 static UINT
load_all_files(MSIPACKAGE
*package
)
1520 static const WCHAR Query
[] =
1521 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1522 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1523 '`','S','e','q','u','e','n','c','e','`', 0};
1525 if (!list_empty(&package
->files
))
1526 return ERROR_SUCCESS
;
1528 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1529 if (rc
!= ERROR_SUCCESS
)
1530 return ERROR_SUCCESS
;
1532 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1533 msiobj_release(&view
->hdr
);
1535 return ERROR_SUCCESS
;
1538 static UINT
load_folder( MSIRECORD
*row
, LPVOID param
)
1540 MSIPACKAGE
*package
= param
;
1541 static const WCHAR szDot
[] = { '.',0 };
1542 static WCHAR szEmpty
[] = { 0 };
1543 LPWSTR p
, tgt_short
, tgt_long
, src_short
, src_long
;
1546 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1548 return ERROR_NOT_ENOUGH_MEMORY
;
1550 folder
->Directory
= msi_dup_record_field( row
, 1 );
1552 TRACE("%s\n", debugstr_w(folder
->Directory
));
1554 p
= msi_dup_record_field(row
, 3);
1556 /* split src and target dir */
1558 src_short
= folder_split_path( p
, ':' );
1560 /* split the long and short paths */
1561 tgt_long
= folder_split_path( tgt_short
, '|' );
1562 src_long
= folder_split_path( src_short
, '|' );
1564 /* check for no-op dirs */
1565 if (!lstrcmpW(szDot
, tgt_short
))
1566 tgt_short
= szEmpty
;
1567 if (!lstrcmpW(szDot
, src_short
))
1568 src_short
= szEmpty
;
1571 tgt_long
= tgt_short
;
1574 src_short
= tgt_short
;
1575 src_long
= tgt_long
;
1579 src_long
= src_short
;
1581 /* FIXME: use the target short path too */
1582 folder
->TargetDefault
= strdupW(tgt_long
);
1583 folder
->SourceShortPath
= strdupW(src_short
);
1584 folder
->SourceLongPath
= strdupW(src_long
);
1587 TRACE("TargetDefault = %s\n",debugstr_w( folder
->TargetDefault
));
1588 TRACE("SourceLong = %s\n", debugstr_w( folder
->SourceLongPath
));
1589 TRACE("SourceShort = %s\n", debugstr_w( folder
->SourceShortPath
));
1591 folder
->Parent
= msi_dup_record_field( row
, 2 );
1593 folder
->Property
= msi_dup_property( package
, folder
->Directory
);
1595 list_add_tail( &package
->folders
, &folder
->entry
);
1597 TRACE("returning %p\n", folder
);
1599 return ERROR_SUCCESS
;
1602 static UINT
load_all_folders( MSIPACKAGE
*package
)
1604 static const WCHAR query
[] = {
1605 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1606 '`','D','i','r','e','c','t','o','r','y','`',0 };
1610 if (!list_empty(&package
->folders
))
1611 return ERROR_SUCCESS
;
1613 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1614 if (r
!= ERROR_SUCCESS
)
1617 r
= MSI_IterateRecords(view
, NULL
, load_folder
, package
);
1618 msiobj_release(&view
->hdr
);
1623 * I am not doing any of the costing functionality yet.
1624 * Mostly looking at doing the Component and Feature loading
1626 * The native MSI does A LOT of modification to tables here. Mostly adding
1627 * a lot of temporary columns to the Feature and Component tables.
1629 * note: Native msi also tracks the short filename. But I am only going to
1630 * track the long ones. Also looking at this directory table
1631 * it appears that the directory table does not get the parents
1632 * resolved base on property only based on their entries in the
1635 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1637 static const WCHAR szCosting
[] =
1638 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1639 static const WCHAR szZero
[] = { '0', 0 };
1641 MSI_SetPropertyW(package
, szCosting
, szZero
);
1642 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1644 load_all_folders( package
);
1645 load_all_components( package
);
1646 load_all_features( package
);
1647 load_all_files( package
);
1649 return ERROR_SUCCESS
;
1652 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1655 UINT rc
= ERROR_SUCCESS
;
1657 TRACE("Executing Script %i\n",script
);
1659 if (!package
->script
)
1661 ERR("no script!\n");
1662 return ERROR_FUNCTION_FAILED
;
1665 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1668 action
= package
->script
->Actions
[script
][i
];
1669 ui_actionstart(package
, action
);
1670 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1671 rc
= ACTION_PerformAction(package
, action
, script
, TRUE
);
1672 if (rc
!= ERROR_SUCCESS
)
1675 msi_free_action_script(package
, script
);
1679 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1681 return ERROR_SUCCESS
;
1684 static void ACTION_GetComponentInstallStates(MSIPACKAGE
*package
)
1690 state
= MsiQueryProductStateW(package
->ProductCode
);
1692 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
1694 if (!comp
->ComponentId
)
1697 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1698 comp
->Installed
= INSTALLSTATE_ABSENT
;
1701 r
= MsiQueryComponentStateW(package
->ProductCode
, NULL
,
1702 package
->Context
, comp
->ComponentId
,
1704 if (r
!= ERROR_SUCCESS
)
1705 comp
->Installed
= INSTALLSTATE_ABSENT
;
1710 static void ACTION_GetFeatureInstallStates(MSIPACKAGE
*package
)
1712 MSIFEATURE
*feature
;
1715 state
= MsiQueryProductStateW(package
->ProductCode
);
1717 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1719 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1720 feature
->Installed
= INSTALLSTATE_ABSENT
;
1723 feature
->Installed
= MsiQueryFeatureStateW(package
->ProductCode
,
1729 static BOOL
process_state_property(MSIPACKAGE
* package
, int level
,
1730 LPCWSTR property
, INSTALLSTATE state
)
1732 static const WCHAR all
[]={'A','L','L',0};
1733 static const WCHAR remove
[] = {'R','E','M','O','V','E',0};
1735 MSIFEATURE
*feature
;
1737 override
= msi_dup_property( package
, property
);
1741 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1743 if (lstrcmpW(property
, remove
) &&
1744 (feature
->Level
<= 0 || feature
->Level
> level
))
1747 if (strcmpiW(override
,all
)==0)
1748 msi_feature_set_state(package
, feature
, state
);
1751 LPWSTR ptr
= override
;
1752 LPWSTR ptr2
= strchrW(override
,',');
1756 if ((ptr2
&& strncmpW(ptr
,feature
->Feature
, ptr2
-ptr
)==0)
1757 || (!ptr2
&& strcmpW(ptr
,feature
->Feature
)==0))
1759 msi_feature_set_state(package
, feature
, state
);
1765 ptr2
= strchrW(ptr
,',');
1777 UINT
MSI_SetFeatureStates(MSIPACKAGE
*package
)
1780 static const WCHAR szlevel
[] =
1781 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1782 static const WCHAR szAddLocal
[] =
1783 {'A','D','D','L','O','C','A','L',0};
1784 static const WCHAR szAddSource
[] =
1785 {'A','D','D','S','O','U','R','C','E',0};
1786 static const WCHAR szRemove
[] =
1787 {'R','E','M','O','V','E',0};
1788 static const WCHAR szReinstall
[] =
1789 {'R','E','I','N','S','T','A','L','L',0};
1790 BOOL override
= FALSE
;
1791 MSICOMPONENT
* component
;
1792 MSIFEATURE
*feature
;
1795 /* I do not know if this is where it should happen.. but */
1797 TRACE("Checking Install Level\n");
1799 level
= msi_get_property_int(package
, szlevel
, 1);
1801 /* ok here is the _real_ rub
1802 * all these activation/deactivation things happen in order and things
1803 * later on the list override things earlier on the list.
1804 * 1) INSTALLLEVEL processing
1814 * 11) FILEADDDEFAULT
1816 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1817 * REMOVE are the big ones, since we don't handle administrative installs
1820 override
|= process_state_property(package
, level
, szAddLocal
, INSTALLSTATE_LOCAL
);
1821 override
|= process_state_property(package
, level
, szRemove
, INSTALLSTATE_ABSENT
);
1822 override
|= process_state_property(package
, level
, szAddSource
, INSTALLSTATE_SOURCE
);
1823 override
|= process_state_property(package
, level
, szReinstall
, INSTALLSTATE_LOCAL
);
1827 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1829 BOOL feature_state
= ((feature
->Level
> 0) &&
1830 (feature
->Level
<= level
));
1832 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1834 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1835 msi_feature_set_state(package
, feature
, INSTALLSTATE_SOURCE
);
1836 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1837 msi_feature_set_state(package
, feature
, INSTALLSTATE_ADVERTISED
);
1839 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1843 /* disable child features of unselected parent features */
1844 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1848 if (feature
->Level
> 0 && feature
->Level
<= level
)
1851 LIST_FOR_EACH_ENTRY( fl
, &feature
->Children
, FeatureList
, entry
)
1852 msi_feature_set_state(package
, fl
->feature
, INSTALLSTATE_UNKNOWN
);
1857 /* set the Preselected Property */
1858 static const WCHAR szPreselected
[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1859 static const WCHAR szOne
[] = { '1', 0 };
1861 MSI_SetPropertyW(package
,szPreselected
,szOne
);
1865 * now we want to enable or disable components base on feature
1868 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1872 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1873 debugstr_w(feature
->Feature
), feature
->Level
, feature
->Installed
, feature
->Action
);
1875 if (!feature
->Level
)
1878 /* features with components that have compressed files are made local */
1879 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1881 if (cl
->component
->Enabled
&&
1882 cl
->component
->ForceLocalState
&&
1883 feature
->Action
== INSTALLSTATE_SOURCE
)
1885 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1890 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1892 component
= cl
->component
;
1894 if (!component
->Enabled
)
1897 switch (feature
->Action
)
1899 case INSTALLSTATE_ABSENT
:
1900 component
->anyAbsent
= 1;
1902 case INSTALLSTATE_ADVERTISED
:
1903 component
->hasAdvertiseFeature
= 1;
1905 case INSTALLSTATE_SOURCE
:
1906 component
->hasSourceFeature
= 1;
1908 case INSTALLSTATE_LOCAL
:
1909 component
->hasLocalFeature
= 1;
1911 case INSTALLSTATE_DEFAULT
:
1912 if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1913 component
->hasAdvertiseFeature
= 1;
1914 else if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1915 component
->hasSourceFeature
= 1;
1917 component
->hasLocalFeature
= 1;
1925 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1927 /* if the component isn't enabled, leave it alone */
1928 if (!component
->Enabled
)
1931 /* check if it's local or source */
1932 if (!(component
->Attributes
& msidbComponentAttributesOptional
) &&
1933 (component
->hasLocalFeature
|| component
->hasSourceFeature
))
1935 if ((component
->Attributes
& msidbComponentAttributesSourceOnly
) &&
1936 !component
->ForceLocalState
)
1937 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1939 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1943 /* if any feature is local, the component must be local too */
1944 if (component
->hasLocalFeature
)
1946 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1950 if (component
->hasSourceFeature
)
1952 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1956 if (component
->hasAdvertiseFeature
)
1958 msi_component_set_state(package
, component
, INSTALLSTATE_ADVERTISED
);
1962 TRACE("nobody wants component %s\n", debugstr_w(component
->Component
));
1963 if (component
->anyAbsent
)
1964 msi_component_set_state(package
, component
, INSTALLSTATE_ABSENT
);
1967 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1969 if (component
->Action
== INSTALLSTATE_DEFAULT
)
1971 TRACE("%s was default, setting to local\n", debugstr_w(component
->Component
));
1972 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1975 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1976 debugstr_w(component
->Component
), component
->Installed
, component
->Action
);
1980 return ERROR_SUCCESS
;
1983 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1985 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1990 name
= MSI_RecordGetString(row
,1);
1992 f
= get_loaded_folder(package
, name
);
1993 if (!f
) return ERROR_SUCCESS
;
1995 /* reset the ResolvedTarget */
1996 msi_free(f
->ResolvedTarget
);
1997 f
->ResolvedTarget
= NULL
;
1999 /* This helper function now does ALL the work */
2000 TRACE("Dir %s ...\n",debugstr_w(name
));
2001 path
= resolve_folder(package
,name
,FALSE
,TRUE
,TRUE
,NULL
);
2002 TRACE("resolves to %s\n",debugstr_w(path
));
2005 return ERROR_SUCCESS
;
2008 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
2010 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2012 MSIFEATURE
*feature
;
2014 name
= MSI_RecordGetString( row
, 1 );
2016 feature
= get_loaded_feature( package
, name
);
2018 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
2022 Condition
= MSI_RecordGetString(row
,3);
2024 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
2026 int level
= MSI_RecordGetInteger(row
,2);
2027 TRACE("Resetting feature %s to level %i\n", debugstr_w(name
), level
);
2028 feature
->Level
= level
;
2031 return ERROR_SUCCESS
;
2034 static LPWSTR
msi_get_disk_file_version( LPCWSTR filename
)
2036 static const WCHAR name_fmt
[] =
2037 {'%','u','.','%','u','.','%','u','.','%','u',0};
2038 static const WCHAR name
[] = {'\\',0};
2039 VS_FIXEDFILEINFO
*lpVer
;
2040 WCHAR filever
[0x100];
2046 TRACE("%s\n", debugstr_w(filename
));
2048 versize
= GetFileVersionInfoSizeW( filename
, &handle
);
2052 version
= msi_alloc( versize
);
2053 GetFileVersionInfoW( filename
, 0, versize
, version
);
2055 if (!VerQueryValueW( version
, name
, (LPVOID
*)&lpVer
, &sz
))
2057 msi_free( version
);
2061 sprintfW( filever
, name_fmt
,
2062 HIWORD(lpVer
->dwFileVersionMS
),
2063 LOWORD(lpVer
->dwFileVersionMS
),
2064 HIWORD(lpVer
->dwFileVersionLS
),
2065 LOWORD(lpVer
->dwFileVersionLS
));
2067 msi_free( version
);
2069 return strdupW( filever
);
2072 static UINT
msi_check_file_install_states( MSIPACKAGE
*package
)
2074 LPWSTR file_version
;
2077 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2079 MSICOMPONENT
* comp
= file
->Component
;
2085 if (file
->IsCompressed
)
2086 comp
->ForceLocalState
= TRUE
;
2088 /* calculate target */
2089 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, TRUE
, NULL
);
2091 msi_free(file
->TargetPath
);
2093 TRACE("file %s is named %s\n",
2094 debugstr_w(file
->File
), debugstr_w(file
->FileName
));
2096 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
2100 TRACE("file %s resolves to %s\n",
2101 debugstr_w(file
->File
), debugstr_w(file
->TargetPath
));
2103 /* don't check files of components that aren't installed */
2104 if (comp
->Installed
== INSTALLSTATE_UNKNOWN
||
2105 comp
->Installed
== INSTALLSTATE_ABSENT
)
2107 file
->state
= msifs_missing
; /* assume files are missing */
2111 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
2113 file
->state
= msifs_missing
;
2114 comp
->Cost
+= file
->FileSize
;
2118 if (file
->Version
&&
2119 (file_version
= msi_get_disk_file_version( file
->TargetPath
)))
2121 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
2122 debugstr_w(file_version
));
2123 /* FIXME: seems like a bad way to compare version numbers */
2124 if (lstrcmpiW(file_version
, file
->Version
)<0)
2126 file
->state
= msifs_overwrite
;
2127 comp
->Cost
+= file
->FileSize
;
2130 file
->state
= msifs_present
;
2131 msi_free( file_version
);
2134 file
->state
= msifs_present
;
2137 return ERROR_SUCCESS
;
2141 * A lot is done in this function aside from just the costing.
2142 * The costing needs to be implemented at some point but for now I am going
2143 * to focus on the directory building
2146 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2148 static const WCHAR ExecSeqQuery
[] =
2149 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2150 '`','D','i','r','e','c','t','o','r','y','`',0};
2151 static const WCHAR ConditionQuery
[] =
2152 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2153 '`','C','o','n','d','i','t','i','o','n','`',0};
2154 static const WCHAR szCosting
[] =
2155 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2156 static const WCHAR szlevel
[] =
2157 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2158 static const WCHAR szOutOfDiskSpace
[] =
2159 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2160 static const WCHAR szOne
[] = { '1', 0 };
2161 static const WCHAR szZero
[] = { '0', 0 };
2167 TRACE("Building Directory properties\n");
2169 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2170 if (rc
== ERROR_SUCCESS
)
2172 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
2174 msiobj_release(&view
->hdr
);
2177 /* read components states from the registry */
2178 ACTION_GetComponentInstallStates(package
);
2179 ACTION_GetFeatureInstallStates(package
);
2181 TRACE("File calculations\n");
2182 msi_check_file_install_states( package
);
2184 TRACE("Evaluating Condition Table\n");
2186 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
2187 if (rc
== ERROR_SUCCESS
)
2189 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeConditions
,
2191 msiobj_release(&view
->hdr
);
2194 TRACE("Enabling or Disabling Components\n");
2195 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2197 if (MSI_EvaluateConditionW(package
, comp
->Condition
) == MSICONDITION_FALSE
)
2199 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
2200 comp
->Enabled
= FALSE
;
2203 comp
->Enabled
= TRUE
;
2206 MSI_SetPropertyW(package
,szCosting
,szOne
);
2207 /* set default run level if not set */
2208 level
= msi_dup_property( package
, szlevel
);
2210 MSI_SetPropertyW(package
,szlevel
, szOne
);
2213 /* FIXME: check volume disk space */
2214 MSI_SetPropertyW(package
, szOutOfDiskSpace
, szZero
);
2216 return MSI_SetFeatureStates(package
);
2219 /* OK this value is "interpreted" and then formatted based on the
2220 first few characters */
2221 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
2226 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2232 LPWSTR deformated
= NULL
;
2235 deformat_string(package
, &value
[2], &deformated
);
2237 /* binary value type */
2241 *size
= (strlenW(ptr
)/2)+1;
2243 *size
= strlenW(ptr
)/2;
2245 data
= msi_alloc(*size
);
2251 /* if uneven pad with a zero in front */
2257 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2259 TRACE("Uneven byte count\n");
2267 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2270 msi_free(deformated
);
2272 TRACE("Data %i bytes(%i)\n",*size
,count
);
2279 deformat_string(package
, &value
[1], &deformated
);
2282 *size
= sizeof(DWORD
);
2283 data
= msi_alloc(*size
);
2289 if ( (*p
< '0') || (*p
> '9') )
2295 if (deformated
[0] == '-')
2298 TRACE("DWORD %i\n",*(LPDWORD
)data
);
2300 msi_free(deformated
);
2305 static const WCHAR szMulti
[] = {'[','~',']',0};
2314 *type
=REG_EXPAND_SZ
;
2322 if (strstrW(value
,szMulti
))
2323 *type
= REG_MULTI_SZ
;
2325 /* remove initial delimiter */
2326 if (!strncmpW(value
, szMulti
, 3))
2329 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2331 /* add double NULL terminator */
2332 if (*type
== REG_MULTI_SZ
)
2334 *size
+= 2 * sizeof(WCHAR
); /* two NULL terminators */
2335 data
= msi_realloc_zero(data
, *size
);
2341 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2343 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2344 static const WCHAR szHCR
[] =
2345 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2346 'R','O','O','T','\\',0};
2347 static const WCHAR szHCU
[] =
2348 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2349 'U','S','E','R','\\',0};
2350 static const WCHAR szHLM
[] =
2351 {'H','K','E','Y','_','L','O','C','A','L','_',
2352 'M','A','C','H','I','N','E','\\',0};
2353 static const WCHAR szHU
[] =
2354 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2356 LPSTR value_data
= NULL
;
2357 HKEY root_key
, hkey
;
2360 LPCWSTR szRoot
, component
, name
, key
, value
;
2365 BOOL check_first
= FALSE
;
2368 ui_progress(package
,2,0,0,0);
2375 component
= MSI_RecordGetString(row
, 6);
2376 comp
= get_loaded_component(package
,component
);
2378 return ERROR_SUCCESS
;
2380 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2382 TRACE("Skipping write due to disabled component %s\n",
2383 debugstr_w(component
));
2385 comp
->Action
= comp
->Installed
;
2387 return ERROR_SUCCESS
;
2390 comp
->Action
= INSTALLSTATE_LOCAL
;
2392 name
= MSI_RecordGetString(row
, 4);
2393 if( MSI_RecordIsNull(row
,5) && name
)
2395 /* null values can have special meanings */
2396 if (name
[0]=='-' && name
[1] == 0)
2397 return ERROR_SUCCESS
;
2398 else if ((name
[0]=='+' && name
[1] == 0) ||
2399 (name
[0] == '*' && name
[1] == 0))
2404 root
= MSI_RecordGetInteger(row
,2);
2405 key
= MSI_RecordGetString(row
, 3);
2407 /* get the root key */
2412 static const WCHAR szALLUSER
[] = {'A','L','L','U','S','E','R','S',0};
2413 LPWSTR all_users
= msi_dup_property( package
, szALLUSER
);
2414 if (all_users
&& all_users
[0] == '1')
2416 root_key
= HKEY_LOCAL_MACHINE
;
2421 root_key
= HKEY_CURRENT_USER
;
2424 msi_free(all_users
);
2427 case 0: root_key
= HKEY_CLASSES_ROOT
;
2430 case 1: root_key
= HKEY_CURRENT_USER
;
2433 case 2: root_key
= HKEY_LOCAL_MACHINE
;
2436 case 3: root_key
= HKEY_USERS
;
2440 ERR("Unknown root %i\n",root
);
2446 return ERROR_SUCCESS
;
2448 deformat_string(package
, key
, &deformated
);
2449 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2450 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2451 strcpyW(uikey
,szRoot
);
2452 strcatW(uikey
,deformated
);
2454 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2456 ERR("Could not create key %s\n",debugstr_w(deformated
));
2457 msi_free(deformated
);
2459 return ERROR_SUCCESS
;
2461 msi_free(deformated
);
2463 value
= MSI_RecordGetString(row
,5);
2465 value_data
= parse_value(package
, value
, &type
, &size
);
2468 static const WCHAR szEmpty
[] = {0};
2469 value_data
= (LPSTR
)strdupW(szEmpty
);
2470 size
= sizeof(szEmpty
);
2474 deformat_string(package
, name
, &deformated
);
2478 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2480 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2485 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2486 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2488 TRACE("value %s of %s checked already exists\n",
2489 debugstr_w(deformated
), debugstr_w(uikey
));
2493 TRACE("Checked and setting value %s of %s\n",
2494 debugstr_w(deformated
), debugstr_w(uikey
));
2495 if (deformated
|| size
)
2496 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2501 uirow
= MSI_CreateRecord(3);
2502 MSI_RecordSetStringW(uirow
,2,deformated
);
2503 MSI_RecordSetStringW(uirow
,1,uikey
);
2506 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2508 MSI_RecordSetStringW(uirow
,3,value
);
2510 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2511 msiobj_release( &uirow
->hdr
);
2513 msi_free(value_data
);
2514 msi_free(deformated
);
2517 return ERROR_SUCCESS
;
2520 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2524 static const WCHAR ExecSeqQuery
[] =
2525 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2526 '`','R','e','g','i','s','t','r','y','`',0 };
2528 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2529 if (rc
!= ERROR_SUCCESS
)
2530 return ERROR_SUCCESS
;
2532 /* increment progress bar each time action data is sent */
2533 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2535 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2537 msiobj_release(&view
->hdr
);
2541 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2543 package
->script
->CurrentlyScripting
= TRUE
;
2545 return ERROR_SUCCESS
;
2549 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2554 static const WCHAR q1
[]=
2555 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2556 '`','R','e','g','i','s','t','r','y','`',0};
2559 MSIFEATURE
*feature
;
2562 TRACE("InstallValidate\n");
2564 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2565 if (rc
== ERROR_SUCCESS
)
2567 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2568 msiobj_release( &view
->hdr
);
2569 total
+= progress
* REG_PROGRESS_VALUE
;
2572 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2573 total
+= COMPONENT_PROGRESS_VALUE
;
2575 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2576 total
+= file
->FileSize
;
2578 ui_progress(package
,0,total
,0,0);
2580 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2582 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2583 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2584 feature
->ActionRequest
);
2587 return ERROR_SUCCESS
;
2590 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2592 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2593 LPCWSTR cond
= NULL
;
2594 LPCWSTR message
= NULL
;
2597 static const WCHAR title
[]=
2598 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2600 cond
= MSI_RecordGetString(row
,1);
2602 r
= MSI_EvaluateConditionW(package
,cond
);
2603 if (r
== MSICONDITION_FALSE
)
2605 if ((gUILevel
& INSTALLUILEVEL_MASK
) != INSTALLUILEVEL_NONE
)
2608 message
= MSI_RecordGetString(row
,2);
2609 deformat_string(package
,message
,&deformated
);
2610 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2611 msi_free(deformated
);
2614 return ERROR_INSTALL_FAILURE
;
2617 return ERROR_SUCCESS
;
2620 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2623 MSIQUERY
* view
= NULL
;
2624 static const WCHAR ExecSeqQuery
[] =
2625 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2626 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2628 TRACE("Checking launch conditions\n");
2630 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2631 if (rc
!= ERROR_SUCCESS
)
2632 return ERROR_SUCCESS
;
2634 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2635 msiobj_release(&view
->hdr
);
2640 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2644 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,TRUE
,NULL
);
2646 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2648 MSIRECORD
* row
= 0;
2650 LPWSTR deformated
,buffer
,deformated_name
;
2652 static const WCHAR ExecSeqQuery
[] =
2653 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2654 '`','R','e','g','i','s','t','r','y','`',' ',
2655 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2656 ' ','=',' ' ,'\'','%','s','\'',0 };
2657 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2658 static const WCHAR fmt2
[]=
2659 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2661 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2665 root
= MSI_RecordGetInteger(row
,2);
2666 key
= MSI_RecordGetString(row
, 3);
2667 name
= MSI_RecordGetString(row
, 4);
2668 deformat_string(package
, key
, &deformated
);
2669 deformat_string(package
, name
, &deformated_name
);
2671 len
= strlenW(deformated
) + 6;
2672 if (deformated_name
)
2673 len
+=strlenW(deformated_name
);
2675 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2677 if (deformated_name
)
2678 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2680 sprintfW(buffer
,fmt
,root
,deformated
);
2682 msi_free(deformated
);
2683 msi_free(deformated_name
);
2684 msiobj_release(&row
->hdr
);
2688 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2690 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2695 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2698 return strdupW( file
->TargetPath
);
2703 static HKEY
openSharedDLLsKey(void)
2706 static const WCHAR path
[] =
2707 {'S','o','f','t','w','a','r','e','\\',
2708 'M','i','c','r','o','s','o','f','t','\\',
2709 'W','i','n','d','o','w','s','\\',
2710 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2711 'S','h','a','r','e','d','D','L','L','s',0};
2713 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2717 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2722 DWORD sz
= sizeof(count
);
2725 hkey
= openSharedDLLsKey();
2726 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2727 if (rc
!= ERROR_SUCCESS
)
2733 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2737 hkey
= openSharedDLLsKey();
2739 msi_reg_set_val_dword( hkey
, path
, count
);
2741 RegDeleteValueW(hkey
,path
);
2747 * Return TRUE if the count should be written out and FALSE if not
2749 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2751 MSIFEATURE
*feature
;
2755 /* only refcount DLLs */
2756 if (comp
->KeyPath
== NULL
||
2757 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2758 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2762 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2763 write
= (count
> 0);
2765 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2769 /* increment counts */
2770 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2774 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
))
2777 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2779 if ( cl
->component
== comp
)
2784 /* decrement counts */
2785 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2789 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ABSENT
))
2792 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2794 if ( cl
->component
== comp
)
2799 /* ref count all the files in the component */
2804 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2806 if (file
->Component
== comp
)
2807 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2811 /* add a count for permanent */
2812 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2815 comp
->RefCount
= count
;
2818 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2821 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2823 WCHAR squished_pc
[GUID_SIZE
];
2824 WCHAR squished_cc
[GUID_SIZE
];
2831 squash_guid(package
->ProductCode
,squished_pc
);
2832 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2834 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2838 ui_progress(package
,2,0,0,0);
2839 if (!comp
->ComponentId
)
2842 squash_guid(comp
->ComponentId
,squished_cc
);
2844 msi_free(comp
->FullKeypath
);
2845 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2847 ACTION_RefCountComponent( package
, comp
);
2849 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2850 debugstr_w(comp
->Component
),
2851 debugstr_w(squished_cc
),
2852 debugstr_w(comp
->FullKeypath
),
2855 if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) ||
2856 ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
))
2858 if (!comp
->FullKeypath
)
2861 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2862 rc
= MSIREG_OpenLocalUserDataComponentKey(comp
->ComponentId
, &hkey
, TRUE
);
2864 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, &hkey
, TRUE
);
2866 if (rc
!= ERROR_SUCCESS
)
2869 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2871 static const WCHAR szPermKey
[] =
2872 { '0','0','0','0','0','0','0','0','0','0','0','0',
2873 '0','0','0','0','0','0','0','0','0','0','0','0',
2874 '0','0','0','0','0','0','0','0',0 };
2876 msi_reg_set_val_str(hkey
, szPermKey
, comp
->FullKeypath
);
2879 if (comp
->Action
== INSTALLSTATE_LOCAL
)
2880 msi_reg_set_val_str(hkey
, squished_pc
, comp
->FullKeypath
);
2886 WCHAR source
[MAX_PATH
];
2887 WCHAR base
[MAX_PATH
];
2890 static const WCHAR fmt
[] = {'%','0','2','d','\\',0};
2891 static const WCHAR query
[] = {
2892 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2893 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2894 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2895 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2896 '`','D','i','s','k','I','d','`',0};
2898 file
= get_loaded_file(package
, comp
->KeyPath
);
2902 row
= MSI_QueryGetRecord(package
->db
, query
, file
->Sequence
);
2903 sprintfW(source
, fmt
, MSI_RecordGetInteger(row
, 1));
2904 ptr2
= strrchrW(source
, '\\') + 1;
2905 msiobj_release(&row
->hdr
);
2907 lstrcpyW(base
, package
->PackagePath
);
2908 ptr
= strrchrW(base
, '\\');
2911 sourcepath
= resolve_file_source(package
, file
);
2912 ptr
= sourcepath
+ lstrlenW(base
);
2913 lstrcpyW(ptr2
, ptr
);
2914 msi_free(sourcepath
);
2916 msi_reg_set_val_str(hkey
, squished_pc
, source
);
2920 else if (ACTION_VerifyComponentForAction(comp
, INSTALLSTATE_ABSENT
))
2922 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2923 MSIREG_DeleteLocalUserDataComponentKey(comp
->ComponentId
);
2925 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
);
2929 uirow
= MSI_CreateRecord(3);
2930 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2931 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2932 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
2933 ui_actiondata(package
,szProcessComponents
,uirow
);
2934 msiobj_release( &uirow
->hdr
);
2937 return ERROR_SUCCESS
;
2948 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
2949 LPWSTR lpszName
, LONG_PTR lParam
)
2952 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
2953 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
2957 if (!IS_INTRESOURCE(lpszName
))
2959 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
2963 sz
= strlenW(tl_struct
->source
)+4;
2964 sz
*= sizeof(WCHAR
);
2966 if ((INT_PTR
)lpszName
== 1)
2967 tl_struct
->path
= strdupW(tl_struct
->source
);
2970 tl_struct
->path
= msi_alloc(sz
);
2971 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
2974 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
2975 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
2978 msi_free(tl_struct
->path
);
2979 tl_struct
->path
= NULL
;
2984 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
2985 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
2987 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2991 msi_free(tl_struct
->path
);
2992 tl_struct
->path
= NULL
;
2994 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2995 ITypeLib_Release(tl_struct
->ptLib
);
3000 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
3002 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
3006 typelib_struct tl_struct
;
3011 static const WCHAR szTYPELIB
[] = {'T','Y','P','E','L','I','B',0};
3013 component
= MSI_RecordGetString(row
,3);
3014 comp
= get_loaded_component(package
,component
);
3016 return ERROR_SUCCESS
;
3018 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3020 TRACE("Skipping typelib reg due to disabled component\n");
3022 comp
->Action
= comp
->Installed
;
3024 return ERROR_SUCCESS
;
3027 comp
->Action
= INSTALLSTATE_LOCAL
;
3029 file
= get_loaded_file( package
, comp
->KeyPath
);
3031 return ERROR_SUCCESS
;
3033 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
3037 guid
= MSI_RecordGetString(row
,1);
3038 CLSIDFromString((LPWSTR
)guid
, &tl_struct
.clsid
);
3039 tl_struct
.source
= strdupW( file
->TargetPath
);
3040 tl_struct
.path
= NULL
;
3042 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
3043 (LONG_PTR
)&tl_struct
);
3051 helpid
= MSI_RecordGetString(row
,6);
3054 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,TRUE
,NULL
);
3055 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
3059 ERR("Failed to register type library %s\n",
3060 debugstr_w(tl_struct
.path
));
3063 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
3065 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
3068 ITypeLib_Release(tl_struct
.ptLib
);
3069 msi_free(tl_struct
.path
);
3072 ERR("Failed to load type library %s\n",
3073 debugstr_w(tl_struct
.source
));
3075 FreeLibrary(module
);
3076 msi_free(tl_struct
.source
);
3080 hr
= LoadTypeLibEx(file
->TargetPath
, REGKIND_REGISTER
, &tlib
);
3083 ERR("Failed to load type library: %08x\n", hr
);
3084 return ERROR_FUNCTION_FAILED
;
3087 ITypeLib_Release(tlib
);
3090 return ERROR_SUCCESS
;
3093 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
3096 * OK this is a bit confusing.. I am given a _Component key and I believe
3097 * that the file that is being registered as a type library is the "key file
3098 * of that component" which I interpret to mean "The file in the KeyPath of
3103 static const WCHAR Query
[] =
3104 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3105 '`','T','y','p','e','L','i','b','`',0};
3107 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3108 if (rc
!= ERROR_SUCCESS
)
3109 return ERROR_SUCCESS
;
3111 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
3112 msiobj_release(&view
->hdr
);
3116 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
3118 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3119 LPWSTR target_file
, target_folder
, filename
;
3120 LPCWSTR buffer
, extension
;
3122 static const WCHAR szlnk
[]={'.','l','n','k',0};
3123 IShellLinkW
*sl
= NULL
;
3124 IPersistFile
*pf
= NULL
;
3127 buffer
= MSI_RecordGetString(row
,4);
3128 comp
= get_loaded_component(package
,buffer
);
3130 return ERROR_SUCCESS
;
3132 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3134 TRACE("Skipping shortcut creation due to disabled component\n");
3136 comp
->Action
= comp
->Installed
;
3138 return ERROR_SUCCESS
;
3141 comp
->Action
= INSTALLSTATE_LOCAL
;
3143 ui_actiondata(package
,szCreateShortcuts
,row
);
3145 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
3146 &IID_IShellLinkW
, (LPVOID
*) &sl
);
3150 ERR("CLSID_ShellLink not available\n");
3154 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
3157 ERR("QueryInterface(IID_IPersistFile) failed\n");
3161 buffer
= MSI_RecordGetString(row
,2);
3162 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,TRUE
,NULL
);
3164 /* may be needed because of a bug somewhere else */
3165 create_full_pathW(target_folder
);
3167 filename
= msi_dup_record_field( row
, 3 );
3168 reduce_to_longfilename(filename
);
3170 extension
= strchrW(filename
,'.');
3171 if (!extension
|| strcmpiW(extension
,szlnk
))
3173 int len
= strlenW(filename
);
3174 filename
= msi_realloc(filename
, len
* sizeof(WCHAR
) + sizeof(szlnk
));
3175 memcpy(filename
+ len
, szlnk
, sizeof(szlnk
));
3177 target_file
= build_directory_name(2, target_folder
, filename
);
3178 msi_free(target_folder
);
3181 buffer
= MSI_RecordGetString(row
,5);
3182 if (strchrW(buffer
,'['))
3185 deformat_string(package
,buffer
,&deformated
);
3186 IShellLinkW_SetPath(sl
,deformated
);
3187 msi_free(deformated
);
3191 FIXME("poorly handled shortcut format, advertised shortcut\n");
3192 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
3195 if (!MSI_RecordIsNull(row
,6))
3198 buffer
= MSI_RecordGetString(row
,6);
3199 deformat_string(package
,buffer
,&deformated
);
3200 IShellLinkW_SetArguments(sl
,deformated
);
3201 msi_free(deformated
);
3204 if (!MSI_RecordIsNull(row
,7))
3206 buffer
= MSI_RecordGetString(row
,7);
3207 IShellLinkW_SetDescription(sl
,buffer
);
3210 if (!MSI_RecordIsNull(row
,8))
3211 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
3213 if (!MSI_RecordIsNull(row
,9))
3218 buffer
= MSI_RecordGetString(row
,9);
3220 Path
= build_icon_path(package
,buffer
);
3221 index
= MSI_RecordGetInteger(row
,10);
3223 /* no value means 0 */
3224 if (index
== MSI_NULL_INTEGER
)
3227 IShellLinkW_SetIconLocation(sl
,Path
,index
);
3231 if (!MSI_RecordIsNull(row
,11))
3232 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
3234 if (!MSI_RecordIsNull(row
,12))
3237 buffer
= MSI_RecordGetString(row
,12);
3238 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, TRUE
, NULL
);
3240 IShellLinkW_SetWorkingDirectory(sl
,Path
);
3244 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
3245 IPersistFile_Save(pf
,target_file
,FALSE
);
3247 msi_free(target_file
);
3251 IPersistFile_Release( pf
);
3253 IShellLinkW_Release( sl
);
3255 return ERROR_SUCCESS
;
3258 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
3263 static const WCHAR Query
[] =
3264 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3265 '`','S','h','o','r','t','c','u','t','`',0};
3267 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3268 if (rc
!= ERROR_SUCCESS
)
3269 return ERROR_SUCCESS
;
3271 res
= CoInitialize( NULL
);
3274 ERR("CoInitialize failed\n");
3275 return ERROR_FUNCTION_FAILED
;
3278 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
3279 msiobj_release(&view
->hdr
);
3286 static UINT
ITERATE_PublishIcon(MSIRECORD
*row
, LPVOID param
)
3288 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
3297 FileName
= MSI_RecordGetString(row
,1);
3300 ERR("Unable to get FileName\n");
3301 return ERROR_SUCCESS
;
3304 FilePath
= build_icon_path(package
,FileName
);
3306 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
3308 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
3309 FILE_ATTRIBUTE_NORMAL
, NULL
);
3311 if (the_file
== INVALID_HANDLE_VALUE
)
3313 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3315 return ERROR_SUCCESS
;
3322 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3323 if (rc
!= ERROR_SUCCESS
)
3325 ERR("Failed to get stream\n");
3326 CloseHandle(the_file
);
3327 DeleteFileW(FilePath
);
3330 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3331 } while (sz
== 1024);
3335 CloseHandle(the_file
);
3337 uirow
= MSI_CreateRecord(1);
3338 MSI_RecordSetStringW(uirow
,1,FileName
);
3339 ui_actiondata(package
,szPublishProduct
,uirow
);
3340 msiobj_release( &uirow
->hdr
);
3342 return ERROR_SUCCESS
;
3345 static UINT
msi_publish_icons(MSIPACKAGE
*package
)
3350 static const WCHAR query
[]= {
3351 'S','E','L','E','C','T',' ','*',' ',
3352 'F','R','O','M',' ','`','I','c','o','n','`',0};
3354 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
3355 if (r
== ERROR_SUCCESS
)
3357 MSI_IterateRecords(view
, NULL
, ITERATE_PublishIcon
, package
);
3358 msiobj_release(&view
->hdr
);
3361 return ERROR_SUCCESS
;
3364 static UINT
msi_publish_sourcelist(MSIPACKAGE
*package
, HKEY hkey
)
3370 MSISOURCELISTINFO
*info
;
3372 static const WCHAR szEmpty
[] = {0};
3373 static const WCHAR szSourceList
[] = {'S','o','u','r','c','e','L','i','s','t',0};
3375 r
= RegCreateKeyW(hkey
, szSourceList
, &source
);
3376 if (r
!= ERROR_SUCCESS
)
3379 RegCloseKey(source
);
3381 buffer
= strrchrW(package
->PackagePath
, '\\') + 1;
3382 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3383 package
->Context
, MSICODE_PRODUCT
,
3384 INSTALLPROPERTY_PACKAGENAMEW
, buffer
);
3385 if (r
!= ERROR_SUCCESS
)
3388 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3389 package
->Context
, MSICODE_PRODUCT
,
3390 INSTALLPROPERTY_MEDIAPACKAGEPATHW
, szEmpty
);
3391 if (r
!= ERROR_SUCCESS
)
3394 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3395 package
->Context
, MSICODE_PRODUCT
,
3396 INSTALLPROPERTY_DISKPROMPTW
, szEmpty
);
3397 if (r
!= ERROR_SUCCESS
)
3400 LIST_FOR_EACH_ENTRY(info
, &package
->sourcelist_info
, MSISOURCELISTINFO
, entry
)
3402 if (!lstrcmpW(info
->property
, INSTALLPROPERTY_LASTUSEDSOURCEW
))
3403 msi_set_last_used_source(package
->ProductCode
, NULL
, info
->context
,
3404 info
->options
, info
->value
);
3406 MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3407 info
->context
, info
->options
,
3408 info
->property
, info
->value
);
3411 LIST_FOR_EACH_ENTRY(disk
, &package
->sourcelist_media
, MSIMEDIADISK
, entry
)
3413 MsiSourceListAddMediaDiskW(package
->ProductCode
, NULL
,
3414 disk
->context
, disk
->options
,
3415 disk
->disk_id
, disk
->volume_label
, disk
->disk_prompt
);
3418 return ERROR_SUCCESS
;
3421 static UINT
msi_publish_product_properties(MSIPACKAGE
*package
, HKEY hkey
)
3423 MSIHANDLE hdb
, suminfo
;
3424 WCHAR guids
[MAX_PATH
];
3425 WCHAR packcode
[SQUISH_GUID_SIZE
];
3432 static const WCHAR szProductLanguage
[] =
3433 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3434 static const WCHAR szARPProductIcon
[] =
3435 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3436 static const WCHAR szProductVersion
[] =
3437 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3438 static const WCHAR szAssignment
[] =
3439 {'A','s','s','i','g','n','m','e','n','t',0};
3440 static const WCHAR szAdvertiseFlags
[] =
3441 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3442 static const WCHAR szClients
[] =
3443 {'C','l','i','e','n','t','s',0};
3444 static const WCHAR szColon
[] = {':',0};
3446 buffer
= msi_dup_property(package
, INSTALLPROPERTY_PRODUCTNAMEW
);
3447 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3450 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
3451 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3453 ptr
= strrchrW(package
->PackagePath
, '\\' ) + 1;
3454 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PACKAGENAMEW
, ptr
);
3457 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_AUTHORIZED_LUA_APPW
, 0);
3459 buffer
= msi_dup_property(package
, szARPProductIcon
);
3462 LPWSTR path
= build_icon_path(package
,buffer
);
3463 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3468 buffer
= msi_dup_property(package
, szProductVersion
);
3471 DWORD verdword
= msi_version_str_to_dword(buffer
);
3472 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3476 msi_reg_set_val_dword(hkey
, szAssignment
, 0);
3477 msi_reg_set_val_dword(hkey
, szAdvertiseFlags
, 0x184);
3478 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_INSTANCETYPEW
, 0);
3479 msi_reg_set_val_str(hkey
, szClients
, szColon
);
3481 hdb
= alloc_msihandle(&package
->db
->hdr
);
3483 return ERROR_NOT_ENOUGH_MEMORY
;
3485 r
= MsiGetSummaryInformationW(hdb
, NULL
, 0, &suminfo
);
3486 MsiCloseHandle(hdb
);
3487 if (r
!= ERROR_SUCCESS
)
3491 r
= MsiSummaryInfoGetPropertyW(suminfo
, PID_REVNUMBER
, NULL
, NULL
,
3492 NULL
, guids
, &size
);
3493 if (r
!= ERROR_SUCCESS
)
3496 ptr
= strchrW(guids
, ';');
3498 squash_guid(guids
, packcode
);
3499 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PACKAGECODEW
, packcode
);
3502 MsiCloseHandle(suminfo
);
3503 return ERROR_SUCCESS
;
3506 static UINT
msi_publish_upgrade_code(MSIPACKAGE
*package
)
3511 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
3513 static const WCHAR szUpgradeCode
[] =
3514 {'U','p','g','r','a','d','e','C','o','d','e',0};
3516 upgrade
= msi_dup_property(package
, szUpgradeCode
);
3518 return ERROR_SUCCESS
;
3520 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3522 r
= MSIREG_OpenClassesUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3523 if (r
!= ERROR_SUCCESS
)
3528 r
= MSIREG_OpenUserUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3529 if (r
!= ERROR_SUCCESS
)
3533 squash_guid(package
->ProductCode
, squashed_pc
);
3534 msi_reg_set_val_str(hkey
, squashed_pc
, NULL
);
3543 static BOOL
msi_check_publish(MSIPACKAGE
*package
)
3545 MSIFEATURE
*feature
;
3547 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3549 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
3556 static BOOL
msi_check_unpublish(MSIPACKAGE
*package
)
3558 MSIFEATURE
*feature
;
3560 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3562 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3570 * 99% of the work done here is only done for
3571 * advertised installs. However this is where the
3572 * Icon table is processed and written out
3573 * so that is what I am going to do here.
3575 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3581 /* FIXME: also need to publish if the product is in advertise mode */
3582 if (!msi_check_publish(package
))
3583 return ERROR_SUCCESS
;
3585 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3587 rc
= MSIREG_OpenLocalClassesProductKey(package
->ProductCode
, &hukey
, TRUE
);
3588 if (rc
!= ERROR_SUCCESS
)
3591 rc
= MSIREG_OpenLocalUserDataProductKey(package
->ProductCode
, &hudkey
, TRUE
);
3592 if (rc
!= ERROR_SUCCESS
)
3597 rc
= MSIREG_OpenUserProductsKey(package
->ProductCode
, &hukey
, TRUE
);
3598 if (rc
!= ERROR_SUCCESS
)
3601 rc
= MSIREG_OpenUserDataProductKey(package
->ProductCode
, &hudkey
, TRUE
);
3602 if (rc
!= ERROR_SUCCESS
)
3606 rc
= msi_publish_upgrade_code(package
);
3607 if (rc
!= ERROR_SUCCESS
)
3610 rc
= msi_publish_product_properties(package
, hukey
);
3611 if (rc
!= ERROR_SUCCESS
)
3614 rc
= msi_publish_sourcelist(package
, hukey
);
3615 if (rc
!= ERROR_SUCCESS
)
3618 rc
= msi_publish_icons(package
);
3622 RegCloseKey(hudkey
);
3627 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3629 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3630 LPCWSTR component
, section
, key
, value
, identifier
, dirproperty
;
3631 LPWSTR deformated_section
, deformated_key
, deformated_value
;
3632 LPWSTR folder
, filename
, fullname
= NULL
;
3633 LPCWSTR filenameptr
;
3637 static const WCHAR szWindowsFolder
[] =
3638 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3640 component
= MSI_RecordGetString(row
, 8);
3641 comp
= get_loaded_component(package
,component
);
3643 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3645 TRACE("Skipping ini file due to disabled component %s\n",
3646 debugstr_w(component
));
3648 comp
->Action
= comp
->Installed
;
3650 return ERROR_SUCCESS
;
3653 comp
->Action
= INSTALLSTATE_LOCAL
;
3655 identifier
= MSI_RecordGetString(row
,1);
3656 dirproperty
= MSI_RecordGetString(row
,3);
3657 section
= MSI_RecordGetString(row
,4);
3658 key
= MSI_RecordGetString(row
,5);
3659 value
= MSI_RecordGetString(row
,6);
3660 action
= MSI_RecordGetInteger(row
,7);
3662 deformat_string(package
,section
,&deformated_section
);
3663 deformat_string(package
,key
,&deformated_key
);
3664 deformat_string(package
,value
,&deformated_value
);
3666 filename
= msi_dup_record_field(row
, 2);
3667 if (filename
&& (filenameptr
= strchrW(filename
, '|')))
3670 filenameptr
= filename
;
3674 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, TRUE
, NULL
);
3676 folder
= msi_dup_property( package
, dirproperty
);
3679 folder
= msi_dup_property( package
, szWindowsFolder
);
3683 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
3687 fullname
= build_directory_name(2, folder
, filenameptr
);
3691 TRACE("Adding value %s to section %s in %s\n",
3692 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3693 debugstr_w(fullname
));
3694 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3695 deformated_value
, fullname
);
3697 else if (action
== 1)
3700 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3701 returned
, 10, fullname
);
3702 if (returned
[0] == 0)
3704 TRACE("Adding value %s to section %s in %s\n",
3705 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3706 debugstr_w(fullname
));
3708 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3709 deformated_value
, fullname
);
3712 else if (action
== 3)
3713 FIXME("Append to existing section not yet implemented\n");
3715 uirow
= MSI_CreateRecord(4);
3716 MSI_RecordSetStringW(uirow
,1,identifier
);
3717 MSI_RecordSetStringW(uirow
,2,deformated_section
);
3718 MSI_RecordSetStringW(uirow
,3,deformated_key
);
3719 MSI_RecordSetStringW(uirow
,4,deformated_value
);
3720 ui_actiondata(package
,szWriteIniValues
,uirow
);
3721 msiobj_release( &uirow
->hdr
);
3727 msi_free(deformated_key
);
3728 msi_free(deformated_value
);
3729 msi_free(deformated_section
);
3730 return ERROR_SUCCESS
;
3733 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
3737 static const WCHAR ExecSeqQuery
[] =
3738 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3739 '`','I','n','i','F','i','l','e','`',0};
3741 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3742 if (rc
!= ERROR_SUCCESS
)
3744 TRACE("no IniFile table\n");
3745 return ERROR_SUCCESS
;
3748 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
3749 msiobj_release(&view
->hdr
);
3753 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
3755 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3760 static const WCHAR ExeStr
[] =
3761 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3762 static const WCHAR close
[] = {'\"',0};
3764 PROCESS_INFORMATION info
;
3769 memset(&si
,0,sizeof(STARTUPINFOW
));
3771 filename
= MSI_RecordGetString(row
,1);
3772 file
= get_loaded_file( package
, filename
);
3776 ERR("Unable to find file id %s\n",debugstr_w(filename
));
3777 return ERROR_SUCCESS
;
3780 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
3782 FullName
= msi_alloc(len
*sizeof(WCHAR
));
3783 strcpyW(FullName
,ExeStr
);
3784 strcatW( FullName
, file
->TargetPath
);
3785 strcatW(FullName
,close
);
3787 TRACE("Registering %s\n",debugstr_w(FullName
));
3788 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
3793 CloseHandle(info
.hThread
);
3794 msi_dialog_check_messages(info
.hProcess
);
3795 CloseHandle(info
.hProcess
);
3801 uirow
= MSI_CreateRecord( 2 );
3802 uipath
= strdupW( file
->TargetPath
);
3803 p
= strrchrW(uipath
,'\\');
3806 MSI_RecordSetStringW( uirow
, 1, &p
[1] );
3807 MSI_RecordSetStringW( uirow
, 2, uipath
);
3808 ui_actiondata( package
, szSelfRegModules
, uirow
);
3809 msiobj_release( &uirow
->hdr
);
3811 /* FIXME: call ui_progress? */
3813 return ERROR_SUCCESS
;
3816 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
3820 static const WCHAR ExecSeqQuery
[] =
3821 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3822 '`','S','e','l','f','R','e','g','`',0};
3824 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3825 if (rc
!= ERROR_SUCCESS
)
3827 TRACE("no SelfReg table\n");
3828 return ERROR_SUCCESS
;
3831 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
3832 msiobj_release(&view
->hdr
);
3834 return ERROR_SUCCESS
;
3837 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
3839 MSIFEATURE
*feature
;
3842 HKEY userdata
= NULL
;
3844 if (!msi_check_publish(package
))
3845 return ERROR_SUCCESS
;
3847 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3849 rc
= MSIREG_OpenLocalClassesFeaturesKey(package
->ProductCode
,
3851 if (rc
!= ERROR_SUCCESS
)
3854 rc
= MSIREG_OpenLocalUserDataFeaturesKey(package
->ProductCode
,
3856 if (rc
!= ERROR_SUCCESS
)
3861 rc
= MSIREG_OpenUserFeaturesKey(package
->ProductCode
, &hkey
, TRUE
);
3862 if (rc
!= ERROR_SUCCESS
)
3865 rc
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
,
3867 if (rc
!= ERROR_SUCCESS
)
3871 /* here the guids are base 85 encoded */
3872 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
3878 BOOL absent
= FALSE
;
3881 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
) &&
3882 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_SOURCE
) &&
3883 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ADVERTISED
))
3887 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3891 if (feature
->Feature_Parent
)
3892 size
+= strlenW( feature
->Feature_Parent
)+2;
3894 data
= msi_alloc(size
* sizeof(WCHAR
));
3897 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3899 MSICOMPONENT
* component
= cl
->component
;
3903 if (component
->ComponentId
)
3905 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
3906 CLSIDFromString(component
->ComponentId
, &clsid
);
3907 encode_base85_guid(&clsid
,buf
);
3908 TRACE("to %s\n",debugstr_w(buf
));
3913 if (feature
->Feature_Parent
)
3915 static const WCHAR sep
[] = {'\2',0};
3917 strcatW(data
,feature
->Feature_Parent
);
3920 msi_reg_set_val_str( userdata
, feature
->Feature
, data
);
3924 if (feature
->Feature_Parent
)
3925 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
3928 static const WCHAR emptyW
[] = {0};
3929 size
+= sizeof(WCHAR
);
3930 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
3931 (LPBYTE
)(feature
->Feature_Parent
? feature
->Feature_Parent
: emptyW
),size
);
3935 size
+= 2*sizeof(WCHAR
);
3936 data
= msi_alloc(size
);
3939 if (feature
->Feature_Parent
)
3940 strcpyW( &data
[1], feature
->Feature_Parent
);
3941 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
3947 uirow
= MSI_CreateRecord( 1 );
3948 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
3949 ui_actiondata( package
, szPublishFeatures
, uirow
);
3950 msiobj_release( &uirow
->hdr
);
3951 /* FIXME: call ui_progress? */
3956 RegCloseKey(userdata
);
3960 static UINT
msi_unpublish_feature(MSIPACKAGE
*package
, MSIFEATURE
*feature
)
3965 TRACE("unpublishing feature %s\n", debugstr_w(feature
->Feature
));
3967 r
= MSIREG_OpenUserFeaturesKey(package
->ProductCode
, &hkey
, FALSE
);
3968 if (r
== ERROR_SUCCESS
)
3970 RegDeleteValueW(hkey
, feature
->Feature
);
3974 r
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, &hkey
, FALSE
);
3975 if (r
== ERROR_SUCCESS
)
3977 RegDeleteValueW(hkey
, feature
->Feature
);
3981 return ERROR_SUCCESS
;
3984 static UINT
ACTION_UnpublishFeatures(MSIPACKAGE
*package
)
3986 MSIFEATURE
*feature
;
3988 if (!msi_check_unpublish(package
))
3989 return ERROR_SUCCESS
;
3991 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3993 msi_unpublish_feature(package
, feature
);
3996 return ERROR_SUCCESS
;
3999 static UINT
msi_get_local_package_name( LPWSTR path
)
4001 static const WCHAR szInstaller
[] = {
4002 '\\','I','n','s','t','a','l','l','e','r','\\',0};
4003 static const WCHAR fmt
[] = { '%','x','.','m','s','i',0};
4007 time
= GetTickCount();
4008 GetWindowsDirectoryW( path
, MAX_PATH
);
4009 lstrcatW( path
, szInstaller
);
4010 CreateDirectoryW( path
, NULL
);
4012 len
= lstrlenW(path
);
4013 for (i
=0; i
<0x10000; i
++)
4015 snprintfW( &path
[len
], MAX_PATH
- len
, fmt
, (time
+i
)&0xffff );
4016 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
,
4017 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
4018 if (handle
!= INVALID_HANDLE_VALUE
)
4020 CloseHandle(handle
);
4023 if (GetLastError() != ERROR_FILE_EXISTS
&&
4024 GetLastError() != ERROR_SHARING_VIOLATION
)
4025 return ERROR_FUNCTION_FAILED
;
4028 return ERROR_SUCCESS
;
4031 static UINT
msi_make_package_local( MSIPACKAGE
*package
, HKEY hkey
)
4033 WCHAR packagefile
[MAX_PATH
];
4036 r
= msi_get_local_package_name( packagefile
);
4037 if (r
!= ERROR_SUCCESS
)
4040 TRACE("Copying to local package %s\n",debugstr_w(packagefile
));
4042 r
= CopyFileW( package
->db
->path
, packagefile
, FALSE
);
4046 ERR("Unable to copy package (%s -> %s) (error %d)\n",
4047 debugstr_w(package
->db
->path
), debugstr_w(packagefile
), GetLastError());
4048 return ERROR_FUNCTION_FAILED
;
4051 msi_reg_set_val_str( hkey
, INSTALLPROPERTY_LOCALPACKAGEW
, packagefile
);
4053 return ERROR_SUCCESS
;
4056 static UINT
msi_publish_install_properties(MSIPACKAGE
*package
, HKEY hkey
)
4058 LPWSTR prop
, val
, key
;
4064 static const WCHAR date_fmt
[] = {'%','i','%','0','2','i','%','0','2','i',0};
4065 static const WCHAR szWindowsInstaller
[] =
4066 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4067 static const WCHAR modpath_fmt
[] =
4068 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4069 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4070 static const WCHAR szModifyPath
[] =
4071 {'M','o','d','i','f','y','P','a','t','h',0};
4072 static const WCHAR szUninstallString
[] =
4073 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4074 static const WCHAR szEstimatedSize
[] =
4075 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4076 static const WCHAR szProductLanguage
[] =
4077 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4078 static const WCHAR szProductVersion
[] =
4079 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4080 static const WCHAR szProductName
[] =
4081 {'P','r','o','d','u','c','t','N','a','m','e',0};
4082 static const WCHAR szDisplayName
[] =
4083 {'D','i','s','p','l','a','y','N','a','m','e',0};
4084 static const WCHAR szDisplayVersion
[] =
4085 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4086 static const WCHAR szManufacturer
[] =
4087 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4089 static const LPCSTR propval
[] = {
4090 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4091 "ARPCONTACT", "Contact",
4092 "ARPCOMMENTS", "Comments",
4093 "ProductName", "DisplayName",
4094 "ProductVersion", "DisplayVersion",
4095 "ARPHELPLINK", "HelpLink",
4096 "ARPHELPTELEPHONE", "HelpTelephone",
4097 "ARPINSTALLLOCATION", "InstallLocation",
4098 "SourceDir", "InstallSource",
4099 "Manufacturer", "Publisher",
4100 "ARPREADME", "Readme",
4102 "ARPURLINFOABOUT", "URLInfoAbout",
4103 "ARPURLUPDATEINFO", "URLUpdateInfo",
4106 const LPCSTR
*p
= propval
;
4110 prop
= strdupAtoW(*p
++);
4111 key
= strdupAtoW(*p
++);
4112 val
= msi_dup_property(package
, prop
);
4113 msi_reg_set_val_str(hkey
, key
, val
);
4119 msi_reg_set_val_dword(hkey
, szWindowsInstaller
, 1);
4121 size
= deformat_string(package
, modpath_fmt
, &buffer
);
4122 RegSetValueExW(hkey
, szModifyPath
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4123 RegSetValueExW(hkey
, szUninstallString
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4126 /* FIXME: Write real Estimated Size when we have it */
4127 msi_reg_set_val_dword(hkey
, szEstimatedSize
, 0);
4129 buffer
= msi_dup_property(package
, szProductName
);
4130 msi_reg_set_val_str(hkey
, szDisplayName
, buffer
);
4133 buffer
= msi_dup_property(package
, cszSourceDir
);
4134 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLSOURCEW
, buffer
);
4137 buffer
= msi_dup_property(package
, szManufacturer
);
4138 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PUBLISHERW
, buffer
);
4141 GetLocalTime(&systime
);
4142 sprintfW(date
, date_fmt
, systime
.wYear
, systime
.wMonth
, systime
.wDay
);
4143 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLDATEW
, date
);
4145 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
4146 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
4148 buffer
= msi_dup_property(package
, szProductVersion
);
4149 msi_reg_set_val_str(hkey
, szDisplayVersion
, buffer
);
4152 DWORD verdword
= msi_version_str_to_dword(buffer
);
4154 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
4155 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>> 24);
4156 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>> 16) & 0xFF);
4160 return ERROR_SUCCESS
;
4163 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
4165 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
4166 LPWSTR upgrade_code
;
4171 static const WCHAR szUpgradeCode
[] = {
4172 'U','p','g','r','a','d','e','C','o','d','e',0};
4174 /* FIXME: also need to publish if the product is in advertise mode */
4175 if (!msi_check_publish(package
))
4176 return ERROR_SUCCESS
;
4178 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
, &hkey
, TRUE
);
4179 if (rc
!= ERROR_SUCCESS
)
4182 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4184 rc
= MSIREG_OpenLocalSystemInstallProps(package
->ProductCode
, &props
, TRUE
);
4185 if (rc
!= ERROR_SUCCESS
)
4190 rc
= MSIREG_OpenCurrentUserInstallProps(package
->ProductCode
, &props
, TRUE
);
4191 if (rc
!= ERROR_SUCCESS
)
4195 msi_make_package_local(package
, props
);
4197 rc
= msi_publish_install_properties(package
, hkey
);
4198 if (rc
!= ERROR_SUCCESS
)
4201 rc
= msi_publish_install_properties(package
, props
);
4202 if (rc
!= ERROR_SUCCESS
)
4205 upgrade_code
= msi_dup_property(package
, szUpgradeCode
);
4208 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &upgrade
, TRUE
);
4209 squash_guid(package
->ProductCode
, squashed_pc
);
4210 msi_reg_set_val_str(upgrade
, squashed_pc
, NULL
);
4211 RegCloseKey(upgrade
);
4212 msi_free(upgrade_code
);
4218 return ERROR_SUCCESS
;
4221 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
4223 return execute_script(package
,INSTALL_SCRIPT
);
4226 static UINT
msi_unpublish_product(MSIPACKAGE
*package
)
4229 LPWSTR remove
= NULL
;
4230 LPWSTR
*features
= NULL
;
4231 BOOL full_uninstall
= TRUE
;
4232 MSIFEATURE
*feature
;
4234 static const WCHAR szRemove
[] = {'R','E','M','O','V','E',0};
4235 static const WCHAR szAll
[] = {'A','L','L',0};
4236 static const WCHAR szUpgradeCode
[] =
4237 {'U','p','g','r','a','d','e','C','o','d','e',0};
4239 remove
= msi_dup_property(package
, szRemove
);
4241 return ERROR_SUCCESS
;
4243 features
= msi_split_string(remove
, ',');
4247 ERR("REMOVE feature list is empty!\n");
4248 return ERROR_FUNCTION_FAILED
;
4251 if (!lstrcmpW(features
[0], szAll
))
4252 full_uninstall
= TRUE
;
4255 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4257 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
4258 full_uninstall
= FALSE
;
4262 if (!full_uninstall
)
4265 MSIREG_DeleteProductKey(package
->ProductCode
);
4266 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4267 MSIREG_DeleteUninstallKey(package
->ProductCode
);
4269 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4271 MSIREG_DeleteLocalClassesProductKey(package
->ProductCode
);
4272 MSIREG_DeleteLocalClassesFeaturesKey(package
->ProductCode
);
4276 MSIREG_DeleteUserProductKey(package
->ProductCode
);
4277 MSIREG_DeleteUserFeaturesKey(package
->ProductCode
);
4280 upgrade
= msi_dup_property(package
, szUpgradeCode
);
4283 MSIREG_DeleteUserUpgradeCodesKey(upgrade
);
4290 return ERROR_SUCCESS
;
4293 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
4297 rc
= msi_unpublish_product(package
);
4298 if (rc
!= ERROR_SUCCESS
)
4301 /* turn off scheduling */
4302 package
->script
->CurrentlyScripting
= FALSE
;
4304 /* first do the same as an InstallExecute */
4305 rc
= ACTION_InstallExecute(package
);
4306 if (rc
!= ERROR_SUCCESS
)
4309 /* then handle Commit Actions */
4310 rc
= execute_script(package
,COMMIT_SCRIPT
);
4315 UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
4317 static const WCHAR RunOnce
[] = {
4318 'S','o','f','t','w','a','r','e','\\',
4319 'M','i','c','r','o','s','o','f','t','\\',
4320 'W','i','n','d','o','w','s','\\',
4321 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4322 'R','u','n','O','n','c','e',0};
4323 static const WCHAR InstallRunOnce
[] = {
4324 'S','o','f','t','w','a','r','e','\\',
4325 'M','i','c','r','o','s','o','f','t','\\',
4326 'W','i','n','d','o','w','s','\\',
4327 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4328 'I','n','s','t','a','l','l','e','r','\\',
4329 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4331 static const WCHAR msiexec_fmt
[] = {
4333 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4334 '\"','%','s','\"',0};
4335 static const WCHAR install_fmt
[] = {
4336 '/','I',' ','\"','%','s','\"',' ',
4337 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4338 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4339 WCHAR buffer
[256], sysdir
[MAX_PATH
];
4341 WCHAR squished_pc
[100];
4343 squash_guid(package
->ProductCode
,squished_pc
);
4345 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
4346 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
4347 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
4350 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4353 TRACE("Reboot command %s\n",debugstr_w(buffer
));
4355 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
4356 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
4358 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4361 return ERROR_INSTALL_SUSPEND
;
4364 static UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
4370 * We are currently doing what should be done here in the top level Install
4371 * however for Administrative and uninstalls this step will be needed
4373 if (!package
->PackagePath
)
4374 return ERROR_SUCCESS
;
4376 msi_set_sourcedir_props(package
, TRUE
);
4378 attrib
= GetFileAttributesW(package
->db
->path
);
4379 if (attrib
== INVALID_FILE_ATTRIBUTES
)
4385 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4386 package
->Context
, MSICODE_PRODUCT
,
4387 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
4388 if (rc
== ERROR_MORE_DATA
)
4390 prompt
= msi_alloc(size
* sizeof(WCHAR
));
4391 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4392 package
->Context
, MSICODE_PRODUCT
,
4393 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
4396 prompt
= strdupW(package
->db
->path
);
4398 msg
= generate_error_string(package
,1302,1,prompt
);
4399 while(attrib
== INVALID_FILE_ATTRIBUTES
)
4401 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
4404 rc
= ERROR_INSTALL_USEREXIT
;
4407 attrib
= GetFileAttributesW(package
->db
->path
);
4413 return ERROR_SUCCESS
;
4418 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
4425 static const WCHAR szPropKeys
[][80] =
4427 {'P','r','o','d','u','c','t','I','D',0},
4428 {'U','S','E','R','N','A','M','E',0},
4429 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4433 static const WCHAR szRegKeys
[][80] =
4435 {'P','r','o','d','u','c','t','I','D',0},
4436 {'R','e','g','O','w','n','e','r',0},
4437 {'R','e','g','C','o','m','p','a','n','y',0},
4441 if (msi_check_unpublish(package
))
4443 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4444 return ERROR_SUCCESS
;
4447 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
4449 return ERROR_SUCCESS
;
4451 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4452 rc
= MSIREG_OpenLocalSystemInstallProps(package
->ProductCode
, &hkey
, TRUE
);
4454 rc
= MSIREG_OpenCurrentUserInstallProps(package
->ProductCode
, &hkey
, TRUE
);
4456 if (rc
!= ERROR_SUCCESS
)
4459 for( i
= 0; szPropKeys
[i
][0]; i
++ )
4461 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
4462 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
4467 msi_free(productid
);
4470 /* FIXME: call ui_actiondata */
4476 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
4480 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
4481 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
4486 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4488 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4489 LPCWSTR compgroupid
=NULL
;
4490 LPCWSTR feature
=NULL
;
4491 LPCWSTR text
= NULL
;
4492 LPCWSTR qualifier
= NULL
;
4493 LPCWSTR component
= NULL
;
4494 LPWSTR advertise
= NULL
;
4495 LPWSTR output
= NULL
;
4497 UINT rc
= ERROR_SUCCESS
;
4502 component
= MSI_RecordGetString(rec
,3);
4503 comp
= get_loaded_component(package
,component
);
4505 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) &&
4506 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
) &&
4507 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ADVERTISED
))
4509 TRACE("Skipping: Component %s not scheduled for install\n",
4510 debugstr_w(component
));
4512 return ERROR_SUCCESS
;
4515 compgroupid
= MSI_RecordGetString(rec
,1);
4516 qualifier
= MSI_RecordGetString(rec
,2);
4518 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
4519 if (rc
!= ERROR_SUCCESS
)
4522 text
= MSI_RecordGetString(rec
,4);
4523 feature
= MSI_RecordGetString(rec
,5);
4525 advertise
= create_component_advertise_string(package
, comp
, feature
);
4527 sz
= strlenW(advertise
);
4530 sz
+= lstrlenW(text
);
4533 sz
*= sizeof(WCHAR
);
4535 output
= msi_alloc_zero(sz
);
4536 strcpyW(output
,advertise
);
4537 msi_free(advertise
);
4540 strcatW(output
,text
);
4542 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
4549 uirow
= MSI_CreateRecord( 2 );
4550 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4551 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4552 ui_actiondata( package
, szPublishComponents
, uirow
);
4553 msiobj_release( &uirow
->hdr
);
4554 /* FIXME: call ui_progress? */
4560 * At present I am ignorning the advertised components part of this and only
4561 * focusing on the qualified component sets
4563 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
4567 static const WCHAR ExecSeqQuery
[] =
4568 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4569 '`','P','u','b','l','i','s','h',
4570 'C','o','m','p','o','n','e','n','t','`',0};
4572 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4573 if (rc
!= ERROR_SUCCESS
)
4574 return ERROR_SUCCESS
;
4576 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
4577 msiobj_release(&view
->hdr
);
4582 static UINT
ITERATE_InstallService(MSIRECORD
*rec
, LPVOID param
)
4584 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4587 SC_HANDLE hscm
, service
= NULL
;
4588 LPCWSTR comp
, depends
, pass
;
4589 LPWSTR name
= NULL
, disp
= NULL
;
4590 LPCWSTR load_order
, serv_name
, key
;
4591 DWORD serv_type
, start_type
;
4594 static const WCHAR query
[] =
4595 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4596 '`','C','o','m','p','o','n','e','n','t','`',' ',
4597 'W','H','E','R','E',' ',
4598 '`','C','o','m','p','o','n','e','n','t','`',' ',
4599 '=','\'','%','s','\'',0};
4601 hscm
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASEW
, GENERIC_WRITE
);
4604 ERR("Failed to open the SC Manager!\n");
4608 start_type
= MSI_RecordGetInteger(rec
, 5);
4609 if (start_type
== SERVICE_BOOT_START
|| start_type
== SERVICE_SYSTEM_START
)
4612 depends
= MSI_RecordGetString(rec
, 8);
4613 if (depends
&& *depends
)
4614 FIXME("Dependency list unhandled!\n");
4616 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
4617 deformat_string(package
, MSI_RecordGetString(rec
, 3), &disp
);
4618 serv_type
= MSI_RecordGetInteger(rec
, 4);
4619 err_control
= MSI_RecordGetInteger(rec
, 6);
4620 load_order
= MSI_RecordGetString(rec
, 7);
4621 serv_name
= MSI_RecordGetString(rec
, 9);
4622 pass
= MSI_RecordGetString(rec
, 10);
4623 comp
= MSI_RecordGetString(rec
, 12);
4625 /* fetch the service path */
4626 row
= MSI_QueryGetRecord(package
->db
, query
, comp
);
4629 ERR("Control query failed!\n");
4633 key
= MSI_RecordGetString(row
, 6);
4635 file
= get_loaded_file(package
, key
);
4636 msiobj_release(&row
->hdr
);
4639 ERR("Failed to load the service file\n");
4643 service
= CreateServiceW(hscm
, name
, disp
, GENERIC_ALL
, serv_type
,
4644 start_type
, err_control
, file
->TargetPath
,
4645 load_order
, NULL
, NULL
, serv_name
, pass
);
4648 if (GetLastError() != ERROR_SERVICE_EXISTS
)
4649 ERR("Failed to create service %s: %d\n", debugstr_w(name
), GetLastError());
4653 CloseServiceHandle(service
);
4654 CloseServiceHandle(hscm
);
4658 return ERROR_SUCCESS
;
4661 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
4665 static const WCHAR ExecSeqQuery
[] =
4666 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4667 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4669 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4670 if (rc
!= ERROR_SUCCESS
)
4671 return ERROR_SUCCESS
;
4673 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallService
, package
);
4674 msiobj_release(&view
->hdr
);
4679 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4680 static LPCWSTR
*msi_service_args_to_vector(LPWSTR args
, DWORD
*numargs
)
4682 LPCWSTR
*vector
, *temp_vector
;
4686 static const WCHAR separator
[] = {'[','~',']',0};
4689 sep_len
= sizeof(separator
) / sizeof(WCHAR
) - 1;
4694 vector
= msi_alloc(sizeof(LPWSTR
));
4702 vector
[*numargs
- 1] = p
;
4704 if ((q
= strstrW(p
, separator
)))
4708 temp_vector
= msi_realloc(vector
, (*numargs
+ 1) * sizeof(LPWSTR
));
4714 vector
= temp_vector
;
4723 static UINT
ITERATE_StartService(MSIRECORD
*rec
, LPVOID param
)
4725 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4727 SC_HANDLE scm
, service
= NULL
;
4728 LPCWSTR name
, *vector
= NULL
;
4730 DWORD event
, numargs
;
4731 UINT r
= ERROR_FUNCTION_FAILED
;
4733 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 6));
4734 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4735 return ERROR_SUCCESS
;
4737 name
= MSI_RecordGetString(rec
, 2);
4738 event
= MSI_RecordGetInteger(rec
, 3);
4739 args
= strdupW(MSI_RecordGetString(rec
, 4));
4741 if (!(event
& msidbServiceControlEventStart
))
4742 return ERROR_SUCCESS
;
4744 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_CONNECT
);
4747 ERR("Failed to open the service control manager\n");
4751 service
= OpenServiceW(scm
, name
, SERVICE_START
);
4754 ERR("Failed to open service %s\n", debugstr_w(name
));
4758 vector
= msi_service_args_to_vector(args
, &numargs
);
4760 if (!StartServiceW(service
, numargs
, vector
))
4762 ERR("Failed to start service %s\n", debugstr_w(name
));
4769 CloseServiceHandle(service
);
4770 CloseServiceHandle(scm
);
4777 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
4782 static const WCHAR query
[] = {
4783 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4784 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4786 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4787 if (rc
!= ERROR_SUCCESS
)
4788 return ERROR_SUCCESS
;
4790 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StartService
, package
);
4791 msiobj_release(&view
->hdr
);
4796 static BOOL
stop_service_dependents(SC_HANDLE scm
, SC_HANDLE service
)
4798 DWORD i
, needed
, count
;
4799 ENUM_SERVICE_STATUSW
*dependencies
;
4803 if (EnumDependentServicesW(service
, SERVICE_ACTIVE
, NULL
,
4804 0, &needed
, &count
))
4807 if (GetLastError() != ERROR_MORE_DATA
)
4810 dependencies
= msi_alloc(needed
);
4814 if (!EnumDependentServicesW(service
, SERVICE_ACTIVE
, dependencies
,
4815 needed
, &needed
, &count
))
4818 for (i
= 0; i
< count
; i
++)
4820 depserv
= OpenServiceW(scm
, dependencies
[i
].lpServiceName
,
4821 SERVICE_STOP
| SERVICE_QUERY_STATUS
);
4825 if (!ControlService(depserv
, SERVICE_CONTROL_STOP
, &ss
))
4832 msi_free(dependencies
);
4836 static UINT
ITERATE_StopService(MSIRECORD
*rec
, LPVOID param
)
4838 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4840 SERVICE_STATUS status
;
4841 SERVICE_STATUS_PROCESS ssp
;
4842 SC_HANDLE scm
= NULL
, service
= NULL
;
4844 DWORD event
, needed
;
4846 event
= MSI_RecordGetInteger(rec
, 3);
4847 if (!(event
& msidbServiceControlEventStop
))
4848 return ERROR_SUCCESS
;
4850 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 6));
4851 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4852 return ERROR_SUCCESS
;
4854 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
4855 deformat_string(package
, MSI_RecordGetString(rec
, 4), &args
);
4856 args
= strdupW(MSI_RecordGetString(rec
, 4));
4858 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
4861 WARN("Failed to open the SCM: %d\n", GetLastError());
4865 service
= OpenServiceW(scm
, name
,
4867 SERVICE_QUERY_STATUS
|
4868 SERVICE_ENUMERATE_DEPENDENTS
);
4871 WARN("Failed to open service (%s): %d\n",
4872 debugstr_w(name
), GetLastError());
4876 if (!QueryServiceStatusEx(service
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&ssp
,
4877 sizeof(SERVICE_STATUS_PROCESS
), &needed
))
4879 WARN("Failed to query service status (%s): %d\n",
4880 debugstr_w(name
), GetLastError());
4884 if (ssp
.dwCurrentState
== SERVICE_STOPPED
)
4887 stop_service_dependents(scm
, service
);
4889 if (!ControlService(service
, SERVICE_CONTROL_STOP
, &status
))
4890 WARN("Failed to stop service (%s): %d\n", debugstr_w(name
), GetLastError());
4893 CloseServiceHandle(service
);
4894 CloseServiceHandle(scm
);
4898 return ERROR_SUCCESS
;
4901 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
4906 static const WCHAR query
[] = {
4907 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4908 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4910 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4911 if (rc
!= ERROR_SUCCESS
)
4912 return ERROR_SUCCESS
;
4914 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StopService
, package
);
4915 msiobj_release(&view
->hdr
);
4920 static MSIFILE
*msi_find_file( MSIPACKAGE
*package
, LPCWSTR filename
)
4924 LIST_FOR_EACH_ENTRY(file
, &package
->files
, MSIFILE
, entry
)
4926 if (!lstrcmpW(file
->File
, filename
))
4933 static UINT
ITERATE_InstallODBCDriver( MSIRECORD
*rec
, LPVOID param
)
4935 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4936 LPWSTR driver
, driver_path
, ptr
;
4937 WCHAR outpath
[MAX_PATH
];
4938 MSIFILE
*driver_file
, *setup_file
;
4941 UINT r
= ERROR_SUCCESS
;
4943 static const WCHAR driver_fmt
[] = {
4944 'D','r','i','v','e','r','=','%','s',0};
4945 static const WCHAR setup_fmt
[] = {
4946 'S','e','t','u','p','=','%','s',0};
4947 static const WCHAR usage_fmt
[] = {
4948 'F','i','l','e','U','s','a','g','e','=','1',0};
4950 desc
= MSI_RecordGetString(rec
, 3);
4952 driver_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
4953 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
4955 if (!driver_file
|| !setup_file
)
4957 ERR("ODBC Driver entry not found!\n");
4958 return ERROR_FUNCTION_FAILED
;
4961 len
= lstrlenW(desc
) + lstrlenW(driver_fmt
) + lstrlenW(driver_file
->FileName
) +
4962 lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
) +
4963 lstrlenW(usage_fmt
) + 1;
4964 driver
= msi_alloc(len
* sizeof(WCHAR
));
4966 return ERROR_OUTOFMEMORY
;
4969 lstrcpyW(ptr
, desc
);
4970 ptr
+= lstrlenW(ptr
) + 1;
4972 sprintfW(ptr
, driver_fmt
, driver_file
->FileName
);
4973 ptr
+= lstrlenW(ptr
) + 1;
4975 sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
4976 ptr
+= lstrlenW(ptr
) + 1;
4978 lstrcpyW(ptr
, usage_fmt
);
4979 ptr
+= lstrlenW(ptr
) + 1;
4982 driver_path
= strdupW(driver_file
->TargetPath
);
4983 ptr
= strrchrW(driver_path
, '\\');
4984 if (ptr
) *ptr
= '\0';
4986 if (!SQLInstallDriverExW(driver
, driver_path
, outpath
, MAX_PATH
,
4987 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
4989 ERR("Failed to install SQL driver!\n");
4990 r
= ERROR_FUNCTION_FAILED
;
4994 msi_free(driver_path
);
4999 static UINT
ITERATE_InstallODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5001 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
5002 LPWSTR translator
, translator_path
, ptr
;
5003 WCHAR outpath
[MAX_PATH
];
5004 MSIFILE
*translator_file
, *setup_file
;
5007 UINT r
= ERROR_SUCCESS
;
5009 static const WCHAR translator_fmt
[] = {
5010 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5011 static const WCHAR setup_fmt
[] = {
5012 'S','e','t','u','p','=','%','s',0};
5014 desc
= MSI_RecordGetString(rec
, 3);
5016 translator_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5017 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5019 if (!translator_file
|| !setup_file
)
5021 ERR("ODBC Translator entry not found!\n");
5022 return ERROR_FUNCTION_FAILED
;
5025 len
= lstrlenW(desc
) + lstrlenW(translator_fmt
) + lstrlenW(translator_file
->FileName
) +
5026 lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
) + 1;
5027 translator
= msi_alloc(len
* sizeof(WCHAR
));
5029 return ERROR_OUTOFMEMORY
;
5032 lstrcpyW(ptr
, desc
);
5033 ptr
+= lstrlenW(ptr
) + 1;
5035 sprintfW(ptr
, translator_fmt
, translator_file
->FileName
);
5036 ptr
+= lstrlenW(ptr
) + 1;
5038 sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5039 ptr
+= lstrlenW(ptr
) + 1;
5042 translator_path
= strdupW(translator_file
->TargetPath
);
5043 ptr
= strrchrW(translator_path
, '\\');
5044 if (ptr
) *ptr
= '\0';
5046 if (!SQLInstallTranslatorExW(translator
, translator_path
, outpath
, MAX_PATH
,
5047 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5049 ERR("Failed to install SQL translator!\n");
5050 r
= ERROR_FUNCTION_FAILED
;
5053 msi_free(translator
);
5054 msi_free(translator_path
);
5059 static UINT
ITERATE_InstallODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5062 LPCWSTR desc
, driver
;
5063 WORD request
= ODBC_ADD_SYS_DSN
;
5066 UINT r
= ERROR_SUCCESS
;
5068 static const WCHAR attrs_fmt
[] = {
5069 'D','S','N','=','%','s',0 };
5071 desc
= MSI_RecordGetString(rec
, 3);
5072 driver
= MSI_RecordGetString(rec
, 4);
5073 registration
= MSI_RecordGetInteger(rec
, 5);
5075 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_ADD_SYS_DSN
;
5076 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_ADD_DSN
;
5078 len
= lstrlenW(attrs_fmt
) + lstrlenW(desc
) + 1 + 1;
5079 attrs
= msi_alloc(len
* sizeof(WCHAR
));
5081 return ERROR_OUTOFMEMORY
;
5083 sprintfW(attrs
, attrs_fmt
, desc
);
5084 attrs
[len
- 1] = '\0';
5086 if (!SQLConfigDataSourceW(NULL
, request
, driver
, attrs
))
5088 ERR("Failed to install SQL data source!\n");
5089 r
= ERROR_FUNCTION_FAILED
;
5097 static UINT
ACTION_InstallODBC( MSIPACKAGE
*package
)
5102 static const WCHAR driver_query
[] = {
5103 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5104 'O','D','B','C','D','r','i','v','e','r',0 };
5106 static const WCHAR translator_query
[] = {
5107 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5108 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5110 static const WCHAR source_query
[] = {
5111 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5112 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5114 rc
= MSI_DatabaseOpenViewW(package
->db
, driver_query
, &view
);
5115 if (rc
!= ERROR_SUCCESS
)
5116 return ERROR_SUCCESS
;
5118 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDriver
, package
);
5119 msiobj_release(&view
->hdr
);
5121 rc
= MSI_DatabaseOpenViewW(package
->db
, translator_query
, &view
);
5122 if (rc
!= ERROR_SUCCESS
)
5123 return ERROR_SUCCESS
;
5125 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCTranslator
, package
);
5126 msiobj_release(&view
->hdr
);
5128 rc
= MSI_DatabaseOpenViewW(package
->db
, source_query
, &view
);
5129 if (rc
!= ERROR_SUCCESS
)
5130 return ERROR_SUCCESS
;
5132 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDataSource
, package
);
5133 msiobj_release(&view
->hdr
);
5138 #define ENV_ACT_SETALWAYS 0x1
5139 #define ENV_ACT_SETABSENT 0x2
5140 #define ENV_ACT_REMOVE 0x4
5141 #define ENV_ACT_REMOVEMATCH 0x8
5143 #define ENV_MOD_MACHINE 0x20000000
5144 #define ENV_MOD_APPEND 0x40000000
5145 #define ENV_MOD_PREFIX 0x80000000
5146 #define ENV_MOD_MASK 0xC0000000
5148 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5150 static LONG
env_set_flags( LPCWSTR
*name
, LPCWSTR
*value
, DWORD
*flags
)
5152 LPCWSTR cptr
= *name
;
5153 LPCWSTR ptr
= *value
;
5155 static const WCHAR prefix
[] = {'[','~',']',0};
5156 static const int prefix_len
= 3;
5162 *flags
|= ENV_ACT_SETALWAYS
;
5163 else if (*cptr
== '+')
5164 *flags
|= ENV_ACT_SETABSENT
;
5165 else if (*cptr
== '-')
5166 *flags
|= ENV_ACT_REMOVE
;
5167 else if (*cptr
== '!')
5168 *flags
|= ENV_ACT_REMOVEMATCH
;
5169 else if (*cptr
== '*')
5170 *flags
|= ENV_MOD_MACHINE
;
5180 ERR("Missing environment variable\n");
5181 return ERROR_FUNCTION_FAILED
;
5184 if (!strncmpW(ptr
, prefix
, prefix_len
))
5186 *flags
|= ENV_MOD_APPEND
;
5187 *value
+= lstrlenW(prefix
);
5189 else if (lstrlenW(*value
) >= prefix_len
)
5191 ptr
+= lstrlenW(ptr
) - prefix_len
;
5192 if (!lstrcmpW(ptr
, prefix
))
5194 *flags
|= ENV_MOD_PREFIX
;
5195 /* the "[~]" will be removed by deformat_string */;
5200 check_flag_combo(*flags
, ENV_ACT_SETALWAYS
| ENV_ACT_SETABSENT
) ||
5201 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETABSENT
) ||
5202 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETALWAYS
) ||
5203 check_flag_combo(*flags
, ENV_ACT_SETABSENT
| ENV_MOD_MASK
))
5205 ERR("Invalid flags: %08x\n", *flags
);
5206 return ERROR_FUNCTION_FAILED
;
5209 return ERROR_SUCCESS
;
5212 static UINT
ITERATE_WriteEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
5214 MSIPACKAGE
*package
= param
;
5215 LPCWSTR name
, value
;
5216 LPWSTR data
= NULL
, newval
= NULL
;
5217 LPWSTR deformatted
= NULL
, ptr
;
5218 DWORD flags
, type
, size
;
5220 HKEY env
= NULL
, root
;
5221 LPCWSTR environment
;
5223 static const WCHAR user_env
[] =
5224 {'E','n','v','i','r','o','n','m','e','n','t',0};
5225 static const WCHAR machine_env
[] =
5226 {'S','y','s','t','e','m','\\',
5227 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5228 'C','o','n','t','r','o','l','\\',
5229 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5230 'E','n','v','i','r','o','n','m','e','n','t',0};
5231 static const WCHAR semicolon
[] = {';',0};
5233 name
= MSI_RecordGetString(rec
, 2);
5234 value
= MSI_RecordGetString(rec
, 3);
5236 res
= env_set_flags(&name
, &value
, &flags
);
5237 if (res
!= ERROR_SUCCESS
)
5240 deformat_string(package
, value
, &deformatted
);
5243 res
= ERROR_OUTOFMEMORY
;
5247 value
= deformatted
;
5249 if (flags
& ENV_MOD_MACHINE
)
5251 environment
= machine_env
;
5252 root
= HKEY_LOCAL_MACHINE
;
5256 environment
= user_env
;
5257 root
= HKEY_CURRENT_USER
;
5260 res
= RegCreateKeyExW(root
, environment
, 0, NULL
, 0,
5261 KEY_ALL_ACCESS
, NULL
, &env
, NULL
);
5262 if (res
!= ERROR_SUCCESS
)
5265 if (flags
& ENV_ACT_REMOVE
)
5266 FIXME("Not removing environment variable on uninstall!\n");
5269 res
= RegQueryValueExW(env
, name
, NULL
, &type
, NULL
, &size
);
5270 if ((res
!= ERROR_SUCCESS
&& res
!= ERROR_FILE_NOT_FOUND
) ||
5271 (res
== ERROR_SUCCESS
&& type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
))
5274 if (res
!= ERROR_FILE_NOT_FOUND
)
5276 if (flags
& ENV_ACT_SETABSENT
)
5278 res
= ERROR_SUCCESS
;
5282 data
= msi_alloc(size
);
5286 return ERROR_OUTOFMEMORY
;
5289 res
= RegQueryValueExW(env
, name
, NULL
, &type
, (LPVOID
)data
, &size
);
5290 if (res
!= ERROR_SUCCESS
)
5293 if (flags
& ENV_ACT_REMOVEMATCH
&& (!value
|| !lstrcmpW(data
, value
)))
5295 res
= RegDeleteKeyW(env
, name
);
5299 size
= (lstrlenW(value
) + 1 + size
) * sizeof(WCHAR
);
5300 newval
= msi_alloc(size
);
5304 res
= ERROR_OUTOFMEMORY
;
5308 if (!(flags
& ENV_MOD_MASK
))
5309 lstrcpyW(newval
, value
);
5312 if (flags
& ENV_MOD_PREFIX
)
5314 lstrcpyW(newval
, value
);
5315 lstrcatW(newval
, semicolon
);
5316 ptr
= newval
+ lstrlenW(value
) + 1;
5319 lstrcpyW(ptr
, data
);
5321 if (flags
& ENV_MOD_APPEND
)
5323 lstrcatW(newval
, semicolon
);
5324 lstrcatW(newval
, value
);
5330 size
= (lstrlenW(value
) + 1) * sizeof(WCHAR
);
5331 newval
= msi_alloc(size
);
5334 res
= ERROR_OUTOFMEMORY
;
5338 lstrcpyW(newval
, value
);
5341 TRACE("setting %s to %s\n", debugstr_w(name
), debugstr_w(newval
));
5342 res
= RegSetValueExW(env
, name
, 0, type
, (LPVOID
)newval
, size
);
5345 if (env
) RegCloseKey(env
);
5346 msi_free(deformatted
);
5352 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
5356 static const WCHAR ExecSeqQuery
[] =
5357 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5358 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5359 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5360 if (rc
!= ERROR_SUCCESS
)
5361 return ERROR_SUCCESS
;
5363 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteEnvironmentString
, package
);
5364 msiobj_release(&view
->hdr
);
5369 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5380 static BOOL
msi_move_file(LPCWSTR source
, LPCWSTR dest
, int options
)
5384 if (GetFileAttributesW(source
) == FILE_ATTRIBUTE_DIRECTORY
||
5385 GetFileAttributesW(dest
) == FILE_ATTRIBUTE_DIRECTORY
)
5387 WARN("Source or dest is directory, not moving\n");
5391 if (options
== msidbMoveFileOptionsMove
)
5393 TRACE("moving %s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
5394 ret
= MoveFileExW(source
, dest
, MOVEFILE_REPLACE_EXISTING
);
5397 WARN("MoveFile failed: %d\n", GetLastError());
5403 TRACE("copying %s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
5404 ret
= CopyFileW(source
, dest
, FALSE
);
5407 WARN("CopyFile failed: %d\n", GetLastError());
5415 static LPWSTR
wildcard_to_file(LPWSTR wildcard
, LPWSTR filename
)
5418 DWORD dirlen
, pathlen
;
5420 ptr
= strrchrW(wildcard
, '\\');
5421 dirlen
= ptr
- wildcard
+ 1;
5423 pathlen
= dirlen
+ lstrlenW(filename
) + 1;
5424 path
= msi_alloc(pathlen
* sizeof(WCHAR
));
5426 lstrcpynW(path
, wildcard
, dirlen
+ 1);
5427 lstrcatW(path
, filename
);
5432 static void free_file_entry(FILE_LIST
*file
)
5434 msi_free(file
->source
);
5435 msi_free(file
->dest
);
5439 static void free_list(FILE_LIST
*list
)
5441 while (!list_empty(&list
->entry
))
5443 FILE_LIST
*file
= LIST_ENTRY(list_head(&list
->entry
), FILE_LIST
, entry
);
5445 list_remove(&file
->entry
);
5446 free_file_entry(file
);
5450 static BOOL
add_wildcard(FILE_LIST
*files
, LPWSTR source
, LPWSTR dest
)
5452 FILE_LIST
*new, *file
;
5453 LPWSTR ptr
, filename
;
5456 new = msi_alloc_zero(sizeof(FILE_LIST
));
5460 new->source
= strdupW(source
);
5461 ptr
= strrchrW(dest
, '\\') + 1;
5462 filename
= strrchrW(new->source
, '\\') + 1;
5464 new->sourcename
= filename
;
5467 new->destname
= ptr
;
5469 new->destname
= new->sourcename
;
5471 size
= (ptr
- dest
) + lstrlenW(filename
) + 1;
5472 new->dest
= msi_alloc(size
* sizeof(WCHAR
));
5475 free_file_entry(new);
5479 lstrcpynW(new->dest
, dest
, ptr
- dest
+ 1);
5480 lstrcatW(new->dest
, filename
);
5482 if (list_empty(&files
->entry
))
5484 list_add_head(&files
->entry
, &new->entry
);
5488 LIST_FOR_EACH_ENTRY(file
, &files
->entry
, FILE_LIST
, entry
)
5490 if (lstrcmpW(source
, file
->source
) < 0)
5492 list_add_before(&file
->entry
, &new->entry
);
5497 list_add_after(&file
->entry
, &new->entry
);
5501 static BOOL
move_files_wildcard(LPWSTR source
, LPWSTR dest
, int options
)
5503 WIN32_FIND_DATAW wfd
;
5507 FILE_LIST files
, *file
;
5510 hfile
= FindFirstFileW(source
, &wfd
);
5511 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
5513 list_init(&files
.entry
);
5515 for (res
= TRUE
; res
; res
= FindNextFileW(hfile
, &wfd
))
5517 if (is_dot_dir(wfd
.cFileName
)) continue;
5519 path
= wildcard_to_file(source
, wfd
.cFileName
);
5526 add_wildcard(&files
, path
, dest
);
5530 /* no files match the wildcard */
5531 if (list_empty(&files
.entry
))
5534 /* only the first wildcard match gets renamed to dest */
5535 file
= LIST_ENTRY(list_head(&files
.entry
), FILE_LIST
, entry
);
5536 size
= (strrchrW(file
->dest
, '\\') - file
->dest
) + lstrlenW(file
->destname
) + 2;
5537 file
->dest
= msi_realloc(file
->dest
, size
* sizeof(WCHAR
));
5544 lstrcpyW(strrchrW(file
->dest
, '\\') + 1, file
->destname
);
5546 while (!list_empty(&files
.entry
))
5548 file
= LIST_ENTRY(list_head(&files
.entry
), FILE_LIST
, entry
);
5550 msi_move_file((LPCWSTR
)file
->source
, (LPCWSTR
)file
->dest
, options
);
5552 list_remove(&file
->entry
);
5553 free_file_entry(file
);
5564 static UINT
ITERATE_MoveFiles( MSIRECORD
*rec
, LPVOID param
)
5566 MSIPACKAGE
*package
= param
;
5569 LPWSTR destname
= NULL
;
5570 LPWSTR sourcedir
= NULL
, destdir
= NULL
;
5571 LPWSTR source
= NULL
, dest
= NULL
;
5574 BOOL ret
, wildcards
;
5576 static const WCHAR backslash
[] = {'\\',0};
5578 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 2));
5579 if (!comp
|| !comp
->Enabled
||
5580 !(comp
->Action
& (INSTALLSTATE_LOCAL
| INSTALLSTATE_SOURCE
)))
5582 TRACE("Component not set for install, not moving file\n");
5583 return ERROR_SUCCESS
;
5586 sourcename
= MSI_RecordGetString(rec
, 3);
5587 options
= MSI_RecordGetInteger(rec
, 7);
5589 sourcedir
= msi_dup_property(package
, MSI_RecordGetString(rec
, 5));
5593 destdir
= msi_dup_property(package
, MSI_RecordGetString(rec
, 6));
5599 if (GetFileAttributesW(sourcedir
) == INVALID_FILE_ATTRIBUTES
)
5602 source
= strdupW(sourcedir
);
5608 size
= lstrlenW(sourcedir
) + lstrlenW(sourcename
) + 2;
5609 source
= msi_alloc(size
* sizeof(WCHAR
));
5613 lstrcpyW(source
, sourcedir
);
5614 if (source
[lstrlenW(source
) - 1] != '\\')
5615 lstrcatW(source
, backslash
);
5616 lstrcatW(source
, sourcename
);
5619 wildcards
= strchrW(source
, '*') || strchrW(source
, '?');
5621 if (MSI_RecordIsNull(rec
, 4))
5625 destname
= strdupW(sourcename
);
5632 destname
= strdupW(MSI_RecordGetString(rec
, 4));
5634 reduce_to_longfilename(destname
);
5639 size
= lstrlenW(destname
);
5641 size
+= lstrlenW(destdir
) + 2;
5642 dest
= msi_alloc(size
* sizeof(WCHAR
));
5646 lstrcpyW(dest
, destdir
);
5647 if (dest
[lstrlenW(dest
) - 1] != '\\')
5648 lstrcatW(dest
, backslash
);
5651 lstrcatW(dest
, destname
);
5653 if (GetFileAttributesW(destdir
) == INVALID_FILE_ATTRIBUTES
)
5655 ret
= CreateDirectoryW(destdir
, NULL
);
5658 WARN("CreateDirectory failed: %d\n", GetLastError());
5659 return ERROR_SUCCESS
;
5664 msi_move_file(source
, dest
, options
);
5666 move_files_wildcard(source
, dest
, options
);
5669 msi_free(sourcedir
);
5675 return ERROR_SUCCESS
;
5678 static UINT
ACTION_MoveFiles( MSIPACKAGE
*package
)
5683 static const WCHAR ExecSeqQuery
[] =
5684 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5685 '`','M','o','v','e','F','i','l','e','`',0};
5687 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5688 if (rc
!= ERROR_SUCCESS
)
5689 return ERROR_SUCCESS
;
5691 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_MoveFiles
, package
);
5692 msiobj_release(&view
->hdr
);
5697 typedef struct tagMSIASSEMBLY
5700 MSICOMPONENT
*component
;
5701 MSIFEATURE
*feature
;
5709 static HRESULT (WINAPI
*pCreateAssemblyCache
)(IAssemblyCache
**ppAsmCache
,
5711 static HRESULT (WINAPI
*pLoadLibraryShim
)(LPCWSTR szDllName
, LPCWSTR szVersion
,
5712 LPVOID pvReserved
, HMODULE
*phModDll
);
5714 static BOOL
init_functionpointers(void)
5720 static const WCHAR szFusion
[] = {'f','u','s','i','o','n','.','d','l','l',0};
5722 hmscoree
= LoadLibraryA("mscoree.dll");
5725 WARN("mscoree.dll not available\n");
5729 pLoadLibraryShim
= (void *)GetProcAddress(hmscoree
, "LoadLibraryShim");
5730 if (!pLoadLibraryShim
)
5732 WARN("LoadLibraryShim not available\n");
5733 FreeLibrary(hmscoree
);
5737 hr
= pLoadLibraryShim(szFusion
, NULL
, NULL
, &hfusion
);
5740 WARN("fusion.dll not available\n");
5741 FreeLibrary(hmscoree
);
5745 pCreateAssemblyCache
= (void *)GetProcAddress(hfusion
, "CreateAssemblyCache");
5747 FreeLibrary(hmscoree
);
5751 static UINT
install_assembly(MSIPACKAGE
*package
, MSIASSEMBLY
*assembly
,
5754 IAssemblyCache
*cache
;
5756 UINT r
= ERROR_FUNCTION_FAILED
;
5758 TRACE("installing assembly: %s\n", debugstr_w(path
));
5760 if (assembly
->feature
)
5761 msi_feature_set_state(package
, assembly
->feature
, INSTALLSTATE_LOCAL
);
5763 if (assembly
->manifest
)
5764 FIXME("Manifest unhandled\n");
5766 if (assembly
->application
)
5768 FIXME("Assembly should be privately installed\n");
5769 return ERROR_SUCCESS
;
5772 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
5774 FIXME("Win32 assemblies not handled\n");
5775 return ERROR_SUCCESS
;
5778 hr
= pCreateAssemblyCache(&cache
, 0);
5782 hr
= IAssemblyCache_InstallAssembly(cache
, 0, path
, NULL
);
5784 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path
), hr
);
5789 IAssemblyCache_Release(cache
);
5793 typedef struct tagASSEMBLY_LIST
5795 MSIPACKAGE
*package
;
5796 IAssemblyCache
*cache
;
5797 struct list
*assemblies
;
5800 typedef struct tagASSEMBLY_NAME
5808 static UINT
parse_assembly_name(MSIRECORD
*rec
, LPVOID param
)
5810 ASSEMBLY_NAME
*asmname
= (ASSEMBLY_NAME
*)param
;
5811 LPCWSTR name
= MSI_RecordGetString(rec
, 2);
5812 LPWSTR val
= msi_dup_record_field(rec
, 3);
5814 static const WCHAR Name
[] = {'N','a','m','e',0};
5815 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
5816 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e',0};
5817 static const WCHAR PublicKeyToken
[] = {
5818 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
5820 if (!lstrcmpW(name
, Name
))
5821 asmname
->name
= val
;
5822 else if (!lstrcmpW(name
, Version
))
5823 asmname
->version
= val
;
5824 else if (!lstrcmpW(name
, Culture
))
5825 asmname
->culture
= val
;
5826 else if (!lstrcmpW(name
, PublicKeyToken
))
5827 asmname
->pubkeytoken
= val
;
5831 return ERROR_SUCCESS
;
5834 static void append_str(LPWSTR
*str
, DWORD
*size
, LPCWSTR append
)
5838 *size
= lstrlenW(append
) + 1;
5839 *str
= msi_alloc((*size
) * sizeof(WCHAR
));
5840 lstrcpyW(*str
, append
);
5844 (*size
) += lstrlenW(append
);
5845 *str
= msi_realloc(*str
, (*size
) * sizeof(WCHAR
));
5846 lstrcatW(*str
, append
);
5849 static BOOL
check_assembly_installed(MSIDATABASE
*db
, IAssemblyCache
*cache
,
5852 ASSEMBLY_INFO asminfo
;
5860 static const WCHAR separator
[] = {',',' ',0};
5861 static const WCHAR Version
[] = {'V','e','r','s','i','o','n','=',0};
5862 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e','=',0};
5863 static const WCHAR PublicKeyToken
[] = {
5864 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
5865 static const WCHAR query
[] = {
5866 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5867 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
5868 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
5869 '=','\'','%','s','\'',0};
5873 ZeroMemory(&name
, sizeof(ASSEMBLY_NAME
));
5874 ZeroMemory(&asminfo
, sizeof(ASSEMBLY_INFO
));
5876 r
= MSI_OpenQuery(db
, &view
, query
, comp
->Component
);
5877 if (r
!= ERROR_SUCCESS
)
5878 return ERROR_SUCCESS
;
5880 MSI_IterateRecords(view
, NULL
, parse_assembly_name
, &name
);
5881 msiobj_release(&view
->hdr
);
5885 ERR("No assembly name specified!\n");
5889 append_str(&disp
, &size
, name
.name
);
5893 append_str(&disp
, &size
, separator
);
5894 append_str(&disp
, &size
, Version
);
5895 append_str(&disp
, &size
, name
.version
);
5900 append_str(&disp
, &size
, separator
);
5901 append_str(&disp
, &size
, Culture
);
5902 append_str(&disp
, &size
, name
.culture
);
5905 if (name
.pubkeytoken
)
5907 append_str(&disp
, &size
, separator
);
5908 append_str(&disp
, &size
, PublicKeyToken
);
5909 append_str(&disp
, &size
, name
.pubkeytoken
);
5912 asminfo
.cbAssemblyInfo
= sizeof(ASSEMBLY_INFO
);
5913 IAssemblyCache_QueryAssemblyInfo(cache
, QUERYASMINFO_FLAG_VALIDATE
,
5915 found
= (asminfo
.dwAssemblyFlags
== ASSEMBLYINFO_FLAG_INSTALLED
);
5918 msiobj_release(&view
->hdr
);
5920 msi_free(name
.name
);
5921 msi_free(name
.version
);
5922 msi_free(name
.culture
);
5923 msi_free(name
.pubkeytoken
);
5928 static UINT
load_assembly(MSIRECORD
*rec
, LPVOID param
)
5930 ASSEMBLY_LIST
*list
= (ASSEMBLY_LIST
*)param
;
5931 MSIASSEMBLY
*assembly
;
5933 assembly
= msi_alloc_zero(sizeof(MSIASSEMBLY
));
5935 return ERROR_OUTOFMEMORY
;
5937 assembly
->component
= get_loaded_component(list
->package
, MSI_RecordGetString(rec
, 1));
5939 if (!assembly
->component
|| !assembly
->component
->Enabled
||
5940 !(assembly
->component
->Action
& (INSTALLSTATE_LOCAL
| INSTALLSTATE_SOURCE
)))
5942 TRACE("Component not set for install, not publishing assembly\n");
5944 return ERROR_SUCCESS
;
5947 assembly
->feature
= find_feature_by_name(list
->package
, MSI_RecordGetString(rec
, 2));
5948 assembly
->file
= msi_find_file(list
->package
, assembly
->component
->KeyPath
);
5950 if (!assembly
->file
)
5952 ERR("File %s not found\n", debugstr_w(assembly
->component
->KeyPath
));
5953 return ERROR_FUNCTION_FAILED
;
5956 assembly
->manifest
= strdupW(MSI_RecordGetString(rec
, 3));
5957 assembly
->application
= strdupW(MSI_RecordGetString(rec
, 4));
5958 assembly
->attributes
= MSI_RecordGetInteger(rec
, 5);
5959 assembly
->installed
= check_assembly_installed(list
->package
->db
,
5961 assembly
->component
);
5963 list_add_head(list
->assemblies
, &assembly
->entry
);
5964 return ERROR_SUCCESS
;
5967 static UINT
load_assemblies(MSIPACKAGE
*package
, struct list
*assemblies
)
5969 IAssemblyCache
*cache
= NULL
;
5975 static const WCHAR query
[] =
5976 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5977 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
5979 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5980 if (r
!= ERROR_SUCCESS
)
5981 return ERROR_SUCCESS
;
5983 hr
= pCreateAssemblyCache(&cache
, 0);
5985 return ERROR_FUNCTION_FAILED
;
5987 list
.package
= package
;
5989 list
.assemblies
= assemblies
;
5991 r
= MSI_IterateRecords(view
, NULL
, load_assembly
, &list
);
5992 msiobj_release(&view
->hdr
);
5994 IAssemblyCache_Release(cache
);
5999 static void free_assemblies(struct list
*assemblies
)
6001 struct list
*item
, *cursor
;
6003 LIST_FOR_EACH_SAFE(item
, cursor
, assemblies
)
6005 MSIASSEMBLY
*assembly
= LIST_ENTRY(item
, MSIASSEMBLY
, entry
);
6007 list_remove(&assembly
->entry
);
6008 msi_free(assembly
->application
);
6009 msi_free(assembly
->manifest
);
6014 static BOOL
find_assembly(struct list
*assemblies
, LPCWSTR file
, MSIASSEMBLY
**out
)
6016 MSIASSEMBLY
*assembly
;
6018 LIST_FOR_EACH_ENTRY(assembly
, assemblies
, MSIASSEMBLY
, entry
)
6020 if (!lstrcmpW(assembly
->file
->File
, file
))
6030 static BOOL
installassembly_cb(MSIPACKAGE
*package
, LPCWSTR file
, DWORD action
,
6031 LPWSTR
*path
, DWORD
*attrs
, PVOID user
)
6033 MSIASSEMBLY
*assembly
;
6034 WCHAR temppath
[MAX_PATH
];
6035 struct list
*assemblies
= (struct list
*)user
;
6038 if (!find_assembly(assemblies
, file
, &assembly
))
6041 GetTempPathW(MAX_PATH
, temppath
);
6042 PathAddBackslashW(temppath
);
6043 lstrcatW(temppath
, assembly
->file
->FileName
);
6045 if (action
== MSICABEXTRACT_BEGINEXTRACT
)
6047 if (assembly
->installed
)
6050 *path
= strdupW(temppath
);
6051 *attrs
= assembly
->file
->Attributes
;
6053 else if (action
== MSICABEXTRACT_FILEEXTRACTED
)
6055 assembly
->installed
= TRUE
;
6057 r
= install_assembly(package
, assembly
, temppath
);
6058 if (r
!= ERROR_SUCCESS
)
6059 ERR("Failed to install assembly\n");
6065 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
6068 struct list assemblies
= LIST_INIT(assemblies
);
6069 MSIASSEMBLY
*assembly
;
6072 if (!init_functionpointers() || !pCreateAssemblyCache
)
6073 return ERROR_FUNCTION_FAILED
;
6075 r
= load_assemblies(package
, &assemblies
);
6076 if (r
!= ERROR_SUCCESS
)
6079 if (list_empty(&assemblies
))
6082 mi
= msi_alloc_zero(sizeof(MSIMEDIAINFO
));
6085 r
= ERROR_OUTOFMEMORY
;
6089 LIST_FOR_EACH_ENTRY(assembly
, &assemblies
, MSIASSEMBLY
, entry
)
6091 if (assembly
->installed
&& !mi
->is_continuous
)
6094 if (assembly
->file
->Sequence
> mi
->last_sequence
|| mi
->is_continuous
||
6095 (assembly
->file
->IsCompressed
&& !mi
->is_extracted
))
6099 r
= ready_media(package
, assembly
->file
, mi
);
6100 if (r
!= ERROR_SUCCESS
)
6102 ERR("Failed to ready media\n");
6107 data
.package
= package
;
6108 data
.cb
= installassembly_cb
;
6109 data
.user
= &assemblies
;
6111 if (assembly
->file
->IsCompressed
&&
6112 !msi_cabextract(package
, mi
, &data
))
6114 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi
->cabinet
));
6115 r
= ERROR_FUNCTION_FAILED
;
6120 if (!assembly
->file
->IsCompressed
)
6122 LPWSTR source
= resolve_file_source(package
, assembly
->file
);
6124 r
= install_assembly(package
, assembly
, source
);
6125 if (r
!= ERROR_SUCCESS
)
6126 ERR("Failed to install assembly\n");
6131 /* FIXME: write Installer assembly reg values */
6135 free_assemblies(&assemblies
);
6139 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
6140 LPCSTR action
, LPCWSTR table
)
6142 static const WCHAR query
[] = {
6143 'S','E','L','E','C','T',' ','*',' ',
6144 'F','R','O','M',' ','`','%','s','`',0 };
6145 MSIQUERY
*view
= NULL
;
6149 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
6150 if (r
== ERROR_SUCCESS
)
6152 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
6153 msiobj_release(&view
->hdr
);
6157 FIXME("%s -> %u ignored %s table values\n",
6158 action
, count
, debugstr_w(table
));
6160 return ERROR_SUCCESS
;
6163 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
6165 TRACE("%p\n", package
);
6166 return ERROR_SUCCESS
;
6169 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
6171 static const WCHAR table
[] =
6172 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
6173 return msi_unimplemented_action_stub( package
, "RemoveIniValues", table
);
6176 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
6178 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
6179 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
6182 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
6184 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
6185 return msi_unimplemented_action_stub( package
, "BindImage", table
);
6188 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
6190 static const WCHAR table
[] = {
6191 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
6192 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
6195 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
6197 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6198 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
6201 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
6203 static const WCHAR table
[] = { 'S','e','l','f','R','e','g',0 };
6204 return msi_unimplemented_action_stub( package
, "SelfUnregModules", table
);
6207 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
6209 static const WCHAR table
[] = {
6210 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6211 return msi_unimplemented_action_stub( package
, "DeleteServices", table
);
6213 static UINT
ACTION_ValidateProductID( MSIPACKAGE
*package
)
6215 static const WCHAR table
[] = {
6216 'P','r','o','d','u','c','t','I','D',0 };
6217 return msi_unimplemented_action_stub( package
, "ValidateProductID", table
);
6220 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
6222 static const WCHAR table
[] = {
6223 'E','n','v','i','r','o','n','m','e','n','t',0 };
6224 return msi_unimplemented_action_stub( package
, "RemoveEnvironmentStrings", table
);
6227 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
6229 static const WCHAR table
[] = {
6230 'M','s','i','A','s','s','e','m','b','l','y',0 };
6231 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
6234 static UINT
ACTION_UnregisterFonts( MSIPACKAGE
*package
)
6236 static const WCHAR table
[] = { 'F','o','n','t',0 };
6237 return msi_unimplemented_action_stub( package
, "UnregisterFonts", table
);
6240 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
6242 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
6243 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
6246 static UINT
ACTION_RegisterComPlus( MSIPACKAGE
*package
)
6248 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6249 return msi_unimplemented_action_stub( package
, "RegisterComPlus", table
);
6252 static UINT
ACTION_UnregisterComPlus( MSIPACKAGE
*package
)
6254 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6255 return msi_unimplemented_action_stub( package
, "UnregisterComPlus", table
);
6258 static UINT
ACTION_InstallSFPCatalogFile( MSIPACKAGE
*package
)
6260 static const WCHAR table
[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6261 return msi_unimplemented_action_stub( package
, "InstallSFPCatalogFile", table
);
6264 static UINT
ACTION_RemoveDuplicateFiles( MSIPACKAGE
*package
)
6266 static const WCHAR table
[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6267 return msi_unimplemented_action_stub( package
, "RemoveDuplicateFiles", table
);
6270 static UINT
ACTION_RemoveExistingProducts( MSIPACKAGE
*package
)
6272 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6273 return msi_unimplemented_action_stub( package
, "RemoveExistingProducts", table
);
6276 static UINT
ACTION_RemoveFolders( MSIPACKAGE
*package
)
6278 static const WCHAR table
[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6279 return msi_unimplemented_action_stub( package
, "RemoveFolders", table
);
6282 static UINT
ACTION_RemoveODBC( MSIPACKAGE
*package
)
6284 static const WCHAR table
[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6285 return msi_unimplemented_action_stub( package
, "RemoveODBC", table
);
6288 static UINT
ACTION_RemoveRegistryValues( MSIPACKAGE
*package
)
6290 static const WCHAR table
[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6291 return msi_unimplemented_action_stub( package
, "RemoveRegistryValues", table
);
6294 static UINT
ACTION_RemoveShortcuts( MSIPACKAGE
*package
)
6296 static const WCHAR table
[] = { 'S','h','o','r','t','c','u','t',0 };
6297 return msi_unimplemented_action_stub( package
, "RemoveShortcuts", table
);
6300 static UINT
ACTION_UnpublishComponents( MSIPACKAGE
*package
)
6302 static const WCHAR table
[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6303 return msi_unimplemented_action_stub( package
, "UnpublishComponents", table
);
6306 static UINT
ACTION_UnregisterClassInfo( MSIPACKAGE
*package
)
6308 static const WCHAR table
[] = { 'A','p','p','I','d',0 };
6309 return msi_unimplemented_action_stub( package
, "UnregisterClassInfo", table
);
6312 static UINT
ACTION_UnregisterExtensionInfo( MSIPACKAGE
*package
)
6314 static const WCHAR table
[] = { 'E','x','t','e','n','s','i','o','n',0 };
6315 return msi_unimplemented_action_stub( package
, "UnregisterExtensionInfo", table
);
6318 static UINT
ACTION_UnregisterMIMEInfo( MSIPACKAGE
*package
)
6320 static const WCHAR table
[] = { 'M','I','M','E',0 };
6321 return msi_unimplemented_action_stub( package
, "UnregisterMIMEInfo", table
);
6324 static UINT
ACTION_UnregisterProgIdInfo( MSIPACKAGE
*package
)
6326 static const WCHAR table
[] = { 'P','r','o','g','I','d',0 };
6327 return msi_unimplemented_action_stub( package
, "UnregisterProgIdInfo", table
);
6330 static UINT
ACTION_UnregisterTypeLibraries( MSIPACKAGE
*package
)
6332 static const WCHAR table
[] = { 'T','y','p','e','L','i','b',0 };
6333 return msi_unimplemented_action_stub( package
, "UnregisterTypeLibraries", table
);
6336 static const struct _actions StandardActions
[] = {
6337 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
6338 { szAppSearch
, ACTION_AppSearch
},
6339 { szBindImage
, ACTION_BindImage
},
6340 { szCCPSearch
, ACTION_CCPSearch
},
6341 { szCostFinalize
, ACTION_CostFinalize
},
6342 { szCostInitialize
, ACTION_CostInitialize
},
6343 { szCreateFolders
, ACTION_CreateFolders
},
6344 { szCreateShortcuts
, ACTION_CreateShortcuts
},
6345 { szDeleteServices
, ACTION_DeleteServices
},
6346 { szDisableRollback
, NULL
},
6347 { szDuplicateFiles
, ACTION_DuplicateFiles
},
6348 { szExecuteAction
, ACTION_ExecuteAction
},
6349 { szFileCost
, ACTION_FileCost
},
6350 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
6351 { szForceReboot
, ACTION_ForceReboot
},
6352 { szInstallAdminPackage
, NULL
},
6353 { szInstallExecute
, ACTION_InstallExecute
},
6354 { szInstallExecuteAgain
, ACTION_InstallExecute
},
6355 { szInstallFiles
, ACTION_InstallFiles
},
6356 { szInstallFinalize
, ACTION_InstallFinalize
},
6357 { szInstallInitialize
, ACTION_InstallInitialize
},
6358 { szInstallSFPCatalogFile
, ACTION_InstallSFPCatalogFile
},
6359 { szInstallValidate
, ACTION_InstallValidate
},
6360 { szIsolateComponents
, ACTION_IsolateComponents
},
6361 { szLaunchConditions
, ACTION_LaunchConditions
},
6362 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
6363 { szMoveFiles
, ACTION_MoveFiles
},
6364 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
6365 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
6366 { szInstallODBC
, ACTION_InstallODBC
},
6367 { szInstallServices
, ACTION_InstallServices
},
6368 { szPatchFiles
, ACTION_PatchFiles
},
6369 { szProcessComponents
, ACTION_ProcessComponents
},
6370 { szPublishComponents
, ACTION_PublishComponents
},
6371 { szPublishFeatures
, ACTION_PublishFeatures
},
6372 { szPublishProduct
, ACTION_PublishProduct
},
6373 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
6374 { szRegisterComPlus
, ACTION_RegisterComPlus
},
6375 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
6376 { szRegisterFonts
, ACTION_RegisterFonts
},
6377 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
6378 { szRegisterProduct
, ACTION_RegisterProduct
},
6379 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
6380 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
6381 { szRegisterUser
, ACTION_RegisterUser
},
6382 { szRemoveDuplicateFiles
, ACTION_RemoveDuplicateFiles
},
6383 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
6384 { szRemoveExistingProducts
, ACTION_RemoveExistingProducts
},
6385 { szRemoveFiles
, ACTION_RemoveFiles
},
6386 { szRemoveFolders
, ACTION_RemoveFolders
},
6387 { szRemoveIniValues
, ACTION_RemoveIniValues
},
6388 { szRemoveODBC
, ACTION_RemoveODBC
},
6389 { szRemoveRegistryValues
, ACTION_RemoveRegistryValues
},
6390 { szRemoveShortcuts
, ACTION_RemoveShortcuts
},
6391 { szResolveSource
, ACTION_ResolveSource
},
6392 { szRMCCPSearch
, ACTION_RMCCPSearch
},
6393 { szScheduleReboot
, NULL
},
6394 { szSelfRegModules
, ACTION_SelfRegModules
},
6395 { szSelfUnregModules
, ACTION_SelfUnregModules
},
6396 { szSetODBCFolders
, NULL
},
6397 { szStartServices
, ACTION_StartServices
},
6398 { szStopServices
, ACTION_StopServices
},
6399 { szUnpublishComponents
, ACTION_UnpublishComponents
},
6400 { szUnpublishFeatures
, ACTION_UnpublishFeatures
},
6401 { szUnregisterClassInfo
, ACTION_UnregisterClassInfo
},
6402 { szUnregisterComPlus
, ACTION_UnregisterComPlus
},
6403 { szUnregisterExtensionInfo
, ACTION_UnregisterExtensionInfo
},
6404 { szUnregisterFonts
, ACTION_UnregisterFonts
},
6405 { szUnregisterMIMEInfo
, ACTION_UnregisterMIMEInfo
},
6406 { szUnregisterProgIdInfo
, ACTION_UnregisterProgIdInfo
},
6407 { szUnregisterTypeLibraries
, ACTION_UnregisterTypeLibraries
},
6408 { szValidateProductID
, ACTION_ValidateProductID
},
6409 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
6410 { szWriteIniValues
, ACTION_WriteIniValues
},
6411 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
6415 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
6416 UINT
* rc
, BOOL force
)
6422 if (!run
&& !package
->script
->CurrentlyScripting
)
6427 if (strcmpW(action
,szInstallFinalize
) == 0 ||
6428 strcmpW(action
,szInstallExecute
) == 0 ||
6429 strcmpW(action
,szInstallExecuteAgain
) == 0)
6434 while (StandardActions
[i
].action
!= NULL
)
6436 if (strcmpW(StandardActions
[i
].action
, action
)==0)
6440 ui_actioninfo(package
, action
, TRUE
, 0);
6441 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
6442 ui_actioninfo(package
, action
, FALSE
, *rc
);
6446 ui_actionstart(package
, action
);
6447 if (StandardActions
[i
].handler
)
6449 *rc
= StandardActions
[i
].handler(package
);
6453 FIXME("unhandled standard action %s\n",debugstr_w(action
));
6454 *rc
= ERROR_SUCCESS
;