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 static const WCHAR szProductCode
[] =
405 { 'P','r','o','d','u','c','t','C','o','d','e',0 };
406 static const WCHAR szSystemLanguageID
[] =
407 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
409 LPWSTR prod_code
, patch_product
, langid
= NULL
, template = NULL
;
410 UINT ret
= ERROR_FUNCTION_FAILED
;
412 prod_code
= msi_dup_property( package
, szProductCode
);
413 patch_product
= msi_get_suminfo_product( patch
);
415 TRACE("db = %s patch = %s\n", debugstr_w(prod_code
), debugstr_w(patch_product
));
417 if ( strstrW( patch_product
, prod_code
) )
419 static const WCHAR zero
[] = {'0',0};
423 si
= MSI_GetSummaryInformationW( patch
, 0 );
426 ERR("no summary information!\n");
430 template = msi_suminfo_dup_string( si
, PID_TEMPLATE
);
433 ERR("no template property!\n");
434 msiobj_release( &si
->hdr
);
441 msiobj_release( &si
->hdr
);
445 langid
= msi_dup_property( package
, szSystemLanguageID
);
448 msiobj_release( &si
->hdr
);
452 p
= strchrW( template, ';' );
453 if (p
&& (!strcmpW( p
+ 1, langid
) || !strcmpW( p
+ 1, zero
)))
455 TRACE("applicable transform\n");
459 /* FIXME: check platform */
461 msiobj_release( &si
->hdr
);
465 msi_free( patch_product
);
466 msi_free( prod_code
);
467 msi_free( template );
473 static UINT
msi_apply_substorage_transform( MSIPACKAGE
*package
,
474 MSIDATABASE
*patch_db
, LPCWSTR name
)
476 UINT ret
= ERROR_FUNCTION_FAILED
;
477 IStorage
*stg
= NULL
;
480 TRACE("%p %s\n", package
, debugstr_w(name
) );
484 ERR("expected a colon in %s\n", debugstr_w(name
));
485 return ERROR_FUNCTION_FAILED
;
488 r
= IStorage_OpenStorage( patch_db
->storage
, name
, NULL
, STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
491 ret
= msi_check_transform_applicable( package
, stg
);
492 if (ret
== ERROR_SUCCESS
)
493 msi_table_apply_transform( package
->db
, stg
);
495 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name
));
496 IStorage_Release( stg
);
499 ERR("failed to open substorage %s\n", debugstr_w(name
));
501 return ERROR_SUCCESS
;
504 static UINT
msi_check_patch_applicable( MSIPACKAGE
*package
, MSISUMMARYINFO
*si
)
506 static const WCHAR szProdCode
[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
507 LPWSTR guid_list
, *guids
, product_code
;
508 UINT i
, ret
= ERROR_FUNCTION_FAILED
;
510 product_code
= msi_dup_property( package
, szProdCode
);
513 /* FIXME: the property ProductCode should be written into the DB somewhere */
514 ERR("no product code to check\n");
515 return ERROR_SUCCESS
;
518 guid_list
= msi_suminfo_dup_string( si
, PID_TEMPLATE
);
519 guids
= msi_split_string( guid_list
, ';' );
520 for ( i
= 0; guids
[i
] && ret
!= ERROR_SUCCESS
; i
++ )
522 if (!lstrcmpW( guids
[i
], product_code
))
526 msi_free( guid_list
);
527 msi_free( product_code
);
532 static UINT
msi_set_media_source_prop(MSIPACKAGE
*package
)
535 MSIRECORD
*rec
= NULL
;
540 static const WCHAR szPatch
[] = {'P','A','T','C','H',0};
541 static const WCHAR query
[] = {'S','E','L','E','C','T',' ',
542 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
543 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
544 '`','S','o','u','r','c','e','`',' ','I','S',' ',
545 'N','O','T',' ','N','U','L','L',0};
547 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
548 if (r
!= ERROR_SUCCESS
)
551 r
= MSI_ViewExecute(view
, 0);
552 if (r
!= ERROR_SUCCESS
)
555 if (MSI_ViewFetch(view
, &rec
) == ERROR_SUCCESS
)
557 prop
= MSI_RecordGetString(rec
, 1);
558 patch
= msi_dup_property(package
, szPatch
);
559 MSI_SetPropertyW(package
, prop
, patch
);
564 if (rec
) msiobj_release(&rec
->hdr
);
565 msiobj_release(&view
->hdr
);
570 static UINT
msi_parse_patch_summary( MSIPACKAGE
*package
, MSIDATABASE
*patch_db
)
573 LPWSTR str
, *substorage
;
574 UINT i
, r
= ERROR_SUCCESS
;
576 si
= MSI_GetSummaryInformationW( patch_db
->storage
, 0 );
578 return ERROR_FUNCTION_FAILED
;
580 if (msi_check_patch_applicable( package
, si
) != ERROR_SUCCESS
)
582 TRACE("Patch not applicable\n");
583 return ERROR_SUCCESS
;
586 package
->patch
= msi_alloc(sizeof(MSIPATCHINFO
));
588 return ERROR_OUTOFMEMORY
;
590 package
->patch
->patchcode
= msi_suminfo_dup_string(si
, PID_REVNUMBER
);
591 if (!package
->patch
->patchcode
)
592 return ERROR_OUTOFMEMORY
;
594 /* enumerate the substorage */
595 str
= msi_suminfo_dup_string( si
, PID_LASTAUTHOR
);
596 package
->patch
->transforms
= str
;
598 substorage
= msi_split_string( str
, ';' );
599 for ( i
= 0; substorage
&& substorage
[i
] && r
== ERROR_SUCCESS
; i
++ )
600 r
= msi_apply_substorage_transform( package
, patch_db
, substorage
[i
] );
602 msi_free( substorage
);
603 msiobj_release( &si
->hdr
);
605 msi_set_media_source_prop(package
);
610 static UINT
msi_apply_patch_package( MSIPACKAGE
*package
, LPCWSTR file
)
612 MSIDATABASE
*patch_db
= NULL
;
615 TRACE("%p %s\n", package
, debugstr_w( file
) );
618 * We probably want to make sure we only open a patch collection here.
619 * Patch collections (.msp) and databases (.msi) have different GUIDs
620 * but currently MSI_OpenDatabaseW will accept both.
622 r
= MSI_OpenDatabaseW( file
, MSIDBOPEN_READONLY
, &patch_db
);
623 if ( r
!= ERROR_SUCCESS
)
625 ERR("failed to open patch collection %s\n", debugstr_w( file
) );
629 msi_parse_patch_summary( package
, patch_db
);
632 * There might be a CAB file in the patch package,
633 * so append it to the list of storage to search for streams.
635 append_storage_to_db( package
->db
, patch_db
->storage
);
637 msiobj_release( &patch_db
->hdr
);
639 return ERROR_SUCCESS
;
642 /* get the PATCH property, and apply all the patches it specifies */
643 static UINT
msi_apply_patches( MSIPACKAGE
*package
)
645 static const WCHAR szPatch
[] = { 'P','A','T','C','H',0 };
646 LPWSTR patch_list
, *patches
;
647 UINT i
, r
= ERROR_SUCCESS
;
649 patch_list
= msi_dup_property( package
, szPatch
);
651 TRACE("patches to be applied: %s\n", debugstr_w( patch_list
) );
653 patches
= msi_split_string( patch_list
, ';' );
654 for( i
=0; patches
&& patches
[i
] && r
== ERROR_SUCCESS
; i
++ )
655 r
= msi_apply_patch_package( package
, patches
[i
] );
658 msi_free( patch_list
);
663 static UINT
msi_apply_transforms( MSIPACKAGE
*package
)
665 static const WCHAR szTransforms
[] = {
666 'T','R','A','N','S','F','O','R','M','S',0 };
667 LPWSTR xform_list
, *xforms
;
668 UINT i
, r
= ERROR_SUCCESS
;
670 xform_list
= msi_dup_property( package
, szTransforms
);
671 xforms
= msi_split_string( xform_list
, ';' );
673 for( i
=0; xforms
&& xforms
[i
] && r
== ERROR_SUCCESS
; i
++ )
675 if (xforms
[i
][0] == ':')
676 r
= msi_apply_substorage_transform( package
, package
->db
, xforms
[i
] );
678 r
= MSI_DatabaseApplyTransformW( package
->db
, xforms
[i
], 0 );
682 msi_free( xform_list
);
687 static BOOL
ui_sequence_exists( MSIPACKAGE
*package
)
692 static const WCHAR ExecSeqQuery
[] =
693 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
694 '`','I','n','s','t','a','l','l',
695 'U','I','S','e','q','u','e','n','c','e','`',
696 ' ','W','H','E','R','E',' ',
697 '`','S','e','q','u','e','n','c','e','`',' ',
698 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
699 '`','S','e','q','u','e','n','c','e','`',0};
701 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
702 if (rc
== ERROR_SUCCESS
)
704 msiobj_release(&view
->hdr
);
711 static UINT
msi_set_sourcedir_props(MSIPACKAGE
*package
, BOOL replace
)
714 LPWSTR source
, check
;
717 static const WCHAR szOriginalDatabase
[] =
718 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
720 db
= msi_dup_property( package
, szOriginalDatabase
);
722 return ERROR_OUTOFMEMORY
;
724 p
= strrchrW( db
, '\\' );
727 p
= strrchrW( db
, '/' );
731 return ERROR_SUCCESS
;
736 source
= msi_alloc( len
* sizeof(WCHAR
) );
737 lstrcpynW( source
, db
, len
);
739 check
= msi_dup_property( package
, cszSourceDir
);
740 if (!check
|| replace
)
741 MSI_SetPropertyW( package
, cszSourceDir
, source
);
745 check
= msi_dup_property( package
, cszSOURCEDIR
);
746 if (!check
|| replace
)
747 MSI_SetPropertyW( package
, cszSOURCEDIR
, source
);
753 return ERROR_SUCCESS
;
756 static UINT
msi_set_context(MSIPACKAGE
*package
)
763 static const WCHAR szOne
[] = {'1',0};
764 static const WCHAR szAllUsers
[] = {'A','L','L','U','S','E','R','S',0};
766 package
->Context
= MSIINSTALLCONTEXT_USERUNMANAGED
;
768 r
= MSI_GetPropertyW(package
, szAllUsers
, val
, &sz
);
769 if (r
== ERROR_SUCCESS
)
772 if (num
== 1 || num
== 2)
773 package
->Context
= MSIINSTALLCONTEXT_MACHINE
;
776 MSI_SetPropertyW(package
, szAllUsers
, szOne
);
777 return ERROR_SUCCESS
;
780 /****************************************************
781 * TOP level entry points
782 *****************************************************/
784 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
785 LPCWSTR szCommandLine
)
788 BOOL ui
= FALSE
, ui_exists
;
789 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
790 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
791 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
793 MSI_SetPropertyW(package
, szAction
, szInstall
);
795 package
->script
= msi_alloc_zero(sizeof(MSISCRIPT
));
797 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
804 dir
= strdupW(szPackagePath
);
805 p
= strrchrW(dir
, '\\');
809 file
= szPackagePath
+ (p
- dir
);
814 dir
= msi_alloc(MAX_PATH
*sizeof(WCHAR
));
815 GetCurrentDirectoryW(MAX_PATH
, dir
);
816 lstrcatW(dir
, cszbs
);
817 file
= szPackagePath
;
820 msi_free( package
->PackagePath
);
821 package
->PackagePath
= msi_alloc((lstrlenW(dir
) + lstrlenW(file
) + 1) * sizeof(WCHAR
));
822 if (!package
->PackagePath
)
825 return ERROR_OUTOFMEMORY
;
828 lstrcpyW(package
->PackagePath
, dir
);
829 lstrcatW(package
->PackagePath
, file
);
832 msi_set_sourcedir_props(package
, FALSE
);
835 msi_parse_command_line( package
, szCommandLine
, FALSE
);
837 msi_apply_transforms( package
);
838 msi_apply_patches( package
);
840 /* properties may have been added by a transform */
841 msi_clone_properties( package
);
842 msi_set_context( package
);
844 if ( (msi_get_property_int(package
, szUILevel
, 0) & INSTALLUILEVEL_MASK
) >= INSTALLUILEVEL_REDUCED
)
846 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
847 rc
= ACTION_ProcessUISequence(package
);
849 ui_exists
= ui_sequence_exists(package
);
850 if (rc
== ERROR_SUCCESS
|| !ui_exists
)
852 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
853 rc
= ACTION_ProcessExecSequence(package
,ui_exists
);
857 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
859 package
->script
->CurrentlyScripting
= FALSE
;
861 /* process the ending type action */
862 if (rc
== ERROR_SUCCESS
)
863 ACTION_PerformActionSequence(package
,-1,ui
);
864 else if (rc
== ERROR_INSTALL_USEREXIT
)
865 ACTION_PerformActionSequence(package
,-2,ui
);
866 else if (rc
== ERROR_INSTALL_SUSPEND
)
867 ACTION_PerformActionSequence(package
,-4,ui
);
869 ACTION_PerformActionSequence(package
,-3,ui
);
871 /* finish up running custom actions */
872 ACTION_FinishCustomActions(package
);
877 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
)
879 UINT rc
= ERROR_SUCCESS
;
881 static const WCHAR ExecSeqQuery
[] =
882 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
883 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
884 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
885 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
887 static const WCHAR UISeqQuery
[] =
888 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
889 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
890 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
891 ' ', '=',' ','%','i',0};
894 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
896 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
900 LPCWSTR action
, cond
;
902 TRACE("Running the actions\n");
904 /* check conditions */
905 cond
= MSI_RecordGetString(row
,2);
907 /* this is a hack to skip errors in the condition code */
908 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
911 action
= MSI_RecordGetString(row
,1);
914 ERR("failed to fetch action\n");
915 rc
= ERROR_FUNCTION_FAILED
;
920 rc
= ACTION_PerformUIAction(package
,action
,-1);
922 rc
= ACTION_PerformAction(package
,action
,-1,FALSE
);
924 msiobj_release(&row
->hdr
);
935 } iterate_action_param
;
937 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
939 iterate_action_param
*iap
= param
;
941 LPCWSTR cond
, action
;
943 action
= MSI_RecordGetString(row
,1);
946 ERR("Error is retrieving action name\n");
947 return ERROR_FUNCTION_FAILED
;
950 /* check conditions */
951 cond
= MSI_RecordGetString(row
,2);
953 /* this is a hack to skip errors in the condition code */
954 if (MSI_EvaluateConditionW(iap
->package
, cond
) == MSICONDITION_FALSE
)
956 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action
));
957 return ERROR_SUCCESS
;
961 rc
= ACTION_PerformUIAction(iap
->package
,action
,-1);
963 rc
= ACTION_PerformAction(iap
->package
,action
,-1,FALSE
);
965 msi_dialog_check_messages( NULL
);
967 if (iap
->package
->CurrentInstallState
!= ERROR_SUCCESS
)
968 rc
= iap
->package
->CurrentInstallState
;
970 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
973 if (rc
!= ERROR_SUCCESS
)
974 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
979 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
983 static const WCHAR query
[] =
984 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
986 ' ','W','H','E','R','E',' ',
987 '`','S','e','q','u','e','n','c','e','`',' ',
988 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
989 '`','S','e','q','u','e','n','c','e','`',0};
990 iterate_action_param iap
;
993 * FIXME: probably should be checking UILevel in the
994 * ACTION_PerformUIAction/ACTION_PerformAction
995 * rather than saving the UI level here. Those
996 * two functions can be merged too.
998 iap
.package
= package
;
1001 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
1003 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
1004 if (r
== ERROR_SUCCESS
)
1006 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, &iap
);
1007 msiobj_release(&view
->hdr
);
1013 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
1017 static const WCHAR ExecSeqQuery
[] =
1018 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1019 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1020 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1021 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
1022 'O','R','D','E','R',' ', 'B','Y',' ',
1023 '`','S','e','q','u','e','n','c','e','`',0 };
1024 MSIRECORD
* row
= 0;
1025 static const WCHAR IVQuery
[] =
1026 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
1027 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
1028 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
1029 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
1030 ' ','\'', 'I','n','s','t','a','l','l',
1031 'V','a','l','i','d','a','t','e','\'', 0};
1033 iterate_action_param iap
;
1035 iap
.package
= package
;
1038 if (package
->script
->ExecuteSequenceRun
)
1040 TRACE("Execute Sequence already Run\n");
1041 return ERROR_SUCCESS
;
1044 package
->script
->ExecuteSequenceRun
= TRUE
;
1046 /* get the sequence number */
1049 row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
1051 return ERROR_FUNCTION_FAILED
;
1052 seq
= MSI_RecordGetInteger(row
,1);
1053 msiobj_release(&row
->hdr
);
1056 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
1057 if (rc
== ERROR_SUCCESS
)
1059 TRACE("Running the actions\n");
1061 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
1062 msiobj_release(&view
->hdr
);
1068 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
1072 static const WCHAR ExecSeqQuery
[] =
1073 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1074 '`','I','n','s','t','a','l','l',
1075 'U','I','S','e','q','u','e','n','c','e','`',
1076 ' ','W','H','E','R','E',' ',
1077 '`','S','e','q','u','e','n','c','e','`',' ',
1078 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1079 '`','S','e','q','u','e','n','c','e','`',0};
1080 iterate_action_param iap
;
1082 iap
.package
= package
;
1085 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1087 if (rc
== ERROR_SUCCESS
)
1089 TRACE("Running the actions\n");
1091 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
1092 msiobj_release(&view
->hdr
);
1098 /********************************************************
1099 * ACTION helper functions and functions that perform the actions
1100 *******************************************************/
1101 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
1102 UINT
* rc
, UINT script
, BOOL force
)
1107 arc
= ACTION_CustomAction(package
, action
, script
, force
);
1109 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
1118 * A lot of actions are really important even if they don't do anything
1119 * explicit... Lots of properties are set at the beginning of the installation
1120 * CostFinalize does a bunch of work to translate the directories and such
1122 * But until I get write access to the database that is hard, so I am going to
1123 * hack it to see if I can get something to run.
1125 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
, BOOL force
)
1127 UINT rc
= ERROR_SUCCESS
;
1130 TRACE("Performing action (%s)\n",debugstr_w(action
));
1132 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
1135 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, force
);
1139 WARN("unhandled msi action %s\n",debugstr_w(action
));
1140 rc
= ERROR_FUNCTION_NOT_CALLED
;
1146 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
)
1148 UINT rc
= ERROR_SUCCESS
;
1149 BOOL handled
= FALSE
;
1151 TRACE("Performing action (%s)\n",debugstr_w(action
));
1153 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
1156 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, FALSE
);
1158 if( !handled
&& ACTION_DialogBox(package
,action
) == ERROR_SUCCESS
)
1163 WARN("unhandled msi action %s\n",debugstr_w(action
));
1164 rc
= ERROR_FUNCTION_NOT_CALLED
;
1172 * Actual Action Handlers
1175 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
1177 MSIPACKAGE
*package
= param
;
1183 dir
= MSI_RecordGetString(row
,1);
1186 ERR("Unable to get folder id\n");
1187 return ERROR_SUCCESS
;
1190 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,TRUE
,&folder
);
1193 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
1194 return ERROR_SUCCESS
;
1197 TRACE("Folder is %s\n",debugstr_w(full_path
));
1200 uirow
= MSI_CreateRecord(1);
1201 MSI_RecordSetStringW(uirow
,1,full_path
);
1202 ui_actiondata(package
,szCreateFolders
,uirow
);
1203 msiobj_release( &uirow
->hdr
);
1205 if (folder
->State
== 0)
1206 create_full_pathW(full_path
);
1210 msi_free(full_path
);
1211 return ERROR_SUCCESS
;
1214 /* FIXME: probably should merge this with the above function */
1215 static UINT
msi_create_directory( MSIPACKAGE
* package
, LPCWSTR dir
)
1217 UINT rc
= ERROR_SUCCESS
;
1219 LPWSTR install_path
;
1221 install_path
= resolve_folder(package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
1223 return ERROR_FUNCTION_FAILED
;
1225 /* create the path */
1226 if (folder
->State
== 0)
1228 create_full_pathW(install_path
);
1231 msi_free(install_path
);
1236 UINT
msi_create_component_directories( MSIPACKAGE
*package
)
1240 /* create all the folders required by the components are going to install */
1241 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1243 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
1245 msi_create_directory( package
, comp
->Directory
);
1248 return ERROR_SUCCESS
;
1252 * Also we cannot enable/disable components either, so for now I am just going
1253 * to do all the directories for all the components.
1255 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1257 static const WCHAR ExecSeqQuery
[] =
1258 {'S','E','L','E','C','T',' ',
1259 '`','D','i','r','e','c','t','o','r','y','_','`',
1260 ' ','F','R','O','M',' ',
1261 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1265 /* create all the empty folders specified in the CreateFolder table */
1266 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1267 if (rc
!= ERROR_SUCCESS
)
1268 return ERROR_SUCCESS
;
1270 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
1271 msiobj_release(&view
->hdr
);
1273 msi_create_component_directories( package
);
1278 static UINT
load_component( MSIRECORD
*row
, LPVOID param
)
1280 MSIPACKAGE
*package
= param
;
1283 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1285 return ERROR_FUNCTION_FAILED
;
1287 list_add_tail( &package
->components
, &comp
->entry
);
1289 /* fill in the data */
1290 comp
->Component
= msi_dup_record_field( row
, 1 );
1292 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1294 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1295 comp
->Directory
= msi_dup_record_field( row
, 3 );
1296 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1297 comp
->Condition
= msi_dup_record_field( row
, 5 );
1298 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1300 comp
->Installed
= INSTALLSTATE_UNKNOWN
;
1301 msi_component_set_state(package
, comp
, INSTALLSTATE_UNKNOWN
);
1303 return ERROR_SUCCESS
;
1306 static UINT
load_all_components( MSIPACKAGE
*package
)
1308 static const WCHAR query
[] = {
1309 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1310 '`','C','o','m','p','o','n','e','n','t','`',0 };
1314 if (!list_empty(&package
->components
))
1315 return ERROR_SUCCESS
;
1317 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1318 if (r
!= ERROR_SUCCESS
)
1321 r
= MSI_IterateRecords(view
, NULL
, load_component
, package
);
1322 msiobj_release(&view
->hdr
);
1327 MSIPACKAGE
*package
;
1328 MSIFEATURE
*feature
;
1331 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1335 cl
= msi_alloc( sizeof (*cl
) );
1337 return ERROR_NOT_ENOUGH_MEMORY
;
1338 cl
->component
= comp
;
1339 list_add_tail( &feature
->Components
, &cl
->entry
);
1341 return ERROR_SUCCESS
;
1344 static UINT
add_feature_child( MSIFEATURE
*parent
, MSIFEATURE
*child
)
1348 fl
= msi_alloc( sizeof(*fl
) );
1350 return ERROR_NOT_ENOUGH_MEMORY
;
1351 fl
->feature
= child
;
1352 list_add_tail( &parent
->Children
, &fl
->entry
);
1354 return ERROR_SUCCESS
;
1357 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1359 _ilfs
* ilfs
= param
;
1363 component
= MSI_RecordGetString(row
,1);
1365 /* check to see if the component is already loaded */
1366 comp
= get_loaded_component( ilfs
->package
, component
);
1369 ERR("unknown component %s\n", debugstr_w(component
));
1370 return ERROR_FUNCTION_FAILED
;
1373 add_feature_component( ilfs
->feature
, comp
);
1374 comp
->Enabled
= TRUE
;
1376 return ERROR_SUCCESS
;
1379 static MSIFEATURE
*find_feature_by_name( MSIPACKAGE
*package
, LPCWSTR name
)
1381 MSIFEATURE
*feature
;
1386 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1388 if ( !lstrcmpW( feature
->Feature
, name
) )
1395 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1397 MSIPACKAGE
* package
= param
;
1398 MSIFEATURE
* feature
;
1399 static const WCHAR Query1
[] =
1400 {'S','E','L','E','C','T',' ',
1401 '`','C','o','m','p','o','n','e','n','t','_','`',
1402 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1403 'C','o','m','p','o','n','e','n','t','s','`',' ',
1404 'W','H','E','R','E',' ',
1405 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1410 /* fill in the data */
1412 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1414 return ERROR_NOT_ENOUGH_MEMORY
;
1416 list_init( &feature
->Children
);
1417 list_init( &feature
->Components
);
1419 feature
->Feature
= msi_dup_record_field( row
, 1 );
1421 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1423 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1424 feature
->Title
= msi_dup_record_field( row
, 3 );
1425 feature
->Description
= msi_dup_record_field( row
, 4 );
1427 if (!MSI_RecordIsNull(row
,5))
1428 feature
->Display
= MSI_RecordGetInteger(row
,5);
1430 feature
->Level
= MSI_RecordGetInteger(row
,6);
1431 feature
->Directory
= msi_dup_record_field( row
, 7 );
1432 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1434 feature
->Installed
= INSTALLSTATE_UNKNOWN
;
1435 msi_feature_set_state(package
, feature
, INSTALLSTATE_UNKNOWN
);
1437 list_add_tail( &package
->features
, &feature
->entry
);
1439 /* load feature components */
1441 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1442 if (rc
!= ERROR_SUCCESS
)
1443 return ERROR_SUCCESS
;
1445 ilfs
.package
= package
;
1446 ilfs
.feature
= feature
;
1448 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1449 msiobj_release(&view
->hdr
);
1451 return ERROR_SUCCESS
;
1454 static UINT
find_feature_children(MSIRECORD
* row
, LPVOID param
)
1456 MSIPACKAGE
* package
= param
;
1457 MSIFEATURE
*parent
, *child
;
1459 child
= find_feature_by_name( package
, MSI_RecordGetString( row
, 1 ) );
1461 return ERROR_FUNCTION_FAILED
;
1463 if (!child
->Feature_Parent
)
1464 return ERROR_SUCCESS
;
1466 parent
= find_feature_by_name( package
, child
->Feature_Parent
);
1468 return ERROR_FUNCTION_FAILED
;
1470 add_feature_child( parent
, child
);
1471 return ERROR_SUCCESS
;
1474 static UINT
load_all_features( MSIPACKAGE
*package
)
1476 static const WCHAR query
[] = {
1477 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1478 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1479 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1483 if (!list_empty(&package
->features
))
1484 return ERROR_SUCCESS
;
1486 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1487 if (r
!= ERROR_SUCCESS
)
1490 r
= MSI_IterateRecords( view
, NULL
, load_feature
, package
);
1491 if (r
!= ERROR_SUCCESS
)
1494 r
= MSI_IterateRecords( view
, NULL
, find_feature_children
, package
);
1495 msiobj_release( &view
->hdr
);
1500 static LPWSTR
folder_split_path(LPWSTR p
, WCHAR ch
)
1511 static UINT
load_file_hash(MSIPACKAGE
*package
, MSIFILE
*file
)
1513 static const WCHAR query
[] = {
1514 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1515 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1516 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1517 MSIQUERY
*view
= NULL
;
1518 MSIRECORD
*row
= NULL
;
1521 TRACE("%s\n", debugstr_w(file
->File
));
1523 r
= MSI_OpenQuery(package
->db
, &view
, query
, file
->File
);
1524 if (r
!= ERROR_SUCCESS
)
1527 r
= MSI_ViewExecute(view
, NULL
);
1528 if (r
!= ERROR_SUCCESS
)
1531 r
= MSI_ViewFetch(view
, &row
);
1532 if (r
!= ERROR_SUCCESS
)
1535 file
->hash
.dwFileHashInfoSize
= sizeof(MSIFILEHASHINFO
);
1536 file
->hash
.dwData
[0] = MSI_RecordGetInteger(row
, 3);
1537 file
->hash
.dwData
[1] = MSI_RecordGetInteger(row
, 4);
1538 file
->hash
.dwData
[2] = MSI_RecordGetInteger(row
, 5);
1539 file
->hash
.dwData
[3] = MSI_RecordGetInteger(row
, 6);
1542 if (view
) msiobj_release(&view
->hdr
);
1543 if (row
) msiobj_release(&row
->hdr
);
1547 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1549 MSIPACKAGE
* package
= param
;
1553 /* fill in the data */
1555 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1557 return ERROR_NOT_ENOUGH_MEMORY
;
1559 file
->File
= msi_dup_record_field( row
, 1 );
1561 component
= MSI_RecordGetString( row
, 2 );
1562 file
->Component
= get_loaded_component( package
, component
);
1564 if (!file
->Component
)
1566 WARN("Component not found: %s\n", debugstr_w(component
));
1567 msi_free(file
->File
);
1569 return ERROR_SUCCESS
;
1572 file
->FileName
= msi_dup_record_field( row
, 3 );
1573 reduce_to_longfilename( file
->FileName
);
1575 file
->ShortName
= msi_dup_record_field( row
, 3 );
1576 file
->LongName
= strdupW( folder_split_path(file
->ShortName
, '|'));
1578 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1579 file
->Version
= msi_dup_record_field( row
, 5 );
1580 file
->Language
= msi_dup_record_field( row
, 6 );
1581 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1582 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1584 file
->state
= msifs_invalid
;
1586 /* if the compressed bits are not set in the file attributes,
1587 * then read the information from the package word count property
1589 if (package
->WordCount
& msidbSumInfoSourceTypeAdminImage
)
1591 file
->IsCompressed
= FALSE
;
1593 else if (file
->Attributes
&
1594 (msidbFileAttributesCompressed
| msidbFileAttributesPatchAdded
))
1596 file
->IsCompressed
= TRUE
;
1598 else if (file
->Attributes
& msidbFileAttributesNoncompressed
)
1600 file
->IsCompressed
= FALSE
;
1604 file
->IsCompressed
= package
->WordCount
& msidbSumInfoSourceTypeCompressed
;
1607 load_file_hash(package
, file
);
1609 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1611 list_add_tail( &package
->files
, &file
->entry
);
1613 return ERROR_SUCCESS
;
1616 static UINT
load_all_files(MSIPACKAGE
*package
)
1620 static const WCHAR Query
[] =
1621 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1622 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1623 '`','S','e','q','u','e','n','c','e','`', 0};
1625 if (!list_empty(&package
->files
))
1626 return ERROR_SUCCESS
;
1628 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1629 if (rc
!= ERROR_SUCCESS
)
1630 return ERROR_SUCCESS
;
1632 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1633 msiobj_release(&view
->hdr
);
1635 return ERROR_SUCCESS
;
1638 static UINT
load_folder( MSIRECORD
*row
, LPVOID param
)
1640 MSIPACKAGE
*package
= param
;
1641 static const WCHAR szDot
[] = { '.',0 };
1642 static WCHAR szEmpty
[] = { 0 };
1643 LPWSTR p
, tgt_short
, tgt_long
, src_short
, src_long
;
1646 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1648 return ERROR_NOT_ENOUGH_MEMORY
;
1650 folder
->Directory
= msi_dup_record_field( row
, 1 );
1652 TRACE("%s\n", debugstr_w(folder
->Directory
));
1654 p
= msi_dup_record_field(row
, 3);
1656 /* split src and target dir */
1658 src_short
= folder_split_path( p
, ':' );
1660 /* split the long and short paths */
1661 tgt_long
= folder_split_path( tgt_short
, '|' );
1662 src_long
= folder_split_path( src_short
, '|' );
1664 /* check for no-op dirs */
1665 if (!lstrcmpW(szDot
, tgt_short
))
1666 tgt_short
= szEmpty
;
1667 if (!lstrcmpW(szDot
, src_short
))
1668 src_short
= szEmpty
;
1671 tgt_long
= tgt_short
;
1674 src_short
= tgt_short
;
1675 src_long
= tgt_long
;
1679 src_long
= src_short
;
1681 /* FIXME: use the target short path too */
1682 folder
->TargetDefault
= strdupW(tgt_long
);
1683 folder
->SourceShortPath
= strdupW(src_short
);
1684 folder
->SourceLongPath
= strdupW(src_long
);
1687 TRACE("TargetDefault = %s\n",debugstr_w( folder
->TargetDefault
));
1688 TRACE("SourceLong = %s\n", debugstr_w( folder
->SourceLongPath
));
1689 TRACE("SourceShort = %s\n", debugstr_w( folder
->SourceShortPath
));
1691 folder
->Parent
= msi_dup_record_field( row
, 2 );
1693 folder
->Property
= msi_dup_property( package
, folder
->Directory
);
1695 list_add_tail( &package
->folders
, &folder
->entry
);
1697 TRACE("returning %p\n", folder
);
1699 return ERROR_SUCCESS
;
1702 static UINT
load_all_folders( MSIPACKAGE
*package
)
1704 static const WCHAR query
[] = {
1705 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1706 '`','D','i','r','e','c','t','o','r','y','`',0 };
1710 if (!list_empty(&package
->folders
))
1711 return ERROR_SUCCESS
;
1713 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1714 if (r
!= ERROR_SUCCESS
)
1717 r
= MSI_IterateRecords(view
, NULL
, load_folder
, package
);
1718 msiobj_release(&view
->hdr
);
1723 * I am not doing any of the costing functionality yet.
1724 * Mostly looking at doing the Component and Feature loading
1726 * The native MSI does A LOT of modification to tables here. Mostly adding
1727 * a lot of temporary columns to the Feature and Component tables.
1729 * note: Native msi also tracks the short filename. But I am only going to
1730 * track the long ones. Also looking at this directory table
1731 * it appears that the directory table does not get the parents
1732 * resolved base on property only based on their entries in the
1735 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1737 static const WCHAR szCosting
[] =
1738 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1739 static const WCHAR szZero
[] = { '0', 0 };
1741 MSI_SetPropertyW(package
, szCosting
, szZero
);
1742 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1744 load_all_folders( package
);
1745 load_all_components( package
);
1746 load_all_features( package
);
1747 load_all_files( package
);
1749 return ERROR_SUCCESS
;
1752 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1755 UINT rc
= ERROR_SUCCESS
;
1757 TRACE("Executing Script %i\n",script
);
1759 if (!package
->script
)
1761 ERR("no script!\n");
1762 return ERROR_FUNCTION_FAILED
;
1765 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1768 action
= package
->script
->Actions
[script
][i
];
1769 ui_actionstart(package
, action
);
1770 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1771 rc
= ACTION_PerformAction(package
, action
, script
, TRUE
);
1772 if (rc
!= ERROR_SUCCESS
)
1775 msi_free_action_script(package
, script
);
1779 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1781 return ERROR_SUCCESS
;
1784 static void ACTION_GetComponentInstallStates(MSIPACKAGE
*package
)
1790 state
= MsiQueryProductStateW(package
->ProductCode
);
1792 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
1794 if (!comp
->ComponentId
)
1797 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1798 comp
->Installed
= INSTALLSTATE_ABSENT
;
1801 r
= MsiQueryComponentStateW(package
->ProductCode
, NULL
,
1802 package
->Context
, comp
->ComponentId
,
1804 if (r
!= ERROR_SUCCESS
)
1805 comp
->Installed
= INSTALLSTATE_ABSENT
;
1810 static void ACTION_GetFeatureInstallStates(MSIPACKAGE
*package
)
1812 MSIFEATURE
*feature
;
1815 state
= MsiQueryProductStateW(package
->ProductCode
);
1817 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1819 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1820 feature
->Installed
= INSTALLSTATE_ABSENT
;
1823 feature
->Installed
= MsiQueryFeatureStateW(package
->ProductCode
,
1829 static BOOL
process_state_property(MSIPACKAGE
* package
, int level
,
1830 LPCWSTR property
, INSTALLSTATE state
)
1832 static const WCHAR all
[]={'A','L','L',0};
1833 static const WCHAR remove
[] = {'R','E','M','O','V','E',0};
1834 static const WCHAR reinstall
[] = {'R','E','I','N','S','T','A','L','L',0};
1836 MSIFEATURE
*feature
;
1838 override
= msi_dup_property( package
, property
);
1842 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1844 if (lstrcmpW(property
, remove
) &&
1845 (feature
->Level
<= 0 || feature
->Level
> level
))
1848 if (!strcmpW(property
, reinstall
)) state
= feature
->Installed
;
1850 if (strcmpiW(override
,all
)==0)
1851 msi_feature_set_state(package
, feature
, state
);
1854 LPWSTR ptr
= override
;
1855 LPWSTR ptr2
= strchrW(override
,',');
1859 if ((ptr2
&& strncmpW(ptr
,feature
->Feature
, ptr2
-ptr
)==0)
1860 || (!ptr2
&& strcmpW(ptr
,feature
->Feature
)==0))
1862 msi_feature_set_state(package
, feature
, state
);
1868 ptr2
= strchrW(ptr
,',');
1880 UINT
MSI_SetFeatureStates(MSIPACKAGE
*package
)
1883 static const WCHAR szlevel
[] =
1884 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1885 static const WCHAR szAddLocal
[] =
1886 {'A','D','D','L','O','C','A','L',0};
1887 static const WCHAR szAddSource
[] =
1888 {'A','D','D','S','O','U','R','C','E',0};
1889 static const WCHAR szRemove
[] =
1890 {'R','E','M','O','V','E',0};
1891 static const WCHAR szReinstall
[] =
1892 {'R','E','I','N','S','T','A','L','L',0};
1893 static const WCHAR szAdvertise
[] =
1894 {'A','D','V','E','R','T','I','S','E',0};
1895 BOOL override
= FALSE
;
1896 MSICOMPONENT
* component
;
1897 MSIFEATURE
*feature
;
1900 /* I do not know if this is where it should happen.. but */
1902 TRACE("Checking Install Level\n");
1904 level
= msi_get_property_int(package
, szlevel
, 1);
1906 /* ok here is the _real_ rub
1907 * all these activation/deactivation things happen in order and things
1908 * later on the list override things earlier on the list.
1909 * 0) INSTALLLEVEL processing
1920 * 11) FILEADDDEFAULT
1922 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1923 * REMOVE are the big ones, since we don't handle administrative installs
1926 override
|= process_state_property(package
, level
, szAddLocal
, INSTALLSTATE_LOCAL
);
1927 override
|= process_state_property(package
, level
, szRemove
, INSTALLSTATE_ABSENT
);
1928 override
|= process_state_property(package
, level
, szAddSource
, INSTALLSTATE_SOURCE
);
1929 override
|= process_state_property(package
, level
, szReinstall
, INSTALLSTATE_UNKNOWN
);
1930 override
|= process_state_property(package
, level
, szAdvertise
, INSTALLSTATE_ADVERTISED
);
1934 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1936 BOOL feature_state
= ((feature
->Level
> 0) &&
1937 (feature
->Level
<= level
));
1939 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1941 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1942 msi_feature_set_state(package
, feature
, INSTALLSTATE_SOURCE
);
1943 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1944 msi_feature_set_state(package
, feature
, INSTALLSTATE_ADVERTISED
);
1946 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1950 /* disable child features of unselected parent features */
1951 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1955 if (feature
->Level
> 0 && feature
->Level
<= level
)
1958 LIST_FOR_EACH_ENTRY( fl
, &feature
->Children
, FeatureList
, entry
)
1959 msi_feature_set_state(package
, fl
->feature
, INSTALLSTATE_UNKNOWN
);
1964 /* set the Preselected Property */
1965 static const WCHAR szPreselected
[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1966 static const WCHAR szOne
[] = { '1', 0 };
1968 MSI_SetPropertyW(package
,szPreselected
,szOne
);
1972 * now we want to enable or disable components base on feature
1975 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1979 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1980 debugstr_w(feature
->Feature
), feature
->Level
, feature
->Installed
, feature
->Action
);
1982 if (!feature
->Level
)
1985 /* features with components that have compressed files are made local */
1986 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1988 if (cl
->component
->Enabled
&&
1989 cl
->component
->ForceLocalState
&&
1990 feature
->Action
== INSTALLSTATE_SOURCE
)
1992 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1997 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1999 component
= cl
->component
;
2001 if (!component
->Enabled
)
2004 switch (feature
->Action
)
2006 case INSTALLSTATE_ABSENT
:
2007 component
->anyAbsent
= 1;
2009 case INSTALLSTATE_ADVERTISED
:
2010 component
->hasAdvertiseFeature
= 1;
2012 case INSTALLSTATE_SOURCE
:
2013 component
->hasSourceFeature
= 1;
2015 case INSTALLSTATE_LOCAL
:
2016 component
->hasLocalFeature
= 1;
2018 case INSTALLSTATE_DEFAULT
:
2019 if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
2020 component
->hasAdvertiseFeature
= 1;
2021 else if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
2022 component
->hasSourceFeature
= 1;
2024 component
->hasLocalFeature
= 1;
2032 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
2034 /* if the component isn't enabled, leave it alone */
2035 if (!component
->Enabled
)
2038 /* check if it's local or source */
2039 if (!(component
->Attributes
& msidbComponentAttributesOptional
) &&
2040 (component
->hasLocalFeature
|| component
->hasSourceFeature
))
2042 if ((component
->Attributes
& msidbComponentAttributesSourceOnly
) &&
2043 !component
->ForceLocalState
)
2044 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
2046 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
2050 /* if any feature is local, the component must be local too */
2051 if (component
->hasLocalFeature
)
2053 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
2057 if (component
->hasSourceFeature
)
2059 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
2063 if (component
->hasAdvertiseFeature
)
2065 msi_component_set_state(package
, component
, INSTALLSTATE_ADVERTISED
);
2069 TRACE("nobody wants component %s\n", debugstr_w(component
->Component
));
2070 if (component
->anyAbsent
)
2071 msi_component_set_state(package
, component
, INSTALLSTATE_ABSENT
);
2074 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
2076 if (component
->Action
== INSTALLSTATE_DEFAULT
)
2078 TRACE("%s was default, setting to local\n", debugstr_w(component
->Component
));
2079 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
2082 TRACE("Result: Component %s (Installed %i, Action %i)\n",
2083 debugstr_w(component
->Component
), component
->Installed
, component
->Action
);
2087 return ERROR_SUCCESS
;
2090 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
2092 MSIPACKAGE
*package
= param
;
2097 name
= MSI_RecordGetString(row
,1);
2099 f
= get_loaded_folder(package
, name
);
2100 if (!f
) return ERROR_SUCCESS
;
2102 /* reset the ResolvedTarget */
2103 msi_free(f
->ResolvedTarget
);
2104 f
->ResolvedTarget
= NULL
;
2106 /* This helper function now does ALL the work */
2107 TRACE("Dir %s ...\n",debugstr_w(name
));
2108 path
= resolve_folder(package
,name
,FALSE
,TRUE
,TRUE
,NULL
);
2109 TRACE("resolves to %s\n",debugstr_w(path
));
2112 return ERROR_SUCCESS
;
2115 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
2117 MSIPACKAGE
*package
= param
;
2119 MSIFEATURE
*feature
;
2121 name
= MSI_RecordGetString( row
, 1 );
2123 feature
= get_loaded_feature( package
, name
);
2125 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
2129 Condition
= MSI_RecordGetString(row
,3);
2131 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
2133 int level
= MSI_RecordGetInteger(row
,2);
2134 TRACE("Resetting feature %s to level %i\n", debugstr_w(name
), level
);
2135 feature
->Level
= level
;
2138 return ERROR_SUCCESS
;
2141 static LPWSTR
msi_get_disk_file_version( LPCWSTR filename
)
2143 static const WCHAR name_fmt
[] =
2144 {'%','u','.','%','u','.','%','u','.','%','u',0};
2145 static const WCHAR name
[] = {'\\',0};
2146 VS_FIXEDFILEINFO
*lpVer
;
2147 WCHAR filever
[0x100];
2153 TRACE("%s\n", debugstr_w(filename
));
2155 versize
= GetFileVersionInfoSizeW( filename
, &handle
);
2159 version
= msi_alloc( versize
);
2160 GetFileVersionInfoW( filename
, 0, versize
, version
);
2162 if (!VerQueryValueW( version
, name
, (LPVOID
*)&lpVer
, &sz
))
2164 msi_free( version
);
2168 sprintfW( filever
, name_fmt
,
2169 HIWORD(lpVer
->dwFileVersionMS
),
2170 LOWORD(lpVer
->dwFileVersionMS
),
2171 HIWORD(lpVer
->dwFileVersionLS
),
2172 LOWORD(lpVer
->dwFileVersionLS
));
2174 msi_free( version
);
2176 return strdupW( filever
);
2179 static UINT
msi_check_file_install_states( MSIPACKAGE
*package
)
2181 LPWSTR file_version
;
2184 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2186 MSICOMPONENT
* comp
= file
->Component
;
2192 if (file
->IsCompressed
)
2193 comp
->ForceLocalState
= TRUE
;
2195 /* calculate target */
2196 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, TRUE
, NULL
);
2198 msi_free(file
->TargetPath
);
2200 TRACE("file %s is named %s\n",
2201 debugstr_w(file
->File
), debugstr_w(file
->FileName
));
2203 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
2207 TRACE("file %s resolves to %s\n",
2208 debugstr_w(file
->File
), debugstr_w(file
->TargetPath
));
2210 /* don't check files of components that aren't installed */
2211 if (comp
->Installed
== INSTALLSTATE_UNKNOWN
||
2212 comp
->Installed
== INSTALLSTATE_ABSENT
)
2214 file
->state
= msifs_missing
; /* assume files are missing */
2218 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
2220 file
->state
= msifs_missing
;
2221 comp
->Cost
+= file
->FileSize
;
2225 if (file
->Version
&&
2226 (file_version
= msi_get_disk_file_version( file
->TargetPath
)))
2228 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
2229 debugstr_w(file_version
));
2230 /* FIXME: seems like a bad way to compare version numbers */
2231 if (lstrcmpiW(file_version
, file
->Version
)<0)
2233 file
->state
= msifs_overwrite
;
2234 comp
->Cost
+= file
->FileSize
;
2237 file
->state
= msifs_present
;
2238 msi_free( file_version
);
2241 file
->state
= msifs_present
;
2244 return ERROR_SUCCESS
;
2248 * A lot is done in this function aside from just the costing.
2249 * The costing needs to be implemented at some point but for now I am going
2250 * to focus on the directory building
2253 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2255 static const WCHAR ExecSeqQuery
[] =
2256 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2257 '`','D','i','r','e','c','t','o','r','y','`',0};
2258 static const WCHAR ConditionQuery
[] =
2259 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2260 '`','C','o','n','d','i','t','i','o','n','`',0};
2261 static const WCHAR szCosting
[] =
2262 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2263 static const WCHAR szlevel
[] =
2264 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2265 static const WCHAR szOutOfDiskSpace
[] =
2266 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2267 static const WCHAR szOne
[] = { '1', 0 };
2268 static const WCHAR szZero
[] = { '0', 0 };
2274 TRACE("Building Directory properties\n");
2276 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2277 if (rc
== ERROR_SUCCESS
)
2279 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
2281 msiobj_release(&view
->hdr
);
2284 /* read components states from the registry */
2285 ACTION_GetComponentInstallStates(package
);
2286 ACTION_GetFeatureInstallStates(package
);
2288 TRACE("File calculations\n");
2289 msi_check_file_install_states( package
);
2291 TRACE("Evaluating Condition Table\n");
2293 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
2294 if (rc
== ERROR_SUCCESS
)
2296 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeConditions
,
2298 msiobj_release(&view
->hdr
);
2301 TRACE("Enabling or Disabling Components\n");
2302 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2304 if (MSI_EvaluateConditionW(package
, comp
->Condition
) == MSICONDITION_FALSE
)
2306 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
2307 comp
->Enabled
= FALSE
;
2310 comp
->Enabled
= TRUE
;
2313 MSI_SetPropertyW(package
,szCosting
,szOne
);
2314 /* set default run level if not set */
2315 level
= msi_dup_property( package
, szlevel
);
2317 MSI_SetPropertyW(package
,szlevel
, szOne
);
2320 /* FIXME: check volume disk space */
2321 MSI_SetPropertyW(package
, szOutOfDiskSpace
, szZero
);
2323 return MSI_SetFeatureStates(package
);
2326 /* OK this value is "interpreted" and then formatted based on the
2327 first few characters */
2328 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
2333 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2339 LPWSTR deformated
= NULL
;
2342 deformat_string(package
, &value
[2], &deformated
);
2344 /* binary value type */
2348 *size
= (strlenW(ptr
)/2)+1;
2350 *size
= strlenW(ptr
)/2;
2352 data
= msi_alloc(*size
);
2358 /* if uneven pad with a zero in front */
2364 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2366 TRACE("Uneven byte count\n");
2374 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2377 msi_free(deformated
);
2379 TRACE("Data %i bytes(%i)\n",*size
,count
);
2386 deformat_string(package
, &value
[1], &deformated
);
2389 *size
= sizeof(DWORD
);
2390 data
= msi_alloc(*size
);
2396 if ( (*p
< '0') || (*p
> '9') )
2402 if (deformated
[0] == '-')
2405 TRACE("DWORD %i\n",*(LPDWORD
)data
);
2407 msi_free(deformated
);
2412 static const WCHAR szMulti
[] = {'[','~',']',0};
2421 *type
=REG_EXPAND_SZ
;
2429 if (strstrW(value
,szMulti
))
2430 *type
= REG_MULTI_SZ
;
2432 /* remove initial delimiter */
2433 if (!strncmpW(value
, szMulti
, 3))
2436 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2438 /* add double NULL terminator */
2439 if (*type
== REG_MULTI_SZ
)
2441 *size
+= 2 * sizeof(WCHAR
); /* two NULL terminators */
2442 data
= msi_realloc_zero(data
, *size
);
2448 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2450 MSIPACKAGE
*package
= param
;
2451 static const WCHAR szHCR
[] =
2452 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2453 'R','O','O','T','\\',0};
2454 static const WCHAR szHCU
[] =
2455 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2456 'U','S','E','R','\\',0};
2457 static const WCHAR szHLM
[] =
2458 {'H','K','E','Y','_','L','O','C','A','L','_',
2459 'M','A','C','H','I','N','E','\\',0};
2460 static const WCHAR szHU
[] =
2461 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2463 LPSTR value_data
= NULL
;
2464 HKEY root_key
, hkey
;
2467 LPCWSTR szRoot
, component
, name
, key
, value
;
2472 BOOL check_first
= FALSE
;
2475 ui_progress(package
,2,0,0,0);
2482 component
= MSI_RecordGetString(row
, 6);
2483 comp
= get_loaded_component(package
,component
);
2485 return ERROR_SUCCESS
;
2487 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2489 TRACE("Skipping write due to disabled component %s\n",
2490 debugstr_w(component
));
2492 comp
->Action
= comp
->Installed
;
2494 return ERROR_SUCCESS
;
2497 comp
->Action
= INSTALLSTATE_LOCAL
;
2499 name
= MSI_RecordGetString(row
, 4);
2500 if( MSI_RecordIsNull(row
,5) && name
)
2502 /* null values can have special meanings */
2503 if (name
[0]=='-' && name
[1] == 0)
2504 return ERROR_SUCCESS
;
2505 else if ((name
[0]=='+' && name
[1] == 0) ||
2506 (name
[0] == '*' && name
[1] == 0))
2511 root
= MSI_RecordGetInteger(row
,2);
2512 key
= MSI_RecordGetString(row
, 3);
2514 /* get the root key */
2519 static const WCHAR szALLUSER
[] = {'A','L','L','U','S','E','R','S',0};
2520 LPWSTR all_users
= msi_dup_property( package
, szALLUSER
);
2521 if (all_users
&& all_users
[0] == '1')
2523 root_key
= HKEY_LOCAL_MACHINE
;
2528 root_key
= HKEY_CURRENT_USER
;
2531 msi_free(all_users
);
2534 case 0: root_key
= HKEY_CLASSES_ROOT
;
2537 case 1: root_key
= HKEY_CURRENT_USER
;
2540 case 2: root_key
= HKEY_LOCAL_MACHINE
;
2543 case 3: root_key
= HKEY_USERS
;
2547 ERR("Unknown root %i\n",root
);
2553 return ERROR_SUCCESS
;
2555 deformat_string(package
, key
, &deformated
);
2556 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2557 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2558 strcpyW(uikey
,szRoot
);
2559 strcatW(uikey
,deformated
);
2561 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2563 ERR("Could not create key %s\n",debugstr_w(deformated
));
2564 msi_free(deformated
);
2566 return ERROR_SUCCESS
;
2568 msi_free(deformated
);
2570 value
= MSI_RecordGetString(row
,5);
2572 value_data
= parse_value(package
, value
, &type
, &size
);
2575 static const WCHAR szEmpty
[] = {0};
2576 value_data
= (LPSTR
)strdupW(szEmpty
);
2577 size
= sizeof(szEmpty
);
2581 deformat_string(package
, name
, &deformated
);
2585 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2587 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2592 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2593 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2595 TRACE("value %s of %s checked already exists\n",
2596 debugstr_w(deformated
), debugstr_w(uikey
));
2600 TRACE("Checked and setting value %s of %s\n",
2601 debugstr_w(deformated
), debugstr_w(uikey
));
2602 if (deformated
|| size
)
2603 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2608 uirow
= MSI_CreateRecord(3);
2609 MSI_RecordSetStringW(uirow
,2,deformated
);
2610 MSI_RecordSetStringW(uirow
,1,uikey
);
2613 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2615 MSI_RecordSetStringW(uirow
,3,value
);
2617 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2618 msiobj_release( &uirow
->hdr
);
2620 msi_free(value_data
);
2621 msi_free(deformated
);
2624 return ERROR_SUCCESS
;
2627 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2631 static const WCHAR ExecSeqQuery
[] =
2632 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2633 '`','R','e','g','i','s','t','r','y','`',0 };
2635 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2636 if (rc
!= ERROR_SUCCESS
)
2637 return ERROR_SUCCESS
;
2639 /* increment progress bar each time action data is sent */
2640 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2642 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2644 msiobj_release(&view
->hdr
);
2648 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2650 package
->script
->CurrentlyScripting
= TRUE
;
2652 return ERROR_SUCCESS
;
2656 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2661 static const WCHAR q1
[]=
2662 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2663 '`','R','e','g','i','s','t','r','y','`',0};
2666 MSIFEATURE
*feature
;
2669 TRACE("InstallValidate\n");
2671 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2672 if (rc
== ERROR_SUCCESS
)
2674 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2675 msiobj_release( &view
->hdr
);
2676 total
+= progress
* REG_PROGRESS_VALUE
;
2679 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2680 total
+= COMPONENT_PROGRESS_VALUE
;
2682 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2683 total
+= file
->FileSize
;
2685 ui_progress(package
,0,total
,0,0);
2687 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2689 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2690 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2691 feature
->ActionRequest
);
2694 return ERROR_SUCCESS
;
2697 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2699 MSIPACKAGE
* package
= param
;
2700 LPCWSTR cond
= NULL
;
2701 LPCWSTR message
= NULL
;
2704 static const WCHAR title
[]=
2705 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2707 cond
= MSI_RecordGetString(row
,1);
2709 r
= MSI_EvaluateConditionW(package
,cond
);
2710 if (r
== MSICONDITION_FALSE
)
2712 if ((gUILevel
& INSTALLUILEVEL_MASK
) != INSTALLUILEVEL_NONE
)
2715 message
= MSI_RecordGetString(row
,2);
2716 deformat_string(package
,message
,&deformated
);
2717 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2718 msi_free(deformated
);
2721 return ERROR_INSTALL_FAILURE
;
2724 return ERROR_SUCCESS
;
2727 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2730 MSIQUERY
* view
= NULL
;
2731 static const WCHAR ExecSeqQuery
[] =
2732 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2733 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2735 TRACE("Checking launch conditions\n");
2737 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2738 if (rc
!= ERROR_SUCCESS
)
2739 return ERROR_SUCCESS
;
2741 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2742 msiobj_release(&view
->hdr
);
2747 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2751 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,TRUE
,NULL
);
2753 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2755 MSIRECORD
* row
= 0;
2757 LPWSTR deformated
,buffer
,deformated_name
;
2759 static const WCHAR ExecSeqQuery
[] =
2760 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2761 '`','R','e','g','i','s','t','r','y','`',' ',
2762 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2763 ' ','=',' ' ,'\'','%','s','\'',0 };
2764 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2765 static const WCHAR fmt2
[]=
2766 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2768 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2772 root
= MSI_RecordGetInteger(row
,2);
2773 key
= MSI_RecordGetString(row
, 3);
2774 name
= MSI_RecordGetString(row
, 4);
2775 deformat_string(package
, key
, &deformated
);
2776 deformat_string(package
, name
, &deformated_name
);
2778 len
= strlenW(deformated
) + 6;
2779 if (deformated_name
)
2780 len
+=strlenW(deformated_name
);
2782 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2784 if (deformated_name
)
2785 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2787 sprintfW(buffer
,fmt
,root
,deformated
);
2789 msi_free(deformated
);
2790 msi_free(deformated_name
);
2791 msiobj_release(&row
->hdr
);
2795 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2797 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2802 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2805 return strdupW( file
->TargetPath
);
2810 static HKEY
openSharedDLLsKey(void)
2813 static const WCHAR path
[] =
2814 {'S','o','f','t','w','a','r','e','\\',
2815 'M','i','c','r','o','s','o','f','t','\\',
2816 'W','i','n','d','o','w','s','\\',
2817 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2818 'S','h','a','r','e','d','D','L','L','s',0};
2820 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2824 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2829 DWORD sz
= sizeof(count
);
2832 hkey
= openSharedDLLsKey();
2833 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2834 if (rc
!= ERROR_SUCCESS
)
2840 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2844 hkey
= openSharedDLLsKey();
2846 msi_reg_set_val_dword( hkey
, path
, count
);
2848 RegDeleteValueW(hkey
,path
);
2854 * Return TRUE if the count should be written out and FALSE if not
2856 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2858 MSIFEATURE
*feature
;
2862 /* only refcount DLLs */
2863 if (comp
->KeyPath
== NULL
||
2864 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2865 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2869 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2870 write
= (count
> 0);
2872 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2876 /* increment counts */
2877 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2881 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
))
2884 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2886 if ( cl
->component
== comp
)
2891 /* decrement counts */
2892 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2896 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ABSENT
))
2899 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2901 if ( cl
->component
== comp
)
2906 /* ref count all the files in the component */
2911 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2913 if (file
->Component
== comp
)
2914 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2918 /* add a count for permanent */
2919 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2922 comp
->RefCount
= count
;
2925 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2928 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2930 WCHAR squished_pc
[GUID_SIZE
];
2931 WCHAR squished_cc
[GUID_SIZE
];
2938 squash_guid(package
->ProductCode
,squished_pc
);
2939 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2941 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2945 ui_progress(package
,2,0,0,0);
2946 if (!comp
->ComponentId
)
2949 squash_guid(comp
->ComponentId
,squished_cc
);
2951 msi_free(comp
->FullKeypath
);
2952 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2954 ACTION_RefCountComponent( package
, comp
);
2956 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2957 debugstr_w(comp
->Component
),
2958 debugstr_w(squished_cc
),
2959 debugstr_w(comp
->FullKeypath
),
2962 if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) ||
2963 ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
))
2965 if (!comp
->FullKeypath
)
2968 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2969 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, szLocalSid
,
2972 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, NULL
,
2975 if (rc
!= ERROR_SUCCESS
)
2978 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2980 static const WCHAR szPermKey
[] =
2981 { '0','0','0','0','0','0','0','0','0','0','0','0',
2982 '0','0','0','0','0','0','0','0','0','0','0','0',
2983 '0','0','0','0','0','0','0','0',0 };
2985 msi_reg_set_val_str(hkey
, szPermKey
, comp
->FullKeypath
);
2988 if (comp
->Action
== INSTALLSTATE_LOCAL
)
2989 msi_reg_set_val_str(hkey
, squished_pc
, comp
->FullKeypath
);
2995 WCHAR source
[MAX_PATH
];
2996 WCHAR base
[MAX_PATH
];
2999 static const WCHAR fmt
[] = {'%','0','2','d','\\',0};
3000 static const WCHAR query
[] = {
3001 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3002 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3003 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3004 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3005 '`','D','i','s','k','I','d','`',0};
3007 file
= get_loaded_file(package
, comp
->KeyPath
);
3011 row
= MSI_QueryGetRecord(package
->db
, query
, file
->Sequence
);
3012 sprintfW(source
, fmt
, MSI_RecordGetInteger(row
, 1));
3013 ptr2
= strrchrW(source
, '\\') + 1;
3014 msiobj_release(&row
->hdr
);
3016 lstrcpyW(base
, package
->PackagePath
);
3017 ptr
= strrchrW(base
, '\\');
3020 sourcepath
= resolve_file_source(package
, file
);
3021 ptr
= sourcepath
+ lstrlenW(base
);
3022 lstrcpyW(ptr2
, ptr
);
3023 msi_free(sourcepath
);
3025 msi_reg_set_val_str(hkey
, squished_pc
, source
);
3029 else if (ACTION_VerifyComponentForAction(comp
, INSTALLSTATE_ABSENT
))
3031 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3032 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, szLocalSid
);
3034 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, NULL
);
3038 uirow
= MSI_CreateRecord(3);
3039 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
3040 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
3041 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
3042 ui_actiondata(package
,szProcessComponents
,uirow
);
3043 msiobj_release( &uirow
->hdr
);
3046 return ERROR_SUCCESS
;
3057 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
3058 LPWSTR lpszName
, LONG_PTR lParam
)
3061 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
3062 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
3066 if (!IS_INTRESOURCE(lpszName
))
3068 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
3072 sz
= strlenW(tl_struct
->source
)+4;
3073 sz
*= sizeof(WCHAR
);
3075 if ((INT_PTR
)lpszName
== 1)
3076 tl_struct
->path
= strdupW(tl_struct
->source
);
3079 tl_struct
->path
= msi_alloc(sz
);
3080 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
3083 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
3084 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
3087 msi_free(tl_struct
->path
);
3088 tl_struct
->path
= NULL
;
3093 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
3094 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
3096 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
3100 msi_free(tl_struct
->path
);
3101 tl_struct
->path
= NULL
;
3103 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
3104 ITypeLib_Release(tl_struct
->ptLib
);
3109 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
3111 MSIPACKAGE
* package
= param
;
3115 typelib_struct tl_struct
;
3120 static const WCHAR szTYPELIB
[] = {'T','Y','P','E','L','I','B',0};
3122 component
= MSI_RecordGetString(row
,3);
3123 comp
= get_loaded_component(package
,component
);
3125 return ERROR_SUCCESS
;
3127 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3129 TRACE("Skipping typelib reg due to disabled component\n");
3131 comp
->Action
= comp
->Installed
;
3133 return ERROR_SUCCESS
;
3136 comp
->Action
= INSTALLSTATE_LOCAL
;
3138 file
= get_loaded_file( package
, comp
->KeyPath
);
3140 return ERROR_SUCCESS
;
3142 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
3146 guid
= MSI_RecordGetString(row
,1);
3147 CLSIDFromString((LPWSTR
)guid
, &tl_struct
.clsid
);
3148 tl_struct
.source
= strdupW( file
->TargetPath
);
3149 tl_struct
.path
= NULL
;
3151 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
3152 (LONG_PTR
)&tl_struct
);
3160 helpid
= MSI_RecordGetString(row
,6);
3163 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,TRUE
,NULL
);
3164 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
3168 ERR("Failed to register type library %s\n",
3169 debugstr_w(tl_struct
.path
));
3172 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
3174 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
3177 ITypeLib_Release(tl_struct
.ptLib
);
3178 msi_free(tl_struct
.path
);
3181 ERR("Failed to load type library %s\n",
3182 debugstr_w(tl_struct
.source
));
3184 FreeLibrary(module
);
3185 msi_free(tl_struct
.source
);
3189 hr
= LoadTypeLibEx(file
->TargetPath
, REGKIND_REGISTER
, &tlib
);
3192 ERR("Failed to load type library: %08x\n", hr
);
3193 return ERROR_FUNCTION_FAILED
;
3196 ITypeLib_Release(tlib
);
3199 return ERROR_SUCCESS
;
3202 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
3205 * OK this is a bit confusing.. I am given a _Component key and I believe
3206 * that the file that is being registered as a type library is the "key file
3207 * of that component" which I interpret to mean "The file in the KeyPath of
3212 static const WCHAR Query
[] =
3213 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3214 '`','T','y','p','e','L','i','b','`',0};
3216 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3217 if (rc
!= ERROR_SUCCESS
)
3218 return ERROR_SUCCESS
;
3220 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
3221 msiobj_release(&view
->hdr
);
3225 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
3227 MSIPACKAGE
*package
= param
;
3228 LPWSTR target_file
, target_folder
, filename
;
3229 LPCWSTR buffer
, extension
;
3231 static const WCHAR szlnk
[]={'.','l','n','k',0};
3232 IShellLinkW
*sl
= NULL
;
3233 IPersistFile
*pf
= NULL
;
3236 buffer
= MSI_RecordGetString(row
,4);
3237 comp
= get_loaded_component(package
,buffer
);
3239 return ERROR_SUCCESS
;
3241 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3243 TRACE("Skipping shortcut creation due to disabled component\n");
3245 comp
->Action
= comp
->Installed
;
3247 return ERROR_SUCCESS
;
3250 comp
->Action
= INSTALLSTATE_LOCAL
;
3252 ui_actiondata(package
,szCreateShortcuts
,row
);
3254 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
3255 &IID_IShellLinkW
, (LPVOID
*) &sl
);
3259 ERR("CLSID_ShellLink not available\n");
3263 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
3266 ERR("QueryInterface(IID_IPersistFile) failed\n");
3270 buffer
= MSI_RecordGetString(row
,2);
3271 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,TRUE
,NULL
);
3273 /* may be needed because of a bug somewhere else */
3274 create_full_pathW(target_folder
);
3276 filename
= msi_dup_record_field( row
, 3 );
3277 reduce_to_longfilename(filename
);
3279 extension
= strchrW(filename
,'.');
3280 if (!extension
|| strcmpiW(extension
,szlnk
))
3282 int len
= strlenW(filename
);
3283 filename
= msi_realloc(filename
, len
* sizeof(WCHAR
) + sizeof(szlnk
));
3284 memcpy(filename
+ len
, szlnk
, sizeof(szlnk
));
3286 target_file
= build_directory_name(2, target_folder
, filename
);
3287 msi_free(target_folder
);
3290 buffer
= MSI_RecordGetString(row
,5);
3291 if (strchrW(buffer
,'['))
3294 deformat_string(package
,buffer
,&deformated
);
3295 IShellLinkW_SetPath(sl
,deformated
);
3296 msi_free(deformated
);
3300 FIXME("poorly handled shortcut format, advertised shortcut\n");
3301 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
3304 if (!MSI_RecordIsNull(row
,6))
3307 buffer
= MSI_RecordGetString(row
,6);
3308 deformat_string(package
,buffer
,&deformated
);
3309 IShellLinkW_SetArguments(sl
,deformated
);
3310 msi_free(deformated
);
3313 if (!MSI_RecordIsNull(row
,7))
3315 buffer
= MSI_RecordGetString(row
,7);
3316 IShellLinkW_SetDescription(sl
,buffer
);
3319 if (!MSI_RecordIsNull(row
,8))
3320 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
3322 if (!MSI_RecordIsNull(row
,9))
3327 buffer
= MSI_RecordGetString(row
,9);
3329 Path
= build_icon_path(package
,buffer
);
3330 index
= MSI_RecordGetInteger(row
,10);
3332 /* no value means 0 */
3333 if (index
== MSI_NULL_INTEGER
)
3336 IShellLinkW_SetIconLocation(sl
,Path
,index
);
3340 if (!MSI_RecordIsNull(row
,11))
3341 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
3343 if (!MSI_RecordIsNull(row
,12))
3346 buffer
= MSI_RecordGetString(row
,12);
3347 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, TRUE
, NULL
);
3349 IShellLinkW_SetWorkingDirectory(sl
,Path
);
3353 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
3354 IPersistFile_Save(pf
,target_file
,FALSE
);
3356 msi_free(target_file
);
3360 IPersistFile_Release( pf
);
3362 IShellLinkW_Release( sl
);
3364 return ERROR_SUCCESS
;
3367 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
3372 static const WCHAR Query
[] =
3373 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3374 '`','S','h','o','r','t','c','u','t','`',0};
3376 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3377 if (rc
!= ERROR_SUCCESS
)
3378 return ERROR_SUCCESS
;
3380 res
= CoInitialize( NULL
);
3383 ERR("CoInitialize failed\n");
3384 return ERROR_FUNCTION_FAILED
;
3387 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
3388 msiobj_release(&view
->hdr
);
3395 static UINT
ITERATE_PublishIcon(MSIRECORD
*row
, LPVOID param
)
3397 MSIPACKAGE
* package
= param
;
3406 FileName
= MSI_RecordGetString(row
,1);
3409 ERR("Unable to get FileName\n");
3410 return ERROR_SUCCESS
;
3413 FilePath
= build_icon_path(package
,FileName
);
3415 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
3417 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
3418 FILE_ATTRIBUTE_NORMAL
, NULL
);
3420 if (the_file
== INVALID_HANDLE_VALUE
)
3422 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3424 return ERROR_SUCCESS
;
3431 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3432 if (rc
!= ERROR_SUCCESS
)
3434 ERR("Failed to get stream\n");
3435 CloseHandle(the_file
);
3436 DeleteFileW(FilePath
);
3439 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3440 } while (sz
== 1024);
3444 CloseHandle(the_file
);
3446 uirow
= MSI_CreateRecord(1);
3447 MSI_RecordSetStringW(uirow
,1,FileName
);
3448 ui_actiondata(package
,szPublishProduct
,uirow
);
3449 msiobj_release( &uirow
->hdr
);
3451 return ERROR_SUCCESS
;
3454 static UINT
msi_publish_icons(MSIPACKAGE
*package
)
3459 static const WCHAR query
[]= {
3460 'S','E','L','E','C','T',' ','*',' ',
3461 'F','R','O','M',' ','`','I','c','o','n','`',0};
3463 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
3464 if (r
== ERROR_SUCCESS
)
3466 MSI_IterateRecords(view
, NULL
, ITERATE_PublishIcon
, package
);
3467 msiobj_release(&view
->hdr
);
3470 return ERROR_SUCCESS
;
3473 static UINT
msi_publish_sourcelist(MSIPACKAGE
*package
, HKEY hkey
)
3479 MSISOURCELISTINFO
*info
;
3481 static const WCHAR szEmpty
[] = {0};
3482 static const WCHAR szSourceList
[] = {'S','o','u','r','c','e','L','i','s','t',0};
3484 r
= RegCreateKeyW(hkey
, szSourceList
, &source
);
3485 if (r
!= ERROR_SUCCESS
)
3488 RegCloseKey(source
);
3490 buffer
= strrchrW(package
->PackagePath
, '\\') + 1;
3491 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3492 package
->Context
, MSICODE_PRODUCT
,
3493 INSTALLPROPERTY_PACKAGENAMEW
, buffer
);
3494 if (r
!= ERROR_SUCCESS
)
3497 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3498 package
->Context
, MSICODE_PRODUCT
,
3499 INSTALLPROPERTY_MEDIAPACKAGEPATHW
, szEmpty
);
3500 if (r
!= ERROR_SUCCESS
)
3503 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3504 package
->Context
, MSICODE_PRODUCT
,
3505 INSTALLPROPERTY_DISKPROMPTW
, szEmpty
);
3506 if (r
!= ERROR_SUCCESS
)
3509 LIST_FOR_EACH_ENTRY(info
, &package
->sourcelist_info
, MSISOURCELISTINFO
, entry
)
3511 if (!lstrcmpW(info
->property
, INSTALLPROPERTY_LASTUSEDSOURCEW
))
3512 msi_set_last_used_source(package
->ProductCode
, NULL
, info
->context
,
3513 info
->options
, info
->value
);
3515 MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3516 info
->context
, info
->options
,
3517 info
->property
, info
->value
);
3520 LIST_FOR_EACH_ENTRY(disk
, &package
->sourcelist_media
, MSIMEDIADISK
, entry
)
3522 MsiSourceListAddMediaDiskW(package
->ProductCode
, NULL
,
3523 disk
->context
, disk
->options
,
3524 disk
->disk_id
, disk
->volume_label
, disk
->disk_prompt
);
3527 return ERROR_SUCCESS
;
3530 static UINT
msi_publish_product_properties(MSIPACKAGE
*package
, HKEY hkey
)
3532 MSIHANDLE hdb
, suminfo
;
3533 WCHAR guids
[MAX_PATH
];
3534 WCHAR packcode
[SQUISH_GUID_SIZE
];
3541 static const WCHAR szProductLanguage
[] =
3542 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3543 static const WCHAR szARPProductIcon
[] =
3544 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3545 static const WCHAR szProductVersion
[] =
3546 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3547 static const WCHAR szAssignment
[] =
3548 {'A','s','s','i','g','n','m','e','n','t',0};
3549 static const WCHAR szAdvertiseFlags
[] =
3550 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3551 static const WCHAR szClients
[] =
3552 {'C','l','i','e','n','t','s',0};
3553 static const WCHAR szColon
[] = {':',0};
3555 buffer
= msi_dup_property(package
, INSTALLPROPERTY_PRODUCTNAMEW
);
3556 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3559 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
3560 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3563 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_AUTHORIZED_LUA_APPW
, 0);
3565 buffer
= msi_dup_property(package
, szARPProductIcon
);
3568 LPWSTR path
= build_icon_path(package
,buffer
);
3569 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3574 buffer
= msi_dup_property(package
, szProductVersion
);
3577 DWORD verdword
= msi_version_str_to_dword(buffer
);
3578 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3582 msi_reg_set_val_dword(hkey
, szAssignment
, 0);
3583 msi_reg_set_val_dword(hkey
, szAdvertiseFlags
, 0x184);
3584 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_INSTANCETYPEW
, 0);
3585 msi_reg_set_val_str(hkey
, szClients
, szColon
);
3587 hdb
= alloc_msihandle(&package
->db
->hdr
);
3589 return ERROR_NOT_ENOUGH_MEMORY
;
3591 r
= MsiGetSummaryInformationW(hdb
, NULL
, 0, &suminfo
);
3592 MsiCloseHandle(hdb
);
3593 if (r
!= ERROR_SUCCESS
)
3597 r
= MsiSummaryInfoGetPropertyW(suminfo
, PID_REVNUMBER
, NULL
, NULL
,
3598 NULL
, guids
, &size
);
3599 if (r
!= ERROR_SUCCESS
)
3602 ptr
= strchrW(guids
, ';');
3604 squash_guid(guids
, packcode
);
3605 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PACKAGECODEW
, packcode
);
3608 MsiCloseHandle(suminfo
);
3609 return ERROR_SUCCESS
;
3612 static UINT
msi_publish_upgrade_code(MSIPACKAGE
*package
)
3617 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
3619 static const WCHAR szUpgradeCode
[] =
3620 {'U','p','g','r','a','d','e','C','o','d','e',0};
3622 upgrade
= msi_dup_property(package
, szUpgradeCode
);
3624 return ERROR_SUCCESS
;
3626 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3628 r
= MSIREG_OpenClassesUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3629 if (r
!= ERROR_SUCCESS
)
3634 r
= MSIREG_OpenUserUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3635 if (r
!= ERROR_SUCCESS
)
3639 squash_guid(package
->ProductCode
, squashed_pc
);
3640 msi_reg_set_val_str(hkey
, squashed_pc
, NULL
);
3649 static BOOL
msi_check_publish(MSIPACKAGE
*package
)
3651 MSIFEATURE
*feature
;
3653 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3655 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
3662 static BOOL
msi_check_unpublish(MSIPACKAGE
*package
)
3664 MSIFEATURE
*feature
;
3666 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3668 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3675 static UINT
msi_publish_patch(MSIPACKAGE
*package
, HKEY prodkey
, HKEY hudkey
)
3677 WCHAR patch_squashed
[GUID_SIZE
];
3680 UINT r
= ERROR_FUNCTION_FAILED
;
3682 static const WCHAR szPatches
[] = {'P','a','t','c','h','e','s',0};
3684 res
= RegCreateKeyExW(prodkey
, szPatches
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
,
3686 if (res
!= ERROR_SUCCESS
)
3687 return ERROR_FUNCTION_FAILED
;
3689 squash_guid(package
->patch
->patchcode
, patch_squashed
);
3691 res
= RegSetValueExW(patches
, szPatches
, 0, REG_MULTI_SZ
,
3692 (const BYTE
*)patch_squashed
,
3693 (lstrlenW(patch_squashed
) + 1) * sizeof(WCHAR
));
3694 if (res
!= ERROR_SUCCESS
)
3697 res
= RegSetValueExW(patches
, patch_squashed
, 0, REG_SZ
,
3698 (const BYTE
*)package
->patch
->transforms
,
3699 (lstrlenW(package
->patch
->transforms
) + 1) * sizeof(WCHAR
));
3700 if (res
== ERROR_SUCCESS
)
3704 RegCloseKey(patches
);
3709 * 99% of the work done here is only done for
3710 * advertised installs. However this is where the
3711 * Icon table is processed and written out
3712 * so that is what I am going to do here.
3714 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3720 /* FIXME: also need to publish if the product is in advertise mode */
3721 if (!msi_check_publish(package
))
3722 return ERROR_SUCCESS
;
3724 rc
= MSIREG_OpenProductKey(package
->ProductCode
, NULL
, package
->Context
,
3726 if (rc
!= ERROR_SUCCESS
)
3729 rc
= MSIREG_OpenUserDataProductKey(package
->ProductCode
, package
->Context
,
3730 NULL
, &hudkey
, TRUE
);
3731 if (rc
!= ERROR_SUCCESS
)
3734 rc
= msi_publish_upgrade_code(package
);
3735 if (rc
!= ERROR_SUCCESS
)
3740 rc
= msi_publish_patch(package
, hukey
, hudkey
);
3741 if (rc
!= ERROR_SUCCESS
)
3745 rc
= msi_publish_product_properties(package
, hukey
);
3746 if (rc
!= ERROR_SUCCESS
)
3749 rc
= msi_publish_sourcelist(package
, hukey
);
3750 if (rc
!= ERROR_SUCCESS
)
3753 rc
= msi_publish_icons(package
);
3757 RegCloseKey(hudkey
);
3762 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3764 MSIPACKAGE
*package
= param
;
3765 LPCWSTR component
, section
, key
, value
, identifier
, dirproperty
;
3766 LPWSTR deformated_section
, deformated_key
, deformated_value
;
3767 LPWSTR folder
, filename
, fullname
= NULL
;
3768 LPCWSTR filenameptr
;
3772 static const WCHAR szWindowsFolder
[] =
3773 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3775 component
= MSI_RecordGetString(row
, 8);
3776 comp
= get_loaded_component(package
,component
);
3778 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3780 TRACE("Skipping ini file due to disabled component %s\n",
3781 debugstr_w(component
));
3783 comp
->Action
= comp
->Installed
;
3785 return ERROR_SUCCESS
;
3788 comp
->Action
= INSTALLSTATE_LOCAL
;
3790 identifier
= MSI_RecordGetString(row
,1);
3791 dirproperty
= MSI_RecordGetString(row
,3);
3792 section
= MSI_RecordGetString(row
,4);
3793 key
= MSI_RecordGetString(row
,5);
3794 value
= MSI_RecordGetString(row
,6);
3795 action
= MSI_RecordGetInteger(row
,7);
3797 deformat_string(package
,section
,&deformated_section
);
3798 deformat_string(package
,key
,&deformated_key
);
3799 deformat_string(package
,value
,&deformated_value
);
3801 filename
= msi_dup_record_field(row
, 2);
3802 if (filename
&& (filenameptr
= strchrW(filename
, '|')))
3805 filenameptr
= filename
;
3809 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, TRUE
, NULL
);
3811 folder
= msi_dup_property( package
, dirproperty
);
3814 folder
= msi_dup_property( package
, szWindowsFolder
);
3818 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
3822 fullname
= build_directory_name(2, folder
, filenameptr
);
3826 TRACE("Adding value %s to section %s in %s\n",
3827 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3828 debugstr_w(fullname
));
3829 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3830 deformated_value
, fullname
);
3832 else if (action
== 1)
3835 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3836 returned
, 10, fullname
);
3837 if (returned
[0] == 0)
3839 TRACE("Adding value %s to section %s in %s\n",
3840 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3841 debugstr_w(fullname
));
3843 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3844 deformated_value
, fullname
);
3847 else if (action
== 3)
3848 FIXME("Append to existing section not yet implemented\n");
3850 uirow
= MSI_CreateRecord(4);
3851 MSI_RecordSetStringW(uirow
,1,identifier
);
3852 MSI_RecordSetStringW(uirow
,2,deformated_section
);
3853 MSI_RecordSetStringW(uirow
,3,deformated_key
);
3854 MSI_RecordSetStringW(uirow
,4,deformated_value
);
3855 ui_actiondata(package
,szWriteIniValues
,uirow
);
3856 msiobj_release( &uirow
->hdr
);
3862 msi_free(deformated_key
);
3863 msi_free(deformated_value
);
3864 msi_free(deformated_section
);
3865 return ERROR_SUCCESS
;
3868 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
3872 static const WCHAR ExecSeqQuery
[] =
3873 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3874 '`','I','n','i','F','i','l','e','`',0};
3876 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3877 if (rc
!= ERROR_SUCCESS
)
3879 TRACE("no IniFile table\n");
3880 return ERROR_SUCCESS
;
3883 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
3884 msiobj_release(&view
->hdr
);
3888 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
3890 MSIPACKAGE
*package
= param
;
3895 static const WCHAR ExeStr
[] =
3896 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3897 static const WCHAR close
[] = {'\"',0};
3899 PROCESS_INFORMATION info
;
3904 memset(&si
,0,sizeof(STARTUPINFOW
));
3906 filename
= MSI_RecordGetString(row
,1);
3907 file
= get_loaded_file( package
, filename
);
3911 ERR("Unable to find file id %s\n",debugstr_w(filename
));
3912 return ERROR_SUCCESS
;
3915 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
3917 FullName
= msi_alloc(len
*sizeof(WCHAR
));
3918 strcpyW(FullName
,ExeStr
);
3919 strcatW( FullName
, file
->TargetPath
);
3920 strcatW(FullName
,close
);
3922 TRACE("Registering %s\n",debugstr_w(FullName
));
3923 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
3928 CloseHandle(info
.hThread
);
3929 msi_dialog_check_messages(info
.hProcess
);
3930 CloseHandle(info
.hProcess
);
3936 uirow
= MSI_CreateRecord( 2 );
3937 uipath
= strdupW( file
->TargetPath
);
3938 p
= strrchrW(uipath
,'\\');
3941 MSI_RecordSetStringW( uirow
, 1, &p
[1] );
3942 MSI_RecordSetStringW( uirow
, 2, uipath
);
3943 ui_actiondata( package
, szSelfRegModules
, uirow
);
3944 msiobj_release( &uirow
->hdr
);
3946 /* FIXME: call ui_progress? */
3948 return ERROR_SUCCESS
;
3951 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
3955 static const WCHAR ExecSeqQuery
[] =
3956 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3957 '`','S','e','l','f','R','e','g','`',0};
3959 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3960 if (rc
!= ERROR_SUCCESS
)
3962 TRACE("no SelfReg table\n");
3963 return ERROR_SUCCESS
;
3966 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
3967 msiobj_release(&view
->hdr
);
3969 return ERROR_SUCCESS
;
3972 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
3974 MSIFEATURE
*feature
;
3977 HKEY userdata
= NULL
;
3979 if (!msi_check_publish(package
))
3980 return ERROR_SUCCESS
;
3982 rc
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
3984 if (rc
!= ERROR_SUCCESS
)
3987 rc
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
3989 if (rc
!= ERROR_SUCCESS
)
3992 /* here the guids are base 85 encoded */
3993 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
3999 BOOL absent
= FALSE
;
4002 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
) &&
4003 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_SOURCE
) &&
4004 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ADVERTISED
))
4008 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
4012 if (feature
->Feature_Parent
)
4013 size
+= strlenW( feature
->Feature_Parent
)+2;
4015 data
= msi_alloc(size
* sizeof(WCHAR
));
4018 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
4020 MSICOMPONENT
* component
= cl
->component
;
4024 if (component
->ComponentId
)
4026 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
4027 CLSIDFromString(component
->ComponentId
, &clsid
);
4028 encode_base85_guid(&clsid
,buf
);
4029 TRACE("to %s\n",debugstr_w(buf
));
4034 if (feature
->Feature_Parent
)
4036 static const WCHAR sep
[] = {'\2',0};
4038 strcatW(data
,feature
->Feature_Parent
);
4041 msi_reg_set_val_str( userdata
, feature
->Feature
, data
);
4045 if (feature
->Feature_Parent
)
4046 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
4049 static const WCHAR emptyW
[] = {0};
4050 size
+= sizeof(WCHAR
);
4051 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
4052 (LPBYTE
)(feature
->Feature_Parent
? feature
->Feature_Parent
: emptyW
),size
);
4056 size
+= 2*sizeof(WCHAR
);
4057 data
= msi_alloc(size
);
4060 if (feature
->Feature_Parent
)
4061 strcpyW( &data
[1], feature
->Feature_Parent
);
4062 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
4068 uirow
= MSI_CreateRecord( 1 );
4069 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
4070 ui_actiondata( package
, szPublishFeatures
, uirow
);
4071 msiobj_release( &uirow
->hdr
);
4072 /* FIXME: call ui_progress? */
4077 RegCloseKey(userdata
);
4081 static UINT
msi_unpublish_feature(MSIPACKAGE
*package
, MSIFEATURE
*feature
)
4086 TRACE("unpublishing feature %s\n", debugstr_w(feature
->Feature
));
4088 r
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
4090 if (r
== ERROR_SUCCESS
)
4092 RegDeleteValueW(hkey
, feature
->Feature
);
4096 r
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
4098 if (r
== ERROR_SUCCESS
)
4100 RegDeleteValueW(hkey
, feature
->Feature
);
4104 return ERROR_SUCCESS
;
4107 static UINT
ACTION_UnpublishFeatures(MSIPACKAGE
*package
)
4109 MSIFEATURE
*feature
;
4111 if (!msi_check_unpublish(package
))
4112 return ERROR_SUCCESS
;
4114 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4116 msi_unpublish_feature(package
, feature
);
4119 return ERROR_SUCCESS
;
4122 static UINT
msi_get_local_package_name( LPWSTR path
)
4124 static const WCHAR szInstaller
[] = {
4125 '\\','I','n','s','t','a','l','l','e','r','\\',0};
4126 static const WCHAR fmt
[] = { '%','x','.','m','s','i',0};
4130 time
= GetTickCount();
4131 GetWindowsDirectoryW( path
, MAX_PATH
);
4132 lstrcatW( path
, szInstaller
);
4133 CreateDirectoryW( path
, NULL
);
4135 len
= lstrlenW(path
);
4136 for (i
=0; i
<0x10000; i
++)
4138 snprintfW( &path
[len
], MAX_PATH
- len
, fmt
, (time
+i
)&0xffff );
4139 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
,
4140 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
4141 if (handle
!= INVALID_HANDLE_VALUE
)
4143 CloseHandle(handle
);
4146 if (GetLastError() != ERROR_FILE_EXISTS
&&
4147 GetLastError() != ERROR_SHARING_VIOLATION
)
4148 return ERROR_FUNCTION_FAILED
;
4151 return ERROR_SUCCESS
;
4154 static UINT
msi_make_package_local( MSIPACKAGE
*package
, HKEY hkey
)
4156 WCHAR packagefile
[MAX_PATH
];
4159 r
= msi_get_local_package_name( packagefile
);
4160 if (r
!= ERROR_SUCCESS
)
4163 TRACE("Copying to local package %s\n",debugstr_w(packagefile
));
4165 r
= CopyFileW( package
->db
->path
, packagefile
, FALSE
);
4169 ERR("Unable to copy package (%s -> %s) (error %d)\n",
4170 debugstr_w(package
->db
->path
), debugstr_w(packagefile
), GetLastError());
4171 return ERROR_FUNCTION_FAILED
;
4174 msi_reg_set_val_str( hkey
, INSTALLPROPERTY_LOCALPACKAGEW
, packagefile
);
4176 return ERROR_SUCCESS
;
4179 static UINT
msi_publish_install_properties(MSIPACKAGE
*package
, HKEY hkey
)
4181 LPWSTR prop
, val
, key
;
4187 static const WCHAR date_fmt
[] = {'%','i','%','0','2','i','%','0','2','i',0};
4188 static const WCHAR szWindowsInstaller
[] =
4189 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4190 static const WCHAR modpath_fmt
[] =
4191 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4192 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4193 static const WCHAR szModifyPath
[] =
4194 {'M','o','d','i','f','y','P','a','t','h',0};
4195 static const WCHAR szUninstallString
[] =
4196 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4197 static const WCHAR szEstimatedSize
[] =
4198 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4199 static const WCHAR szProductLanguage
[] =
4200 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4201 static const WCHAR szProductVersion
[] =
4202 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4203 static const WCHAR szProductName
[] =
4204 {'P','r','o','d','u','c','t','N','a','m','e',0};
4205 static const WCHAR szDisplayName
[] =
4206 {'D','i','s','p','l','a','y','N','a','m','e',0};
4207 static const WCHAR szDisplayVersion
[] =
4208 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4209 static const WCHAR szManufacturer
[] =
4210 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4212 static const LPCSTR propval
[] = {
4213 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4214 "ARPCONTACT", "Contact",
4215 "ARPCOMMENTS", "Comments",
4216 "ProductName", "DisplayName",
4217 "ProductVersion", "DisplayVersion",
4218 "ARPHELPLINK", "HelpLink",
4219 "ARPHELPTELEPHONE", "HelpTelephone",
4220 "ARPINSTALLLOCATION", "InstallLocation",
4221 "SourceDir", "InstallSource",
4222 "Manufacturer", "Publisher",
4223 "ARPREADME", "Readme",
4225 "ARPURLINFOABOUT", "URLInfoAbout",
4226 "ARPURLUPDATEINFO", "URLUpdateInfo",
4229 const LPCSTR
*p
= propval
;
4233 prop
= strdupAtoW(*p
++);
4234 key
= strdupAtoW(*p
++);
4235 val
= msi_dup_property(package
, prop
);
4236 msi_reg_set_val_str(hkey
, key
, val
);
4242 msi_reg_set_val_dword(hkey
, szWindowsInstaller
, 1);
4244 size
= deformat_string(package
, modpath_fmt
, &buffer
);
4245 RegSetValueExW(hkey
, szModifyPath
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4246 RegSetValueExW(hkey
, szUninstallString
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4249 /* FIXME: Write real Estimated Size when we have it */
4250 msi_reg_set_val_dword(hkey
, szEstimatedSize
, 0);
4252 buffer
= msi_dup_property(package
, szProductName
);
4253 msi_reg_set_val_str(hkey
, szDisplayName
, buffer
);
4256 buffer
= msi_dup_property(package
, cszSourceDir
);
4257 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLSOURCEW
, buffer
);
4260 buffer
= msi_dup_property(package
, szManufacturer
);
4261 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PUBLISHERW
, buffer
);
4264 GetLocalTime(&systime
);
4265 sprintfW(date
, date_fmt
, systime
.wYear
, systime
.wMonth
, systime
.wDay
);
4266 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLDATEW
, date
);
4268 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
4269 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
4271 buffer
= msi_dup_property(package
, szProductVersion
);
4272 msi_reg_set_val_str(hkey
, szDisplayVersion
, buffer
);
4275 DWORD verdword
= msi_version_str_to_dword(buffer
);
4277 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
4278 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>> 24);
4279 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>> 16) & 0xFF);
4283 return ERROR_SUCCESS
;
4286 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
4288 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
4289 LPWSTR upgrade_code
;
4294 static const WCHAR szUpgradeCode
[] = {
4295 'U','p','g','r','a','d','e','C','o','d','e',0};
4297 /* FIXME: also need to publish if the product is in advertise mode */
4298 if (!msi_check_publish(package
))
4299 return ERROR_SUCCESS
;
4301 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
, &hkey
, TRUE
);
4302 if (rc
!= ERROR_SUCCESS
)
4305 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4306 NULL
, &props
, TRUE
);
4307 if (rc
!= ERROR_SUCCESS
)
4310 msi_make_package_local(package
, props
);
4312 rc
= msi_publish_install_properties(package
, hkey
);
4313 if (rc
!= ERROR_SUCCESS
)
4316 rc
= msi_publish_install_properties(package
, props
);
4317 if (rc
!= ERROR_SUCCESS
)
4320 upgrade_code
= msi_dup_property(package
, szUpgradeCode
);
4323 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &upgrade
, TRUE
);
4324 squash_guid(package
->ProductCode
, squashed_pc
);
4325 msi_reg_set_val_str(upgrade
, squashed_pc
, NULL
);
4326 RegCloseKey(upgrade
);
4327 msi_free(upgrade_code
);
4333 return ERROR_SUCCESS
;
4336 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
4338 return execute_script(package
,INSTALL_SCRIPT
);
4341 static UINT
msi_unpublish_product(MSIPACKAGE
*package
)
4344 LPWSTR remove
= NULL
;
4345 LPWSTR
*features
= NULL
;
4346 BOOL full_uninstall
= TRUE
;
4347 MSIFEATURE
*feature
;
4349 static const WCHAR szRemove
[] = {'R','E','M','O','V','E',0};
4350 static const WCHAR szAll
[] = {'A','L','L',0};
4351 static const WCHAR szUpgradeCode
[] =
4352 {'U','p','g','r','a','d','e','C','o','d','e',0};
4354 remove
= msi_dup_property(package
, szRemove
);
4356 return ERROR_SUCCESS
;
4358 features
= msi_split_string(remove
, ',');
4362 ERR("REMOVE feature list is empty!\n");
4363 return ERROR_FUNCTION_FAILED
;
4366 if (!lstrcmpW(features
[0], szAll
))
4367 full_uninstall
= TRUE
;
4370 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4372 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
4373 full_uninstall
= FALSE
;
4377 if (!full_uninstall
)
4380 MSIREG_DeleteProductKey(package
->ProductCode
);
4381 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4382 MSIREG_DeleteUninstallKey(package
->ProductCode
);
4384 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4386 MSIREG_DeleteLocalClassesProductKey(package
->ProductCode
);
4387 MSIREG_DeleteLocalClassesFeaturesKey(package
->ProductCode
);
4391 MSIREG_DeleteUserProductKey(package
->ProductCode
);
4392 MSIREG_DeleteUserFeaturesKey(package
->ProductCode
);
4395 upgrade
= msi_dup_property(package
, szUpgradeCode
);
4398 MSIREG_DeleteUserUpgradeCodesKey(upgrade
);
4405 return ERROR_SUCCESS
;
4408 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
4412 rc
= msi_unpublish_product(package
);
4413 if (rc
!= ERROR_SUCCESS
)
4416 /* turn off scheduling */
4417 package
->script
->CurrentlyScripting
= FALSE
;
4419 /* first do the same as an InstallExecute */
4420 rc
= ACTION_InstallExecute(package
);
4421 if (rc
!= ERROR_SUCCESS
)
4424 /* then handle Commit Actions */
4425 rc
= execute_script(package
,COMMIT_SCRIPT
);
4430 UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
4432 static const WCHAR RunOnce
[] = {
4433 'S','o','f','t','w','a','r','e','\\',
4434 'M','i','c','r','o','s','o','f','t','\\',
4435 'W','i','n','d','o','w','s','\\',
4436 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4437 'R','u','n','O','n','c','e',0};
4438 static const WCHAR InstallRunOnce
[] = {
4439 'S','o','f','t','w','a','r','e','\\',
4440 'M','i','c','r','o','s','o','f','t','\\',
4441 'W','i','n','d','o','w','s','\\',
4442 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4443 'I','n','s','t','a','l','l','e','r','\\',
4444 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4446 static const WCHAR msiexec_fmt
[] = {
4448 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4449 '\"','%','s','\"',0};
4450 static const WCHAR install_fmt
[] = {
4451 '/','I',' ','\"','%','s','\"',' ',
4452 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4453 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4454 WCHAR buffer
[256], sysdir
[MAX_PATH
];
4456 WCHAR squished_pc
[100];
4458 squash_guid(package
->ProductCode
,squished_pc
);
4460 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
4461 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
4462 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
4465 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4468 TRACE("Reboot command %s\n",debugstr_w(buffer
));
4470 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
4471 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
4473 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4476 return ERROR_INSTALL_SUSPEND
;
4479 static UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
4485 * We are currently doing what should be done here in the top level Install
4486 * however for Administrative and uninstalls this step will be needed
4488 if (!package
->PackagePath
)
4489 return ERROR_SUCCESS
;
4491 msi_set_sourcedir_props(package
, TRUE
);
4493 attrib
= GetFileAttributesW(package
->db
->path
);
4494 if (attrib
== INVALID_FILE_ATTRIBUTES
)
4500 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4501 package
->Context
, MSICODE_PRODUCT
,
4502 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
4503 if (rc
== ERROR_MORE_DATA
)
4505 prompt
= msi_alloc(size
* sizeof(WCHAR
));
4506 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4507 package
->Context
, MSICODE_PRODUCT
,
4508 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
4511 prompt
= strdupW(package
->db
->path
);
4513 msg
= generate_error_string(package
,1302,1,prompt
);
4514 while(attrib
== INVALID_FILE_ATTRIBUTES
)
4516 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
4519 rc
= ERROR_INSTALL_USEREXIT
;
4522 attrib
= GetFileAttributesW(package
->db
->path
);
4528 return ERROR_SUCCESS
;
4533 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
4540 static const WCHAR szPropKeys
[][80] =
4542 {'P','r','o','d','u','c','t','I','D',0},
4543 {'U','S','E','R','N','A','M','E',0},
4544 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4548 static const WCHAR szRegKeys
[][80] =
4550 {'P','r','o','d','u','c','t','I','D',0},
4551 {'R','e','g','O','w','n','e','r',0},
4552 {'R','e','g','C','o','m','p','a','n','y',0},
4556 if (msi_check_unpublish(package
))
4558 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4559 return ERROR_SUCCESS
;
4562 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
4564 return ERROR_SUCCESS
;
4566 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4568 if (rc
!= ERROR_SUCCESS
)
4571 for( i
= 0; szPropKeys
[i
][0]; i
++ )
4573 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
4574 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
4579 msi_free(productid
);
4582 /* FIXME: call ui_actiondata */
4588 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
4592 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
4593 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
4598 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4600 MSIPACKAGE
*package
= param
;
4601 LPCWSTR compgroupid
=NULL
;
4602 LPCWSTR feature
=NULL
;
4603 LPCWSTR text
= NULL
;
4604 LPCWSTR qualifier
= NULL
;
4605 LPCWSTR component
= NULL
;
4606 LPWSTR advertise
= NULL
;
4607 LPWSTR output
= NULL
;
4609 UINT rc
= ERROR_SUCCESS
;
4614 component
= MSI_RecordGetString(rec
,3);
4615 comp
= get_loaded_component(package
,component
);
4617 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) &&
4618 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
) &&
4619 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ADVERTISED
))
4621 TRACE("Skipping: Component %s not scheduled for install\n",
4622 debugstr_w(component
));
4624 return ERROR_SUCCESS
;
4627 compgroupid
= MSI_RecordGetString(rec
,1);
4628 qualifier
= MSI_RecordGetString(rec
,2);
4630 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
4631 if (rc
!= ERROR_SUCCESS
)
4634 text
= MSI_RecordGetString(rec
,4);
4635 feature
= MSI_RecordGetString(rec
,5);
4637 advertise
= create_component_advertise_string(package
, comp
, feature
);
4639 sz
= strlenW(advertise
);
4642 sz
+= lstrlenW(text
);
4645 sz
*= sizeof(WCHAR
);
4647 output
= msi_alloc_zero(sz
);
4648 strcpyW(output
,advertise
);
4649 msi_free(advertise
);
4652 strcatW(output
,text
);
4654 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
4661 uirow
= MSI_CreateRecord( 2 );
4662 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4663 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4664 ui_actiondata( package
, szPublishComponents
, uirow
);
4665 msiobj_release( &uirow
->hdr
);
4666 /* FIXME: call ui_progress? */
4672 * At present I am ignorning the advertised components part of this and only
4673 * focusing on the qualified component sets
4675 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
4679 static const WCHAR ExecSeqQuery
[] =
4680 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4681 '`','P','u','b','l','i','s','h',
4682 'C','o','m','p','o','n','e','n','t','`',0};
4684 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4685 if (rc
!= ERROR_SUCCESS
)
4686 return ERROR_SUCCESS
;
4688 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
4689 msiobj_release(&view
->hdr
);
4694 static UINT
ITERATE_InstallService(MSIRECORD
*rec
, LPVOID param
)
4696 MSIPACKAGE
*package
= param
;
4699 SC_HANDLE hscm
, service
= NULL
;
4700 LPCWSTR comp
, depends
, pass
;
4701 LPWSTR name
= NULL
, disp
= NULL
;
4702 LPCWSTR load_order
, serv_name
, key
;
4703 DWORD serv_type
, start_type
;
4706 static const WCHAR query
[] =
4707 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4708 '`','C','o','m','p','o','n','e','n','t','`',' ',
4709 'W','H','E','R','E',' ',
4710 '`','C','o','m','p','o','n','e','n','t','`',' ',
4711 '=','\'','%','s','\'',0};
4713 hscm
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASEW
, GENERIC_WRITE
);
4716 ERR("Failed to open the SC Manager!\n");
4720 start_type
= MSI_RecordGetInteger(rec
, 5);
4721 if (start_type
== SERVICE_BOOT_START
|| start_type
== SERVICE_SYSTEM_START
)
4724 depends
= MSI_RecordGetString(rec
, 8);
4725 if (depends
&& *depends
)
4726 FIXME("Dependency list unhandled!\n");
4728 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
4729 deformat_string(package
, MSI_RecordGetString(rec
, 3), &disp
);
4730 serv_type
= MSI_RecordGetInteger(rec
, 4);
4731 err_control
= MSI_RecordGetInteger(rec
, 6);
4732 load_order
= MSI_RecordGetString(rec
, 7);
4733 serv_name
= MSI_RecordGetString(rec
, 9);
4734 pass
= MSI_RecordGetString(rec
, 10);
4735 comp
= MSI_RecordGetString(rec
, 12);
4737 /* fetch the service path */
4738 row
= MSI_QueryGetRecord(package
->db
, query
, comp
);
4741 ERR("Control query failed!\n");
4745 key
= MSI_RecordGetString(row
, 6);
4747 file
= get_loaded_file(package
, key
);
4748 msiobj_release(&row
->hdr
);
4751 ERR("Failed to load the service file\n");
4755 service
= CreateServiceW(hscm
, name
, disp
, GENERIC_ALL
, serv_type
,
4756 start_type
, err_control
, file
->TargetPath
,
4757 load_order
, NULL
, NULL
, serv_name
, pass
);
4760 if (GetLastError() != ERROR_SERVICE_EXISTS
)
4761 ERR("Failed to create service %s: %d\n", debugstr_w(name
), GetLastError());
4765 CloseServiceHandle(service
);
4766 CloseServiceHandle(hscm
);
4770 return ERROR_SUCCESS
;
4773 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
4777 static const WCHAR ExecSeqQuery
[] =
4778 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4779 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4781 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4782 if (rc
!= ERROR_SUCCESS
)
4783 return ERROR_SUCCESS
;
4785 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallService
, package
);
4786 msiobj_release(&view
->hdr
);
4791 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4792 static LPCWSTR
*msi_service_args_to_vector(LPWSTR args
, DWORD
*numargs
)
4794 LPCWSTR
*vector
, *temp_vector
;
4798 static const WCHAR separator
[] = {'[','~',']',0};
4801 sep_len
= sizeof(separator
) / sizeof(WCHAR
) - 1;
4806 vector
= msi_alloc(sizeof(LPWSTR
));
4814 vector
[*numargs
- 1] = p
;
4816 if ((q
= strstrW(p
, separator
)))
4820 temp_vector
= msi_realloc(vector
, (*numargs
+ 1) * sizeof(LPWSTR
));
4826 vector
= temp_vector
;
4835 static UINT
ITERATE_StartService(MSIRECORD
*rec
, LPVOID param
)
4837 MSIPACKAGE
*package
= param
;
4839 SC_HANDLE scm
, service
= NULL
;
4840 LPCWSTR name
, *vector
= NULL
;
4842 DWORD event
, numargs
;
4843 UINT r
= ERROR_FUNCTION_FAILED
;
4845 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 6));
4846 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4847 return ERROR_SUCCESS
;
4849 name
= MSI_RecordGetString(rec
, 2);
4850 event
= MSI_RecordGetInteger(rec
, 3);
4851 args
= strdupW(MSI_RecordGetString(rec
, 4));
4853 if (!(event
& msidbServiceControlEventStart
))
4854 return ERROR_SUCCESS
;
4856 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_CONNECT
);
4859 ERR("Failed to open the service control manager\n");
4863 service
= OpenServiceW(scm
, name
, SERVICE_START
);
4866 ERR("Failed to open service %s\n", debugstr_w(name
));
4870 vector
= msi_service_args_to_vector(args
, &numargs
);
4872 if (!StartServiceW(service
, numargs
, vector
))
4874 ERR("Failed to start service %s\n", debugstr_w(name
));
4881 CloseServiceHandle(service
);
4882 CloseServiceHandle(scm
);
4889 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
4894 static const WCHAR query
[] = {
4895 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4896 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4898 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4899 if (rc
!= ERROR_SUCCESS
)
4900 return ERROR_SUCCESS
;
4902 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StartService
, package
);
4903 msiobj_release(&view
->hdr
);
4908 static BOOL
stop_service_dependents(SC_HANDLE scm
, SC_HANDLE service
)
4910 DWORD i
, needed
, count
;
4911 ENUM_SERVICE_STATUSW
*dependencies
;
4915 if (EnumDependentServicesW(service
, SERVICE_ACTIVE
, NULL
,
4916 0, &needed
, &count
))
4919 if (GetLastError() != ERROR_MORE_DATA
)
4922 dependencies
= msi_alloc(needed
);
4926 if (!EnumDependentServicesW(service
, SERVICE_ACTIVE
, dependencies
,
4927 needed
, &needed
, &count
))
4930 for (i
= 0; i
< count
; i
++)
4932 depserv
= OpenServiceW(scm
, dependencies
[i
].lpServiceName
,
4933 SERVICE_STOP
| SERVICE_QUERY_STATUS
);
4937 if (!ControlService(depserv
, SERVICE_CONTROL_STOP
, &ss
))
4944 msi_free(dependencies
);
4948 static UINT
ITERATE_StopService(MSIRECORD
*rec
, LPVOID param
)
4950 MSIPACKAGE
*package
= param
;
4952 SERVICE_STATUS status
;
4953 SERVICE_STATUS_PROCESS ssp
;
4954 SC_HANDLE scm
= NULL
, service
= NULL
;
4956 DWORD event
, needed
;
4958 event
= MSI_RecordGetInteger(rec
, 3);
4959 if (!(event
& msidbServiceControlEventStop
))
4960 return ERROR_SUCCESS
;
4962 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 6));
4963 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4964 return ERROR_SUCCESS
;
4966 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
4967 deformat_string(package
, MSI_RecordGetString(rec
, 4), &args
);
4968 args
= strdupW(MSI_RecordGetString(rec
, 4));
4970 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
4973 WARN("Failed to open the SCM: %d\n", GetLastError());
4977 service
= OpenServiceW(scm
, name
,
4979 SERVICE_QUERY_STATUS
|
4980 SERVICE_ENUMERATE_DEPENDENTS
);
4983 WARN("Failed to open service (%s): %d\n",
4984 debugstr_w(name
), GetLastError());
4988 if (!QueryServiceStatusEx(service
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&ssp
,
4989 sizeof(SERVICE_STATUS_PROCESS
), &needed
))
4991 WARN("Failed to query service status (%s): %d\n",
4992 debugstr_w(name
), GetLastError());
4996 if (ssp
.dwCurrentState
== SERVICE_STOPPED
)
4999 stop_service_dependents(scm
, service
);
5001 if (!ControlService(service
, SERVICE_CONTROL_STOP
, &status
))
5002 WARN("Failed to stop service (%s): %d\n", debugstr_w(name
), GetLastError());
5005 CloseServiceHandle(service
);
5006 CloseServiceHandle(scm
);
5010 return ERROR_SUCCESS
;
5013 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
5018 static const WCHAR query
[] = {
5019 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5020 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5022 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5023 if (rc
!= ERROR_SUCCESS
)
5024 return ERROR_SUCCESS
;
5026 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StopService
, package
);
5027 msiobj_release(&view
->hdr
);
5032 static MSIFILE
*msi_find_file( MSIPACKAGE
*package
, LPCWSTR filename
)
5036 LIST_FOR_EACH_ENTRY(file
, &package
->files
, MSIFILE
, entry
)
5038 if (!lstrcmpW(file
->File
, filename
))
5045 static UINT
ITERATE_InstallODBCDriver( MSIRECORD
*rec
, LPVOID param
)
5047 MSIPACKAGE
*package
= param
;
5048 LPWSTR driver
, driver_path
, ptr
;
5049 WCHAR outpath
[MAX_PATH
];
5050 MSIFILE
*driver_file
, *setup_file
;
5053 UINT r
= ERROR_SUCCESS
;
5055 static const WCHAR driver_fmt
[] = {
5056 'D','r','i','v','e','r','=','%','s',0};
5057 static const WCHAR setup_fmt
[] = {
5058 'S','e','t','u','p','=','%','s',0};
5059 static const WCHAR usage_fmt
[] = {
5060 'F','i','l','e','U','s','a','g','e','=','1',0};
5062 desc
= MSI_RecordGetString(rec
, 3);
5064 driver_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5065 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5067 if (!driver_file
|| !setup_file
)
5069 ERR("ODBC Driver entry not found!\n");
5070 return ERROR_FUNCTION_FAILED
;
5073 len
= lstrlenW(desc
) + lstrlenW(driver_fmt
) + lstrlenW(driver_file
->FileName
) +
5074 lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
) +
5075 lstrlenW(usage_fmt
) + 1;
5076 driver
= msi_alloc(len
* sizeof(WCHAR
));
5078 return ERROR_OUTOFMEMORY
;
5081 lstrcpyW(ptr
, desc
);
5082 ptr
+= lstrlenW(ptr
) + 1;
5084 sprintfW(ptr
, driver_fmt
, driver_file
->FileName
);
5085 ptr
+= lstrlenW(ptr
) + 1;
5087 sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5088 ptr
+= lstrlenW(ptr
) + 1;
5090 lstrcpyW(ptr
, usage_fmt
);
5091 ptr
+= lstrlenW(ptr
) + 1;
5094 driver_path
= strdupW(driver_file
->TargetPath
);
5095 ptr
= strrchrW(driver_path
, '\\');
5096 if (ptr
) *ptr
= '\0';
5098 if (!SQLInstallDriverExW(driver
, driver_path
, outpath
, MAX_PATH
,
5099 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5101 ERR("Failed to install SQL driver!\n");
5102 r
= ERROR_FUNCTION_FAILED
;
5106 msi_free(driver_path
);
5111 static UINT
ITERATE_InstallODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5113 MSIPACKAGE
*package
= param
;
5114 LPWSTR translator
, translator_path
, ptr
;
5115 WCHAR outpath
[MAX_PATH
];
5116 MSIFILE
*translator_file
, *setup_file
;
5119 UINT r
= ERROR_SUCCESS
;
5121 static const WCHAR translator_fmt
[] = {
5122 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5123 static const WCHAR setup_fmt
[] = {
5124 'S','e','t','u','p','=','%','s',0};
5126 desc
= MSI_RecordGetString(rec
, 3);
5128 translator_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5129 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5131 if (!translator_file
|| !setup_file
)
5133 ERR("ODBC Translator entry not found!\n");
5134 return ERROR_FUNCTION_FAILED
;
5137 len
= lstrlenW(desc
) + lstrlenW(translator_fmt
) + lstrlenW(translator_file
->FileName
) +
5138 lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
) + 1;
5139 translator
= msi_alloc(len
* sizeof(WCHAR
));
5141 return ERROR_OUTOFMEMORY
;
5144 lstrcpyW(ptr
, desc
);
5145 ptr
+= lstrlenW(ptr
) + 1;
5147 sprintfW(ptr
, translator_fmt
, translator_file
->FileName
);
5148 ptr
+= lstrlenW(ptr
) + 1;
5150 sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5151 ptr
+= lstrlenW(ptr
) + 1;
5154 translator_path
= strdupW(translator_file
->TargetPath
);
5155 ptr
= strrchrW(translator_path
, '\\');
5156 if (ptr
) *ptr
= '\0';
5158 if (!SQLInstallTranslatorExW(translator
, translator_path
, outpath
, MAX_PATH
,
5159 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5161 ERR("Failed to install SQL translator!\n");
5162 r
= ERROR_FUNCTION_FAILED
;
5165 msi_free(translator
);
5166 msi_free(translator_path
);
5171 static UINT
ITERATE_InstallODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5174 LPCWSTR desc
, driver
;
5175 WORD request
= ODBC_ADD_SYS_DSN
;
5178 UINT r
= ERROR_SUCCESS
;
5180 static const WCHAR attrs_fmt
[] = {
5181 'D','S','N','=','%','s',0 };
5183 desc
= MSI_RecordGetString(rec
, 3);
5184 driver
= MSI_RecordGetString(rec
, 4);
5185 registration
= MSI_RecordGetInteger(rec
, 5);
5187 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_ADD_SYS_DSN
;
5188 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_ADD_DSN
;
5190 len
= lstrlenW(attrs_fmt
) + lstrlenW(desc
) + 1 + 1;
5191 attrs
= msi_alloc(len
* sizeof(WCHAR
));
5193 return ERROR_OUTOFMEMORY
;
5195 sprintfW(attrs
, attrs_fmt
, desc
);
5196 attrs
[len
- 1] = '\0';
5198 if (!SQLConfigDataSourceW(NULL
, request
, driver
, attrs
))
5200 ERR("Failed to install SQL data source!\n");
5201 r
= ERROR_FUNCTION_FAILED
;
5209 static UINT
ACTION_InstallODBC( MSIPACKAGE
*package
)
5214 static const WCHAR driver_query
[] = {
5215 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5216 'O','D','B','C','D','r','i','v','e','r',0 };
5218 static const WCHAR translator_query
[] = {
5219 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5220 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5222 static const WCHAR source_query
[] = {
5223 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5224 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5226 rc
= MSI_DatabaseOpenViewW(package
->db
, driver_query
, &view
);
5227 if (rc
!= ERROR_SUCCESS
)
5228 return ERROR_SUCCESS
;
5230 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDriver
, package
);
5231 msiobj_release(&view
->hdr
);
5233 rc
= MSI_DatabaseOpenViewW(package
->db
, translator_query
, &view
);
5234 if (rc
!= ERROR_SUCCESS
)
5235 return ERROR_SUCCESS
;
5237 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCTranslator
, package
);
5238 msiobj_release(&view
->hdr
);
5240 rc
= MSI_DatabaseOpenViewW(package
->db
, source_query
, &view
);
5241 if (rc
!= ERROR_SUCCESS
)
5242 return ERROR_SUCCESS
;
5244 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDataSource
, package
);
5245 msiobj_release(&view
->hdr
);
5250 #define ENV_ACT_SETALWAYS 0x1
5251 #define ENV_ACT_SETABSENT 0x2
5252 #define ENV_ACT_REMOVE 0x4
5253 #define ENV_ACT_REMOVEMATCH 0x8
5255 #define ENV_MOD_MACHINE 0x20000000
5256 #define ENV_MOD_APPEND 0x40000000
5257 #define ENV_MOD_PREFIX 0x80000000
5258 #define ENV_MOD_MASK 0xC0000000
5260 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5262 static LONG
env_set_flags( LPCWSTR
*name
, LPCWSTR
*value
, DWORD
*flags
)
5264 LPCWSTR cptr
= *name
;
5265 LPCWSTR ptr
= *value
;
5267 static const WCHAR prefix
[] = {'[','~',']',0};
5268 static const int prefix_len
= 3;
5274 *flags
|= ENV_ACT_SETALWAYS
;
5275 else if (*cptr
== '+')
5276 *flags
|= ENV_ACT_SETABSENT
;
5277 else if (*cptr
== '-')
5278 *flags
|= ENV_ACT_REMOVE
;
5279 else if (*cptr
== '!')
5280 *flags
|= ENV_ACT_REMOVEMATCH
;
5281 else if (*cptr
== '*')
5282 *flags
|= ENV_MOD_MACHINE
;
5292 ERR("Missing environment variable\n");
5293 return ERROR_FUNCTION_FAILED
;
5296 if (!strncmpW(ptr
, prefix
, prefix_len
))
5298 *flags
|= ENV_MOD_APPEND
;
5299 *value
+= lstrlenW(prefix
);
5301 else if (lstrlenW(*value
) >= prefix_len
)
5303 ptr
+= lstrlenW(ptr
) - prefix_len
;
5304 if (!lstrcmpW(ptr
, prefix
))
5306 *flags
|= ENV_MOD_PREFIX
;
5307 /* the "[~]" will be removed by deformat_string */;
5312 check_flag_combo(*flags
, ENV_ACT_SETALWAYS
| ENV_ACT_SETABSENT
) ||
5313 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETABSENT
) ||
5314 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETALWAYS
) ||
5315 check_flag_combo(*flags
, ENV_ACT_SETABSENT
| ENV_MOD_MASK
))
5317 ERR("Invalid flags: %08x\n", *flags
);
5318 return ERROR_FUNCTION_FAILED
;
5321 return ERROR_SUCCESS
;
5324 static UINT
ITERATE_WriteEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
5326 MSIPACKAGE
*package
= param
;
5327 LPCWSTR name
, value
;
5328 LPWSTR data
= NULL
, newval
= NULL
;
5329 LPWSTR deformatted
= NULL
, ptr
;
5330 DWORD flags
, type
, size
;
5332 HKEY env
= NULL
, root
;
5333 LPCWSTR environment
;
5335 static const WCHAR user_env
[] =
5336 {'E','n','v','i','r','o','n','m','e','n','t',0};
5337 static const WCHAR machine_env
[] =
5338 {'S','y','s','t','e','m','\\',
5339 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5340 'C','o','n','t','r','o','l','\\',
5341 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5342 'E','n','v','i','r','o','n','m','e','n','t',0};
5343 static const WCHAR semicolon
[] = {';',0};
5345 name
= MSI_RecordGetString(rec
, 2);
5346 value
= MSI_RecordGetString(rec
, 3);
5348 res
= env_set_flags(&name
, &value
, &flags
);
5349 if (res
!= ERROR_SUCCESS
)
5352 deformat_string(package
, value
, &deformatted
);
5355 res
= ERROR_OUTOFMEMORY
;
5359 value
= deformatted
;
5361 if (flags
& ENV_MOD_MACHINE
)
5363 environment
= machine_env
;
5364 root
= HKEY_LOCAL_MACHINE
;
5368 environment
= user_env
;
5369 root
= HKEY_CURRENT_USER
;
5372 res
= RegCreateKeyExW(root
, environment
, 0, NULL
, 0,
5373 KEY_ALL_ACCESS
, NULL
, &env
, NULL
);
5374 if (res
!= ERROR_SUCCESS
)
5377 if (flags
& ENV_ACT_REMOVE
)
5378 FIXME("Not removing environment variable on uninstall!\n");
5381 res
= RegQueryValueExW(env
, name
, NULL
, &type
, NULL
, &size
);
5382 if ((res
!= ERROR_SUCCESS
&& res
!= ERROR_FILE_NOT_FOUND
) ||
5383 (res
== ERROR_SUCCESS
&& type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
))
5386 if (res
!= ERROR_FILE_NOT_FOUND
)
5388 if (flags
& ENV_ACT_SETABSENT
)
5390 res
= ERROR_SUCCESS
;
5394 data
= msi_alloc(size
);
5398 return ERROR_OUTOFMEMORY
;
5401 res
= RegQueryValueExW(env
, name
, NULL
, &type
, (LPVOID
)data
, &size
);
5402 if (res
!= ERROR_SUCCESS
)
5405 if (flags
& ENV_ACT_REMOVEMATCH
&& (!value
|| !lstrcmpW(data
, value
)))
5407 res
= RegDeleteKeyW(env
, name
);
5411 size
= (lstrlenW(value
) + 1 + size
) * sizeof(WCHAR
);
5412 newval
= msi_alloc(size
);
5416 res
= ERROR_OUTOFMEMORY
;
5420 if (!(flags
& ENV_MOD_MASK
))
5421 lstrcpyW(newval
, value
);
5424 if (flags
& ENV_MOD_PREFIX
)
5426 lstrcpyW(newval
, value
);
5427 lstrcatW(newval
, semicolon
);
5428 ptr
= newval
+ lstrlenW(value
) + 1;
5431 lstrcpyW(ptr
, data
);
5433 if (flags
& ENV_MOD_APPEND
)
5435 lstrcatW(newval
, semicolon
);
5436 lstrcatW(newval
, value
);
5442 size
= (lstrlenW(value
) + 1) * sizeof(WCHAR
);
5443 newval
= msi_alloc(size
);
5446 res
= ERROR_OUTOFMEMORY
;
5450 lstrcpyW(newval
, value
);
5453 TRACE("setting %s to %s\n", debugstr_w(name
), debugstr_w(newval
));
5454 res
= RegSetValueExW(env
, name
, 0, type
, (LPVOID
)newval
, size
);
5457 if (env
) RegCloseKey(env
);
5458 msi_free(deformatted
);
5464 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
5468 static const WCHAR ExecSeqQuery
[] =
5469 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5470 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5471 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5472 if (rc
!= ERROR_SUCCESS
)
5473 return ERROR_SUCCESS
;
5475 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteEnvironmentString
, package
);
5476 msiobj_release(&view
->hdr
);
5481 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5492 static BOOL
msi_move_file(LPCWSTR source
, LPCWSTR dest
, int options
)
5496 if (GetFileAttributesW(source
) == FILE_ATTRIBUTE_DIRECTORY
||
5497 GetFileAttributesW(dest
) == FILE_ATTRIBUTE_DIRECTORY
)
5499 WARN("Source or dest is directory, not moving\n");
5503 if (options
== msidbMoveFileOptionsMove
)
5505 TRACE("moving %s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
5506 ret
= MoveFileExW(source
, dest
, MOVEFILE_REPLACE_EXISTING
);
5509 WARN("MoveFile failed: %d\n", GetLastError());
5515 TRACE("copying %s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
5516 ret
= CopyFileW(source
, dest
, FALSE
);
5519 WARN("CopyFile failed: %d\n", GetLastError());
5527 static LPWSTR
wildcard_to_file(LPWSTR wildcard
, LPWSTR filename
)
5530 DWORD dirlen
, pathlen
;
5532 ptr
= strrchrW(wildcard
, '\\');
5533 dirlen
= ptr
- wildcard
+ 1;
5535 pathlen
= dirlen
+ lstrlenW(filename
) + 1;
5536 path
= msi_alloc(pathlen
* sizeof(WCHAR
));
5538 lstrcpynW(path
, wildcard
, dirlen
+ 1);
5539 lstrcatW(path
, filename
);
5544 static void free_file_entry(FILE_LIST
*file
)
5546 msi_free(file
->source
);
5547 msi_free(file
->dest
);
5551 static void free_list(FILE_LIST
*list
)
5553 while (!list_empty(&list
->entry
))
5555 FILE_LIST
*file
= LIST_ENTRY(list_head(&list
->entry
), FILE_LIST
, entry
);
5557 list_remove(&file
->entry
);
5558 free_file_entry(file
);
5562 static BOOL
add_wildcard(FILE_LIST
*files
, LPWSTR source
, LPWSTR dest
)
5564 FILE_LIST
*new, *file
;
5565 LPWSTR ptr
, filename
;
5568 new = msi_alloc_zero(sizeof(FILE_LIST
));
5572 new->source
= strdupW(source
);
5573 ptr
= strrchrW(dest
, '\\') + 1;
5574 filename
= strrchrW(new->source
, '\\') + 1;
5576 new->sourcename
= filename
;
5579 new->destname
= ptr
;
5581 new->destname
= new->sourcename
;
5583 size
= (ptr
- dest
) + lstrlenW(filename
) + 1;
5584 new->dest
= msi_alloc(size
* sizeof(WCHAR
));
5587 free_file_entry(new);
5591 lstrcpynW(new->dest
, dest
, ptr
- dest
+ 1);
5592 lstrcatW(new->dest
, filename
);
5594 if (list_empty(&files
->entry
))
5596 list_add_head(&files
->entry
, &new->entry
);
5600 LIST_FOR_EACH_ENTRY(file
, &files
->entry
, FILE_LIST
, entry
)
5602 if (lstrcmpW(source
, file
->source
) < 0)
5604 list_add_before(&file
->entry
, &new->entry
);
5609 list_add_after(&file
->entry
, &new->entry
);
5613 static BOOL
move_files_wildcard(LPWSTR source
, LPWSTR dest
, int options
)
5615 WIN32_FIND_DATAW wfd
;
5619 FILE_LIST files
, *file
;
5622 hfile
= FindFirstFileW(source
, &wfd
);
5623 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
5625 list_init(&files
.entry
);
5627 for (res
= TRUE
; res
; res
= FindNextFileW(hfile
, &wfd
))
5629 if (is_dot_dir(wfd
.cFileName
)) continue;
5631 path
= wildcard_to_file(source
, wfd
.cFileName
);
5638 add_wildcard(&files
, path
, dest
);
5642 /* no files match the wildcard */
5643 if (list_empty(&files
.entry
))
5646 /* only the first wildcard match gets renamed to dest */
5647 file
= LIST_ENTRY(list_head(&files
.entry
), FILE_LIST
, entry
);
5648 size
= (strrchrW(file
->dest
, '\\') - file
->dest
) + lstrlenW(file
->destname
) + 2;
5649 file
->dest
= msi_realloc(file
->dest
, size
* sizeof(WCHAR
));
5656 lstrcpyW(strrchrW(file
->dest
, '\\') + 1, file
->destname
);
5658 while (!list_empty(&files
.entry
))
5660 file
= LIST_ENTRY(list_head(&files
.entry
), FILE_LIST
, entry
);
5662 msi_move_file(file
->source
, file
->dest
, options
);
5664 list_remove(&file
->entry
);
5665 free_file_entry(file
);
5676 static UINT
ITERATE_MoveFiles( MSIRECORD
*rec
, LPVOID param
)
5678 MSIPACKAGE
*package
= param
;
5681 LPWSTR destname
= NULL
;
5682 LPWSTR sourcedir
= NULL
, destdir
= NULL
;
5683 LPWSTR source
= NULL
, dest
= NULL
;
5686 BOOL ret
, wildcards
;
5688 static const WCHAR backslash
[] = {'\\',0};
5690 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 2));
5691 if (!comp
|| !comp
->Enabled
||
5692 !(comp
->Action
& (INSTALLSTATE_LOCAL
| INSTALLSTATE_SOURCE
)))
5694 TRACE("Component not set for install, not moving file\n");
5695 return ERROR_SUCCESS
;
5698 sourcename
= MSI_RecordGetString(rec
, 3);
5699 options
= MSI_RecordGetInteger(rec
, 7);
5701 sourcedir
= msi_dup_property(package
, MSI_RecordGetString(rec
, 5));
5705 destdir
= msi_dup_property(package
, MSI_RecordGetString(rec
, 6));
5711 if (GetFileAttributesW(sourcedir
) == INVALID_FILE_ATTRIBUTES
)
5714 source
= strdupW(sourcedir
);
5720 size
= lstrlenW(sourcedir
) + lstrlenW(sourcename
) + 2;
5721 source
= msi_alloc(size
* sizeof(WCHAR
));
5725 lstrcpyW(source
, sourcedir
);
5726 if (source
[lstrlenW(source
) - 1] != '\\')
5727 lstrcatW(source
, backslash
);
5728 lstrcatW(source
, sourcename
);
5731 wildcards
= strchrW(source
, '*') || strchrW(source
, '?');
5733 if (MSI_RecordIsNull(rec
, 4))
5737 destname
= strdupW(sourcename
);
5744 destname
= strdupW(MSI_RecordGetString(rec
, 4));
5746 reduce_to_longfilename(destname
);
5751 size
= lstrlenW(destname
);
5753 size
+= lstrlenW(destdir
) + 2;
5754 dest
= msi_alloc(size
* sizeof(WCHAR
));
5758 lstrcpyW(dest
, destdir
);
5759 if (dest
[lstrlenW(dest
) - 1] != '\\')
5760 lstrcatW(dest
, backslash
);
5763 lstrcatW(dest
, destname
);
5765 if (GetFileAttributesW(destdir
) == INVALID_FILE_ATTRIBUTES
)
5767 ret
= CreateDirectoryW(destdir
, NULL
);
5770 WARN("CreateDirectory failed: %d\n", GetLastError());
5771 return ERROR_SUCCESS
;
5776 msi_move_file(source
, dest
, options
);
5778 move_files_wildcard(source
, dest
, options
);
5781 msi_free(sourcedir
);
5787 return ERROR_SUCCESS
;
5790 static UINT
ACTION_MoveFiles( MSIPACKAGE
*package
)
5795 static const WCHAR ExecSeqQuery
[] =
5796 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5797 '`','M','o','v','e','F','i','l','e','`',0};
5799 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5800 if (rc
!= ERROR_SUCCESS
)
5801 return ERROR_SUCCESS
;
5803 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_MoveFiles
, package
);
5804 msiobj_release(&view
->hdr
);
5809 typedef struct tagMSIASSEMBLY
5812 MSICOMPONENT
*component
;
5813 MSIFEATURE
*feature
;
5821 static HRESULT (WINAPI
*pCreateAssemblyCache
)(IAssemblyCache
**ppAsmCache
,
5823 static HRESULT (WINAPI
*pLoadLibraryShim
)(LPCWSTR szDllName
, LPCWSTR szVersion
,
5824 LPVOID pvReserved
, HMODULE
*phModDll
);
5826 static BOOL
init_functionpointers(void)
5832 static const WCHAR szFusion
[] = {'f','u','s','i','o','n','.','d','l','l',0};
5834 hmscoree
= LoadLibraryA("mscoree.dll");
5837 WARN("mscoree.dll not available\n");
5841 pLoadLibraryShim
= (void *)GetProcAddress(hmscoree
, "LoadLibraryShim");
5842 if (!pLoadLibraryShim
)
5844 WARN("LoadLibraryShim not available\n");
5845 FreeLibrary(hmscoree
);
5849 hr
= pLoadLibraryShim(szFusion
, NULL
, NULL
, &hfusion
);
5852 WARN("fusion.dll not available\n");
5853 FreeLibrary(hmscoree
);
5857 pCreateAssemblyCache
= (void *)GetProcAddress(hfusion
, "CreateAssemblyCache");
5859 FreeLibrary(hmscoree
);
5863 static UINT
install_assembly(MSIPACKAGE
*package
, MSIASSEMBLY
*assembly
,
5866 IAssemblyCache
*cache
;
5868 UINT r
= ERROR_FUNCTION_FAILED
;
5870 TRACE("installing assembly: %s\n", debugstr_w(path
));
5872 if (assembly
->feature
)
5873 msi_feature_set_state(package
, assembly
->feature
, INSTALLSTATE_LOCAL
);
5875 if (assembly
->manifest
)
5876 FIXME("Manifest unhandled\n");
5878 if (assembly
->application
)
5880 FIXME("Assembly should be privately installed\n");
5881 return ERROR_SUCCESS
;
5884 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
5886 FIXME("Win32 assemblies not handled\n");
5887 return ERROR_SUCCESS
;
5890 hr
= pCreateAssemblyCache(&cache
, 0);
5894 hr
= IAssemblyCache_InstallAssembly(cache
, 0, path
, NULL
);
5896 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path
), hr
);
5901 IAssemblyCache_Release(cache
);
5905 typedef struct tagASSEMBLY_LIST
5907 MSIPACKAGE
*package
;
5908 IAssemblyCache
*cache
;
5909 struct list
*assemblies
;
5912 typedef struct tagASSEMBLY_NAME
5920 static UINT
parse_assembly_name(MSIRECORD
*rec
, LPVOID param
)
5922 ASSEMBLY_NAME
*asmname
= param
;
5923 LPCWSTR name
= MSI_RecordGetString(rec
, 2);
5924 LPWSTR val
= msi_dup_record_field(rec
, 3);
5926 static const WCHAR Name
[] = {'N','a','m','e',0};
5927 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
5928 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e',0};
5929 static const WCHAR PublicKeyToken
[] = {
5930 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
5932 if (!strcmpiW(name
, Name
))
5933 asmname
->name
= val
;
5934 else if (!strcmpiW(name
, Version
))
5935 asmname
->version
= val
;
5936 else if (!strcmpiW(name
, Culture
))
5937 asmname
->culture
= val
;
5938 else if (!strcmpiW(name
, PublicKeyToken
))
5939 asmname
->pubkeytoken
= val
;
5943 return ERROR_SUCCESS
;
5946 static void append_str(LPWSTR
*str
, DWORD
*size
, LPCWSTR append
)
5950 *size
= lstrlenW(append
) + 1;
5951 *str
= msi_alloc((*size
) * sizeof(WCHAR
));
5952 lstrcpyW(*str
, append
);
5956 (*size
) += lstrlenW(append
);
5957 *str
= msi_realloc(*str
, (*size
) * sizeof(WCHAR
));
5958 lstrcatW(*str
, append
);
5961 static BOOL
check_assembly_installed(MSIDATABASE
*db
, IAssemblyCache
*cache
,
5964 ASSEMBLY_INFO asminfo
;
5972 static const WCHAR separator
[] = {',',' ',0};
5973 static const WCHAR Version
[] = {'V','e','r','s','i','o','n','=',0};
5974 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e','=',0};
5975 static const WCHAR PublicKeyToken
[] = {
5976 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
5977 static const WCHAR query
[] = {
5978 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5979 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
5980 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
5981 '=','\'','%','s','\'',0};
5985 ZeroMemory(&name
, sizeof(ASSEMBLY_NAME
));
5986 ZeroMemory(&asminfo
, sizeof(ASSEMBLY_INFO
));
5988 r
= MSI_OpenQuery(db
, &view
, query
, comp
->Component
);
5989 if (r
!= ERROR_SUCCESS
)
5990 return ERROR_SUCCESS
;
5992 MSI_IterateRecords(view
, NULL
, parse_assembly_name
, &name
);
5993 msiobj_release(&view
->hdr
);
5997 ERR("No assembly name specified!\n");
6001 append_str(&disp
, &size
, name
.name
);
6005 append_str(&disp
, &size
, separator
);
6006 append_str(&disp
, &size
, Version
);
6007 append_str(&disp
, &size
, name
.version
);
6012 append_str(&disp
, &size
, separator
);
6013 append_str(&disp
, &size
, Culture
);
6014 append_str(&disp
, &size
, name
.culture
);
6017 if (name
.pubkeytoken
)
6019 append_str(&disp
, &size
, separator
);
6020 append_str(&disp
, &size
, PublicKeyToken
);
6021 append_str(&disp
, &size
, name
.pubkeytoken
);
6024 asminfo
.cbAssemblyInfo
= sizeof(ASSEMBLY_INFO
);
6025 IAssemblyCache_QueryAssemblyInfo(cache
, QUERYASMINFO_FLAG_VALIDATE
,
6027 found
= (asminfo
.dwAssemblyFlags
== ASSEMBLYINFO_FLAG_INSTALLED
);
6031 msi_free(name
.name
);
6032 msi_free(name
.version
);
6033 msi_free(name
.culture
);
6034 msi_free(name
.pubkeytoken
);
6039 static UINT
load_assembly(MSIRECORD
*rec
, LPVOID param
)
6041 ASSEMBLY_LIST
*list
= param
;
6042 MSIASSEMBLY
*assembly
;
6044 assembly
= msi_alloc_zero(sizeof(MSIASSEMBLY
));
6046 return ERROR_OUTOFMEMORY
;
6048 assembly
->component
= get_loaded_component(list
->package
, MSI_RecordGetString(rec
, 1));
6050 if (!assembly
->component
|| !assembly
->component
->Enabled
||
6051 !(assembly
->component
->Action
& (INSTALLSTATE_LOCAL
| INSTALLSTATE_SOURCE
)))
6053 TRACE("Component not set for install, not publishing assembly\n");
6055 return ERROR_SUCCESS
;
6058 assembly
->feature
= find_feature_by_name(list
->package
, MSI_RecordGetString(rec
, 2));
6059 assembly
->file
= msi_find_file(list
->package
, assembly
->component
->KeyPath
);
6061 if (!assembly
->file
)
6063 ERR("File %s not found\n", debugstr_w(assembly
->component
->KeyPath
));
6064 return ERROR_FUNCTION_FAILED
;
6067 assembly
->manifest
= strdupW(MSI_RecordGetString(rec
, 3));
6068 assembly
->application
= strdupW(MSI_RecordGetString(rec
, 4));
6069 assembly
->attributes
= MSI_RecordGetInteger(rec
, 5);
6071 if (assembly
->application
)
6074 DWORD size
= sizeof(version
)/sizeof(WCHAR
);
6076 /* FIXME: we should probably check the manifest file here */
6078 if (!MsiGetFileVersionW(assembly
->file
->TargetPath
, version
, &size
, NULL
, NULL
) &&
6079 (!assembly
->file
->Version
|| strcmpW(version
, assembly
->file
->Version
) >= 0))
6081 assembly
->installed
= TRUE
;
6085 assembly
->installed
= check_assembly_installed(list
->package
->db
,
6087 assembly
->component
);
6089 list_add_head(list
->assemblies
, &assembly
->entry
);
6090 return ERROR_SUCCESS
;
6093 static UINT
load_assemblies(MSIPACKAGE
*package
, struct list
*assemblies
)
6095 IAssemblyCache
*cache
= NULL
;
6101 static const WCHAR query
[] =
6102 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6103 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6105 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
6106 if (r
!= ERROR_SUCCESS
)
6107 return ERROR_SUCCESS
;
6109 hr
= pCreateAssemblyCache(&cache
, 0);
6111 return ERROR_FUNCTION_FAILED
;
6113 list
.package
= package
;
6115 list
.assemblies
= assemblies
;
6117 r
= MSI_IterateRecords(view
, NULL
, load_assembly
, &list
);
6118 msiobj_release(&view
->hdr
);
6120 IAssemblyCache_Release(cache
);
6125 static void free_assemblies(struct list
*assemblies
)
6127 struct list
*item
, *cursor
;
6129 LIST_FOR_EACH_SAFE(item
, cursor
, assemblies
)
6131 MSIASSEMBLY
*assembly
= LIST_ENTRY(item
, MSIASSEMBLY
, entry
);
6133 list_remove(&assembly
->entry
);
6134 msi_free(assembly
->application
);
6135 msi_free(assembly
->manifest
);
6140 static BOOL
find_assembly(struct list
*assemblies
, LPCWSTR file
, MSIASSEMBLY
**out
)
6142 MSIASSEMBLY
*assembly
;
6144 LIST_FOR_EACH_ENTRY(assembly
, assemblies
, MSIASSEMBLY
, entry
)
6146 if (!lstrcmpW(assembly
->file
->File
, file
))
6156 static BOOL
installassembly_cb(MSIPACKAGE
*package
, LPCWSTR file
, DWORD action
,
6157 LPWSTR
*path
, DWORD
*attrs
, PVOID user
)
6159 MSIASSEMBLY
*assembly
;
6160 WCHAR temppath
[MAX_PATH
];
6161 struct list
*assemblies
= user
;
6164 if (!find_assembly(assemblies
, file
, &assembly
))
6167 GetTempPathW(MAX_PATH
, temppath
);
6168 PathAddBackslashW(temppath
);
6169 lstrcatW(temppath
, assembly
->file
->FileName
);
6171 if (action
== MSICABEXTRACT_BEGINEXTRACT
)
6173 if (assembly
->installed
)
6176 *path
= strdupW(temppath
);
6177 *attrs
= assembly
->file
->Attributes
;
6179 else if (action
== MSICABEXTRACT_FILEEXTRACTED
)
6181 assembly
->installed
= TRUE
;
6183 r
= install_assembly(package
, assembly
, temppath
);
6184 if (r
!= ERROR_SUCCESS
)
6185 ERR("Failed to install assembly\n");
6191 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
6194 struct list assemblies
= LIST_INIT(assemblies
);
6195 MSIASSEMBLY
*assembly
;
6198 if (!init_functionpointers() || !pCreateAssemblyCache
)
6199 return ERROR_FUNCTION_FAILED
;
6201 r
= load_assemblies(package
, &assemblies
);
6202 if (r
!= ERROR_SUCCESS
)
6205 if (list_empty(&assemblies
))
6208 mi
= msi_alloc_zero(sizeof(MSIMEDIAINFO
));
6211 r
= ERROR_OUTOFMEMORY
;
6215 LIST_FOR_EACH_ENTRY(assembly
, &assemblies
, MSIASSEMBLY
, entry
)
6217 if (assembly
->installed
&& !mi
->is_continuous
)
6220 if (assembly
->file
->Sequence
> mi
->last_sequence
|| mi
->is_continuous
||
6221 (assembly
->file
->IsCompressed
&& !mi
->is_extracted
))
6225 r
= ready_media(package
, assembly
->file
, mi
);
6226 if (r
!= ERROR_SUCCESS
)
6228 ERR("Failed to ready media\n");
6233 data
.package
= package
;
6234 data
.cb
= installassembly_cb
;
6235 data
.user
= &assemblies
;
6237 if (assembly
->file
->IsCompressed
&&
6238 !msi_cabextract(package
, mi
, &data
))
6240 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi
->cabinet
));
6241 r
= ERROR_FUNCTION_FAILED
;
6246 if (!assembly
->file
->IsCompressed
)
6248 LPWSTR source
= resolve_file_source(package
, assembly
->file
);
6250 r
= install_assembly(package
, assembly
, source
);
6251 if (r
!= ERROR_SUCCESS
)
6252 ERR("Failed to install assembly\n");
6257 /* FIXME: write Installer assembly reg values */
6261 free_assemblies(&assemblies
);
6265 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
6266 LPCSTR action
, LPCWSTR table
)
6268 static const WCHAR query
[] = {
6269 'S','E','L','E','C','T',' ','*',' ',
6270 'F','R','O','M',' ','`','%','s','`',0 };
6271 MSIQUERY
*view
= NULL
;
6275 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
6276 if (r
== ERROR_SUCCESS
)
6278 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
6279 msiobj_release(&view
->hdr
);
6283 FIXME("%s -> %u ignored %s table values\n",
6284 action
, count
, debugstr_w(table
));
6286 return ERROR_SUCCESS
;
6289 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
6291 TRACE("%p\n", package
);
6292 return ERROR_SUCCESS
;
6295 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
6297 static const WCHAR table
[] =
6298 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
6299 return msi_unimplemented_action_stub( package
, "RemoveIniValues", table
);
6302 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
6304 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
6305 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
6308 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
6310 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
6311 return msi_unimplemented_action_stub( package
, "BindImage", table
);
6314 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
6316 static const WCHAR table
[] = {
6317 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
6318 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
6321 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
6323 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6324 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
6327 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
6329 static const WCHAR table
[] = { 'S','e','l','f','R','e','g',0 };
6330 return msi_unimplemented_action_stub( package
, "SelfUnregModules", table
);
6333 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
6335 static const WCHAR table
[] = {
6336 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6337 return msi_unimplemented_action_stub( package
, "DeleteServices", table
);
6339 static UINT
ACTION_ValidateProductID( MSIPACKAGE
*package
)
6341 static const WCHAR table
[] = {
6342 'P','r','o','d','u','c','t','I','D',0 };
6343 return msi_unimplemented_action_stub( package
, "ValidateProductID", table
);
6346 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
6348 static const WCHAR table
[] = {
6349 'E','n','v','i','r','o','n','m','e','n','t',0 };
6350 return msi_unimplemented_action_stub( package
, "RemoveEnvironmentStrings", table
);
6353 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
6355 static const WCHAR table
[] = {
6356 'M','s','i','A','s','s','e','m','b','l','y',0 };
6357 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
6360 static UINT
ACTION_UnregisterFonts( MSIPACKAGE
*package
)
6362 static const WCHAR table
[] = { 'F','o','n','t',0 };
6363 return msi_unimplemented_action_stub( package
, "UnregisterFonts", table
);
6366 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
6368 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
6369 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
6372 static UINT
ACTION_RegisterComPlus( MSIPACKAGE
*package
)
6374 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6375 return msi_unimplemented_action_stub( package
, "RegisterComPlus", table
);
6378 static UINT
ACTION_UnregisterComPlus( MSIPACKAGE
*package
)
6380 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6381 return msi_unimplemented_action_stub( package
, "UnregisterComPlus", table
);
6384 static UINT
ACTION_InstallSFPCatalogFile( MSIPACKAGE
*package
)
6386 static const WCHAR table
[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6387 return msi_unimplemented_action_stub( package
, "InstallSFPCatalogFile", table
);
6390 static UINT
ACTION_RemoveDuplicateFiles( MSIPACKAGE
*package
)
6392 static const WCHAR table
[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6393 return msi_unimplemented_action_stub( package
, "RemoveDuplicateFiles", table
);
6396 static UINT
ACTION_RemoveExistingProducts( MSIPACKAGE
*package
)
6398 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6399 return msi_unimplemented_action_stub( package
, "RemoveExistingProducts", table
);
6402 static UINT
ACTION_RemoveFolders( MSIPACKAGE
*package
)
6404 static const WCHAR table
[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6405 return msi_unimplemented_action_stub( package
, "RemoveFolders", table
);
6408 static UINT
ACTION_RemoveODBC( MSIPACKAGE
*package
)
6410 static const WCHAR table
[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6411 return msi_unimplemented_action_stub( package
, "RemoveODBC", table
);
6414 static UINT
ACTION_RemoveRegistryValues( MSIPACKAGE
*package
)
6416 static const WCHAR table
[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6417 return msi_unimplemented_action_stub( package
, "RemoveRegistryValues", table
);
6420 static UINT
ACTION_RemoveShortcuts( MSIPACKAGE
*package
)
6422 static const WCHAR table
[] = { 'S','h','o','r','t','c','u','t',0 };
6423 return msi_unimplemented_action_stub( package
, "RemoveShortcuts", table
);
6426 static UINT
ACTION_UnpublishComponents( MSIPACKAGE
*package
)
6428 static const WCHAR table
[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6429 return msi_unimplemented_action_stub( package
, "UnpublishComponents", table
);
6432 static UINT
ACTION_UnregisterClassInfo( MSIPACKAGE
*package
)
6434 static const WCHAR table
[] = { 'A','p','p','I','d',0 };
6435 return msi_unimplemented_action_stub( package
, "UnregisterClassInfo", table
);
6438 static UINT
ACTION_UnregisterExtensionInfo( MSIPACKAGE
*package
)
6440 static const WCHAR table
[] = { 'E','x','t','e','n','s','i','o','n',0 };
6441 return msi_unimplemented_action_stub( package
, "UnregisterExtensionInfo", table
);
6444 static UINT
ACTION_UnregisterMIMEInfo( MSIPACKAGE
*package
)
6446 static const WCHAR table
[] = { 'M','I','M','E',0 };
6447 return msi_unimplemented_action_stub( package
, "UnregisterMIMEInfo", table
);
6450 static UINT
ACTION_UnregisterProgIdInfo( MSIPACKAGE
*package
)
6452 static const WCHAR table
[] = { 'P','r','o','g','I','d',0 };
6453 return msi_unimplemented_action_stub( package
, "UnregisterProgIdInfo", table
);
6456 static UINT
ACTION_UnregisterTypeLibraries( MSIPACKAGE
*package
)
6458 static const WCHAR table
[] = { 'T','y','p','e','L','i','b',0 };
6459 return msi_unimplemented_action_stub( package
, "UnregisterTypeLibraries", table
);
6462 static const struct _actions StandardActions
[] = {
6463 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
6464 { szAppSearch
, ACTION_AppSearch
},
6465 { szBindImage
, ACTION_BindImage
},
6466 { szCCPSearch
, ACTION_CCPSearch
},
6467 { szCostFinalize
, ACTION_CostFinalize
},
6468 { szCostInitialize
, ACTION_CostInitialize
},
6469 { szCreateFolders
, ACTION_CreateFolders
},
6470 { szCreateShortcuts
, ACTION_CreateShortcuts
},
6471 { szDeleteServices
, ACTION_DeleteServices
},
6472 { szDisableRollback
, NULL
},
6473 { szDuplicateFiles
, ACTION_DuplicateFiles
},
6474 { szExecuteAction
, ACTION_ExecuteAction
},
6475 { szFileCost
, ACTION_FileCost
},
6476 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
6477 { szForceReboot
, ACTION_ForceReboot
},
6478 { szInstallAdminPackage
, NULL
},
6479 { szInstallExecute
, ACTION_InstallExecute
},
6480 { szInstallExecuteAgain
, ACTION_InstallExecute
},
6481 { szInstallFiles
, ACTION_InstallFiles
},
6482 { szInstallFinalize
, ACTION_InstallFinalize
},
6483 { szInstallInitialize
, ACTION_InstallInitialize
},
6484 { szInstallSFPCatalogFile
, ACTION_InstallSFPCatalogFile
},
6485 { szInstallValidate
, ACTION_InstallValidate
},
6486 { szIsolateComponents
, ACTION_IsolateComponents
},
6487 { szLaunchConditions
, ACTION_LaunchConditions
},
6488 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
6489 { szMoveFiles
, ACTION_MoveFiles
},
6490 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
6491 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
6492 { szInstallODBC
, ACTION_InstallODBC
},
6493 { szInstallServices
, ACTION_InstallServices
},
6494 { szPatchFiles
, ACTION_PatchFiles
},
6495 { szProcessComponents
, ACTION_ProcessComponents
},
6496 { szPublishComponents
, ACTION_PublishComponents
},
6497 { szPublishFeatures
, ACTION_PublishFeatures
},
6498 { szPublishProduct
, ACTION_PublishProduct
},
6499 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
6500 { szRegisterComPlus
, ACTION_RegisterComPlus
},
6501 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
6502 { szRegisterFonts
, ACTION_RegisterFonts
},
6503 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
6504 { szRegisterProduct
, ACTION_RegisterProduct
},
6505 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
6506 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
6507 { szRegisterUser
, ACTION_RegisterUser
},
6508 { szRemoveDuplicateFiles
, ACTION_RemoveDuplicateFiles
},
6509 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
6510 { szRemoveExistingProducts
, ACTION_RemoveExistingProducts
},
6511 { szRemoveFiles
, ACTION_RemoveFiles
},
6512 { szRemoveFolders
, ACTION_RemoveFolders
},
6513 { szRemoveIniValues
, ACTION_RemoveIniValues
},
6514 { szRemoveODBC
, ACTION_RemoveODBC
},
6515 { szRemoveRegistryValues
, ACTION_RemoveRegistryValues
},
6516 { szRemoveShortcuts
, ACTION_RemoveShortcuts
},
6517 { szResolveSource
, ACTION_ResolveSource
},
6518 { szRMCCPSearch
, ACTION_RMCCPSearch
},
6519 { szScheduleReboot
, NULL
},
6520 { szSelfRegModules
, ACTION_SelfRegModules
},
6521 { szSelfUnregModules
, ACTION_SelfUnregModules
},
6522 { szSetODBCFolders
, NULL
},
6523 { szStartServices
, ACTION_StartServices
},
6524 { szStopServices
, ACTION_StopServices
},
6525 { szUnpublishComponents
, ACTION_UnpublishComponents
},
6526 { szUnpublishFeatures
, ACTION_UnpublishFeatures
},
6527 { szUnregisterClassInfo
, ACTION_UnregisterClassInfo
},
6528 { szUnregisterComPlus
, ACTION_UnregisterComPlus
},
6529 { szUnregisterExtensionInfo
, ACTION_UnregisterExtensionInfo
},
6530 { szUnregisterFonts
, ACTION_UnregisterFonts
},
6531 { szUnregisterMIMEInfo
, ACTION_UnregisterMIMEInfo
},
6532 { szUnregisterProgIdInfo
, ACTION_UnregisterProgIdInfo
},
6533 { szUnregisterTypeLibraries
, ACTION_UnregisterTypeLibraries
},
6534 { szValidateProductID
, ACTION_ValidateProductID
},
6535 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
6536 { szWriteIniValues
, ACTION_WriteIniValues
},
6537 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
6541 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
6542 UINT
* rc
, BOOL force
)
6548 if (!run
&& !package
->script
->CurrentlyScripting
)
6553 if (strcmpW(action
,szInstallFinalize
) == 0 ||
6554 strcmpW(action
,szInstallExecute
) == 0 ||
6555 strcmpW(action
,szInstallExecuteAgain
) == 0)
6560 while (StandardActions
[i
].action
!= NULL
)
6562 if (strcmpW(StandardActions
[i
].action
, action
)==0)
6566 ui_actioninfo(package
, action
, TRUE
, 0);
6567 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
6568 ui_actioninfo(package
, action
, FALSE
, *rc
);
6572 ui_actionstart(package
, action
);
6573 if (StandardActions
[i
].handler
)
6575 *rc
= StandardActions
[i
].handler(package
);
6579 FIXME("unhandled standard action %s\n",debugstr_w(action
));
6580 *rc
= ERROR_SUCCESS
;