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);
3562 ptr = strrchrW(package->PackagePath, '\\' ) + 1;
3563 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGENAMEW, ptr);
3566 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3568 buffer = msi_dup_property(package, szARPProductIcon);
3571 LPWSTR path = build_icon_path(package,buffer);
3572 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3577 buffer = msi_dup_property(package, szProductVersion);
3580 DWORD verdword = msi_version_str_to_dword(buffer);
3581 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3585 msi_reg_set_val_dword(hkey, szAssignment, 0);
3586 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3587 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3588 msi_reg_set_val_str(hkey, szClients, szColon);
3590 hdb = alloc_msihandle(&package->db->hdr);
3592 return ERROR_NOT_ENOUGH_MEMORY;
3594 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3595 MsiCloseHandle(hdb);
3596 if (r != ERROR_SUCCESS)
3600 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3601 NULL, guids, &size);
3602 if (r != ERROR_SUCCESS)
3605 ptr = strchrW(guids, ';');
3607 squash_guid(guids, packcode);
3608 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3611 MsiCloseHandle(suminfo);
3612 return ERROR_SUCCESS;
3615 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3620 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3622 static const WCHAR szUpgradeCode[] =
3623 {'U','p','g','r','a','d','e','C','o','d','e',0};
3625 upgrade = msi_dup_property(package, szUpgradeCode);
3627 return ERROR_SUCCESS;
3629 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3631 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3632 if (r != ERROR_SUCCESS)
3637 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3638 if (r != ERROR_SUCCESS)
3642 squash_guid(package->ProductCode, squashed_pc);
3643 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3652 static BOOL msi_check_publish(MSIPACKAGE *package)
3654 MSIFEATURE *feature;
3656 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3658 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3665 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3667 MSIFEATURE *feature;
3669 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3671 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3678 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3680 WCHAR patch_squashed[GUID_SIZE];
3683 UINT r = ERROR_FUNCTION_FAILED;
3685 static const WCHAR szPatches[] = {'P','a','t','c','h','e','s',0};
3687 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3689 if (res != ERROR_SUCCESS)
3690 return ERROR_FUNCTION_FAILED;
3692 squash_guid(package->patch->patchcode, patch_squashed);
3694 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3695 (const BYTE *)patch_squashed,
3696 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3697 if (res != ERROR_SUCCESS)
3700 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3701 (const BYTE *)package->patch->transforms,
3702 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3703 if (res == ERROR_SUCCESS)
3707 RegCloseKey(patches);
3712 * 99% of the work done here is only done for
3713 * advertised installs. However this is where the
3714 * Icon table is processed and written out
3715 * so that is what I am going to do here.
3717 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3723 /* FIXME: also need to publish if the product is in advertise mode */
3724 if (!msi_check_publish(package))
3725 return ERROR_SUCCESS;
3727 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3729 if (rc != ERROR_SUCCESS)
3732 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3733 NULL, &hudkey, TRUE);
3734 if (rc != ERROR_SUCCESS)
3737 rc = msi_publish_upgrade_code(package);
3738 if (rc != ERROR_SUCCESS)
3743 rc = msi_publish_patch(package, hukey, hudkey);
3744 if (rc != ERROR_SUCCESS)
3748 rc = msi_publish_product_properties(package, hukey);
3749 if (rc != ERROR_SUCCESS)
3752 rc = msi_publish_sourcelist(package, hukey);
3753 if (rc != ERROR_SUCCESS)
3756 rc = msi_publish_icons(package);
3760 RegCloseKey(hudkey);
3765 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3767 MSIPACKAGE *package = param;
3768 LPCWSTR component, section, key, value, identifier, dirproperty;
3769 LPWSTR deformated_section, deformated_key, deformated_value;
3770 LPWSTR folder, filename, fullname = NULL;
3771 LPCWSTR filenameptr;
3775 static const WCHAR szWindowsFolder[] =
3776 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3778 component = MSI_RecordGetString(row, 8);
3779 comp = get_loaded_component(package,component);
3781 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3783 TRACE("Skipping ini file due to disabled component %s\n",
3784 debugstr_w(component));
3786 comp->Action = comp->Installed;
3788 return ERROR_SUCCESS;
3791 comp->Action = INSTALLSTATE_LOCAL;
3793 identifier = MSI_RecordGetString(row,1);
3794 dirproperty = MSI_RecordGetString(row,3);
3795 section = MSI_RecordGetString(row,4);
3796 key = MSI_RecordGetString(row,5);
3797 value = MSI_RecordGetString(row,6);
3798 action = MSI_RecordGetInteger(row,7);
3800 deformat_string(package,section,&deformated_section);
3801 deformat_string(package,key,&deformated_key);
3802 deformat_string(package,value,&deformated_value);
3804 filename = msi_dup_record_field(row, 2);
3805 if (filename && (filenameptr = strchrW(filename, '|')))
3808 filenameptr = filename;
3812 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3814 folder = msi_dup_property( package, dirproperty );
3817 folder = msi_dup_property( package, szWindowsFolder );
3821 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3825 fullname = build_directory_name(2, folder, filenameptr);
3829 TRACE("Adding value %s to section %s in %s\n",
3830 debugstr_w(deformated_key), debugstr_w(deformated_section),
3831 debugstr_w(fullname));
3832 WritePrivateProfileStringW(deformated_section, deformated_key,
3833 deformated_value, fullname);
3835 else if (action == 1)
3838 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3839 returned, 10, fullname);
3840 if (returned[0] == 0)
3842 TRACE("Adding value %s to section %s in %s\n",
3843 debugstr_w(deformated_key), debugstr_w(deformated_section),
3844 debugstr_w(fullname));
3846 WritePrivateProfileStringW(deformated_section, deformated_key,
3847 deformated_value, fullname);
3850 else if (action == 3)
3851 FIXME("Append to existing section not yet implemented\n");
3853 uirow = MSI_CreateRecord(4);
3854 MSI_RecordSetStringW(uirow,1,identifier);
3855 MSI_RecordSetStringW(uirow,2,deformated_section);
3856 MSI_RecordSetStringW(uirow,3,deformated_key);
3857 MSI_RecordSetStringW(uirow,4,deformated_value);
3858 ui_actiondata(package,szWriteIniValues,uirow);
3859 msiobj_release( &uirow->hdr );
3865 msi_free(deformated_key);
3866 msi_free(deformated_value);
3867 msi_free(deformated_section);
3868 return ERROR_SUCCESS;
3871 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3875 static const WCHAR ExecSeqQuery[] =
3876 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3877 '`','I','n','i','F','i','l','e','`',0};
3879 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3880 if (rc != ERROR_SUCCESS)
3882 TRACE("no IniFile table\n");
3883 return ERROR_SUCCESS;
3886 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3887 msiobj_release(&view->hdr);
3891 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3893 MSIPACKAGE *package = param;
3898 static const WCHAR ExeStr[] =
3899 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3900 static const WCHAR close[] = {'\"',0};
3902 PROCESS_INFORMATION info;
3907 memset(&si,0,sizeof(STARTUPINFOW));
3909 filename = MSI_RecordGetString(row,1);
3910 file = get_loaded_file( package, filename );
3914 ERR("Unable to find file id %s\n",debugstr_w(filename));
3915 return ERROR_SUCCESS;
3918 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3920 FullName = msi_alloc(len*sizeof(WCHAR));
3921 strcpyW(FullName,ExeStr);
3922 strcatW( FullName, file->TargetPath );
3923 strcatW(FullName,close);
3925 TRACE("Registering %s\n",debugstr_w(FullName));
3926 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3931 CloseHandle(info.hThread);
3932 msi_dialog_check_messages(info.hProcess);
3933 CloseHandle(info.hProcess);
3939 uirow = MSI_CreateRecord( 2 );
3940 uipath = strdupW( file->TargetPath );
3941 p = strrchrW(uipath,'\\');
3944 MSI_RecordSetStringW( uirow, 1, &p[1] );
3945 MSI_RecordSetStringW( uirow, 2, uipath);
3946 ui_actiondata( package, szSelfRegModules, uirow);
3947 msiobj_release( &uirow->hdr );
3949 /* FIXME: call ui_progress? */
3951 return ERROR_SUCCESS;
3954 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3958 static const WCHAR ExecSeqQuery[] =
3959 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3960 '`','S','e','l','f','R','e','g','`',0};
3962 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3963 if (rc != ERROR_SUCCESS)
3965 TRACE("no SelfReg table\n");
3966 return ERROR_SUCCESS;
3969 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3970 msiobj_release(&view->hdr);
3972 return ERROR_SUCCESS;
3975 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3977 MSIFEATURE *feature;
3980 HKEY userdata = NULL;
3982 if (!msi_check_publish(package))
3983 return ERROR_SUCCESS;
3985 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3987 if (rc != ERROR_SUCCESS)
3990 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3992 if (rc != ERROR_SUCCESS)
3995 /* here the guids are base 85 encoded */
3996 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4002 BOOL absent = FALSE;
4005 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
4006 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
4007 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
4011 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4015 if (feature->Feature_Parent)
4016 size += strlenW( feature->Feature_Parent )+2;
4018 data = msi_alloc(size * sizeof(WCHAR));
4021 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4023 MSICOMPONENT* component = cl->component;
4027 if (component->ComponentId)
4029 TRACE("From %s\n",debugstr_w(component->ComponentId));
4030 CLSIDFromString(component->ComponentId, &clsid);
4031 encode_base85_guid(&clsid,buf);
4032 TRACE("to %s\n",debugstr_w(buf));
4037 if (feature->Feature_Parent)
4039 static const WCHAR sep[] = {'\2',0};
4041 strcatW(data,feature->Feature_Parent);
4044 msi_reg_set_val_str( userdata, feature->Feature, data );
4048 if (feature->Feature_Parent)
4049 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4052 static const WCHAR emptyW[] = {0};
4053 size += sizeof(WCHAR);
4054 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4055 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : emptyW),size);
4059 size += 2*sizeof(WCHAR);
4060 data = msi_alloc(size);
4063 if (feature->Feature_Parent)
4064 strcpyW( &data[1], feature->Feature_Parent );
4065 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4071 uirow = MSI_CreateRecord( 1 );
4072 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4073 ui_actiondata( package, szPublishFeatures, uirow);
4074 msiobj_release( &uirow->hdr );
4075 /* FIXME: call ui_progress? */
4080 RegCloseKey(userdata);
4084 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4089 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4091 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4093 if (r == ERROR_SUCCESS)
4095 RegDeleteValueW(hkey, feature->Feature);
4099 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4101 if (r == ERROR_SUCCESS)
4103 RegDeleteValueW(hkey, feature->Feature);
4107 return ERROR_SUCCESS;
4110 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4112 MSIFEATURE *feature;
4114 if (!msi_check_unpublish(package))
4115 return ERROR_SUCCESS;
4117 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4119 msi_unpublish_feature(package, feature);
4122 return ERROR_SUCCESS;
4125 static UINT msi_get_local_package_name( LPWSTR path )
4127 static const WCHAR szInstaller[] = {
4128 '\\','I','n','s','t','a','l','l','e','r','\\',0};
4129 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
4133 time = GetTickCount();
4134 GetWindowsDirectoryW( path, MAX_PATH );
4135 lstrcatW( path, szInstaller );
4136 CreateDirectoryW( path, NULL );
4138 len = lstrlenW(path);
4139 for (i=0; i<0x10000; i++)
4141 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
4142 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
4143 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
4144 if (handle != INVALID_HANDLE_VALUE)
4146 CloseHandle(handle);
4149 if (GetLastError() != ERROR_FILE_EXISTS &&
4150 GetLastError() != ERROR_SHARING_VIOLATION)
4151 return ERROR_FUNCTION_FAILED;
4154 return ERROR_SUCCESS;
4157 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
4159 WCHAR packagefile[MAX_PATH];
4162 r = msi_get_local_package_name( packagefile );
4163 if (r != ERROR_SUCCESS)
4166 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
4168 r = CopyFileW( package->db->path, packagefile, FALSE);
4172 ERR("Unable to copy package (%s -> %s) (error %d)\n",
4173 debugstr_w(package->db->path), debugstr_w(packagefile), GetLastError());
4174 return ERROR_FUNCTION_FAILED;
4177 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
4179 return ERROR_SUCCESS;
4182 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4184 LPWSTR prop, val, key;
4190 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4191 static const WCHAR szWindowsInstaller[] =
4192 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4193 static const WCHAR modpath_fmt[] =
4194 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4195 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4196 static const WCHAR szModifyPath[] =
4197 {'M','o','d','i','f','y','P','a','t','h',0};
4198 static const WCHAR szUninstallString[] =
4199 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4200 static const WCHAR szEstimatedSize[] =
4201 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4202 static const WCHAR szProductLanguage[] =
4203 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4204 static const WCHAR szProductVersion[] =
4205 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4206 static const WCHAR szProductName[] =
4207 {'P','r','o','d','u','c','t','N','a','m','e',0};
4208 static const WCHAR szDisplayName[] =
4209 {'D','i','s','p','l','a','y','N','a','m','e',0};
4210 static const WCHAR szDisplayVersion[] =
4211 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4212 static const WCHAR szManufacturer[] =
4213 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4215 static const LPCSTR propval[] = {
4216 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4217 "ARPCONTACT", "Contact",
4218 "ARPCOMMENTS", "Comments",
4219 "ProductName", "DisplayName",
4220 "ProductVersion", "DisplayVersion",
4221 "ARPHELPLINK", "HelpLink",
4222 "ARPHELPTELEPHONE", "HelpTelephone",
4223 "ARPINSTALLLOCATION", "InstallLocation",
4224 "SourceDir", "InstallSource",
4225 "Manufacturer", "Publisher",
4226 "ARPREADME", "Readme",
4228 "ARPURLINFOABOUT", "URLInfoAbout",
4229 "ARPURLUPDATEINFO", "URLUpdateInfo",
4232 const LPCSTR *p = propval;
4236 prop = strdupAtoW(*p++);
4237 key = strdupAtoW(*p++);
4238 val = msi_dup_property(package, prop);
4239 msi_reg_set_val_str(hkey, key, val);
4245 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4247 size = deformat_string(package, modpath_fmt, &buffer);
4248 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4249 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4252 /* FIXME: Write real Estimated Size when we have it */
4253 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4255 buffer = msi_dup_property(package, szProductName);
4256 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4259 buffer = msi_dup_property(package, cszSourceDir);
4260 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4263 buffer = msi_dup_property(package, szManufacturer);
4264 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4267 GetLocalTime(&systime);
4268 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4269 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4271 langid = msi_get_property_int(package, szProductLanguage, 0);
4272 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4274 buffer = msi_dup_property(package, szProductVersion);
4275 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4278 DWORD verdword = msi_version_str_to_dword(buffer);
4280 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4281 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4282 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4286 return ERROR_SUCCESS;
4289 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4291 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4292 LPWSTR upgrade_code;
4297 static const WCHAR szUpgradeCode[] = {
4298 'U','p','g','r','a','d','e','C','o','d','e',0};
4300 /* FIXME: also need to publish if the product is in advertise mode */
4301 if (!msi_check_publish(package))
4302 return ERROR_SUCCESS;
4304 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4305 if (rc != ERROR_SUCCESS)
4308 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4309 NULL, &props, TRUE);
4310 if (rc != ERROR_SUCCESS)
4313 msi_make_package_local(package, props);
4315 rc = msi_publish_install_properties(package, hkey);
4316 if (rc != ERROR_SUCCESS)
4319 rc = msi_publish_install_properties(package, props);
4320 if (rc != ERROR_SUCCESS)
4323 upgrade_code = msi_dup_property(package, szUpgradeCode);
4326 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4327 squash_guid(package->ProductCode, squashed_pc);
4328 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4329 RegCloseKey(upgrade);
4330 msi_free(upgrade_code);
4336 return ERROR_SUCCESS;
4339 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4341 return execute_script(package,INSTALL_SCRIPT);
4344 static UINT msi_unpublish_product(MSIPACKAGE *package)
4347 LPWSTR remove = NULL;
4348 LPWSTR *features = NULL;
4349 BOOL full_uninstall = TRUE;
4350 MSIFEATURE *feature;
4352 static const WCHAR szRemove[] = {'R','E','M','O','V','E',0};
4353 static const WCHAR szAll[] = {'A','L','L',0};
4354 static const WCHAR szUpgradeCode[] =
4355 {'U','p','g','r','a','d','e','C','o','d','e',0};
4357 remove = msi_dup_property(package, szRemove);
4359 return ERROR_SUCCESS;
4361 features = msi_split_string(remove, ',');
4365 ERR("REMOVE feature list is empty!\n");
4366 return ERROR_FUNCTION_FAILED;
4369 if (!lstrcmpW(features[0], szAll))
4370 full_uninstall = TRUE;
4373 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4375 if (feature->Action != INSTALLSTATE_ABSENT)
4376 full_uninstall = FALSE;
4380 if (!full_uninstall)
4383 MSIREG_DeleteProductKey(package->ProductCode);
4384 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4385 MSIREG_DeleteUninstallKey(package->ProductCode);
4387 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4389 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4390 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4394 MSIREG_DeleteUserProductKey(package->ProductCode);
4395 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4398 upgrade = msi_dup_property(package, szUpgradeCode);
4401 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4408 return ERROR_SUCCESS;
4411 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4415 rc = msi_unpublish_product(package);
4416 if (rc != ERROR_SUCCESS)
4419 /* turn off scheduling */
4420 package->script->CurrentlyScripting= FALSE;
4422 /* first do the same as an InstallExecute */
4423 rc = ACTION_InstallExecute(package);
4424 if (rc != ERROR_SUCCESS)
4427 /* then handle Commit Actions */
4428 rc = execute_script(package,COMMIT_SCRIPT);
4433 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4435 static const WCHAR RunOnce[] = {
4436 'S','o','f','t','w','a','r','e','\\',
4437 'M','i','c','r','o','s','o','f','t','\\',
4438 'W','i','n','d','o','w','s','\\',
4439 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4440 'R','u','n','O','n','c','e',0};
4441 static const WCHAR InstallRunOnce[] = {
4442 'S','o','f','t','w','a','r','e','\\',
4443 'M','i','c','r','o','s','o','f','t','\\',
4444 'W','i','n','d','o','w','s','\\',
4445 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4446 'I','n','s','t','a','l','l','e','r','\\',
4447 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4449 static const WCHAR msiexec_fmt[] = {
4451 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4452 '\"','%','s','\"',0};
4453 static const WCHAR install_fmt[] = {
4454 '/','I',' ','\"','%','s','\"',' ',
4455 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4456 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4457 WCHAR buffer[256], sysdir[MAX_PATH];
4459 WCHAR squished_pc[100];
4461 squash_guid(package->ProductCode,squished_pc);
4463 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4464 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4465 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4468 msi_reg_set_val_str( hkey, squished_pc, buffer );
4471 TRACE("Reboot command %s\n",debugstr_w(buffer));
4473 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4474 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4476 msi_reg_set_val_str( hkey, squished_pc, buffer );
4479 return ERROR_INSTALL_SUSPEND;
4482 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4488 * We are currently doing what should be done here in the top level Install
4489 * however for Administrative and uninstalls this step will be needed
4491 if (!package->PackagePath)
4492 return ERROR_SUCCESS;
4494 msi_set_sourcedir_props(package, TRUE);
4496 attrib = GetFileAttributesW(package->db->path);
4497 if (attrib == INVALID_FILE_ATTRIBUTES)
4503 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4504 package->Context, MSICODE_PRODUCT,
4505 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4506 if (rc == ERROR_MORE_DATA)
4508 prompt = msi_alloc(size * sizeof(WCHAR));
4509 MsiSourceListGetInfoW(package->ProductCode, NULL,
4510 package->Context, MSICODE_PRODUCT,
4511 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4514 prompt = strdupW(package->db->path);
4516 msg = generate_error_string(package,1302,1,prompt);
4517 while(attrib == INVALID_FILE_ATTRIBUTES)
4519 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4522 rc = ERROR_INSTALL_USEREXIT;
4525 attrib = GetFileAttributesW(package->db->path);
4531 return ERROR_SUCCESS;
4536 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4543 static const WCHAR szPropKeys[][80] =
4545 {'P','r','o','d','u','c','t','I','D',0},
4546 {'U','S','E','R','N','A','M','E',0},
4547 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4551 static const WCHAR szRegKeys[][80] =
4553 {'P','r','o','d','u','c','t','I','D',0},
4554 {'R','e','g','O','w','n','e','r',0},
4555 {'R','e','g','C','o','m','p','a','n','y',0},
4559 if (msi_check_unpublish(package))
4561 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4562 return ERROR_SUCCESS;
4565 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4567 return ERROR_SUCCESS;
4569 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4571 if (rc != ERROR_SUCCESS)
4574 for( i = 0; szPropKeys[i][0]; i++ )
4576 buffer = msi_dup_property( package, szPropKeys[i] );
4577 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4582 msi_free(productid);
4585 /* FIXME: call ui_actiondata */
4591 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4595 package->script->InWhatSequence |= SEQUENCE_EXEC;
4596 rc = ACTION_ProcessExecSequence(package,FALSE);
4601 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4603 MSIPACKAGE *package = param;
4604 LPCWSTR compgroupid=NULL;
4605 LPCWSTR feature=NULL;
4606 LPCWSTR text = NULL;
4607 LPCWSTR qualifier = NULL;
4608 LPCWSTR component = NULL;
4609 LPWSTR advertise = NULL;
4610 LPWSTR output = NULL;
4612 UINT rc = ERROR_SUCCESS;
4617 component = MSI_RecordGetString(rec,3);
4618 comp = get_loaded_component(package,component);
4620 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4621 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4622 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4624 TRACE("Skipping: Component %s not scheduled for install\n",
4625 debugstr_w(component));
4627 return ERROR_SUCCESS;
4630 compgroupid = MSI_RecordGetString(rec,1);
4631 qualifier = MSI_RecordGetString(rec,2);
4633 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4634 if (rc != ERROR_SUCCESS)
4637 text = MSI_RecordGetString(rec,4);
4638 feature = MSI_RecordGetString(rec,5);
4640 advertise = create_component_advertise_string(package, comp, feature);
4642 sz = strlenW(advertise);
4645 sz += lstrlenW(text);
4648 sz *= sizeof(WCHAR);
4650 output = msi_alloc_zero(sz);
4651 strcpyW(output,advertise);
4652 msi_free(advertise);
4655 strcatW(output,text);
4657 msi_reg_set_val_multi_str( hkey, qualifier, output );
4664 uirow = MSI_CreateRecord( 2 );
4665 MSI_RecordSetStringW( uirow, 1, compgroupid );
4666 MSI_RecordSetStringW( uirow, 2, qualifier);
4667 ui_actiondata( package, szPublishComponents, uirow);
4668 msiobj_release( &uirow->hdr );
4669 /* FIXME: call ui_progress? */
4675 * At present I am ignorning the advertised components part of this and only
4676 * focusing on the qualified component sets
4678 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4682 static const WCHAR ExecSeqQuery[] =
4683 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4684 '`','P','u','b','l','i','s','h',
4685 'C','o','m','p','o','n','e','n','t','`',0};
4687 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4688 if (rc != ERROR_SUCCESS)
4689 return ERROR_SUCCESS;
4691 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4692 msiobj_release(&view->hdr);
4697 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4699 MSIPACKAGE *package = param;
4702 SC_HANDLE hscm, service = NULL;
4703 LPCWSTR comp, depends, pass;
4704 LPWSTR name = NULL, disp = NULL;
4705 LPCWSTR load_order, serv_name, key;
4706 DWORD serv_type, start_type;
4709 static const WCHAR query[] =
4710 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4711 '`','C','o','m','p','o','n','e','n','t','`',' ',
4712 'W','H','E','R','E',' ',
4713 '`','C','o','m','p','o','n','e','n','t','`',' ',
4714 '=','\'','%','s','\'',0};
4716 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4719 ERR("Failed to open the SC Manager!\n");
4723 start_type = MSI_RecordGetInteger(rec, 5);
4724 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4727 depends = MSI_RecordGetString(rec, 8);
4728 if (depends && *depends)
4729 FIXME("Dependency list unhandled!\n");
4731 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4732 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
4733 serv_type = MSI_RecordGetInteger(rec, 4);
4734 err_control = MSI_RecordGetInteger(rec, 6);
4735 load_order = MSI_RecordGetString(rec, 7);
4736 serv_name = MSI_RecordGetString(rec, 9);
4737 pass = MSI_RecordGetString(rec, 10);
4738 comp = MSI_RecordGetString(rec, 12);
4740 /* fetch the service path */
4741 row = MSI_QueryGetRecord(package->db, query, comp);
4744 ERR("Control query failed!\n");
4748 key = MSI_RecordGetString(row, 6);
4750 file = get_loaded_file(package, key);
4751 msiobj_release(&row->hdr);
4754 ERR("Failed to load the service file\n");
4758 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4759 start_type, err_control, file->TargetPath,
4760 load_order, NULL, NULL, serv_name, pass);
4763 if (GetLastError() != ERROR_SERVICE_EXISTS)
4764 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4768 CloseServiceHandle(service);
4769 CloseServiceHandle(hscm);
4773 return ERROR_SUCCESS;
4776 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4780 static const WCHAR ExecSeqQuery[] =
4781 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4782 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4784 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4785 if (rc != ERROR_SUCCESS)
4786 return ERROR_SUCCESS;
4788 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4789 msiobj_release(&view->hdr);
4794 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4795 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
4797 LPCWSTR *vector, *temp_vector;
4801 static const WCHAR separator[] = {'[','~',']',0};
4804 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4809 vector = msi_alloc(sizeof(LPWSTR));
4817 vector[*numargs - 1] = p;
4819 if ((q = strstrW(p, separator)))
4823 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4829 vector = temp_vector;
4838 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4840 MSIPACKAGE *package = param;
4842 SC_HANDLE scm, service = NULL;
4843 LPCWSTR name, *vector = NULL;
4845 DWORD event, numargs;
4846 UINT r = ERROR_FUNCTION_FAILED;
4848 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4849 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4850 return ERROR_SUCCESS;
4852 name = MSI_RecordGetString(rec, 2);
4853 event = MSI_RecordGetInteger(rec, 3);
4854 args = strdupW(MSI_RecordGetString(rec, 4));
4856 if (!(event & msidbServiceControlEventStart))
4857 return ERROR_SUCCESS;
4859 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4862 ERR("Failed to open the service control manager\n");
4866 service = OpenServiceW(scm, name, SERVICE_START);
4869 ERR("Failed to open service %s\n", debugstr_w(name));
4873 vector = msi_service_args_to_vector(args, &numargs);
4875 if (!StartServiceW(service, numargs, vector))
4877 ERR("Failed to start service %s\n", debugstr_w(name));
4884 CloseServiceHandle(service);
4885 CloseServiceHandle(scm);
4892 static UINT ACTION_StartServices( MSIPACKAGE *package )
4897 static const WCHAR query[] = {
4898 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4899 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4901 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4902 if (rc != ERROR_SUCCESS)
4903 return ERROR_SUCCESS;
4905 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4906 msiobj_release(&view->hdr);
4911 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4913 DWORD i, needed, count;
4914 ENUM_SERVICE_STATUSW *dependencies;
4918 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4919 0, &needed, &count))
4922 if (GetLastError() != ERROR_MORE_DATA)
4925 dependencies = msi_alloc(needed);
4929 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4930 needed, &needed, &count))
4933 for (i = 0; i < count; i++)
4935 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4936 SERVICE_STOP | SERVICE_QUERY_STATUS);
4940 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4947 msi_free(dependencies);
4951 static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
4953 MSIPACKAGE *package = param;
4955 SERVICE_STATUS status;
4956 SERVICE_STATUS_PROCESS ssp;
4957 SC_HANDLE scm = NULL, service = NULL;
4959 DWORD event, needed;
4961 event = MSI_RecordGetInteger(rec, 3);
4962 if (!(event & msidbServiceControlEventStop))
4963 return ERROR_SUCCESS;
4965 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4966 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4967 return ERROR_SUCCESS;
4969 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4970 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4971 args = strdupW(MSI_RecordGetString(rec, 4));
4973 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4976 WARN("Failed to open the SCM: %d\n", GetLastError());
4980 service = OpenServiceW(scm, name,
4982 SERVICE_QUERY_STATUS |
4983 SERVICE_ENUMERATE_DEPENDENTS);
4986 WARN("Failed to open service (%s): %d\n",
4987 debugstr_w(name), GetLastError());
4991 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4992 sizeof(SERVICE_STATUS_PROCESS), &needed))
4994 WARN("Failed to query service status (%s): %d\n",
4995 debugstr_w(name), GetLastError());
4999 if (ssp.dwCurrentState == SERVICE_STOPPED)
5002 stop_service_dependents(scm, service);
5004 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5005 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5008 CloseServiceHandle(service);
5009 CloseServiceHandle(scm);
5013 return ERROR_SUCCESS;
5016 static UINT ACTION_StopServices( MSIPACKAGE *package )
5021 static const WCHAR query[] = {
5022 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5023 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5025 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5026 if (rc != ERROR_SUCCESS)
5027 return ERROR_SUCCESS;
5029 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5030 msiobj_release(&view->hdr);
5035 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5039 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5041 if (!lstrcmpW(file->File, filename))
5048 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5050 MSIPACKAGE *package = param;
5051 LPWSTR driver, driver_path, ptr;
5052 WCHAR outpath[MAX_PATH];
5053 MSIFILE *driver_file, *setup_file;
5056 UINT r = ERROR_SUCCESS;
5058 static const WCHAR driver_fmt[] = {
5059 'D','r','i','v','e','r','=','%','s',0};
5060 static const WCHAR setup_fmt[] = {
5061 'S','e','t','u','p','=','%','s',0};
5062 static const WCHAR usage_fmt[] = {
5063 'F','i','l','e','U','s','a','g','e','=','1',0};
5065 desc = MSI_RecordGetString(rec, 3);
5067 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5068 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5070 if (!driver_file || !setup_file)
5072 ERR("ODBC Driver entry not found!\n");
5073 return ERROR_FUNCTION_FAILED;
5076 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
5077 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
5078 lstrlenW(usage_fmt) + 1;
5079 driver = msi_alloc(len * sizeof(WCHAR));
5081 return ERROR_OUTOFMEMORY;
5084 lstrcpyW(ptr, desc);
5085 ptr += lstrlenW(ptr) + 1;
5087 sprintfW(ptr, driver_fmt, driver_file->FileName);
5088 ptr += lstrlenW(ptr) + 1;
5090 sprintfW(ptr, setup_fmt, setup_file->FileName);
5091 ptr += lstrlenW(ptr) + 1;
5093 lstrcpyW(ptr, usage_fmt);
5094 ptr += lstrlenW(ptr) + 1;
5097 driver_path = strdupW(driver_file->TargetPath);
5098 ptr = strrchrW(driver_path, '\\');
5099 if (ptr) *ptr = '\0';
5101 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5102 NULL, ODBC_INSTALL_COMPLETE, &usage))
5104 ERR("Failed to install SQL driver!\n");
5105 r = ERROR_FUNCTION_FAILED;
5109 msi_free(driver_path);
5114 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5116 MSIPACKAGE *package = param;
5117 LPWSTR translator, translator_path, ptr;
5118 WCHAR outpath[MAX_PATH];
5119 MSIFILE *translator_file, *setup_file;
5122 UINT r = ERROR_SUCCESS;
5124 static const WCHAR translator_fmt[] = {
5125 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5126 static const WCHAR setup_fmt[] = {
5127 'S','e','t','u','p','=','%','s',0};
5129 desc = MSI_RecordGetString(rec, 3);
5131 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5132 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5134 if (!translator_file || !setup_file)
5136 ERR("ODBC Translator entry not found!\n");
5137 return ERROR_FUNCTION_FAILED;
5140 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
5141 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
5142 translator = msi_alloc(len * sizeof(WCHAR));
5144 return ERROR_OUTOFMEMORY;
5147 lstrcpyW(ptr, desc);
5148 ptr += lstrlenW(ptr) + 1;
5150 sprintfW(ptr, translator_fmt, translator_file->FileName);
5151 ptr += lstrlenW(ptr) + 1;
5153 sprintfW(ptr, setup_fmt, setup_file->FileName);
5154 ptr += lstrlenW(ptr) + 1;
5157 translator_path = strdupW(translator_file->TargetPath);
5158 ptr = strrchrW(translator_path, '\\');
5159 if (ptr) *ptr = '\0';
5161 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5162 NULL, ODBC_INSTALL_COMPLETE, &usage))
5164 ERR("Failed to install SQL translator!\n");
5165 r = ERROR_FUNCTION_FAILED;
5168 msi_free(translator);
5169 msi_free(translator_path);
5174 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5177 LPCWSTR desc, driver;
5178 WORD request = ODBC_ADD_SYS_DSN;
5181 UINT r = ERROR_SUCCESS;
5183 static const WCHAR attrs_fmt[] = {
5184 'D','S','N','=','%','s',0 };
5186 desc = MSI_RecordGetString(rec, 3);
5187 driver = MSI_RecordGetString(rec, 4);
5188 registration = MSI_RecordGetInteger(rec, 5);
5190 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5191 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5193 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
5194 attrs = msi_alloc(len * sizeof(WCHAR));
5196 return ERROR_OUTOFMEMORY;
5198 sprintfW(attrs, attrs_fmt, desc);
5199 attrs[len - 1] = '\0';
5201 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5203 ERR("Failed to install SQL data source!\n");
5204 r = ERROR_FUNCTION_FAILED;
5212 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5217 static const WCHAR driver_query[] = {
5218 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5219 'O','D','B','C','D','r','i','v','e','r',0 };
5221 static const WCHAR translator_query[] = {
5222 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5223 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5225 static const WCHAR source_query[] = {
5226 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5227 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5229 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5230 if (rc != ERROR_SUCCESS)
5231 return ERROR_SUCCESS;
5233 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5234 msiobj_release(&view->hdr);
5236 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5237 if (rc != ERROR_SUCCESS)
5238 return ERROR_SUCCESS;
5240 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5241 msiobj_release(&view->hdr);
5243 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5244 if (rc != ERROR_SUCCESS)
5245 return ERROR_SUCCESS;
5247 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5248 msiobj_release(&view->hdr);
5253 #define ENV_ACT_SETALWAYS 0x1
5254 #define ENV_ACT_SETABSENT 0x2
5255 #define ENV_ACT_REMOVE 0x4
5256 #define ENV_ACT_REMOVEMATCH 0x8
5258 #define ENV_MOD_MACHINE 0x20000000
5259 #define ENV_MOD_APPEND 0x40000000
5260 #define ENV_MOD_PREFIX 0x80000000
5261 #define ENV_MOD_MASK 0xC0000000
5263 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5265 static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5267 LPCWSTR cptr = *name;
5268 LPCWSTR ptr = *value;
5270 static const WCHAR prefix[] = {'[','~',']',0};
5271 static const int prefix_len = 3;
5277 *flags |= ENV_ACT_SETALWAYS;
5278 else if (*cptr == '+')
5279 *flags |= ENV_ACT_SETABSENT;
5280 else if (*cptr == '-')
5281 *flags |= ENV_ACT_REMOVE;
5282 else if (*cptr == '!')
5283 *flags |= ENV_ACT_REMOVEMATCH;
5284 else if (*cptr == '*')
5285 *flags |= ENV_MOD_MACHINE;
5295 ERR("Missing environment variable\n");
5296 return ERROR_FUNCTION_FAILED;
5299 if (!strncmpW(ptr, prefix, prefix_len))
5301 *flags |= ENV_MOD_APPEND;
5302 *value += lstrlenW(prefix);
5304 else if (lstrlenW(*value) >= prefix_len)
5306 ptr += lstrlenW(ptr) - prefix_len;
5307 if (!lstrcmpW(ptr, prefix))
5309 *flags |= ENV_MOD_PREFIX;
5310 /* the "[~]" will be removed by deformat_string */;
5315 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5316 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5317 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5318 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5320 ERR("Invalid flags: %08x\n", *flags);
5321 return ERROR_FUNCTION_FAILED;
5324 return ERROR_SUCCESS;
5327 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5329 MSIPACKAGE *package = param;
5330 LPCWSTR name, value;
5331 LPWSTR data = NULL, newval = NULL;
5332 LPWSTR deformatted = NULL, ptr;
5333 DWORD flags, type, size;
5335 HKEY env = NULL, root;
5336 LPCWSTR environment;
5338 static const WCHAR user_env[] =
5339 {'E','n','v','i','r','o','n','m','e','n','t',0};
5340 static const WCHAR machine_env[] =
5341 {'S','y','s','t','e','m','\\',
5342 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5343 'C','o','n','t','r','o','l','\\',
5344 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5345 'E','n','v','i','r','o','n','m','e','n','t',0};
5346 static const WCHAR semicolon[] = {';',0};
5348 name = MSI_RecordGetString(rec, 2);
5349 value = MSI_RecordGetString(rec, 3);
5351 res = env_set_flags(&name, &value, &flags);
5352 if (res != ERROR_SUCCESS)
5355 deformat_string(package, value, &deformatted);
5358 res = ERROR_OUTOFMEMORY;
5362 value = deformatted;
5364 if (flags & ENV_MOD_MACHINE)
5366 environment = machine_env;
5367 root = HKEY_LOCAL_MACHINE;
5371 environment = user_env;
5372 root = HKEY_CURRENT_USER;
5375 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5376 KEY_ALL_ACCESS, NULL, &env, NULL);
5377 if (res != ERROR_SUCCESS)
5380 if (flags & ENV_ACT_REMOVE)
5381 FIXME("Not removing environment variable on uninstall!\n");
5384 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5385 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
5386 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
5389 if (res != ERROR_FILE_NOT_FOUND)
5391 if (flags & ENV_ACT_SETABSENT)
5393 res = ERROR_SUCCESS;
5397 data = msi_alloc(size);
5401 return ERROR_OUTOFMEMORY;
5404 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5405 if (res != ERROR_SUCCESS)
5408 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5410 res = RegDeleteKeyW(env, name);
5414 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
5415 newval = msi_alloc(size);
5419 res = ERROR_OUTOFMEMORY;
5423 if (!(flags & ENV_MOD_MASK))
5424 lstrcpyW(newval, value);
5427 if (flags & ENV_MOD_PREFIX)
5429 lstrcpyW(newval, value);
5430 lstrcatW(newval, semicolon);
5431 ptr = newval + lstrlenW(value) + 1;
5434 lstrcpyW(ptr, data);
5436 if (flags & ENV_MOD_APPEND)
5438 lstrcatW(newval, semicolon);
5439 lstrcatW(newval, value);
5445 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
5446 newval = msi_alloc(size);
5449 res = ERROR_OUTOFMEMORY;
5453 lstrcpyW(newval, value);
5456 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5457 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
5460 if (env) RegCloseKey(env);
5461 msi_free(deformatted);
5467 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5471 static const WCHAR ExecSeqQuery[] =
5472 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5473 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5474 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5475 if (rc != ERROR_SUCCESS)
5476 return ERROR_SUCCESS;
5478 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5479 msiobj_release(&view->hdr);
5484 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5495 static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5499 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5500 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5502 WARN("Source or dest is directory, not moving\n");
5506 if (options == msidbMoveFileOptionsMove)
5508 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5509 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5512 WARN("MoveFile failed: %d\n", GetLastError());
5518 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5519 ret = CopyFileW(source, dest, FALSE);
5522 WARN("CopyFile failed: %d\n", GetLastError());
5530 static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5533 DWORD dirlen, pathlen;
5535 ptr = strrchrW(wildcard, '\\');
5536 dirlen = ptr - wildcard + 1;
5538 pathlen = dirlen + lstrlenW(filename) + 1;
5539 path = msi_alloc(pathlen * sizeof(WCHAR));
5541 lstrcpynW(path, wildcard, dirlen + 1);
5542 lstrcatW(path, filename);
5547 static void free_file_entry(FILE_LIST *file)
5549 msi_free(file->source);
5550 msi_free(file->dest);
5554 static void free_list(FILE_LIST *list)
5556 while (!list_empty(&list->entry))
5558 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5560 list_remove(&file->entry);
5561 free_file_entry(file);
5565 static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5567 FILE_LIST *new, *file;
5568 LPWSTR ptr, filename;
5571 new = msi_alloc_zero(sizeof(FILE_LIST));
5575 new->source = strdupW(source);
5576 ptr = strrchrW(dest, '\\') + 1;
5577 filename = strrchrW(new->source, '\\') + 1;
5579 new->sourcename = filename;
5582 new->destname = ptr;
5584 new->destname = new->sourcename;
5586 size = (ptr - dest) + lstrlenW(filename) + 1;
5587 new->dest = msi_alloc(size * sizeof(WCHAR));
5590 free_file_entry(new);
5594 lstrcpynW(new->dest, dest, ptr - dest + 1);
5595 lstrcatW(new->dest, filename);
5597 if (list_empty(&files->entry))
5599 list_add_head(&files->entry, &new->entry);
5603 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5605 if (lstrcmpW(source, file->source) < 0)
5607 list_add_before(&file->entry, &new->entry);
5612 list_add_after(&file->entry, &new->entry);
5616 static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
5618 WIN32_FIND_DATAW wfd;
5622 FILE_LIST files, *file;
5625 hfile = FindFirstFileW(source, &wfd);
5626 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5628 list_init(&files.entry);
5630 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5632 if (is_dot_dir(wfd.cFileName)) continue;
5634 path = wildcard_to_file(source, wfd.cFileName);
5641 add_wildcard(&files, path, dest);
5645 /* no files match the wildcard */
5646 if (list_empty(&files.entry))
5649 /* only the first wildcard match gets renamed to dest */
5650 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5651 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5652 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5659 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5661 while (!list_empty(&files.entry))
5663 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5665 msi_move_file(file->source, file->dest, options);
5667 list_remove(&file->entry);
5668 free_file_entry(file);
5679 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5681 MSIPACKAGE *package = param;
5684 LPWSTR destname = NULL;
5685 LPWSTR sourcedir = NULL, destdir = NULL;
5686 LPWSTR source = NULL, dest = NULL;
5689 BOOL ret, wildcards;
5691 static const WCHAR backslash[] = {'\\',0};
5693 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5694 if (!comp || !comp->Enabled ||
5695 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5697 TRACE("Component not set for install, not moving file\n");
5698 return ERROR_SUCCESS;
5701 sourcename = MSI_RecordGetString(rec, 3);
5702 options = MSI_RecordGetInteger(rec, 7);
5704 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5708 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5714 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5717 source = strdupW(sourcedir);
5723 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5724 source = msi_alloc(size * sizeof(WCHAR));
5728 lstrcpyW(source, sourcedir);
5729 if (source[lstrlenW(source) - 1] != '\\')
5730 lstrcatW(source, backslash);
5731 lstrcatW(source, sourcename);
5734 wildcards = strchrW(source, '*') || strchrW(source, '?');
5736 if (MSI_RecordIsNull(rec, 4))
5740 destname = strdupW(sourcename);
5747 destname = strdupW(MSI_RecordGetString(rec, 4));
5749 reduce_to_longfilename(destname);
5754 size = lstrlenW(destname);
5756 size += lstrlenW(destdir) + 2;
5757 dest = msi_alloc(size * sizeof(WCHAR));
5761 lstrcpyW(dest, destdir);
5762 if (dest[lstrlenW(dest) - 1] != '\\')
5763 lstrcatW(dest, backslash);
5766 lstrcatW(dest, destname);
5768 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5770 ret = CreateDirectoryW(destdir, NULL);
5773 WARN("CreateDirectory failed: %d\n", GetLastError());
5774 return ERROR_SUCCESS;
5779 msi_move_file(source, dest, options);
5781 move_files_wildcard(source, dest, options);
5784 msi_free(sourcedir);
5790 return ERROR_SUCCESS;
5793 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5798 static const WCHAR ExecSeqQuery[] =
5799 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5800 '`','M','o','v','e','F','i','l','e','`',0};
5802 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5803 if (rc != ERROR_SUCCESS)
5804 return ERROR_SUCCESS;
5806 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5807 msiobj_release(&view->hdr);
5812 typedef struct tagMSIASSEMBLY
5815 MSICOMPONENT *component;
5816 MSIFEATURE *feature;
5824 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
5826 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
5827 LPVOID pvReserved, HMODULE *phModDll);
5829 static BOOL init_functionpointers(void)
5835 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
5837 hmscoree = LoadLibraryA("mscoree.dll");
5840 WARN("mscoree.dll not available\n");
5844 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
5845 if (!pLoadLibraryShim)
5847 WARN("LoadLibraryShim not available\n");
5848 FreeLibrary(hmscoree);
5852 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
5855 WARN("fusion.dll not available\n");
5856 FreeLibrary(hmscoree);
5860 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
5862 FreeLibrary(hmscoree);
5866 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
5869 IAssemblyCache *cache;
5871 UINT r = ERROR_FUNCTION_FAILED;
5873 TRACE("installing assembly: %s\n", debugstr_w(path));
5875 if (assembly->feature)
5876 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
5878 if (assembly->manifest)
5879 FIXME("Manifest unhandled\n");
5881 if (assembly->application)
5883 FIXME("Assembly should be privately installed\n");
5884 return ERROR_SUCCESS;
5887 if (assembly->attributes == msidbAssemblyAttributesWin32)
5889 FIXME("Win32 assemblies not handled\n");
5890 return ERROR_SUCCESS;
5893 hr = pCreateAssemblyCache(&cache, 0);
5897 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
5899 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
5904 IAssemblyCache_Release(cache);
5908 typedef struct tagASSEMBLY_LIST
5910 MSIPACKAGE *package;
5911 IAssemblyCache *cache;
5912 struct list *assemblies;
5915 typedef struct tagASSEMBLY_NAME
5923 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
5925 ASSEMBLY_NAME *asmname = param;
5926 LPCWSTR name = MSI_RecordGetString(rec, 2);
5927 LPWSTR val = msi_dup_record_field(rec, 3);
5929 static const WCHAR Name[] = {'N','a','m','e',0};
5930 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
5931 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
5932 static const WCHAR PublicKeyToken[] = {
5933 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
5935 if (!strcmpiW(name, Name))
5936 asmname->name = val;
5937 else if (!strcmpiW(name, Version))
5938 asmname->version = val;
5939 else if (!strcmpiW(name, Culture))
5940 asmname->culture = val;
5941 else if (!strcmpiW(name, PublicKeyToken))
5942 asmname->pubkeytoken = val;
5946 return ERROR_SUCCESS;
5949 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
5953 *size = lstrlenW(append) + 1;
5954 *str = msi_alloc((*size) * sizeof(WCHAR));
5955 lstrcpyW(*str, append);
5959 (*size) += lstrlenW(append);
5960 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
5961 lstrcatW(*str, append);
5964 static BOOL check_assembly_installed(MSIDATABASE *db, IAssemblyCache *cache,
5967 ASSEMBLY_INFO asminfo;
5975 static const WCHAR separator[] = {',',' ',0};
5976 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
5977 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
5978 static const WCHAR PublicKeyToken[] = {
5979 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
5980 static const WCHAR query[] = {
5981 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5982 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
5983 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
5984 '=','\'','%','s','\'',0};
5988 ZeroMemory(&name, sizeof(ASSEMBLY_NAME));
5989 ZeroMemory(&asminfo, sizeof(ASSEMBLY_INFO));
5991 r = MSI_OpenQuery(db, &view, query, comp->Component);
5992 if (r != ERROR_SUCCESS)
5993 return ERROR_SUCCESS;
5995 MSI_IterateRecords(view, NULL, parse_assembly_name, &name);
5996 msiobj_release(&view->hdr);
6000 ERR("No assembly name specified!\n");
6004 append_str(&disp, &size, name.name);
6008 append_str(&disp, &size, separator);
6009 append_str(&disp, &size, Version);
6010 append_str(&disp, &size, name.version);
6015 append_str(&disp, &size, separator);
6016 append_str(&disp, &size, Culture);
6017 append_str(&disp, &size, name.culture);
6020 if (name.pubkeytoken)
6022 append_str(&disp, &size, separator);
6023 append_str(&disp, &size, PublicKeyToken);
6024 append_str(&disp, &size, name.pubkeytoken);
6027 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6028 IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE,
6030 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6034 msi_free(name.name);
6035 msi_free(name.version);
6036 msi_free(name.culture);
6037 msi_free(name.pubkeytoken);
6042 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6044 ASSEMBLY_LIST *list = param;
6045 MSIASSEMBLY *assembly;
6047 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6049 return ERROR_OUTOFMEMORY;
6051 assembly->component = get_loaded_component(list->package, MSI_RecordGetString(rec, 1));
6053 if (!assembly->component || !assembly->component->Enabled ||
6054 !(assembly->component->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
6056 TRACE("Component not set for install, not publishing assembly\n");
6058 return ERROR_SUCCESS;
6061 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6062 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6064 if (!assembly->file)
6066 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6067 return ERROR_FUNCTION_FAILED;
6070 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6071 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6072 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6074 if (assembly->application)
6077 DWORD size = sizeof(version)/sizeof(WCHAR);
6079 /* FIXME: we should probably check the manifest file here */
6081 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6082 strcmpW(version, assembly->file->Version) >= 0)
6084 assembly->installed = TRUE;
6088 assembly->installed = check_assembly_installed(list->package->db,
6090 assembly->component);
6092 list_add_head(list->assemblies, &assembly->entry);
6093 return ERROR_SUCCESS;
6096 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6098 IAssemblyCache *cache = NULL;
6104 static const WCHAR query[] =
6105 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6106 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6108 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6109 if (r != ERROR_SUCCESS)
6110 return ERROR_SUCCESS;
6112 hr = pCreateAssemblyCache(&cache, 0);
6114 return ERROR_FUNCTION_FAILED;
6116 list.package = package;
6118 list.assemblies = assemblies;
6120 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6121 msiobj_release(&view->hdr);
6123 IAssemblyCache_Release(cache);
6128 static void free_assemblies(struct list *assemblies)
6130 struct list *item, *cursor;
6132 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6134 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6136 list_remove(&assembly->entry);
6137 msi_free(assembly->application);
6138 msi_free(assembly->manifest);
6143 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6145 MSIASSEMBLY *assembly;
6147 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6149 if (!lstrcmpW(assembly->file->File, file))
6159 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6160 LPWSTR *path, DWORD *attrs, PVOID user)
6162 MSIASSEMBLY *assembly;
6163 WCHAR temppath[MAX_PATH];
6164 struct list *assemblies = user;
6167 if (!find_assembly(assemblies, file, &assembly))
6170 GetTempPathW(MAX_PATH, temppath);
6171 PathAddBackslashW(temppath);
6172 lstrcatW(temppath, assembly->file->FileName);
6174 if (action == MSICABEXTRACT_BEGINEXTRACT)
6176 if (assembly->installed)
6179 *path = strdupW(temppath);
6180 *attrs = assembly->file->Attributes;
6182 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6184 assembly->installed = TRUE;
6186 r = install_assembly(package, assembly, temppath);
6187 if (r != ERROR_SUCCESS)
6188 ERR("Failed to install assembly\n");
6194 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6197 struct list assemblies = LIST_INIT(assemblies);
6198 MSIASSEMBLY *assembly;
6201 if (!init_functionpointers() || !pCreateAssemblyCache)
6202 return ERROR_FUNCTION_FAILED;
6204 r = load_assemblies(package, &assemblies);
6205 if (r != ERROR_SUCCESS)
6208 if (list_empty(&assemblies))
6211 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6214 r = ERROR_OUTOFMEMORY;
6218 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6220 if (assembly->installed && !mi->is_continuous)
6223 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6224 (assembly->file->IsCompressed && !mi->is_extracted))
6228 r = ready_media(package, assembly->file, mi);
6229 if (r != ERROR_SUCCESS)
6231 ERR("Failed to ready media\n");
6236 data.package = package;
6237 data.cb = installassembly_cb;
6238 data.user = &assemblies;
6240 if (assembly->file->IsCompressed &&
6241 !msi_cabextract(package, mi, &data))
6243 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6244 r = ERROR_FUNCTION_FAILED;
6249 if (!assembly->file->IsCompressed)
6251 LPWSTR source = resolve_file_source(package, assembly->file);
6253 r = install_assembly(package, assembly, source);
6254 if (r != ERROR_SUCCESS)
6255 ERR("Failed to install assembly\n");
6260 /* FIXME: write Installer assembly reg values */
6264 free_assemblies(&assemblies);
6268 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6269 LPCSTR action, LPCWSTR table )
6271 static const WCHAR query[] = {
6272 'S','E','L','E','C','T',' ','*',' ',
6273 'F','R','O','M',' ','`','%','s','`',0 };
6274 MSIQUERY *view = NULL;
6278 r = MSI_OpenQuery( package->db, &view, query, table );
6279 if (r == ERROR_SUCCESS)
6281 r = MSI_IterateRecords(view, &count, NULL, package);
6282 msiobj_release(&view->hdr);
6286 FIXME("%s -> %u ignored %s table values\n",
6287 action, count, debugstr_w(table));
6289 return ERROR_SUCCESS;
6292 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6294 TRACE("%p\n", package);
6295 return ERROR_SUCCESS;
6298 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
6300 static const WCHAR table[] =
6301 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
6302 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
6305 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6307 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6308 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6311 static UINT ACTION_BindImage( MSIPACKAGE *package )
6313 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6314 return msi_unimplemented_action_stub( package, "BindImage", table );
6317 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6319 static const WCHAR table[] = {
6320 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
6321 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6324 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6326 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6327 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6330 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
6332 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
6333 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
6336 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6338 static const WCHAR table[] = {
6339 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6340 return msi_unimplemented_action_stub( package, "DeleteServices", table );
6342 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6344 static const WCHAR table[] = {
6345 'P','r','o','d','u','c','t','I','D',0 };
6346 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
6349 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6351 static const WCHAR table[] = {
6352 'E','n','v','i','r','o','n','m','e','n','t',0 };
6353 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
6356 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6358 static const WCHAR table[] = {
6359 'M','s','i','A','s','s','e','m','b','l','y',0 };
6360 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6363 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
6365 static const WCHAR table[] = { 'F','o','n','t',0 };
6366 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
6369 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6371 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6372 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6375 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6377 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6378 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6381 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6383 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6384 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6387 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6389 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6390 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6393 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
6395 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6396 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
6399 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6401 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6402 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6405 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
6407 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6408 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
6411 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6413 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6414 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
6417 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
6419 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6420 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
6423 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
6425 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
6426 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
6429 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
6431 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6432 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
6435 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6437 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6438 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6441 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6443 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6444 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6447 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6449 static const WCHAR table[] = { 'M','I','M','E',0 };
6450 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6453 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6455 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6456 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6459 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
6461 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
6462 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
6465 static const struct _actions StandardActions[] = {
6466 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6467 { szAppSearch, ACTION_AppSearch },
6468 { szBindImage, ACTION_BindImage },
6469 { szCCPSearch, ACTION_CCPSearch },
6470 { szCostFinalize, ACTION_CostFinalize },
6471 { szCostInitialize, ACTION_CostInitialize },
6472 { szCreateFolders, ACTION_CreateFolders },
6473 { szCreateShortcuts, ACTION_CreateShortcuts },
6474 { szDeleteServices, ACTION_DeleteServices },
6475 { szDisableRollback, NULL },
6476 { szDuplicateFiles, ACTION_DuplicateFiles },
6477 { szExecuteAction, ACTION_ExecuteAction },
6478 { szFileCost, ACTION_FileCost },
6479 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6480 { szForceReboot, ACTION_ForceReboot },
6481 { szInstallAdminPackage, NULL },
6482 { szInstallExecute, ACTION_InstallExecute },
6483 { szInstallExecuteAgain, ACTION_InstallExecute },
6484 { szInstallFiles, ACTION_InstallFiles},
6485 { szInstallFinalize, ACTION_InstallFinalize },
6486 { szInstallInitialize, ACTION_InstallInitialize },
6487 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6488 { szInstallValidate, ACTION_InstallValidate },
6489 { szIsolateComponents, ACTION_IsolateComponents },
6490 { szLaunchConditions, ACTION_LaunchConditions },
6491 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6492 { szMoveFiles, ACTION_MoveFiles },
6493 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6494 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6495 { szInstallODBC, ACTION_InstallODBC },
6496 { szInstallServices, ACTION_InstallServices },
6497 { szPatchFiles, ACTION_PatchFiles },
6498 { szProcessComponents, ACTION_ProcessComponents },
6499 { szPublishComponents, ACTION_PublishComponents },
6500 { szPublishFeatures, ACTION_PublishFeatures },
6501 { szPublishProduct, ACTION_PublishProduct },
6502 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6503 { szRegisterComPlus, ACTION_RegisterComPlus},
6504 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6505 { szRegisterFonts, ACTION_RegisterFonts },
6506 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6507 { szRegisterProduct, ACTION_RegisterProduct },
6508 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6509 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6510 { szRegisterUser, ACTION_RegisterUser },
6511 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6512 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6513 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6514 { szRemoveFiles, ACTION_RemoveFiles },
6515 { szRemoveFolders, ACTION_RemoveFolders },
6516 { szRemoveIniValues, ACTION_RemoveIniValues },
6517 { szRemoveODBC, ACTION_RemoveODBC },
6518 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6519 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6520 { szResolveSource, ACTION_ResolveSource },
6521 { szRMCCPSearch, ACTION_RMCCPSearch },
6522 { szScheduleReboot, NULL },
6523 { szSelfRegModules, ACTION_SelfRegModules },
6524 { szSelfUnregModules, ACTION_SelfUnregModules },
6525 { szSetODBCFolders, NULL },
6526 { szStartServices, ACTION_StartServices },
6527 { szStopServices, ACTION_StopServices },
6528 { szUnpublishComponents, ACTION_UnpublishComponents },
6529 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6530 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6531 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6532 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6533 { szUnregisterFonts, ACTION_UnregisterFonts },
6534 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6535 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6536 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6537 { szValidateProductID, ACTION_ValidateProductID },
6538 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6539 { szWriteIniValues, ACTION_WriteIniValues },
6540 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6544 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
6545 UINT* rc, BOOL force )
6551 if (!run && !package->script->CurrentlyScripting)
6556 if (strcmpW(action,szInstallFinalize) == 0 ||
6557 strcmpW(action,szInstallExecute) == 0 ||
6558 strcmpW(action,szInstallExecuteAgain) == 0)
6563 while (StandardActions[i].action != NULL)
6565 if (strcmpW(StandardActions[i].action, action)==0)
6569 ui_actioninfo(package, action, TRUE, 0);
6570 *rc = schedule_action(package,INSTALL_SCRIPT,action);
6571 ui_actioninfo(package, action, FALSE, *rc);
6575 ui_actionstart(package, action);
6576 if (StandardActions[i].handler)
6578 *rc = StandardActions[i].handler(package);
6582 FIXME("unhandled standard action %s\n",debugstr_w(action));
6583 *rc = ERROR_SUCCESS;