2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
51 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
52 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
53 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
54 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc, BOOL force);
57 * consts and values used
59 static const WCHAR c_colon[] = {'C',':','\\',0};
61 static const WCHAR szCreateFolders[] =
62 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
63 static const WCHAR szCostFinalize[] =
64 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
65 const WCHAR szInstallFiles[] =
66 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
67 const WCHAR szDuplicateFiles[] =
68 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
69 static const WCHAR szWriteRegistryValues[] =
70 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
71 'V','a','l','u','e','s',0};
72 static const WCHAR szCostInitialize[] =
73 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
74 static const WCHAR szFileCost[] =
75 {'F','i','l','e','C','o','s','t',0};
76 static const WCHAR szInstallInitialize[] =
77 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
78 static const WCHAR szInstallValidate[] =
79 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
80 static const WCHAR szLaunchConditions[] =
81 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
82 static const WCHAR szProcessComponents[] =
83 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
84 static const WCHAR szRegisterTypeLibraries[] =
85 {'R','e','g','i','s','t','e','r','T','y','p','e',
86 'L','i','b','r','a','r','i','e','s',0};
87 const WCHAR szRegisterClassInfo[] =
88 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
89 const WCHAR szRegisterProgIdInfo[] =
90 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
91 static const WCHAR szCreateShortcuts[] =
92 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
93 static const WCHAR szPublishProduct[] =
94 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
95 static const WCHAR szWriteIniValues[] =
96 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
97 static const WCHAR szSelfRegModules[] =
98 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
99 static const WCHAR szPublishFeatures[] =
100 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
101 static const WCHAR szRegisterProduct[] =
102 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
103 static const WCHAR szInstallExecute[] =
104 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
105 static const WCHAR szInstallExecuteAgain[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
107 'A','g','a','i','n',0};
108 static const WCHAR szInstallFinalize[] =
109 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
110 static const WCHAR szForceReboot[] =
111 {'F','o','r','c','e','R','e','b','o','o','t',0};
112 static const WCHAR szResolveSource[] =
113 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
114 static const WCHAR szAppSearch[] =
115 {'A','p','p','S','e','a','r','c','h',0};
116 static const WCHAR szAllocateRegistrySpace[] =
117 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
118 'S','p','a','c','e',0};
119 static const WCHAR szBindImage[] =
120 {'B','i','n','d','I','m','a','g','e',0};
121 static const WCHAR szCCPSearch[] =
122 {'C','C','P','S','e','a','r','c','h',0};
123 static const WCHAR szDeleteServices[] =
124 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
125 static const WCHAR szDisableRollback[] =
126 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
127 static const WCHAR szExecuteAction[] =
128 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
129 const WCHAR szFindRelatedProducts[] =
130 {'F','i','n','d','R','e','l','a','t','e','d',
131 'P','r','o','d','u','c','t','s',0};
132 static const WCHAR szInstallAdminPackage[] =
133 {'I','n','s','t','a','l','l','A','d','m','i','n',
134 'P','a','c','k','a','g','e',0};
135 static const WCHAR szInstallSFPCatalogFile[] =
136 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
138 static const WCHAR szIsolateComponents[] =
139 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
140 const WCHAR szMigrateFeatureStates[] =
141 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
142 'S','t','a','t','e','s',0};
143 const WCHAR szMoveFiles[] =
144 {'M','o','v','e','F','i','l','e','s',0};
145 static const WCHAR szMsiPublishAssemblies[] =
146 {'M','s','i','P','u','b','l','i','s','h',
147 'A','s','s','e','m','b','l','i','e','s',0};
148 static const WCHAR szMsiUnpublishAssemblies[] =
149 {'M','s','i','U','n','p','u','b','l','i','s','h',
150 'A','s','s','e','m','b','l','i','e','s',0};
151 static const WCHAR szInstallODBC[] =
152 {'I','n','s','t','a','l','l','O','D','B','C',0};
153 static const WCHAR szInstallServices[] =
154 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
155 const WCHAR szPatchFiles[] =
156 {'P','a','t','c','h','F','i','l','e','s',0};
157 static const WCHAR szPublishComponents[] =
158 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
159 static const WCHAR szRegisterComPlus[] =
160 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
161 const WCHAR szRegisterExtensionInfo[] =
162 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
164 static const WCHAR szRegisterFonts[] =
165 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
166 const WCHAR szRegisterMIMEInfo[] =
167 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
168 static const WCHAR szRegisterUser[] =
169 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
170 const WCHAR szRemoveDuplicateFiles[] =
171 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
172 'F','i','l','e','s',0};
173 static const WCHAR szRemoveEnvironmentStrings[] =
174 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
175 'S','t','r','i','n','g','s',0};
176 const WCHAR szRemoveExistingProducts[] =
177 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
178 'P','r','o','d','u','c','t','s',0};
179 const WCHAR szRemoveFiles[] =
180 {'R','e','m','o','v','e','F','i','l','e','s',0};
181 static const WCHAR szRemoveFolders[] =
182 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
183 static const WCHAR szRemoveIniValues[] =
184 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
185 static const WCHAR szRemoveODBC[] =
186 {'R','e','m','o','v','e','O','D','B','C',0};
187 static const WCHAR szRemoveRegistryValues[] =
188 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
189 'V','a','l','u','e','s',0};
190 static const WCHAR szRemoveShortcuts[] =
191 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
192 static const WCHAR szRMCCPSearch[] =
193 {'R','M','C','C','P','S','e','a','r','c','h',0};
194 static const WCHAR szScheduleReboot[] =
195 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
196 static const WCHAR szSelfUnregModules[] =
197 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
198 static const WCHAR szSetODBCFolders[] =
199 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
200 static const WCHAR szStartServices[] =
201 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
202 static const WCHAR szStopServices[] =
203 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szUnpublishComponents[] =
205 {'U','n','p','u','b','l','i','s','h',
206 'C','o','m','p','o','n','e','n','t','s',0};
207 static const WCHAR szUnpublishFeatures[] =
208 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
209 const WCHAR szUnregisterClassInfo[] =
210 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
212 static const WCHAR szUnregisterComPlus[] =
213 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
214 const WCHAR szUnregisterExtensionInfo[] =
215 {'U','n','r','e','g','i','s','t','e','r',
216 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
217 static const WCHAR szUnregisterFonts[] =
218 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
219 const WCHAR szUnregisterMIMEInfo[] =
220 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
221 const WCHAR szUnregisterProgIdInfo[] =
222 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
224 static const WCHAR szUnregisterTypeLibraries[] =
225 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
226 'L','i','b','r','a','r','i','e','s',0};
227 static const WCHAR szValidateProductID[] =
228 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
229 static const WCHAR szWriteEnvironmentStrings[] =
230 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
231 'S','t','r','i','n','g','s',0};
233 /* action handlers */
234 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
238 STANDARDACTIONHANDLER handler;
242 /********************************************************
244 ********************************************************/
246 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
248 static const WCHAR Query_t[] =
249 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
250 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
251 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
252 ' ','\'','%','s','\'',0};
255 row = MSI_QueryGetRecord( package->db, Query_t, action );
258 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
259 msiobj_release(&row->hdr);
262 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
266 static const WCHAR template_s[]=
267 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
269 static const WCHAR template_e[]=
270 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
271 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
273 static const WCHAR format[] =
274 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
278 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
280 sprintfW(message,template_s,timet,action);
282 sprintfW(message,template_e,timet,action,rc);
284 row = MSI_CreateRecord(1);
285 MSI_RecordSetStringW(row,1,message);
287 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
288 msiobj_release(&row->hdr);
291 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
297 LPWSTR prop = NULL, val = NULL;
300 return ERROR_SUCCESS;
312 TRACE("Looking at %s\n",debugstr_w(ptr));
314 ptr2 = strchrW(ptr,'=');
317 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
324 prop = msi_alloc((len+1)*sizeof(WCHAR));
325 memcpy(prop,ptr,len*sizeof(WCHAR));
335 while (*ptr && (quote || (!quote && *ptr!=' ')))
348 val = msi_alloc((len+1)*sizeof(WCHAR));
349 memcpy(val,ptr2,len*sizeof(WCHAR));
352 if (lstrlenW(prop) > 0)
354 TRACE("Found commandline property (%s) = (%s)\n",
355 debugstr_w(prop), debugstr_w(val));
356 MSI_SetPropertyW(package,prop,val);
362 return ERROR_SUCCESS;
366 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
369 LPWSTR p, *ret = NULL;
375 /* count the number of substrings */
376 for ( pc = str, count = 0; pc; count++ )
378 pc = strchrW( pc, sep );
383 /* allocate space for an array of substring pointers and the substrings */
384 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
385 (lstrlenW(str)+1) * sizeof(WCHAR) );
389 /* copy the string and set the pointers */
390 p = (LPWSTR) &ret[count+1];
392 for( count = 0; (ret[count] = p); count++ )
394 p = strchrW( p, sep );
402 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
404 WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
405 LPWSTR prod_code, patch_product;
408 prod_code = msi_dup_property( package, szProductCode );
409 patch_product = msi_get_suminfo_product( patch );
411 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
413 if ( strstrW( patch_product, prod_code ) )
416 ret = ERROR_FUNCTION_FAILED;
418 msi_free( patch_product );
419 msi_free( prod_code );
424 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
425 MSIDATABASE *patch_db, LPCWSTR name )
427 UINT ret = ERROR_FUNCTION_FAILED;
428 IStorage *stg = NULL;
431 TRACE("%p %s\n", package, debugstr_w(name) );
435 ERR("expected a colon in %s\n", debugstr_w(name));
436 return ERROR_FUNCTION_FAILED;
439 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
442 ret = msi_check_transform_applicable( package, stg );
443 if (ret == ERROR_SUCCESS)
444 msi_table_apply_transform( package->db, stg );
446 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
447 IStorage_Release( stg );
450 ERR("failed to open substorage %s\n", debugstr_w(name));
452 return ERROR_SUCCESS;
455 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
457 static const WCHAR szProdCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
458 LPWSTR guid_list, *guids, product_code;
459 UINT i, ret = ERROR_FUNCTION_FAILED;
461 product_code = msi_dup_property( package, szProdCode );
464 /* FIXME: the property ProductCode should be written into the DB somewhere */
465 ERR("no product code to check\n");
466 return ERROR_SUCCESS;
469 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
470 guids = msi_split_string( guid_list, ';' );
471 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
473 if (!lstrcmpW( guids[i], product_code ))
477 msi_free( guid_list );
478 msi_free( product_code );
483 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
486 MSIRECORD *rec = NULL;
491 static const WCHAR szPatch[] = {'P','A','T','C','H',0};
492 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
493 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
494 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
495 '`','S','o','u','r','c','e','`',' ','I','S',' ',
496 'N','O','T',' ','N','U','L','L',0};
498 r = MSI_DatabaseOpenViewW(package->db, query, &view);
499 if (r != ERROR_SUCCESS)
502 r = MSI_ViewExecute(view, 0);
503 if (r != ERROR_SUCCESS)
506 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
508 prop = MSI_RecordGetString(rec, 1);
509 patch = msi_dup_property(package, szPatch);
510 MSI_SetPropertyW(package, prop, patch);
515 if (rec) msiobj_release(&rec->hdr);
516 msiobj_release(&view->hdr);
521 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
524 LPWSTR str, *substorage;
525 UINT i, r = ERROR_SUCCESS;
527 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
529 return ERROR_FUNCTION_FAILED;
531 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
533 TRACE("Patch not applicable\n");
534 return ERROR_SUCCESS;
537 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
539 return ERROR_OUTOFMEMORY;
541 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
542 if (!package->patch->patchcode)
543 return ERROR_OUTOFMEMORY;
545 /* enumerate the substorage */
546 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
547 package->patch->transforms = str;
549 substorage = msi_split_string( str, ';' );
550 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
551 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
553 msi_free( substorage );
554 msiobj_release( &si->hdr );
556 msi_set_media_source_prop(package);
561 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
563 MSIDATABASE *patch_db = NULL;
566 TRACE("%p %s\n", package, debugstr_w( file ) );
569 * We probably want to make sure we only open a patch collection here.
570 * Patch collections (.msp) and databases (.msi) have different GUIDs
571 * but currently MSI_OpenDatabaseW will accept both.
573 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
574 if ( r != ERROR_SUCCESS )
576 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
580 msi_parse_patch_summary( package, patch_db );
583 * There might be a CAB file in the patch package,
584 * so append it to the list of storage to search for streams.
586 append_storage_to_db( package->db, patch_db->storage );
588 msiobj_release( &patch_db->hdr );
590 return ERROR_SUCCESS;
593 /* get the PATCH property, and apply all the patches it specifies */
594 static UINT msi_apply_patches( MSIPACKAGE *package )
596 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
597 LPWSTR patch_list, *patches;
598 UINT i, r = ERROR_SUCCESS;
600 patch_list = msi_dup_property( package, szPatch );
602 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
604 patches = msi_split_string( patch_list, ';' );
605 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
606 r = msi_apply_patch_package( package, patches[i] );
609 msi_free( patch_list );
614 static UINT msi_apply_transforms( MSIPACKAGE *package )
616 static const WCHAR szTransforms[] = {
617 'T','R','A','N','S','F','O','R','M','S',0 };
618 LPWSTR xform_list, *xforms;
619 UINT i, r = ERROR_SUCCESS;
621 xform_list = msi_dup_property( package, szTransforms );
622 xforms = msi_split_string( xform_list, ';' );
624 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
626 if (xforms[i][0] == ':')
627 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
629 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
633 msi_free( xform_list );
638 static BOOL ui_sequence_exists( MSIPACKAGE *package )
643 static const WCHAR ExecSeqQuery [] =
644 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
645 '`','I','n','s','t','a','l','l',
646 'U','I','S','e','q','u','e','n','c','e','`',
647 ' ','W','H','E','R','E',' ',
648 '`','S','e','q','u','e','n','c','e','`',' ',
649 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
650 '`','S','e','q','u','e','n','c','e','`',0};
652 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
653 if (rc == ERROR_SUCCESS)
655 msiobj_release(&view->hdr);
662 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
665 LPWSTR source, check;
668 static const WCHAR szOriginalDatabase[] =
669 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
671 db = msi_dup_property( package, szOriginalDatabase );
673 return ERROR_OUTOFMEMORY;
675 p = strrchrW( db, '\\' );
678 p = strrchrW( db, '/' );
682 return ERROR_SUCCESS;
687 source = msi_alloc( len * sizeof(WCHAR) );
688 lstrcpynW( source, db, len );
690 check = msi_dup_property( package, cszSourceDir );
691 if (!check || replace)
692 MSI_SetPropertyW( package, cszSourceDir, source );
696 check = msi_dup_property( package, cszSOURCEDIR );
697 if (!check || replace)
698 MSI_SetPropertyW( package, cszSOURCEDIR, source );
704 return ERROR_SUCCESS;
707 static UINT msi_set_context(MSIPACKAGE *package)
714 static const WCHAR szOne[] = {'1',0};
715 static const WCHAR szAllUsers[] = {'A','L','L','U','S','E','R','S',0};
717 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
719 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
720 if (r == ERROR_SUCCESS)
723 if (num == 1 || num == 2)
724 package->Context = MSIINSTALLCONTEXT_MACHINE;
727 MSI_SetPropertyW(package, szAllUsers, szOne);
728 return ERROR_SUCCESS;
731 /****************************************************
732 * TOP level entry points
733 *****************************************************/
735 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
736 LPCWSTR szCommandLine )
739 BOOL ui = FALSE, ui_exists;
740 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
741 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
742 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
744 MSI_SetPropertyW(package, szAction, szInstall);
746 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
748 package->script->InWhatSequence = SEQUENCE_INSTALL;
755 dir = strdupW(szPackagePath);
756 p = strrchrW(dir, '\\');
760 file = szPackagePath + (p - dir);
765 dir = msi_alloc(MAX_PATH*sizeof(WCHAR));
766 GetCurrentDirectoryW(MAX_PATH, dir);
767 lstrcatW(dir, cszbs);
768 file = szPackagePath;
771 msi_free( package->PackagePath );
772 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
773 if (!package->PackagePath)
776 return ERROR_OUTOFMEMORY;
779 lstrcpyW(package->PackagePath, dir);
780 lstrcatW(package->PackagePath, file);
783 msi_set_sourcedir_props(package, FALSE);
786 msi_parse_command_line( package, szCommandLine, FALSE );
788 msi_apply_transforms( package );
789 msi_apply_patches( package );
791 /* properties may have been added by a transform */
792 msi_clone_properties( package );
793 msi_set_context( package );
795 if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED )
797 package->script->InWhatSequence |= SEQUENCE_UI;
798 rc = ACTION_ProcessUISequence(package);
800 ui_exists = ui_sequence_exists(package);
801 if (rc == ERROR_SUCCESS || !ui_exists)
803 package->script->InWhatSequence |= SEQUENCE_EXEC;
804 rc = ACTION_ProcessExecSequence(package,ui_exists);
808 rc = ACTION_ProcessExecSequence(package,FALSE);
810 package->script->CurrentlyScripting= FALSE;
812 /* process the ending type action */
813 if (rc == ERROR_SUCCESS)
814 ACTION_PerformActionSequence(package,-1,ui);
815 else if (rc == ERROR_INSTALL_USEREXIT)
816 ACTION_PerformActionSequence(package,-2,ui);
817 else if (rc == ERROR_INSTALL_SUSPEND)
818 ACTION_PerformActionSequence(package,-4,ui);
820 ACTION_PerformActionSequence(package,-3,ui);
822 /* finish up running custom actions */
823 ACTION_FinishCustomActions(package);
828 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
830 UINT rc = ERROR_SUCCESS;
832 static const WCHAR ExecSeqQuery[] =
833 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
834 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
835 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
836 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
838 static const WCHAR UISeqQuery[] =
839 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
840 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
841 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
842 ' ', '=',' ','%','i',0};
845 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
847 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
851 LPCWSTR action, cond;
853 TRACE("Running the actions\n");
855 /* check conditions */
856 cond = MSI_RecordGetString(row,2);
858 /* this is a hack to skip errors in the condition code */
859 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
862 action = MSI_RecordGetString(row,1);
865 ERR("failed to fetch action\n");
866 rc = ERROR_FUNCTION_FAILED;
871 rc = ACTION_PerformUIAction(package,action,-1);
873 rc = ACTION_PerformAction(package,action,-1,FALSE);
875 msiobj_release(&row->hdr);
886 } iterate_action_param;
888 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
890 iterate_action_param *iap = param;
892 LPCWSTR cond, action;
894 action = MSI_RecordGetString(row,1);
897 ERR("Error is retrieving action name\n");
898 return ERROR_FUNCTION_FAILED;
901 /* check conditions */
902 cond = MSI_RecordGetString(row,2);
904 /* this is a hack to skip errors in the condition code */
905 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
907 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
908 return ERROR_SUCCESS;
912 rc = ACTION_PerformUIAction(iap->package,action,-1);
914 rc = ACTION_PerformAction(iap->package,action,-1,FALSE);
916 msi_dialog_check_messages( NULL );
918 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
919 rc = iap->package->CurrentInstallState;
921 if (rc == ERROR_FUNCTION_NOT_CALLED)
924 if (rc != ERROR_SUCCESS)
925 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
930 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
934 static const WCHAR query[] =
935 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
937 ' ','W','H','E','R','E',' ',
938 '`','S','e','q','u','e','n','c','e','`',' ',
939 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
940 '`','S','e','q','u','e','n','c','e','`',0};
941 iterate_action_param iap;
944 * FIXME: probably should be checking UILevel in the
945 * ACTION_PerformUIAction/ACTION_PerformAction
946 * rather than saving the UI level here. Those
947 * two functions can be merged too.
949 iap.package = package;
952 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
954 r = MSI_OpenQuery( package->db, &view, query, szTable );
955 if (r == ERROR_SUCCESS)
957 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
958 msiobj_release(&view->hdr);
964 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
968 static const WCHAR ExecSeqQuery[] =
969 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
970 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
971 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
972 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
973 'O','R','D','E','R',' ', 'B','Y',' ',
974 '`','S','e','q','u','e','n','c','e','`',0 };
976 static const WCHAR IVQuery[] =
977 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
978 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
979 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
980 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
981 ' ','\'', 'I','n','s','t','a','l','l',
982 'V','a','l','i','d','a','t','e','\'', 0};
984 iterate_action_param iap;
986 iap.package = package;
989 if (package->script->ExecuteSequenceRun)
991 TRACE("Execute Sequence already Run\n");
992 return ERROR_SUCCESS;
995 package->script->ExecuteSequenceRun = TRUE;
997 /* get the sequence number */
1000 row = MSI_QueryGetRecord(package->db, IVQuery);
1002 return ERROR_FUNCTION_FAILED;
1003 seq = MSI_RecordGetInteger(row,1);
1004 msiobj_release(&row->hdr);
1007 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
1008 if (rc == ERROR_SUCCESS)
1010 TRACE("Running the actions\n");
1012 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
1013 msiobj_release(&view->hdr);
1019 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1023 static const WCHAR ExecSeqQuery [] =
1024 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1025 '`','I','n','s','t','a','l','l',
1026 'U','I','S','e','q','u','e','n','c','e','`',
1027 ' ','W','H','E','R','E',' ',
1028 '`','S','e','q','u','e','n','c','e','`',' ',
1029 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1030 '`','S','e','q','u','e','n','c','e','`',0};
1031 iterate_action_param iap;
1033 iap.package = package;
1036 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1038 if (rc == ERROR_SUCCESS)
1040 TRACE("Running the actions\n");
1042 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
1043 msiobj_release(&view->hdr);
1049 /********************************************************
1050 * ACTION helper functions and functions that perform the actions
1051 *******************************************************/
1052 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1053 UINT* rc, UINT script, BOOL force )
1058 arc = ACTION_CustomAction(package, action, script, force);
1060 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1069 * A lot of actions are really important even if they don't do anything
1070 * explicit... Lots of properties are set at the beginning of the installation
1071 * CostFinalize does a bunch of work to translate the directories and such
1073 * But until I get write access to the database that is hard, so I am going to
1074 * hack it to see if I can get something to run.
1076 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
1078 UINT rc = ERROR_SUCCESS;
1081 TRACE("Performing action (%s)\n",debugstr_w(action));
1083 handled = ACTION_HandleStandardAction(package, action, &rc, force);
1086 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
1090 WARN("unhandled msi action %s\n",debugstr_w(action));
1091 rc = ERROR_FUNCTION_NOT_CALLED;
1097 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
1099 UINT rc = ERROR_SUCCESS;
1100 BOOL handled = FALSE;
1102 TRACE("Performing action (%s)\n",debugstr_w(action));
1104 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1107 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
1109 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1114 WARN("unhandled msi action %s\n",debugstr_w(action));
1115 rc = ERROR_FUNCTION_NOT_CALLED;
1123 * Actual Action Handlers
1126 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1128 MSIPACKAGE *package = param;
1134 dir = MSI_RecordGetString(row,1);
1137 ERR("Unable to get folder id\n");
1138 return ERROR_SUCCESS;
1141 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1144 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1145 return ERROR_SUCCESS;
1148 TRACE("Folder is %s\n",debugstr_w(full_path));
1151 uirow = MSI_CreateRecord(1);
1152 MSI_RecordSetStringW(uirow,1,full_path);
1153 ui_actiondata(package,szCreateFolders,uirow);
1154 msiobj_release( &uirow->hdr );
1156 if (folder->State == 0)
1157 create_full_pathW(full_path);
1161 msi_free(full_path);
1162 return ERROR_SUCCESS;
1165 /* FIXME: probably should merge this with the above function */
1166 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1168 UINT rc = ERROR_SUCCESS;
1170 LPWSTR install_path;
1172 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
1174 return ERROR_FUNCTION_FAILED;
1176 /* create the path */
1177 if (folder->State == 0)
1179 create_full_pathW(install_path);
1182 msi_free(install_path);
1187 UINT msi_create_component_directories( MSIPACKAGE *package )
1191 /* create all the folders required by the components are going to install */
1192 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1194 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1196 msi_create_directory( package, comp->Directory );
1199 return ERROR_SUCCESS;
1203 * Also we cannot enable/disable components either, so for now I am just going
1204 * to do all the directories for all the components.
1206 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1208 static const WCHAR ExecSeqQuery[] =
1209 {'S','E','L','E','C','T',' ',
1210 '`','D','i','r','e','c','t','o','r','y','_','`',
1211 ' ','F','R','O','M',' ',
1212 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1216 /* create all the empty folders specified in the CreateFolder table */
1217 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1218 if (rc != ERROR_SUCCESS)
1219 return ERROR_SUCCESS;
1221 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1222 msiobj_release(&view->hdr);
1224 msi_create_component_directories( package );
1229 static UINT load_component( MSIRECORD *row, LPVOID param )
1231 MSIPACKAGE *package = param;
1234 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1236 return ERROR_FUNCTION_FAILED;
1238 list_add_tail( &package->components, &comp->entry );
1240 /* fill in the data */
1241 comp->Component = msi_dup_record_field( row, 1 );
1243 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1245 comp->ComponentId = msi_dup_record_field( row, 2 );
1246 comp->Directory = msi_dup_record_field( row, 3 );
1247 comp->Attributes = MSI_RecordGetInteger(row,4);
1248 comp->Condition = msi_dup_record_field( row, 5 );
1249 comp->KeyPath = msi_dup_record_field( row, 6 );
1251 comp->Installed = INSTALLSTATE_UNKNOWN;
1252 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1254 return ERROR_SUCCESS;
1257 static UINT load_all_components( MSIPACKAGE *package )
1259 static const WCHAR query[] = {
1260 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1261 '`','C','o','m','p','o','n','e','n','t','`',0 };
1265 if (!list_empty(&package->components))
1266 return ERROR_SUCCESS;
1268 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1269 if (r != ERROR_SUCCESS)
1272 r = MSI_IterateRecords(view, NULL, load_component, package);
1273 msiobj_release(&view->hdr);
1278 MSIPACKAGE *package;
1279 MSIFEATURE *feature;
1282 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1286 cl = msi_alloc( sizeof (*cl) );
1288 return ERROR_NOT_ENOUGH_MEMORY;
1289 cl->component = comp;
1290 list_add_tail( &feature->Components, &cl->entry );
1292 return ERROR_SUCCESS;
1295 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1299 fl = msi_alloc( sizeof(*fl) );
1301 return ERROR_NOT_ENOUGH_MEMORY;
1302 fl->feature = child;
1303 list_add_tail( &parent->Children, &fl->entry );
1305 return ERROR_SUCCESS;
1308 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1310 _ilfs* ilfs = param;
1314 component = MSI_RecordGetString(row,1);
1316 /* check to see if the component is already loaded */
1317 comp = get_loaded_component( ilfs->package, component );
1320 ERR("unknown component %s\n", debugstr_w(component));
1321 return ERROR_FUNCTION_FAILED;
1324 add_feature_component( ilfs->feature, comp );
1325 comp->Enabled = TRUE;
1327 return ERROR_SUCCESS;
1330 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1332 MSIFEATURE *feature;
1337 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1339 if ( !lstrcmpW( feature->Feature, name ) )
1346 static UINT load_feature(MSIRECORD * row, LPVOID param)
1348 MSIPACKAGE* package = param;
1349 MSIFEATURE* feature;
1350 static const WCHAR Query1[] =
1351 {'S','E','L','E','C','T',' ',
1352 '`','C','o','m','p','o','n','e','n','t','_','`',
1353 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1354 'C','o','m','p','o','n','e','n','t','s','`',' ',
1355 'W','H','E','R','E',' ',
1356 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1361 /* fill in the data */
1363 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1365 return ERROR_NOT_ENOUGH_MEMORY;
1367 list_init( &feature->Children );
1368 list_init( &feature->Components );
1370 feature->Feature = msi_dup_record_field( row, 1 );
1372 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1374 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1375 feature->Title = msi_dup_record_field( row, 3 );
1376 feature->Description = msi_dup_record_field( row, 4 );
1378 if (!MSI_RecordIsNull(row,5))
1379 feature->Display = MSI_RecordGetInteger(row,5);
1381 feature->Level= MSI_RecordGetInteger(row,6);
1382 feature->Directory = msi_dup_record_field( row, 7 );
1383 feature->Attributes = MSI_RecordGetInteger(row,8);
1385 feature->Installed = INSTALLSTATE_UNKNOWN;
1386 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1388 list_add_tail( &package->features, &feature->entry );
1390 /* load feature components */
1392 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1393 if (rc != ERROR_SUCCESS)
1394 return ERROR_SUCCESS;
1396 ilfs.package = package;
1397 ilfs.feature = feature;
1399 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1400 msiobj_release(&view->hdr);
1402 return ERROR_SUCCESS;
1405 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1407 MSIPACKAGE* package = param;
1408 MSIFEATURE *parent, *child;
1410 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1412 return ERROR_FUNCTION_FAILED;
1414 if (!child->Feature_Parent)
1415 return ERROR_SUCCESS;
1417 parent = find_feature_by_name( package, child->Feature_Parent );
1419 return ERROR_FUNCTION_FAILED;
1421 add_feature_child( parent, child );
1422 return ERROR_SUCCESS;
1425 static UINT load_all_features( MSIPACKAGE *package )
1427 static const WCHAR query[] = {
1428 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1429 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1430 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1434 if (!list_empty(&package->features))
1435 return ERROR_SUCCESS;
1437 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1438 if (r != ERROR_SUCCESS)
1441 r = MSI_IterateRecords( view, NULL, load_feature, package );
1442 if (r != ERROR_SUCCESS)
1445 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1446 msiobj_release( &view->hdr );
1451 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1462 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1464 static const WCHAR query[] = {
1465 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1466 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1467 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1468 MSIQUERY *view = NULL;
1469 MSIRECORD *row = NULL;
1472 TRACE("%s\n", debugstr_w(file->File));
1474 r = MSI_OpenQuery(package->db, &view, query, file->File);
1475 if (r != ERROR_SUCCESS)
1478 r = MSI_ViewExecute(view, NULL);
1479 if (r != ERROR_SUCCESS)
1482 r = MSI_ViewFetch(view, &row);
1483 if (r != ERROR_SUCCESS)
1486 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1487 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1488 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1489 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1490 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1493 if (view) msiobj_release(&view->hdr);
1494 if (row) msiobj_release(&row->hdr);
1498 static UINT load_file(MSIRECORD *row, LPVOID param)
1500 MSIPACKAGE* package = param;
1504 /* fill in the data */
1506 file = msi_alloc_zero( sizeof (MSIFILE) );
1508 return ERROR_NOT_ENOUGH_MEMORY;
1510 file->File = msi_dup_record_field( row, 1 );
1512 component = MSI_RecordGetString( row, 2 );
1513 file->Component = get_loaded_component( package, component );
1515 if (!file->Component)
1517 WARN("Component not found: %s\n", debugstr_w(component));
1518 msi_free(file->File);
1520 return ERROR_SUCCESS;
1523 file->FileName = msi_dup_record_field( row, 3 );
1524 reduce_to_longfilename( file->FileName );
1526 file->ShortName = msi_dup_record_field( row, 3 );
1527 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1529 file->FileSize = MSI_RecordGetInteger( row, 4 );
1530 file->Version = msi_dup_record_field( row, 5 );
1531 file->Language = msi_dup_record_field( row, 6 );
1532 file->Attributes = MSI_RecordGetInteger( row, 7 );
1533 file->Sequence = MSI_RecordGetInteger( row, 8 );
1535 file->state = msifs_invalid;
1537 /* if the compressed bits are not set in the file attributes,
1538 * then read the information from the package word count property
1540 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1542 file->IsCompressed = FALSE;
1544 else if (file->Attributes &
1545 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1547 file->IsCompressed = TRUE;
1549 else if (file->Attributes & msidbFileAttributesNoncompressed)
1551 file->IsCompressed = FALSE;
1555 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1558 load_file_hash(package, file);
1560 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1562 list_add_tail( &package->files, &file->entry );
1564 return ERROR_SUCCESS;
1567 static UINT load_all_files(MSIPACKAGE *package)
1571 static const WCHAR Query[] =
1572 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1573 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1574 '`','S','e','q','u','e','n','c','e','`', 0};
1576 if (!list_empty(&package->files))
1577 return ERROR_SUCCESS;
1579 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1580 if (rc != ERROR_SUCCESS)
1581 return ERROR_SUCCESS;
1583 rc = MSI_IterateRecords(view, NULL, load_file, package);
1584 msiobj_release(&view->hdr);
1586 return ERROR_SUCCESS;
1589 static UINT load_folder( MSIRECORD *row, LPVOID param )
1591 MSIPACKAGE *package = param;
1592 static const WCHAR szDot[] = { '.',0 };
1593 static WCHAR szEmpty[] = { 0 };
1594 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1597 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1599 return ERROR_NOT_ENOUGH_MEMORY;
1601 folder->Directory = msi_dup_record_field( row, 1 );
1603 TRACE("%s\n", debugstr_w(folder->Directory));
1605 p = msi_dup_record_field(row, 3);
1607 /* split src and target dir */
1609 src_short = folder_split_path( p, ':' );
1611 /* split the long and short paths */
1612 tgt_long = folder_split_path( tgt_short, '|' );
1613 src_long = folder_split_path( src_short, '|' );
1615 /* check for no-op dirs */
1616 if (!lstrcmpW(szDot, tgt_short))
1617 tgt_short = szEmpty;
1618 if (!lstrcmpW(szDot, src_short))
1619 src_short = szEmpty;
1622 tgt_long = tgt_short;
1625 src_short = tgt_short;
1626 src_long = tgt_long;
1630 src_long = src_short;
1632 /* FIXME: use the target short path too */
1633 folder->TargetDefault = strdupW(tgt_long);
1634 folder->SourceShortPath = strdupW(src_short);
1635 folder->SourceLongPath = strdupW(src_long);
1638 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1639 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1640 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1642 folder->Parent = msi_dup_record_field( row, 2 );
1644 folder->Property = msi_dup_property( package, folder->Directory );
1646 list_add_tail( &package->folders, &folder->entry );
1648 TRACE("returning %p\n", folder);
1650 return ERROR_SUCCESS;
1653 static UINT load_all_folders( MSIPACKAGE *package )
1655 static const WCHAR query[] = {
1656 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1657 '`','D','i','r','e','c','t','o','r','y','`',0 };
1661 if (!list_empty(&package->folders))
1662 return ERROR_SUCCESS;
1664 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1665 if (r != ERROR_SUCCESS)
1668 r = MSI_IterateRecords(view, NULL, load_folder, package);
1669 msiobj_release(&view->hdr);
1674 * I am not doing any of the costing functionality yet.
1675 * Mostly looking at doing the Component and Feature loading
1677 * The native MSI does A LOT of modification to tables here. Mostly adding
1678 * a lot of temporary columns to the Feature and Component tables.
1680 * note: Native msi also tracks the short filename. But I am only going to
1681 * track the long ones. Also looking at this directory table
1682 * it appears that the directory table does not get the parents
1683 * resolved base on property only based on their entries in the
1686 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1688 static const WCHAR szCosting[] =
1689 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1690 static const WCHAR szZero[] = { '0', 0 };
1692 MSI_SetPropertyW(package, szCosting, szZero);
1693 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1695 load_all_folders( package );
1696 load_all_components( package );
1697 load_all_features( package );
1698 load_all_files( package );
1700 return ERROR_SUCCESS;
1703 static UINT execute_script(MSIPACKAGE *package, UINT script )
1706 UINT rc = ERROR_SUCCESS;
1708 TRACE("Executing Script %i\n",script);
1710 if (!package->script)
1712 ERR("no script!\n");
1713 return ERROR_FUNCTION_FAILED;
1716 for (i = 0; i < package->script->ActionCount[script]; i++)
1719 action = package->script->Actions[script][i];
1720 ui_actionstart(package, action);
1721 TRACE("Executing Action (%s)\n",debugstr_w(action));
1722 rc = ACTION_PerformAction(package, action, script, TRUE);
1723 if (rc != ERROR_SUCCESS)
1726 msi_free_action_script(package, script);
1730 static UINT ACTION_FileCost(MSIPACKAGE *package)
1732 return ERROR_SUCCESS;
1735 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1741 state = MsiQueryProductStateW(package->ProductCode);
1743 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1745 if (!comp->ComponentId)
1748 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1749 comp->Installed = INSTALLSTATE_ABSENT;
1752 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1753 package->Context, comp->ComponentId,
1755 if (r != ERROR_SUCCESS)
1756 comp->Installed = INSTALLSTATE_ABSENT;
1761 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1763 MSIFEATURE *feature;
1766 state = MsiQueryProductStateW(package->ProductCode);
1768 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1770 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1771 feature->Installed = INSTALLSTATE_ABSENT;
1774 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1780 static BOOL process_state_property(MSIPACKAGE* package, int level,
1781 LPCWSTR property, INSTALLSTATE state)
1783 static const WCHAR all[]={'A','L','L',0};
1784 static const WCHAR remove[] = {'R','E','M','O','V','E',0};
1786 MSIFEATURE *feature;
1788 override = msi_dup_property( package, property );
1792 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1794 if (lstrcmpW(property, remove) &&
1795 (feature->Level <= 0 || feature->Level > level))
1798 if (strcmpiW(override,all)==0)
1799 msi_feature_set_state(package, feature, state);
1802 LPWSTR ptr = override;
1803 LPWSTR ptr2 = strchrW(override,',');
1807 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1808 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1810 msi_feature_set_state(package, feature, state);
1816 ptr2 = strchrW(ptr,',');
1828 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1831 static const WCHAR szlevel[] =
1832 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1833 static const WCHAR szAddLocal[] =
1834 {'A','D','D','L','O','C','A','L',0};
1835 static const WCHAR szAddSource[] =
1836 {'A','D','D','S','O','U','R','C','E',0};
1837 static const WCHAR szRemove[] =
1838 {'R','E','M','O','V','E',0};
1839 static const WCHAR szReinstall[] =
1840 {'R','E','I','N','S','T','A','L','L',0};
1841 BOOL override = FALSE;
1842 MSICOMPONENT* component;
1843 MSIFEATURE *feature;
1846 /* I do not know if this is where it should happen.. but */
1848 TRACE("Checking Install Level\n");
1850 level = msi_get_property_int(package, szlevel, 1);
1852 /* ok here is the _real_ rub
1853 * all these activation/deactivation things happen in order and things
1854 * later on the list override things earlier on the list.
1855 * 1) INSTALLLEVEL processing
1865 * 11) FILEADDDEFAULT
1867 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1868 * REMOVE are the big ones, since we don't handle administrative installs
1871 override |= process_state_property(package, level, szAddLocal, INSTALLSTATE_LOCAL);
1872 override |= process_state_property(package, level, szRemove, INSTALLSTATE_ABSENT);
1873 override |= process_state_property(package, level, szAddSource, INSTALLSTATE_SOURCE);
1874 override |= process_state_property(package, level, szReinstall, INSTALLSTATE_LOCAL);
1878 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1880 BOOL feature_state = ((feature->Level > 0) &&
1881 (feature->Level <= level));
1883 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1885 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1886 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1887 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1888 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1890 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1894 /* disable child features of unselected parent features */
1895 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1899 if (feature->Level > 0 && feature->Level <= level)
1902 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1903 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1908 /* set the Preselected Property */
1909 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1910 static const WCHAR szOne[] = { '1', 0 };
1912 MSI_SetPropertyW(package,szPreselected,szOne);
1916 * now we want to enable or disable components base on feature
1919 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1923 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1924 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1926 if (!feature->Level)
1929 /* features with components that have compressed files are made local */
1930 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1932 if (cl->component->Enabled &&
1933 cl->component->ForceLocalState &&
1934 feature->Action == INSTALLSTATE_SOURCE)
1936 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1941 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1943 component = cl->component;
1945 if (!component->Enabled)
1948 switch (feature->Action)
1950 case INSTALLSTATE_ABSENT:
1951 component->anyAbsent = 1;
1953 case INSTALLSTATE_ADVERTISED:
1954 component->hasAdvertiseFeature = 1;
1956 case INSTALLSTATE_SOURCE:
1957 component->hasSourceFeature = 1;
1959 case INSTALLSTATE_LOCAL:
1960 component->hasLocalFeature = 1;
1962 case INSTALLSTATE_DEFAULT:
1963 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1964 component->hasAdvertiseFeature = 1;
1965 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1966 component->hasSourceFeature = 1;
1968 component->hasLocalFeature = 1;
1976 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1978 /* if the component isn't enabled, leave it alone */
1979 if (!component->Enabled)
1982 /* check if it's local or source */
1983 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1984 (component->hasLocalFeature || component->hasSourceFeature))
1986 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1987 !component->ForceLocalState)
1988 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1990 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1994 /* if any feature is local, the component must be local too */
1995 if (component->hasLocalFeature)
1997 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2001 if (component->hasSourceFeature)
2003 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
2007 if (component->hasAdvertiseFeature)
2009 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
2013 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2014 if (component->anyAbsent)
2015 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
2018 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2020 if (component->Action == INSTALLSTATE_DEFAULT)
2022 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2023 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2026 TRACE("Result: Component %s (Installed %i, Action %i)\n",
2027 debugstr_w(component->Component), component->Installed, component->Action);
2031 return ERROR_SUCCESS;
2034 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2036 MSIPACKAGE *package = param;
2041 name = MSI_RecordGetString(row,1);
2043 f = get_loaded_folder(package, name);
2044 if (!f) return ERROR_SUCCESS;
2046 /* reset the ResolvedTarget */
2047 msi_free(f->ResolvedTarget);
2048 f->ResolvedTarget = NULL;
2050 /* This helper function now does ALL the work */
2051 TRACE("Dir %s ...\n",debugstr_w(name));
2052 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
2053 TRACE("resolves to %s\n",debugstr_w(path));
2056 return ERROR_SUCCESS;
2059 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2061 MSIPACKAGE *package = param;
2063 MSIFEATURE *feature;
2065 name = MSI_RecordGetString( row, 1 );
2067 feature = get_loaded_feature( package, name );
2069 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2073 Condition = MSI_RecordGetString(row,3);
2075 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2077 int level = MSI_RecordGetInteger(row,2);
2078 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2079 feature->Level = level;
2082 return ERROR_SUCCESS;
2085 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
2087 static const WCHAR name_fmt[] =
2088 {'%','u','.','%','u','.','%','u','.','%','u',0};
2089 static const WCHAR name[] = {'\\',0};
2090 VS_FIXEDFILEINFO *lpVer;
2091 WCHAR filever[0x100];
2097 TRACE("%s\n", debugstr_w(filename));
2099 versize = GetFileVersionInfoSizeW( filename, &handle );
2103 version = msi_alloc( versize );
2104 GetFileVersionInfoW( filename, 0, versize, version );
2106 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
2108 msi_free( version );
2112 sprintfW( filever, name_fmt,
2113 HIWORD(lpVer->dwFileVersionMS),
2114 LOWORD(lpVer->dwFileVersionMS),
2115 HIWORD(lpVer->dwFileVersionLS),
2116 LOWORD(lpVer->dwFileVersionLS));
2118 msi_free( version );
2120 return strdupW( filever );
2123 static UINT msi_check_file_install_states( MSIPACKAGE *package )
2125 LPWSTR file_version;
2128 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2130 MSICOMPONENT* comp = file->Component;
2136 if (file->IsCompressed)
2137 comp->ForceLocalState = TRUE;
2139 /* calculate target */
2140 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2142 msi_free(file->TargetPath);
2144 TRACE("file %s is named %s\n",
2145 debugstr_w(file->File), debugstr_w(file->FileName));
2147 file->TargetPath = build_directory_name(2, p, file->FileName);
2151 TRACE("file %s resolves to %s\n",
2152 debugstr_w(file->File), debugstr_w(file->TargetPath));
2154 /* don't check files of components that aren't installed */
2155 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2156 comp->Installed == INSTALLSTATE_ABSENT)
2158 file->state = msifs_missing; /* assume files are missing */
2162 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2164 file->state = msifs_missing;
2165 comp->Cost += file->FileSize;
2169 if (file->Version &&
2170 (file_version = msi_get_disk_file_version( file->TargetPath )))
2172 TRACE("new %s old %s\n", debugstr_w(file->Version),
2173 debugstr_w(file_version));
2174 /* FIXME: seems like a bad way to compare version numbers */
2175 if (lstrcmpiW(file_version, file->Version)<0)
2177 file->state = msifs_overwrite;
2178 comp->Cost += file->FileSize;
2181 file->state = msifs_present;
2182 msi_free( file_version );
2185 file->state = msifs_present;
2188 return ERROR_SUCCESS;
2192 * A lot is done in this function aside from just the costing.
2193 * The costing needs to be implemented at some point but for now I am going
2194 * to focus on the directory building
2197 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2199 static const WCHAR ExecSeqQuery[] =
2200 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2201 '`','D','i','r','e','c','t','o','r','y','`',0};
2202 static const WCHAR ConditionQuery[] =
2203 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2204 '`','C','o','n','d','i','t','i','o','n','`',0};
2205 static const WCHAR szCosting[] =
2206 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2207 static const WCHAR szlevel[] =
2208 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2209 static const WCHAR szOutOfDiskSpace[] =
2210 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2211 static const WCHAR szOne[] = { '1', 0 };
2212 static const WCHAR szZero[] = { '0', 0 };
2218 TRACE("Building Directory properties\n");
2220 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2221 if (rc == ERROR_SUCCESS)
2223 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2225 msiobj_release(&view->hdr);
2228 /* read components states from the registry */
2229 ACTION_GetComponentInstallStates(package);
2230 ACTION_GetFeatureInstallStates(package);
2232 TRACE("File calculations\n");
2233 msi_check_file_install_states( package );
2235 TRACE("Evaluating Condition Table\n");
2237 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2238 if (rc == ERROR_SUCCESS)
2240 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2242 msiobj_release(&view->hdr);
2245 TRACE("Enabling or Disabling Components\n");
2246 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2248 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2250 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2251 comp->Enabled = FALSE;
2254 comp->Enabled = TRUE;
2257 MSI_SetPropertyW(package,szCosting,szOne);
2258 /* set default run level if not set */
2259 level = msi_dup_property( package, szlevel );
2261 MSI_SetPropertyW(package,szlevel, szOne);
2264 /* FIXME: check volume disk space */
2265 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2267 return MSI_SetFeatureStates(package);
2270 /* OK this value is "interpreted" and then formatted based on the
2271 first few characters */
2272 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2277 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2283 LPWSTR deformated = NULL;
2286 deformat_string(package, &value[2], &deformated);
2288 /* binary value type */
2292 *size = (strlenW(ptr)/2)+1;
2294 *size = strlenW(ptr)/2;
2296 data = msi_alloc(*size);
2302 /* if uneven pad with a zero in front */
2308 data[count] = (BYTE)strtol(byte,NULL,0);
2310 TRACE("Uneven byte count\n");
2318 data[count] = (BYTE)strtol(byte,NULL,0);
2321 msi_free(deformated);
2323 TRACE("Data %i bytes(%i)\n",*size,count);
2330 deformat_string(package, &value[1], &deformated);
2333 *size = sizeof(DWORD);
2334 data = msi_alloc(*size);
2340 if ( (*p < '0') || (*p > '9') )
2346 if (deformated[0] == '-')
2349 TRACE("DWORD %i\n",*(LPDWORD)data);
2351 msi_free(deformated);
2356 static const WCHAR szMulti[] = {'[','~',']',0};
2365 *type=REG_EXPAND_SZ;
2373 if (strstrW(value,szMulti))
2374 *type = REG_MULTI_SZ;
2376 /* remove initial delimiter */
2377 if (!strncmpW(value, szMulti, 3))
2380 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2382 /* add double NULL terminator */
2383 if (*type == REG_MULTI_SZ)
2385 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2386 data = msi_realloc_zero(data, *size);
2392 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2394 MSIPACKAGE *package = param;
2395 static const WCHAR szHCR[] =
2396 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2397 'R','O','O','T','\\',0};
2398 static const WCHAR szHCU[] =
2399 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2400 'U','S','E','R','\\',0};
2401 static const WCHAR szHLM[] =
2402 {'H','K','E','Y','_','L','O','C','A','L','_',
2403 'M','A','C','H','I','N','E','\\',0};
2404 static const WCHAR szHU[] =
2405 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2407 LPSTR value_data = NULL;
2408 HKEY root_key, hkey;
2411 LPCWSTR szRoot, component, name, key, value;
2416 BOOL check_first = FALSE;
2419 ui_progress(package,2,0,0,0);
2426 component = MSI_RecordGetString(row, 6);
2427 comp = get_loaded_component(package,component);
2429 return ERROR_SUCCESS;
2431 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2433 TRACE("Skipping write due to disabled component %s\n",
2434 debugstr_w(component));
2436 comp->Action = comp->Installed;
2438 return ERROR_SUCCESS;
2441 comp->Action = INSTALLSTATE_LOCAL;
2443 name = MSI_RecordGetString(row, 4);
2444 if( MSI_RecordIsNull(row,5) && name )
2446 /* null values can have special meanings */
2447 if (name[0]=='-' && name[1] == 0)
2448 return ERROR_SUCCESS;
2449 else if ((name[0]=='+' && name[1] == 0) ||
2450 (name[0] == '*' && name[1] == 0))
2455 root = MSI_RecordGetInteger(row,2);
2456 key = MSI_RecordGetString(row, 3);
2458 /* get the root key */
2463 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2464 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2465 if (all_users && all_users[0] == '1')
2467 root_key = HKEY_LOCAL_MACHINE;
2472 root_key = HKEY_CURRENT_USER;
2475 msi_free(all_users);
2478 case 0: root_key = HKEY_CLASSES_ROOT;
2481 case 1: root_key = HKEY_CURRENT_USER;
2484 case 2: root_key = HKEY_LOCAL_MACHINE;
2487 case 3: root_key = HKEY_USERS;
2491 ERR("Unknown root %i\n",root);
2497 return ERROR_SUCCESS;
2499 deformat_string(package, key , &deformated);
2500 size = strlenW(deformated) + strlenW(szRoot) + 1;
2501 uikey = msi_alloc(size*sizeof(WCHAR));
2502 strcpyW(uikey,szRoot);
2503 strcatW(uikey,deformated);
2505 if (RegCreateKeyW( root_key, deformated, &hkey))
2507 ERR("Could not create key %s\n",debugstr_w(deformated));
2508 msi_free(deformated);
2510 return ERROR_SUCCESS;
2512 msi_free(deformated);
2514 value = MSI_RecordGetString(row,5);
2516 value_data = parse_value(package, value, &type, &size);
2519 static const WCHAR szEmpty[] = {0};
2520 value_data = (LPSTR)strdupW(szEmpty);
2521 size = sizeof(szEmpty);
2525 deformat_string(package, name, &deformated);
2529 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2531 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2536 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2537 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2539 TRACE("value %s of %s checked already exists\n",
2540 debugstr_w(deformated), debugstr_w(uikey));
2544 TRACE("Checked and setting value %s of %s\n",
2545 debugstr_w(deformated), debugstr_w(uikey));
2546 if (deformated || size)
2547 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2552 uirow = MSI_CreateRecord(3);
2553 MSI_RecordSetStringW(uirow,2,deformated);
2554 MSI_RecordSetStringW(uirow,1,uikey);
2557 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2559 MSI_RecordSetStringW(uirow,3,value);
2561 ui_actiondata(package,szWriteRegistryValues,uirow);
2562 msiobj_release( &uirow->hdr );
2564 msi_free(value_data);
2565 msi_free(deformated);
2568 return ERROR_SUCCESS;
2571 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2575 static const WCHAR ExecSeqQuery[] =
2576 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2577 '`','R','e','g','i','s','t','r','y','`',0 };
2579 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2580 if (rc != ERROR_SUCCESS)
2581 return ERROR_SUCCESS;
2583 /* increment progress bar each time action data is sent */
2584 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2586 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2588 msiobj_release(&view->hdr);
2592 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2594 package->script->CurrentlyScripting = TRUE;
2596 return ERROR_SUCCESS;
2600 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2605 static const WCHAR q1[]=
2606 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2607 '`','R','e','g','i','s','t','r','y','`',0};
2610 MSIFEATURE *feature;
2613 TRACE("InstallValidate\n");
2615 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2616 if (rc == ERROR_SUCCESS)
2618 MSI_IterateRecords( view, &progress, NULL, package );
2619 msiobj_release( &view->hdr );
2620 total += progress * REG_PROGRESS_VALUE;
2623 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2624 total += COMPONENT_PROGRESS_VALUE;
2626 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2627 total += file->FileSize;
2629 ui_progress(package,0,total,0,0);
2631 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2633 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2634 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2635 feature->ActionRequest);
2638 return ERROR_SUCCESS;
2641 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2643 MSIPACKAGE* package = param;
2644 LPCWSTR cond = NULL;
2645 LPCWSTR message = NULL;
2648 static const WCHAR title[]=
2649 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2651 cond = MSI_RecordGetString(row,1);
2653 r = MSI_EvaluateConditionW(package,cond);
2654 if (r == MSICONDITION_FALSE)
2656 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2659 message = MSI_RecordGetString(row,2);
2660 deformat_string(package,message,&deformated);
2661 MessageBoxW(NULL,deformated,title,MB_OK);
2662 msi_free(deformated);
2665 return ERROR_INSTALL_FAILURE;
2668 return ERROR_SUCCESS;
2671 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2674 MSIQUERY * view = NULL;
2675 static const WCHAR ExecSeqQuery[] =
2676 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2677 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2679 TRACE("Checking launch conditions\n");
2681 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2682 if (rc != ERROR_SUCCESS)
2683 return ERROR_SUCCESS;
2685 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2686 msiobj_release(&view->hdr);
2691 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2695 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2697 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2699 MSIRECORD * row = 0;
2701 LPWSTR deformated,buffer,deformated_name;
2703 static const WCHAR ExecSeqQuery[] =
2704 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2705 '`','R','e','g','i','s','t','r','y','`',' ',
2706 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2707 ' ','=',' ' ,'\'','%','s','\'',0 };
2708 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2709 static const WCHAR fmt2[]=
2710 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2712 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2716 root = MSI_RecordGetInteger(row,2);
2717 key = MSI_RecordGetString(row, 3);
2718 name = MSI_RecordGetString(row, 4);
2719 deformat_string(package, key , &deformated);
2720 deformat_string(package, name, &deformated_name);
2722 len = strlenW(deformated) + 6;
2723 if (deformated_name)
2724 len+=strlenW(deformated_name);
2726 buffer = msi_alloc( len *sizeof(WCHAR));
2728 if (deformated_name)
2729 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2731 sprintfW(buffer,fmt,root,deformated);
2733 msi_free(deformated);
2734 msi_free(deformated_name);
2735 msiobj_release(&row->hdr);
2739 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2741 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2746 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2749 return strdupW( file->TargetPath );
2754 static HKEY openSharedDLLsKey(void)
2757 static const WCHAR path[] =
2758 {'S','o','f','t','w','a','r','e','\\',
2759 'M','i','c','r','o','s','o','f','t','\\',
2760 'W','i','n','d','o','w','s','\\',
2761 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2762 'S','h','a','r','e','d','D','L','L','s',0};
2764 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2768 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2773 DWORD sz = sizeof(count);
2776 hkey = openSharedDLLsKey();
2777 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2778 if (rc != ERROR_SUCCESS)
2784 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2788 hkey = openSharedDLLsKey();
2790 msi_reg_set_val_dword( hkey, path, count );
2792 RegDeleteValueW(hkey,path);
2798 * Return TRUE if the count should be written out and FALSE if not
2800 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2802 MSIFEATURE *feature;
2806 /* only refcount DLLs */
2807 if (comp->KeyPath == NULL ||
2808 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2809 comp->Attributes & msidbComponentAttributesODBCDataSource)
2813 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2814 write = (count > 0);
2816 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2820 /* increment counts */
2821 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2825 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2828 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2830 if ( cl->component == comp )
2835 /* decrement counts */
2836 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2840 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2843 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2845 if ( cl->component == comp )
2850 /* ref count all the files in the component */
2855 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2857 if (file->Component == comp)
2858 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2862 /* add a count for permanent */
2863 if (comp->Attributes & msidbComponentAttributesPermanent)
2866 comp->RefCount = count;
2869 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2872 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2874 WCHAR squished_pc[GUID_SIZE];
2875 WCHAR squished_cc[GUID_SIZE];
2882 squash_guid(package->ProductCode,squished_pc);
2883 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2885 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2889 ui_progress(package,2,0,0,0);
2890 if (!comp->ComponentId)
2893 squash_guid(comp->ComponentId,squished_cc);
2895 msi_free(comp->FullKeypath);
2896 comp->FullKeypath = resolve_keypath( package, comp );
2898 ACTION_RefCountComponent( package, comp );
2900 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2901 debugstr_w(comp->Component),
2902 debugstr_w(squished_cc),
2903 debugstr_w(comp->FullKeypath),
2906 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL) ||
2907 ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE))
2909 if (!comp->FullKeypath)
2912 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2913 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2916 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2919 if (rc != ERROR_SUCCESS)
2922 if (comp->Attributes & msidbComponentAttributesPermanent)
2924 static const WCHAR szPermKey[] =
2925 { '0','0','0','0','0','0','0','0','0','0','0','0',
2926 '0','0','0','0','0','0','0','0','0','0','0','0',
2927 '0','0','0','0','0','0','0','0',0 };
2929 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2932 if (comp->Action == INSTALLSTATE_LOCAL)
2933 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2939 WCHAR source[MAX_PATH];
2940 WCHAR base[MAX_PATH];
2943 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2944 static const WCHAR query[] = {
2945 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2946 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2947 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2948 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2949 '`','D','i','s','k','I','d','`',0};
2951 file = get_loaded_file(package, comp->KeyPath);
2955 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2956 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2957 ptr2 = strrchrW(source, '\\') + 1;
2958 msiobj_release(&row->hdr);
2960 lstrcpyW(base, package->PackagePath);
2961 ptr = strrchrW(base, '\\');
2964 sourcepath = resolve_file_source(package, file);
2965 ptr = sourcepath + lstrlenW(base);
2966 lstrcpyW(ptr2, ptr);
2967 msi_free(sourcepath);
2969 msi_reg_set_val_str(hkey, squished_pc, source);
2973 else if (ACTION_VerifyComponentForAction(comp, INSTALLSTATE_ABSENT))
2975 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2976 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2978 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2982 uirow = MSI_CreateRecord(3);
2983 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2984 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2985 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2986 ui_actiondata(package,szProcessComponents,uirow);
2987 msiobj_release( &uirow->hdr );
2990 return ERROR_SUCCESS;
3001 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3002 LPWSTR lpszName, LONG_PTR lParam)
3005 typelib_struct *tl_struct = (typelib_struct*) lParam;
3006 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3010 if (!IS_INTRESOURCE(lpszName))
3012 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3016 sz = strlenW(tl_struct->source)+4;
3017 sz *= sizeof(WCHAR);
3019 if ((INT_PTR)lpszName == 1)
3020 tl_struct->path = strdupW(tl_struct->source);
3023 tl_struct->path = msi_alloc(sz);
3024 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3027 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3028 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3031 msi_free(tl_struct->path);
3032 tl_struct->path = NULL;
3037 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3038 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3040 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3044 msi_free(tl_struct->path);
3045 tl_struct->path = NULL;
3047 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3048 ITypeLib_Release(tl_struct->ptLib);
3053 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3055 MSIPACKAGE* package = param;
3059 typelib_struct tl_struct;
3064 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
3066 component = MSI_RecordGetString(row,3);
3067 comp = get_loaded_component(package,component);
3069 return ERROR_SUCCESS;
3071 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3073 TRACE("Skipping typelib reg due to disabled component\n");
3075 comp->Action = comp->Installed;
3077 return ERROR_SUCCESS;
3080 comp->Action = INSTALLSTATE_LOCAL;
3082 file = get_loaded_file( package, comp->KeyPath );
3084 return ERROR_SUCCESS;
3086 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3090 guid = MSI_RecordGetString(row,1);
3091 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
3092 tl_struct.source = strdupW( file->TargetPath );
3093 tl_struct.path = NULL;
3095 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3096 (LONG_PTR)&tl_struct);
3104 helpid = MSI_RecordGetString(row,6);
3107 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3108 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3112 ERR("Failed to register type library %s\n",
3113 debugstr_w(tl_struct.path));
3116 ui_actiondata(package,szRegisterTypeLibraries,row);
3118 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3121 ITypeLib_Release(tl_struct.ptLib);
3122 msi_free(tl_struct.path);
3125 ERR("Failed to load type library %s\n",
3126 debugstr_w(tl_struct.source));
3128 FreeLibrary(module);
3129 msi_free(tl_struct.source);
3133 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3136 ERR("Failed to load type library: %08x\n", hr);
3137 return ERROR_FUNCTION_FAILED;
3140 ITypeLib_Release(tlib);
3143 return ERROR_SUCCESS;
3146 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3149 * OK this is a bit confusing.. I am given a _Component key and I believe
3150 * that the file that is being registered as a type library is the "key file
3151 * of that component" which I interpret to mean "The file in the KeyPath of
3156 static const WCHAR Query[] =
3157 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3158 '`','T','y','p','e','L','i','b','`',0};
3160 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3161 if (rc != ERROR_SUCCESS)
3162 return ERROR_SUCCESS;
3164 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3165 msiobj_release(&view->hdr);
3169 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3171 MSIPACKAGE *package = param;
3172 LPWSTR target_file, target_folder, filename;
3173 LPCWSTR buffer, extension;
3175 static const WCHAR szlnk[]={'.','l','n','k',0};
3176 IShellLinkW *sl = NULL;
3177 IPersistFile *pf = NULL;
3180 buffer = MSI_RecordGetString(row,4);
3181 comp = get_loaded_component(package,buffer);
3183 return ERROR_SUCCESS;
3185 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
3187 TRACE("Skipping shortcut creation due to disabled component\n");
3189 comp->Action = comp->Installed;
3191 return ERROR_SUCCESS;
3194 comp->Action = INSTALLSTATE_LOCAL;
3196 ui_actiondata(package,szCreateShortcuts,row);
3198 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3199 &IID_IShellLinkW, (LPVOID *) &sl );
3203 ERR("CLSID_ShellLink not available\n");
3207 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3210 ERR("QueryInterface(IID_IPersistFile) failed\n");
3214 buffer = MSI_RecordGetString(row,2);
3215 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
3217 /* may be needed because of a bug somewhere else */
3218 create_full_pathW(target_folder);
3220 filename = msi_dup_record_field( row, 3 );
3221 reduce_to_longfilename(filename);
3223 extension = strchrW(filename,'.');
3224 if (!extension || strcmpiW(extension,szlnk))
3226 int len = strlenW(filename);
3227 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3228 memcpy(filename + len, szlnk, sizeof(szlnk));
3230 target_file = build_directory_name(2, target_folder, filename);
3231 msi_free(target_folder);
3234 buffer = MSI_RecordGetString(row,5);
3235 if (strchrW(buffer,'['))
3238 deformat_string(package,buffer,&deformated);
3239 IShellLinkW_SetPath(sl,deformated);
3240 msi_free(deformated);
3244 FIXME("poorly handled shortcut format, advertised shortcut\n");
3245 IShellLinkW_SetPath(sl,comp->FullKeypath);
3248 if (!MSI_RecordIsNull(row,6))
3251 buffer = MSI_RecordGetString(row,6);
3252 deformat_string(package,buffer,&deformated);
3253 IShellLinkW_SetArguments(sl,deformated);
3254 msi_free(deformated);
3257 if (!MSI_RecordIsNull(row,7))
3259 buffer = MSI_RecordGetString(row,7);
3260 IShellLinkW_SetDescription(sl,buffer);
3263 if (!MSI_RecordIsNull(row,8))
3264 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3266 if (!MSI_RecordIsNull(row,9))
3271 buffer = MSI_RecordGetString(row,9);
3273 Path = build_icon_path(package,buffer);
3274 index = MSI_RecordGetInteger(row,10);
3276 /* no value means 0 */
3277 if (index == MSI_NULL_INTEGER)
3280 IShellLinkW_SetIconLocation(sl,Path,index);
3284 if (!MSI_RecordIsNull(row,11))
3285 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3287 if (!MSI_RecordIsNull(row,12))
3290 buffer = MSI_RecordGetString(row,12);
3291 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3293 IShellLinkW_SetWorkingDirectory(sl,Path);
3297 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3298 IPersistFile_Save(pf,target_file,FALSE);
3300 msi_free(target_file);
3304 IPersistFile_Release( pf );
3306 IShellLinkW_Release( sl );
3308 return ERROR_SUCCESS;
3311 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3316 static const WCHAR Query[] =
3317 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3318 '`','S','h','o','r','t','c','u','t','`',0};
3320 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3321 if (rc != ERROR_SUCCESS)
3322 return ERROR_SUCCESS;
3324 res = CoInitialize( NULL );
3327 ERR("CoInitialize failed\n");
3328 return ERROR_FUNCTION_FAILED;
3331 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3332 msiobj_release(&view->hdr);
3339 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3341 MSIPACKAGE* package = param;
3350 FileName = MSI_RecordGetString(row,1);
3353 ERR("Unable to get FileName\n");
3354 return ERROR_SUCCESS;
3357 FilePath = build_icon_path(package,FileName);
3359 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3361 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3362 FILE_ATTRIBUTE_NORMAL, NULL);
3364 if (the_file == INVALID_HANDLE_VALUE)
3366 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3368 return ERROR_SUCCESS;
3375 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3376 if (rc != ERROR_SUCCESS)
3378 ERR("Failed to get stream\n");
3379 CloseHandle(the_file);
3380 DeleteFileW(FilePath);
3383 WriteFile(the_file,buffer,sz,&write,NULL);
3384 } while (sz == 1024);
3388 CloseHandle(the_file);
3390 uirow = MSI_CreateRecord(1);
3391 MSI_RecordSetStringW(uirow,1,FileName);
3392 ui_actiondata(package,szPublishProduct,uirow);
3393 msiobj_release( &uirow->hdr );
3395 return ERROR_SUCCESS;
3398 static UINT msi_publish_icons(MSIPACKAGE *package)
3403 static const WCHAR query[]= {
3404 'S','E','L','E','C','T',' ','*',' ',
3405 'F','R','O','M',' ','`','I','c','o','n','`',0};
3407 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3408 if (r == ERROR_SUCCESS)
3410 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3411 msiobj_release(&view->hdr);
3414 return ERROR_SUCCESS;
3417 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3423 MSISOURCELISTINFO *info;
3425 static const WCHAR szEmpty[] = {0};
3426 static const WCHAR szSourceList[] = {'S','o','u','r','c','e','L','i','s','t',0};
3428 r = RegCreateKeyW(hkey, szSourceList, &source);
3429 if (r != ERROR_SUCCESS)
3432 RegCloseKey(source);
3434 buffer = strrchrW(package->PackagePath, '\\') + 1;
3435 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3436 package->Context, MSICODE_PRODUCT,
3437 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3438 if (r != ERROR_SUCCESS)
3441 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3442 package->Context, MSICODE_PRODUCT,
3443 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3444 if (r != ERROR_SUCCESS)
3447 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3448 package->Context, MSICODE_PRODUCT,
3449 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3450 if (r != ERROR_SUCCESS)
3453 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3455 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3456 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3457 info->options, info->value);
3459 MsiSourceListSetInfoW(package->ProductCode, NULL,
3460 info->context, info->options,
3461 info->property, info->value);
3464 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3466 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3467 disk->context, disk->options,
3468 disk->disk_id, disk->volume_label, disk->disk_prompt);
3471 return ERROR_SUCCESS;
3474 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3476 MSIHANDLE hdb, suminfo;
3477 WCHAR guids[MAX_PATH];
3478 WCHAR packcode[SQUISH_GUID_SIZE];
3485 static const WCHAR szProductLanguage[] =
3486 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3487 static const WCHAR szARPProductIcon[] =
3488 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3489 static const WCHAR szProductVersion[] =
3490 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3491 static const WCHAR szAssignment[] =
3492 {'A','s','s','i','g','n','m','e','n','t',0};
3493 static const WCHAR szAdvertiseFlags[] =
3494 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3495 static const WCHAR szClients[] =
3496 {'C','l','i','e','n','t','s',0};
3497 static const WCHAR szColon[] = {':',0};
3499 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3500 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3503 langid = msi_get_property_int(package, szProductLanguage, 0);
3504 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3506 ptr = strrchrW(package->PackagePath, '\\' ) + 1;
3507 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGENAMEW, ptr);
3510 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3512 buffer = msi_dup_property(package, szARPProductIcon);
3515 LPWSTR path = build_icon_path(package,buffer);
3516 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3521 buffer = msi_dup_property(package, szProductVersion);
3524 DWORD verdword = msi_version_str_to_dword(buffer);
3525 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3529 msi_reg_set_val_dword(hkey, szAssignment, 0);
3530 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3531 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3532 msi_reg_set_val_str(hkey, szClients, szColon);
3534 hdb = alloc_msihandle(&package->db->hdr);
3536 return ERROR_NOT_ENOUGH_MEMORY;
3538 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3539 MsiCloseHandle(hdb);
3540 if (r != ERROR_SUCCESS)
3544 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3545 NULL, guids, &size);
3546 if (r != ERROR_SUCCESS)
3549 ptr = strchrW(guids, ';');
3551 squash_guid(guids, packcode);
3552 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3555 MsiCloseHandle(suminfo);
3556 return ERROR_SUCCESS;
3559 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3564 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3566 static const WCHAR szUpgradeCode[] =
3567 {'U','p','g','r','a','d','e','C','o','d','e',0};
3569 upgrade = msi_dup_property(package, szUpgradeCode);
3571 return ERROR_SUCCESS;
3573 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3575 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3576 if (r != ERROR_SUCCESS)
3581 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3582 if (r != ERROR_SUCCESS)
3586 squash_guid(package->ProductCode, squashed_pc);
3587 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3596 static BOOL msi_check_publish(MSIPACKAGE *package)
3598 MSIFEATURE *feature;
3600 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3602 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3609 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3611 MSIFEATURE *feature;
3613 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3615 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3622 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3624 WCHAR patch_squashed[GUID_SIZE];
3627 UINT r = ERROR_FUNCTION_FAILED;
3629 static const WCHAR szPatches[] = {'P','a','t','c','h','e','s',0};
3631 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3633 if (res != ERROR_SUCCESS)
3634 return ERROR_FUNCTION_FAILED;
3636 squash_guid(package->patch->patchcode, patch_squashed);
3638 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3639 (const BYTE *)patch_squashed,
3640 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3641 if (res != ERROR_SUCCESS)
3644 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3645 (const BYTE *)package->patch->transforms,
3646 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3647 if (res == ERROR_SUCCESS)
3651 RegCloseKey(patches);
3656 * 99% of the work done here is only done for
3657 * advertised installs. However this is where the
3658 * Icon table is processed and written out
3659 * so that is what I am going to do here.
3661 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3667 /* FIXME: also need to publish if the product is in advertise mode */
3668 if (!msi_check_publish(package))
3669 return ERROR_SUCCESS;
3671 rc = MSIREG_OpenProductKey(package->ProductCode, package->Context,
3673 if (rc != ERROR_SUCCESS)
3676 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3677 NULL, &hudkey, TRUE);
3678 if (rc != ERROR_SUCCESS)
3681 rc = msi_publish_upgrade_code(package);
3682 if (rc != ERROR_SUCCESS)
3687 rc = msi_publish_patch(package, hukey, hudkey);
3688 if (rc != ERROR_SUCCESS)
3692 rc = msi_publish_product_properties(package, hukey);
3693 if (rc != ERROR_SUCCESS)
3696 rc = msi_publish_sourcelist(package, hukey);
3697 if (rc != ERROR_SUCCESS)
3700 rc = msi_publish_icons(package);
3704 RegCloseKey(hudkey);
3709 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3711 MSIPACKAGE *package = param;
3712 LPCWSTR component, section, key, value, identifier, dirproperty;
3713 LPWSTR deformated_section, deformated_key, deformated_value;
3714 LPWSTR folder, filename, fullname = NULL;
3715 LPCWSTR filenameptr;
3719 static const WCHAR szWindowsFolder[] =
3720 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3722 component = MSI_RecordGetString(row, 8);
3723 comp = get_loaded_component(package,component);
3725 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3727 TRACE("Skipping ini file due to disabled component %s\n",
3728 debugstr_w(component));
3730 comp->Action = comp->Installed;
3732 return ERROR_SUCCESS;
3735 comp->Action = INSTALLSTATE_LOCAL;
3737 identifier = MSI_RecordGetString(row,1);
3738 dirproperty = MSI_RecordGetString(row,3);
3739 section = MSI_RecordGetString(row,4);
3740 key = MSI_RecordGetString(row,5);
3741 value = MSI_RecordGetString(row,6);
3742 action = MSI_RecordGetInteger(row,7);
3744 deformat_string(package,section,&deformated_section);
3745 deformat_string(package,key,&deformated_key);
3746 deformat_string(package,value,&deformated_value);
3748 filename = msi_dup_record_field(row, 2);
3749 if (filename && (filenameptr = strchrW(filename, '|')))
3752 filenameptr = filename;
3756 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3758 folder = msi_dup_property( package, dirproperty );
3761 folder = msi_dup_property( package, szWindowsFolder );
3765 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3769 fullname = build_directory_name(2, folder, filenameptr);
3773 TRACE("Adding value %s to section %s in %s\n",
3774 debugstr_w(deformated_key), debugstr_w(deformated_section),
3775 debugstr_w(fullname));
3776 WritePrivateProfileStringW(deformated_section, deformated_key,
3777 deformated_value, fullname);
3779 else if (action == 1)
3782 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3783 returned, 10, fullname);
3784 if (returned[0] == 0)
3786 TRACE("Adding value %s to section %s in %s\n",
3787 debugstr_w(deformated_key), debugstr_w(deformated_section),
3788 debugstr_w(fullname));
3790 WritePrivateProfileStringW(deformated_section, deformated_key,
3791 deformated_value, fullname);
3794 else if (action == 3)
3795 FIXME("Append to existing section not yet implemented\n");
3797 uirow = MSI_CreateRecord(4);
3798 MSI_RecordSetStringW(uirow,1,identifier);
3799 MSI_RecordSetStringW(uirow,2,deformated_section);
3800 MSI_RecordSetStringW(uirow,3,deformated_key);
3801 MSI_RecordSetStringW(uirow,4,deformated_value);
3802 ui_actiondata(package,szWriteIniValues,uirow);
3803 msiobj_release( &uirow->hdr );
3809 msi_free(deformated_key);
3810 msi_free(deformated_value);
3811 msi_free(deformated_section);
3812 return ERROR_SUCCESS;
3815 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3819 static const WCHAR ExecSeqQuery[] =
3820 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3821 '`','I','n','i','F','i','l','e','`',0};
3823 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3824 if (rc != ERROR_SUCCESS)
3826 TRACE("no IniFile table\n");
3827 return ERROR_SUCCESS;
3830 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3831 msiobj_release(&view->hdr);
3835 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3837 MSIPACKAGE *package = param;
3842 static const WCHAR ExeStr[] =
3843 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3844 static const WCHAR close[] = {'\"',0};
3846 PROCESS_INFORMATION info;
3851 memset(&si,0,sizeof(STARTUPINFOW));
3853 filename = MSI_RecordGetString(row,1);
3854 file = get_loaded_file( package, filename );
3858 ERR("Unable to find file id %s\n",debugstr_w(filename));
3859 return ERROR_SUCCESS;
3862 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3864 FullName = msi_alloc(len*sizeof(WCHAR));
3865 strcpyW(FullName,ExeStr);
3866 strcatW( FullName, file->TargetPath );
3867 strcatW(FullName,close);
3869 TRACE("Registering %s\n",debugstr_w(FullName));
3870 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3875 CloseHandle(info.hThread);
3876 msi_dialog_check_messages(info.hProcess);
3877 CloseHandle(info.hProcess);
3883 uirow = MSI_CreateRecord( 2 );
3884 uipath = strdupW( file->TargetPath );
3885 p = strrchrW(uipath,'\\');
3888 MSI_RecordSetStringW( uirow, 1, &p[1] );
3889 MSI_RecordSetStringW( uirow, 2, uipath);
3890 ui_actiondata( package, szSelfRegModules, uirow);
3891 msiobj_release( &uirow->hdr );
3893 /* FIXME: call ui_progress? */
3895 return ERROR_SUCCESS;
3898 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3902 static const WCHAR ExecSeqQuery[] =
3903 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3904 '`','S','e','l','f','R','e','g','`',0};
3906 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3907 if (rc != ERROR_SUCCESS)
3909 TRACE("no SelfReg table\n");
3910 return ERROR_SUCCESS;
3913 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3914 msiobj_release(&view->hdr);
3916 return ERROR_SUCCESS;
3919 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3921 MSIFEATURE *feature;
3924 HKEY userdata = NULL;
3926 if (!msi_check_publish(package))
3927 return ERROR_SUCCESS;
3929 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3931 if (rc != ERROR_SUCCESS)
3934 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3936 if (rc != ERROR_SUCCESS)
3939 /* here the guids are base 85 encoded */
3940 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3946 BOOL absent = FALSE;
3949 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3950 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3951 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3955 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3959 if (feature->Feature_Parent)
3960 size += strlenW( feature->Feature_Parent )+2;
3962 data = msi_alloc(size * sizeof(WCHAR));
3965 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3967 MSICOMPONENT* component = cl->component;
3971 if (component->ComponentId)
3973 TRACE("From %s\n",debugstr_w(component->ComponentId));
3974 CLSIDFromString(component->ComponentId, &clsid);
3975 encode_base85_guid(&clsid,buf);
3976 TRACE("to %s\n",debugstr_w(buf));
3981 if (feature->Feature_Parent)
3983 static const WCHAR sep[] = {'\2',0};
3985 strcatW(data,feature->Feature_Parent);
3988 msi_reg_set_val_str( userdata, feature->Feature, data );
3992 if (feature->Feature_Parent)
3993 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3996 static const WCHAR emptyW[] = {0};
3997 size += sizeof(WCHAR);
3998 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3999 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : emptyW),size);
4003 size += 2*sizeof(WCHAR);
4004 data = msi_alloc(size);
4007 if (feature->Feature_Parent)
4008 strcpyW( &data[1], feature->Feature_Parent );
4009 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4015 uirow = MSI_CreateRecord( 1 );
4016 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4017 ui_actiondata( package, szPublishFeatures, uirow);
4018 msiobj_release( &uirow->hdr );
4019 /* FIXME: call ui_progress? */
4024 RegCloseKey(userdata);
4028 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4033 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4035 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4037 if (r == ERROR_SUCCESS)
4039 RegDeleteValueW(hkey, feature->Feature);
4043 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4045 if (r == ERROR_SUCCESS)
4047 RegDeleteValueW(hkey, feature->Feature);
4051 return ERROR_SUCCESS;
4054 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4056 MSIFEATURE *feature;
4058 if (!msi_check_unpublish(package))
4059 return ERROR_SUCCESS;
4061 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4063 msi_unpublish_feature(package, feature);
4066 return ERROR_SUCCESS;
4069 static UINT msi_get_local_package_name( LPWSTR path )
4071 static const WCHAR szInstaller[] = {
4072 '\\','I','n','s','t','a','l','l','e','r','\\',0};
4073 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
4077 time = GetTickCount();
4078 GetWindowsDirectoryW( path, MAX_PATH );
4079 lstrcatW( path, szInstaller );
4080 CreateDirectoryW( path, NULL );
4082 len = lstrlenW(path);
4083 for (i=0; i<0x10000; i++)
4085 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
4086 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
4087 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
4088 if (handle != INVALID_HANDLE_VALUE)
4090 CloseHandle(handle);
4093 if (GetLastError() != ERROR_FILE_EXISTS &&
4094 GetLastError() != ERROR_SHARING_VIOLATION)
4095 return ERROR_FUNCTION_FAILED;
4098 return ERROR_SUCCESS;
4101 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
4103 WCHAR packagefile[MAX_PATH];
4106 r = msi_get_local_package_name( packagefile );
4107 if (r != ERROR_SUCCESS)
4110 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
4112 r = CopyFileW( package->db->path, packagefile, FALSE);
4116 ERR("Unable to copy package (%s -> %s) (error %d)\n",
4117 debugstr_w(package->db->path), debugstr_w(packagefile), GetLastError());
4118 return ERROR_FUNCTION_FAILED;
4121 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
4123 return ERROR_SUCCESS;
4126 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4128 LPWSTR prop, val, key;
4134 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4135 static const WCHAR szWindowsInstaller[] =
4136 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4137 static const WCHAR modpath_fmt[] =
4138 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4139 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4140 static const WCHAR szModifyPath[] =
4141 {'M','o','d','i','f','y','P','a','t','h',0};
4142 static const WCHAR szUninstallString[] =
4143 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4144 static const WCHAR szEstimatedSize[] =
4145 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4146 static const WCHAR szProductLanguage[] =
4147 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4148 static const WCHAR szProductVersion[] =
4149 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4150 static const WCHAR szProductName[] =
4151 {'P','r','o','d','u','c','t','N','a','m','e',0};
4152 static const WCHAR szDisplayName[] =
4153 {'D','i','s','p','l','a','y','N','a','m','e',0};
4154 static const WCHAR szDisplayVersion[] =
4155 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4156 static const WCHAR szManufacturer[] =
4157 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4159 static const LPCSTR propval[] = {
4160 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4161 "ARPCONTACT", "Contact",
4162 "ARPCOMMENTS", "Comments",
4163 "ProductName", "DisplayName",
4164 "ProductVersion", "DisplayVersion",
4165 "ARPHELPLINK", "HelpLink",
4166 "ARPHELPTELEPHONE", "HelpTelephone",
4167 "ARPINSTALLLOCATION", "InstallLocation",
4168 "SourceDir", "InstallSource",
4169 "Manufacturer", "Publisher",
4170 "ARPREADME", "Readme",
4172 "ARPURLINFOABOUT", "URLInfoAbout",
4173 "ARPURLUPDATEINFO", "URLUpdateInfo",
4176 const LPCSTR *p = propval;
4180 prop = strdupAtoW(*p++);
4181 key = strdupAtoW(*p++);
4182 val = msi_dup_property(package, prop);
4183 msi_reg_set_val_str(hkey, key, val);
4189 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4191 size = deformat_string(package, modpath_fmt, &buffer);
4192 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4193 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4196 /* FIXME: Write real Estimated Size when we have it */
4197 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4199 buffer = msi_dup_property(package, szProductName);
4200 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4203 buffer = msi_dup_property(package, cszSourceDir);
4204 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4207 buffer = msi_dup_property(package, szManufacturer);
4208 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4211 GetLocalTime(&systime);
4212 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4213 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4215 langid = msi_get_property_int(package, szProductLanguage, 0);
4216 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4218 buffer = msi_dup_property(package, szProductVersion);
4219 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4222 DWORD verdword = msi_version_str_to_dword(buffer);
4224 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4225 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4226 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4230 return ERROR_SUCCESS;
4233 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4235 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4236 LPWSTR upgrade_code;
4241 static const WCHAR szUpgradeCode[] = {
4242 'U','p','g','r','a','d','e','C','o','d','e',0};
4244 /* FIXME: also need to publish if the product is in advertise mode */
4245 if (!msi_check_publish(package))
4246 return ERROR_SUCCESS;
4248 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4249 if (rc != ERROR_SUCCESS)
4252 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4253 NULL, &props, TRUE);
4254 if (rc != ERROR_SUCCESS)
4257 msi_make_package_local(package, props);
4259 rc = msi_publish_install_properties(package, hkey);
4260 if (rc != ERROR_SUCCESS)
4263 rc = msi_publish_install_properties(package, props);
4264 if (rc != ERROR_SUCCESS)
4267 upgrade_code = msi_dup_property(package, szUpgradeCode);
4270 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4271 squash_guid(package->ProductCode, squashed_pc);
4272 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4273 RegCloseKey(upgrade);
4274 msi_free(upgrade_code);
4280 return ERROR_SUCCESS;
4283 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4285 return execute_script(package,INSTALL_SCRIPT);
4288 static UINT msi_unpublish_product(MSIPACKAGE *package)
4291 LPWSTR remove = NULL;
4292 LPWSTR *features = NULL;
4293 BOOL full_uninstall = TRUE;
4294 MSIFEATURE *feature;
4296 static const WCHAR szRemove[] = {'R','E','M','O','V','E',0};
4297 static const WCHAR szAll[] = {'A','L','L',0};
4298 static const WCHAR szUpgradeCode[] =
4299 {'U','p','g','r','a','d','e','C','o','d','e',0};
4301 remove = msi_dup_property(package, szRemove);
4303 return ERROR_SUCCESS;
4305 features = msi_split_string(remove, ',');
4309 ERR("REMOVE feature list is empty!\n");
4310 return ERROR_FUNCTION_FAILED;
4313 if (!lstrcmpW(features[0], szAll))
4314 full_uninstall = TRUE;
4317 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4319 if (feature->Action != INSTALLSTATE_ABSENT)
4320 full_uninstall = FALSE;
4324 if (!full_uninstall)
4327 MSIREG_DeleteProductKey(package->ProductCode);
4328 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4329 MSIREG_DeleteUninstallKey(package->ProductCode);
4331 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4333 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4334 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4338 MSIREG_DeleteUserProductKey(package->ProductCode);
4339 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4342 upgrade = msi_dup_property(package, szUpgradeCode);
4345 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4352 return ERROR_SUCCESS;
4355 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4359 rc = msi_unpublish_product(package);
4360 if (rc != ERROR_SUCCESS)
4363 /* turn off scheduling */
4364 package->script->CurrentlyScripting= FALSE;
4366 /* first do the same as an InstallExecute */
4367 rc = ACTION_InstallExecute(package);
4368 if (rc != ERROR_SUCCESS)
4371 /* then handle Commit Actions */
4372 rc = execute_script(package,COMMIT_SCRIPT);
4377 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4379 static const WCHAR RunOnce[] = {
4380 'S','o','f','t','w','a','r','e','\\',
4381 'M','i','c','r','o','s','o','f','t','\\',
4382 'W','i','n','d','o','w','s','\\',
4383 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4384 'R','u','n','O','n','c','e',0};
4385 static const WCHAR InstallRunOnce[] = {
4386 'S','o','f','t','w','a','r','e','\\',
4387 'M','i','c','r','o','s','o','f','t','\\',
4388 'W','i','n','d','o','w','s','\\',
4389 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4390 'I','n','s','t','a','l','l','e','r','\\',
4391 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4393 static const WCHAR msiexec_fmt[] = {
4395 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4396 '\"','%','s','\"',0};
4397 static const WCHAR install_fmt[] = {
4398 '/','I',' ','\"','%','s','\"',' ',
4399 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4400 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4401 WCHAR buffer[256], sysdir[MAX_PATH];
4403 WCHAR squished_pc[100];
4405 squash_guid(package->ProductCode,squished_pc);
4407 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4408 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4409 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4412 msi_reg_set_val_str( hkey, squished_pc, buffer );
4415 TRACE("Reboot command %s\n",debugstr_w(buffer));
4417 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4418 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4420 msi_reg_set_val_str( hkey, squished_pc, buffer );
4423 return ERROR_INSTALL_SUSPEND;
4426 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4432 * We are currently doing what should be done here in the top level Install
4433 * however for Administrative and uninstalls this step will be needed
4435 if (!package->PackagePath)
4436 return ERROR_SUCCESS;
4438 msi_set_sourcedir_props(package, TRUE);
4440 attrib = GetFileAttributesW(package->db->path);
4441 if (attrib == INVALID_FILE_ATTRIBUTES)
4447 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4448 package->Context, MSICODE_PRODUCT,
4449 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4450 if (rc == ERROR_MORE_DATA)
4452 prompt = msi_alloc(size * sizeof(WCHAR));
4453 MsiSourceListGetInfoW(package->ProductCode, NULL,
4454 package->Context, MSICODE_PRODUCT,
4455 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4458 prompt = strdupW(package->db->path);
4460 msg = generate_error_string(package,1302,1,prompt);
4461 while(attrib == INVALID_FILE_ATTRIBUTES)
4463 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4466 rc = ERROR_INSTALL_USEREXIT;
4469 attrib = GetFileAttributesW(package->db->path);
4475 return ERROR_SUCCESS;
4480 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4487 static const WCHAR szPropKeys[][80] =
4489 {'P','r','o','d','u','c','t','I','D',0},
4490 {'U','S','E','R','N','A','M','E',0},
4491 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4495 static const WCHAR szRegKeys[][80] =
4497 {'P','r','o','d','u','c','t','I','D',0},
4498 {'R','e','g','O','w','n','e','r',0},
4499 {'R','e','g','C','o','m','p','a','n','y',0},
4503 if (msi_check_unpublish(package))
4505 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4506 return ERROR_SUCCESS;
4509 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4511 return ERROR_SUCCESS;
4513 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4515 if (rc != ERROR_SUCCESS)
4518 for( i = 0; szPropKeys[i][0]; i++ )
4520 buffer = msi_dup_property( package, szPropKeys[i] );
4521 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4526 msi_free(productid);
4529 /* FIXME: call ui_actiondata */
4535 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4539 package->script->InWhatSequence |= SEQUENCE_EXEC;
4540 rc = ACTION_ProcessExecSequence(package,FALSE);
4545 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4547 MSIPACKAGE *package = param;
4548 LPCWSTR compgroupid=NULL;
4549 LPCWSTR feature=NULL;
4550 LPCWSTR text = NULL;
4551 LPCWSTR qualifier = NULL;
4552 LPCWSTR component = NULL;
4553 LPWSTR advertise = NULL;
4554 LPWSTR output = NULL;
4556 UINT rc = ERROR_SUCCESS;
4561 component = MSI_RecordGetString(rec,3);
4562 comp = get_loaded_component(package,component);
4564 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4565 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4566 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4568 TRACE("Skipping: Component %s not scheduled for install\n",
4569 debugstr_w(component));
4571 return ERROR_SUCCESS;
4574 compgroupid = MSI_RecordGetString(rec,1);
4575 qualifier = MSI_RecordGetString(rec,2);
4577 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4578 if (rc != ERROR_SUCCESS)
4581 text = MSI_RecordGetString(rec,4);
4582 feature = MSI_RecordGetString(rec,5);
4584 advertise = create_component_advertise_string(package, comp, feature);
4586 sz = strlenW(advertise);
4589 sz += lstrlenW(text);
4592 sz *= sizeof(WCHAR);
4594 output = msi_alloc_zero(sz);
4595 strcpyW(output,advertise);
4596 msi_free(advertise);
4599 strcatW(output,text);
4601 msi_reg_set_val_multi_str( hkey, qualifier, output );
4608 uirow = MSI_CreateRecord( 2 );
4609 MSI_RecordSetStringW( uirow, 1, compgroupid );
4610 MSI_RecordSetStringW( uirow, 2, qualifier);
4611 ui_actiondata( package, szPublishComponents, uirow);
4612 msiobj_release( &uirow->hdr );
4613 /* FIXME: call ui_progress? */
4619 * At present I am ignorning the advertised components part of this and only
4620 * focusing on the qualified component sets
4622 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4626 static const WCHAR ExecSeqQuery[] =
4627 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4628 '`','P','u','b','l','i','s','h',
4629 'C','o','m','p','o','n','e','n','t','`',0};
4631 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4632 if (rc != ERROR_SUCCESS)
4633 return ERROR_SUCCESS;
4635 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4636 msiobj_release(&view->hdr);
4641 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4643 MSIPACKAGE *package = param;
4646 SC_HANDLE hscm, service = NULL;
4647 LPCWSTR comp, depends, pass;
4648 LPWSTR name = NULL, disp = NULL;
4649 LPCWSTR load_order, serv_name, key;
4650 DWORD serv_type, start_type;
4653 static const WCHAR query[] =
4654 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4655 '`','C','o','m','p','o','n','e','n','t','`',' ',
4656 'W','H','E','R','E',' ',
4657 '`','C','o','m','p','o','n','e','n','t','`',' ',
4658 '=','\'','%','s','\'',0};
4660 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4663 ERR("Failed to open the SC Manager!\n");
4667 start_type = MSI_RecordGetInteger(rec, 5);
4668 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4671 depends = MSI_RecordGetString(rec, 8);
4672 if (depends && *depends)
4673 FIXME("Dependency list unhandled!\n");
4675 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4676 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
4677 serv_type = MSI_RecordGetInteger(rec, 4);
4678 err_control = MSI_RecordGetInteger(rec, 6);
4679 load_order = MSI_RecordGetString(rec, 7);
4680 serv_name = MSI_RecordGetString(rec, 9);
4681 pass = MSI_RecordGetString(rec, 10);
4682 comp = MSI_RecordGetString(rec, 12);
4684 /* fetch the service path */
4685 row = MSI_QueryGetRecord(package->db, query, comp);
4688 ERR("Control query failed!\n");
4692 key = MSI_RecordGetString(row, 6);
4694 file = get_loaded_file(package, key);
4695 msiobj_release(&row->hdr);
4698 ERR("Failed to load the service file\n");
4702 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4703 start_type, err_control, file->TargetPath,
4704 load_order, NULL, NULL, serv_name, pass);
4707 if (GetLastError() != ERROR_SERVICE_EXISTS)
4708 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4712 CloseServiceHandle(service);
4713 CloseServiceHandle(hscm);
4717 return ERROR_SUCCESS;
4720 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4724 static const WCHAR ExecSeqQuery[] =
4725 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4726 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4728 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4729 if (rc != ERROR_SUCCESS)
4730 return ERROR_SUCCESS;
4732 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4733 msiobj_release(&view->hdr);
4738 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4739 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
4741 LPCWSTR *vector, *temp_vector;
4745 static const WCHAR separator[] = {'[','~',']',0};
4748 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4753 vector = msi_alloc(sizeof(LPWSTR));
4761 vector[*numargs - 1] = p;
4763 if ((q = strstrW(p, separator)))
4767 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4773 vector = temp_vector;
4782 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4784 MSIPACKAGE *package = param;
4786 SC_HANDLE scm, service = NULL;
4787 LPCWSTR name, *vector = NULL;
4789 DWORD event, numargs;
4790 UINT r = ERROR_FUNCTION_FAILED;
4792 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4793 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4794 return ERROR_SUCCESS;
4796 name = MSI_RecordGetString(rec, 2);
4797 event = MSI_RecordGetInteger(rec, 3);
4798 args = strdupW(MSI_RecordGetString(rec, 4));
4800 if (!(event & msidbServiceControlEventStart))
4801 return ERROR_SUCCESS;
4803 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4806 ERR("Failed to open the service control manager\n");
4810 service = OpenServiceW(scm, name, SERVICE_START);
4813 ERR("Failed to open service %s\n", debugstr_w(name));
4817 vector = msi_service_args_to_vector(args, &numargs);
4819 if (!StartServiceW(service, numargs, vector))
4821 ERR("Failed to start service %s\n", debugstr_w(name));
4828 CloseServiceHandle(service);
4829 CloseServiceHandle(scm);
4836 static UINT ACTION_StartServices( MSIPACKAGE *package )
4841 static const WCHAR query[] = {
4842 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4843 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4845 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4846 if (rc != ERROR_SUCCESS)
4847 return ERROR_SUCCESS;
4849 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4850 msiobj_release(&view->hdr);
4855 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4857 DWORD i, needed, count;
4858 ENUM_SERVICE_STATUSW *dependencies;
4862 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4863 0, &needed, &count))
4866 if (GetLastError() != ERROR_MORE_DATA)
4869 dependencies = msi_alloc(needed);
4873 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4874 needed, &needed, &count))
4877 for (i = 0; i < count; i++)
4879 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4880 SERVICE_STOP | SERVICE_QUERY_STATUS);
4884 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4891 msi_free(dependencies);
4895 static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
4897 MSIPACKAGE *package = param;
4899 SERVICE_STATUS status;
4900 SERVICE_STATUS_PROCESS ssp;
4901 SC_HANDLE scm = NULL, service = NULL;
4903 DWORD event, needed;
4905 event = MSI_RecordGetInteger(rec, 3);
4906 if (!(event & msidbServiceControlEventStop))
4907 return ERROR_SUCCESS;
4909 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4910 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4911 return ERROR_SUCCESS;
4913 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4914 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4915 args = strdupW(MSI_RecordGetString(rec, 4));
4917 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4920 WARN("Failed to open the SCM: %d\n", GetLastError());
4924 service = OpenServiceW(scm, name,
4926 SERVICE_QUERY_STATUS |
4927 SERVICE_ENUMERATE_DEPENDENTS);
4930 WARN("Failed to open service (%s): %d\n",
4931 debugstr_w(name), GetLastError());
4935 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4936 sizeof(SERVICE_STATUS_PROCESS), &needed))
4938 WARN("Failed to query service status (%s): %d\n",
4939 debugstr_w(name), GetLastError());
4943 if (ssp.dwCurrentState == SERVICE_STOPPED)
4946 stop_service_dependents(scm, service);
4948 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
4949 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
4952 CloseServiceHandle(service);
4953 CloseServiceHandle(scm);
4957 return ERROR_SUCCESS;
4960 static UINT ACTION_StopServices( MSIPACKAGE *package )
4965 static const WCHAR query[] = {
4966 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4967 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4969 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4970 if (rc != ERROR_SUCCESS)
4971 return ERROR_SUCCESS;
4973 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
4974 msiobj_release(&view->hdr);
4979 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4983 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4985 if (!lstrcmpW(file->File, filename))
4992 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4994 MSIPACKAGE *package = param;
4995 LPWSTR driver, driver_path, ptr;
4996 WCHAR outpath[MAX_PATH];
4997 MSIFILE *driver_file, *setup_file;
5000 UINT r = ERROR_SUCCESS;
5002 static const WCHAR driver_fmt[] = {
5003 'D','r','i','v','e','r','=','%','s',0};
5004 static const WCHAR setup_fmt[] = {
5005 'S','e','t','u','p','=','%','s',0};
5006 static const WCHAR usage_fmt[] = {
5007 'F','i','l','e','U','s','a','g','e','=','1',0};
5009 desc = MSI_RecordGetString(rec, 3);
5011 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5012 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5014 if (!driver_file || !setup_file)
5016 ERR("ODBC Driver entry not found!\n");
5017 return ERROR_FUNCTION_FAILED;
5020 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
5021 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
5022 lstrlenW(usage_fmt) + 1;
5023 driver = msi_alloc(len * sizeof(WCHAR));
5025 return ERROR_OUTOFMEMORY;
5028 lstrcpyW(ptr, desc);
5029 ptr += lstrlenW(ptr) + 1;
5031 sprintfW(ptr, driver_fmt, driver_file->FileName);
5032 ptr += lstrlenW(ptr) + 1;
5034 sprintfW(ptr, setup_fmt, setup_file->FileName);
5035 ptr += lstrlenW(ptr) + 1;
5037 lstrcpyW(ptr, usage_fmt);
5038 ptr += lstrlenW(ptr) + 1;
5041 driver_path = strdupW(driver_file->TargetPath);
5042 ptr = strrchrW(driver_path, '\\');
5043 if (ptr) *ptr = '\0';
5045 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5046 NULL, ODBC_INSTALL_COMPLETE, &usage))
5048 ERR("Failed to install SQL driver!\n");
5049 r = ERROR_FUNCTION_FAILED;
5053 msi_free(driver_path);
5058 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5060 MSIPACKAGE *package = param;
5061 LPWSTR translator, translator_path, ptr;
5062 WCHAR outpath[MAX_PATH];
5063 MSIFILE *translator_file, *setup_file;
5066 UINT r = ERROR_SUCCESS;
5068 static const WCHAR translator_fmt[] = {
5069 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5070 static const WCHAR setup_fmt[] = {
5071 'S','e','t','u','p','=','%','s',0};
5073 desc = MSI_RecordGetString(rec, 3);
5075 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5076 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5078 if (!translator_file || !setup_file)
5080 ERR("ODBC Translator entry not found!\n");
5081 return ERROR_FUNCTION_FAILED;
5084 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
5085 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
5086 translator = msi_alloc(len * sizeof(WCHAR));
5088 return ERROR_OUTOFMEMORY;
5091 lstrcpyW(ptr, desc);
5092 ptr += lstrlenW(ptr) + 1;
5094 sprintfW(ptr, translator_fmt, translator_file->FileName);
5095 ptr += lstrlenW(ptr) + 1;
5097 sprintfW(ptr, setup_fmt, setup_file->FileName);
5098 ptr += lstrlenW(ptr) + 1;
5101 translator_path = strdupW(translator_file->TargetPath);
5102 ptr = strrchrW(translator_path, '\\');
5103 if (ptr) *ptr = '\0';
5105 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5106 NULL, ODBC_INSTALL_COMPLETE, &usage))
5108 ERR("Failed to install SQL translator!\n");
5109 r = ERROR_FUNCTION_FAILED;
5112 msi_free(translator);
5113 msi_free(translator_path);
5118 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5121 LPCWSTR desc, driver;
5122 WORD request = ODBC_ADD_SYS_DSN;
5125 UINT r = ERROR_SUCCESS;
5127 static const WCHAR attrs_fmt[] = {
5128 'D','S','N','=','%','s',0 };
5130 desc = MSI_RecordGetString(rec, 3);
5131 driver = MSI_RecordGetString(rec, 4);
5132 registration = MSI_RecordGetInteger(rec, 5);
5134 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5135 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5137 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
5138 attrs = msi_alloc(len * sizeof(WCHAR));
5140 return ERROR_OUTOFMEMORY;
5142 sprintfW(attrs, attrs_fmt, desc);
5143 attrs[len - 1] = '\0';
5145 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5147 ERR("Failed to install SQL data source!\n");
5148 r = ERROR_FUNCTION_FAILED;
5156 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5161 static const WCHAR driver_query[] = {
5162 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5163 'O','D','B','C','D','r','i','v','e','r',0 };
5165 static const WCHAR translator_query[] = {
5166 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5167 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5169 static const WCHAR source_query[] = {
5170 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5171 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5173 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5174 if (rc != ERROR_SUCCESS)
5175 return ERROR_SUCCESS;
5177 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5178 msiobj_release(&view->hdr);
5180 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5181 if (rc != ERROR_SUCCESS)
5182 return ERROR_SUCCESS;
5184 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5185 msiobj_release(&view->hdr);
5187 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5188 if (rc != ERROR_SUCCESS)
5189 return ERROR_SUCCESS;
5191 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5192 msiobj_release(&view->hdr);
5197 #define ENV_ACT_SETALWAYS 0x1
5198 #define ENV_ACT_SETABSENT 0x2
5199 #define ENV_ACT_REMOVE 0x4
5200 #define ENV_ACT_REMOVEMATCH 0x8
5202 #define ENV_MOD_MACHINE 0x20000000
5203 #define ENV_MOD_APPEND 0x40000000
5204 #define ENV_MOD_PREFIX 0x80000000
5205 #define ENV_MOD_MASK 0xC0000000
5207 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5209 static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5211 LPCWSTR cptr = *name;
5212 LPCWSTR ptr = *value;
5214 static const WCHAR prefix[] = {'[','~',']',0};
5215 static const int prefix_len = 3;
5221 *flags |= ENV_ACT_SETALWAYS;
5222 else if (*cptr == '+')
5223 *flags |= ENV_ACT_SETABSENT;
5224 else if (*cptr == '-')
5225 *flags |= ENV_ACT_REMOVE;
5226 else if (*cptr == '!')
5227 *flags |= ENV_ACT_REMOVEMATCH;
5228 else if (*cptr == '*')
5229 *flags |= ENV_MOD_MACHINE;
5239 ERR("Missing environment variable\n");
5240 return ERROR_FUNCTION_FAILED;
5243 if (!strncmpW(ptr, prefix, prefix_len))
5245 *flags |= ENV_MOD_APPEND;
5246 *value += lstrlenW(prefix);
5248 else if (lstrlenW(*value) >= prefix_len)
5250 ptr += lstrlenW(ptr) - prefix_len;
5251 if (!lstrcmpW(ptr, prefix))
5253 *flags |= ENV_MOD_PREFIX;
5254 /* the "[~]" will be removed by deformat_string */;
5259 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5260 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5261 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5262 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5264 ERR("Invalid flags: %08x\n", *flags);
5265 return ERROR_FUNCTION_FAILED;
5268 return ERROR_SUCCESS;
5271 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5273 MSIPACKAGE *package = param;
5274 LPCWSTR name, value;
5275 LPWSTR data = NULL, newval = NULL;
5276 LPWSTR deformatted = NULL, ptr;
5277 DWORD flags, type, size;
5279 HKEY env = NULL, root;
5280 LPCWSTR environment;
5282 static const WCHAR user_env[] =
5283 {'E','n','v','i','r','o','n','m','e','n','t',0};
5284 static const WCHAR machine_env[] =
5285 {'S','y','s','t','e','m','\\',
5286 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5287 'C','o','n','t','r','o','l','\\',
5288 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5289 'E','n','v','i','r','o','n','m','e','n','t',0};
5290 static const WCHAR semicolon[] = {';',0};
5292 name = MSI_RecordGetString(rec, 2);
5293 value = MSI_RecordGetString(rec, 3);
5295 res = env_set_flags(&name, &value, &flags);
5296 if (res != ERROR_SUCCESS)
5299 deformat_string(package, value, &deformatted);
5302 res = ERROR_OUTOFMEMORY;
5306 value = deformatted;
5308 if (flags & ENV_MOD_MACHINE)
5310 environment = machine_env;
5311 root = HKEY_LOCAL_MACHINE;
5315 environment = user_env;
5316 root = HKEY_CURRENT_USER;
5319 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5320 KEY_ALL_ACCESS, NULL, &env, NULL);
5321 if (res != ERROR_SUCCESS)
5324 if (flags & ENV_ACT_REMOVE)
5325 FIXME("Not removing environment variable on uninstall!\n");
5328 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5329 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
5330 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
5333 if (res != ERROR_FILE_NOT_FOUND)
5335 if (flags & ENV_ACT_SETABSENT)
5337 res = ERROR_SUCCESS;
5341 data = msi_alloc(size);
5345 return ERROR_OUTOFMEMORY;
5348 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5349 if (res != ERROR_SUCCESS)
5352 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5354 res = RegDeleteKeyW(env, name);
5358 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
5359 newval = msi_alloc(size);
5363 res = ERROR_OUTOFMEMORY;
5367 if (!(flags & ENV_MOD_MASK))
5368 lstrcpyW(newval, value);
5371 if (flags & ENV_MOD_PREFIX)
5373 lstrcpyW(newval, value);
5374 lstrcatW(newval, semicolon);
5375 ptr = newval + lstrlenW(value) + 1;
5378 lstrcpyW(ptr, data);
5380 if (flags & ENV_MOD_APPEND)
5382 lstrcatW(newval, semicolon);
5383 lstrcatW(newval, value);
5389 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
5390 newval = msi_alloc(size);
5393 res = ERROR_OUTOFMEMORY;
5397 lstrcpyW(newval, value);
5400 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5401 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
5404 if (env) RegCloseKey(env);
5405 msi_free(deformatted);
5411 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5415 static const WCHAR ExecSeqQuery[] =
5416 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5417 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5418 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5419 if (rc != ERROR_SUCCESS)
5420 return ERROR_SUCCESS;
5422 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5423 msiobj_release(&view->hdr);
5428 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5439 static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5443 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5444 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5446 WARN("Source or dest is directory, not moving\n");
5450 if (options == msidbMoveFileOptionsMove)
5452 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5453 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5456 WARN("MoveFile failed: %d\n", GetLastError());
5462 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5463 ret = CopyFileW(source, dest, FALSE);
5466 WARN("CopyFile failed: %d\n", GetLastError());
5474 static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5477 DWORD dirlen, pathlen;
5479 ptr = strrchrW(wildcard, '\\');
5480 dirlen = ptr - wildcard + 1;
5482 pathlen = dirlen + lstrlenW(filename) + 1;
5483 path = msi_alloc(pathlen * sizeof(WCHAR));
5485 lstrcpynW(path, wildcard, dirlen + 1);
5486 lstrcatW(path, filename);
5491 static void free_file_entry(FILE_LIST *file)
5493 msi_free(file->source);
5494 msi_free(file->dest);
5498 static void free_list(FILE_LIST *list)
5500 while (!list_empty(&list->entry))
5502 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5504 list_remove(&file->entry);
5505 free_file_entry(file);
5509 static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5511 FILE_LIST *new, *file;
5512 LPWSTR ptr, filename;
5515 new = msi_alloc_zero(sizeof(FILE_LIST));
5519 new->source = strdupW(source);
5520 ptr = strrchrW(dest, '\\') + 1;
5521 filename = strrchrW(new->source, '\\') + 1;
5523 new->sourcename = filename;
5526 new->destname = ptr;
5528 new->destname = new->sourcename;
5530 size = (ptr - dest) + lstrlenW(filename) + 1;
5531 new->dest = msi_alloc(size * sizeof(WCHAR));
5534 free_file_entry(new);
5538 lstrcpynW(new->dest, dest, ptr - dest + 1);
5539 lstrcatW(new->dest, filename);
5541 if (list_empty(&files->entry))
5543 list_add_head(&files->entry, &new->entry);
5547 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5549 if (lstrcmpW(source, file->source) < 0)
5551 list_add_before(&file->entry, &new->entry);
5556 list_add_after(&file->entry, &new->entry);
5560 static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
5562 WIN32_FIND_DATAW wfd;
5566 FILE_LIST files, *file;
5569 hfile = FindFirstFileW(source, &wfd);
5570 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5572 list_init(&files.entry);
5574 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5576 if (is_dot_dir(wfd.cFileName)) continue;
5578 path = wildcard_to_file(source, wfd.cFileName);
5585 add_wildcard(&files, path, dest);
5589 /* no files match the wildcard */
5590 if (list_empty(&files.entry))
5593 /* only the first wildcard match gets renamed to dest */
5594 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5595 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5596 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5603 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5605 while (!list_empty(&files.entry))
5607 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5609 msi_move_file(file->source, file->dest, options);
5611 list_remove(&file->entry);
5612 free_file_entry(file);
5623 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5625 MSIPACKAGE *package = param;
5628 LPWSTR destname = NULL;
5629 LPWSTR sourcedir = NULL, destdir = NULL;
5630 LPWSTR source = NULL, dest = NULL;
5633 BOOL ret, wildcards;
5635 static const WCHAR backslash[] = {'\\',0};
5637 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5638 if (!comp || !comp->Enabled ||
5639 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5641 TRACE("Component not set for install, not moving file\n");
5642 return ERROR_SUCCESS;
5645 sourcename = MSI_RecordGetString(rec, 3);
5646 options = MSI_RecordGetInteger(rec, 7);
5648 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5652 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5658 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5661 source = strdupW(sourcedir);
5667 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5668 source = msi_alloc(size * sizeof(WCHAR));
5672 lstrcpyW(source, sourcedir);
5673 if (source[lstrlenW(source) - 1] != '\\')
5674 lstrcatW(source, backslash);
5675 lstrcatW(source, sourcename);
5678 wildcards = strchrW(source, '*') || strchrW(source, '?');
5680 if (MSI_RecordIsNull(rec, 4))
5684 destname = strdupW(sourcename);
5691 destname = strdupW(MSI_RecordGetString(rec, 4));
5693 reduce_to_longfilename(destname);
5698 size = lstrlenW(destname);
5700 size += lstrlenW(destdir) + 2;
5701 dest = msi_alloc(size * sizeof(WCHAR));
5705 lstrcpyW(dest, destdir);
5706 if (dest[lstrlenW(dest) - 1] != '\\')
5707 lstrcatW(dest, backslash);
5710 lstrcatW(dest, destname);
5712 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5714 ret = CreateDirectoryW(destdir, NULL);
5717 WARN("CreateDirectory failed: %d\n", GetLastError());
5718 return ERROR_SUCCESS;
5723 msi_move_file(source, dest, options);
5725 move_files_wildcard(source, dest, options);
5728 msi_free(sourcedir);
5734 return ERROR_SUCCESS;
5737 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5742 static const WCHAR ExecSeqQuery[] =
5743 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5744 '`','M','o','v','e','F','i','l','e','`',0};
5746 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5747 if (rc != ERROR_SUCCESS)
5748 return ERROR_SUCCESS;
5750 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5751 msiobj_release(&view->hdr);
5756 typedef struct tagMSIASSEMBLY
5759 MSICOMPONENT *component;
5760 MSIFEATURE *feature;
5768 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
5770 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
5771 LPVOID pvReserved, HMODULE *phModDll);
5773 static BOOL init_functionpointers(void)
5779 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
5781 hmscoree = LoadLibraryA("mscoree.dll");
5784 WARN("mscoree.dll not available\n");
5788 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
5789 if (!pLoadLibraryShim)
5791 WARN("LoadLibraryShim not available\n");
5792 FreeLibrary(hmscoree);
5796 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
5799 WARN("fusion.dll not available\n");
5800 FreeLibrary(hmscoree);
5804 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
5806 FreeLibrary(hmscoree);
5810 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
5813 IAssemblyCache *cache;
5815 UINT r = ERROR_FUNCTION_FAILED;
5817 TRACE("installing assembly: %s\n", debugstr_w(path));
5819 if (assembly->feature)
5820 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
5822 if (assembly->manifest)
5823 FIXME("Manifest unhandled\n");
5825 if (assembly->application)
5827 FIXME("Assembly should be privately installed\n");
5828 return ERROR_SUCCESS;
5831 if (assembly->attributes == msidbAssemblyAttributesWin32)
5833 FIXME("Win32 assemblies not handled\n");
5834 return ERROR_SUCCESS;
5837 hr = pCreateAssemblyCache(&cache, 0);
5841 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
5843 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
5848 IAssemblyCache_Release(cache);
5852 typedef struct tagASSEMBLY_LIST
5854 MSIPACKAGE *package;
5855 IAssemblyCache *cache;
5856 struct list *assemblies;
5859 typedef struct tagASSEMBLY_NAME
5867 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
5869 ASSEMBLY_NAME *asmname = param;
5870 LPCWSTR name = MSI_RecordGetString(rec, 2);
5871 LPWSTR val = msi_dup_record_field(rec, 3);
5873 static const WCHAR Name[] = {'N','a','m','e',0};
5874 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
5875 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
5876 static const WCHAR PublicKeyToken[] = {
5877 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
5879 if (!lstrcmpW(name, Name))
5880 asmname->name = val;
5881 else if (!lstrcmpW(name, Version))
5882 asmname->version = val;
5883 else if (!lstrcmpW(name, Culture))
5884 asmname->culture = val;
5885 else if (!lstrcmpW(name, PublicKeyToken))
5886 asmname->pubkeytoken = val;
5890 return ERROR_SUCCESS;
5893 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
5897 *size = lstrlenW(append) + 1;
5898 *str = msi_alloc((*size) * sizeof(WCHAR));
5899 lstrcpyW(*str, append);
5903 (*size) += lstrlenW(append);
5904 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
5905 lstrcatW(*str, append);
5908 static BOOL check_assembly_installed(MSIDATABASE *db, IAssemblyCache *cache,
5911 ASSEMBLY_INFO asminfo;
5919 static const WCHAR separator[] = {',',' ',0};
5920 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
5921 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
5922 static const WCHAR PublicKeyToken[] = {
5923 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
5924 static const WCHAR query[] = {
5925 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5926 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
5927 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
5928 '=','\'','%','s','\'',0};
5932 ZeroMemory(&name, sizeof(ASSEMBLY_NAME));
5933 ZeroMemory(&asminfo, sizeof(ASSEMBLY_INFO));
5935 r = MSI_OpenQuery(db, &view, query, comp->Component);
5936 if (r != ERROR_SUCCESS)
5937 return ERROR_SUCCESS;
5939 MSI_IterateRecords(view, NULL, parse_assembly_name, &name);
5940 msiobj_release(&view->hdr);
5944 ERR("No assembly name specified!\n");
5948 append_str(&disp, &size, name.name);
5952 append_str(&disp, &size, separator);
5953 append_str(&disp, &size, Version);
5954 append_str(&disp, &size, name.version);
5959 append_str(&disp, &size, separator);
5960 append_str(&disp, &size, Culture);
5961 append_str(&disp, &size, name.culture);
5964 if (name.pubkeytoken)
5966 append_str(&disp, &size, separator);
5967 append_str(&disp, &size, PublicKeyToken);
5968 append_str(&disp, &size, name.pubkeytoken);
5971 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
5972 IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE,
5974 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
5977 msiobj_release(&view->hdr);
5979 msi_free(name.name);
5980 msi_free(name.version);
5981 msi_free(name.culture);
5982 msi_free(name.pubkeytoken);
5987 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
5989 ASSEMBLY_LIST *list = param;
5990 MSIASSEMBLY *assembly;
5992 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
5994 return ERROR_OUTOFMEMORY;
5996 assembly->component = get_loaded_component(list->package, MSI_RecordGetString(rec, 1));
5998 if (!assembly->component || !assembly->component->Enabled ||
5999 !(assembly->component->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
6001 TRACE("Component not set for install, not publishing assembly\n");
6003 return ERROR_SUCCESS;
6006 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6007 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6009 if (!assembly->file)
6011 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6012 return ERROR_FUNCTION_FAILED;
6015 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6016 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6017 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6018 assembly->installed = check_assembly_installed(list->package->db,
6020 assembly->component);
6022 list_add_head(list->assemblies, &assembly->entry);
6023 return ERROR_SUCCESS;
6026 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6028 IAssemblyCache *cache = NULL;
6034 static const WCHAR query[] =
6035 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6036 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6038 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6039 if (r != ERROR_SUCCESS)
6040 return ERROR_SUCCESS;
6042 hr = pCreateAssemblyCache(&cache, 0);
6044 return ERROR_FUNCTION_FAILED;
6046 list.package = package;
6048 list.assemblies = assemblies;
6050 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6051 msiobj_release(&view->hdr);
6053 IAssemblyCache_Release(cache);
6058 static void free_assemblies(struct list *assemblies)
6060 struct list *item, *cursor;
6062 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6064 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6066 list_remove(&assembly->entry);
6067 msi_free(assembly->application);
6068 msi_free(assembly->manifest);
6073 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6075 MSIASSEMBLY *assembly;
6077 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6079 if (!lstrcmpW(assembly->file->File, file))
6089 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6090 LPWSTR *path, DWORD *attrs, PVOID user)
6092 MSIASSEMBLY *assembly;
6093 WCHAR temppath[MAX_PATH];
6094 struct list *assemblies = user;
6097 if (!find_assembly(assemblies, file, &assembly))
6100 GetTempPathW(MAX_PATH, temppath);
6101 PathAddBackslashW(temppath);
6102 lstrcatW(temppath, assembly->file->FileName);
6104 if (action == MSICABEXTRACT_BEGINEXTRACT)
6106 if (assembly->installed)
6109 *path = strdupW(temppath);
6110 *attrs = assembly->file->Attributes;
6112 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6114 assembly->installed = TRUE;
6116 r = install_assembly(package, assembly, temppath);
6117 if (r != ERROR_SUCCESS)
6118 ERR("Failed to install assembly\n");
6124 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6127 struct list assemblies = LIST_INIT(assemblies);
6128 MSIASSEMBLY *assembly;
6131 if (!init_functionpointers() || !pCreateAssemblyCache)
6132 return ERROR_FUNCTION_FAILED;
6134 r = load_assemblies(package, &assemblies);
6135 if (r != ERROR_SUCCESS)
6138 if (list_empty(&assemblies))
6141 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6144 r = ERROR_OUTOFMEMORY;
6148 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6150 if (assembly->installed && !mi->is_continuous)
6153 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6154 (assembly->file->IsCompressed && !mi->is_extracted))
6158 r = ready_media(package, assembly->file, mi);
6159 if (r != ERROR_SUCCESS)
6161 ERR("Failed to ready media\n");
6166 data.package = package;
6167 data.cb = installassembly_cb;
6168 data.user = &assemblies;
6170 if (assembly->file->IsCompressed &&
6171 !msi_cabextract(package, mi, &data))
6173 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6174 r = ERROR_FUNCTION_FAILED;
6179 if (!assembly->file->IsCompressed)
6181 LPWSTR source = resolve_file_source(package, assembly->file);
6183 r = install_assembly(package, assembly, source);
6184 if (r != ERROR_SUCCESS)
6185 ERR("Failed to install assembly\n");
6190 /* FIXME: write Installer assembly reg values */
6194 free_assemblies(&assemblies);
6198 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6199 LPCSTR action, LPCWSTR table )
6201 static const WCHAR query[] = {
6202 'S','E','L','E','C','T',' ','*',' ',
6203 'F','R','O','M',' ','`','%','s','`',0 };
6204 MSIQUERY *view = NULL;
6208 r = MSI_OpenQuery( package->db, &view, query, table );
6209 if (r == ERROR_SUCCESS)
6211 r = MSI_IterateRecords(view, &count, NULL, package);
6212 msiobj_release(&view->hdr);
6216 FIXME("%s -> %u ignored %s table values\n",
6217 action, count, debugstr_w(table));
6219 return ERROR_SUCCESS;
6222 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6224 TRACE("%p\n", package);
6225 return ERROR_SUCCESS;
6228 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
6230 static const WCHAR table[] =
6231 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
6232 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
6235 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6237 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6238 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6241 static UINT ACTION_BindImage( MSIPACKAGE *package )
6243 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6244 return msi_unimplemented_action_stub( package, "BindImage", table );
6247 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6249 static const WCHAR table[] = {
6250 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
6251 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6254 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6256 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6257 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6260 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
6262 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
6263 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
6266 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6268 static const WCHAR table[] = {
6269 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6270 return msi_unimplemented_action_stub( package, "DeleteServices", table );
6272 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6274 static const WCHAR table[] = {
6275 'P','r','o','d','u','c','t','I','D',0 };
6276 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
6279 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6281 static const WCHAR table[] = {
6282 'E','n','v','i','r','o','n','m','e','n','t',0 };
6283 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
6286 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6288 static const WCHAR table[] = {
6289 'M','s','i','A','s','s','e','m','b','l','y',0 };
6290 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6293 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
6295 static const WCHAR table[] = { 'F','o','n','t',0 };
6296 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
6299 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6301 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6302 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6305 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6307 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6308 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6311 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6313 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6314 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6317 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6319 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6320 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6323 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
6325 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6326 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
6329 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6331 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6332 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6335 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
6337 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6338 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
6341 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6343 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6344 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
6347 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
6349 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6350 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
6353 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
6355 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
6356 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
6359 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
6361 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6362 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
6365 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6367 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6368 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6371 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6373 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6374 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6377 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6379 static const WCHAR table[] = { 'M','I','M','E',0 };
6380 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6383 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6385 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6386 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6389 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
6391 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
6392 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
6395 static const struct _actions StandardActions[] = {
6396 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6397 { szAppSearch, ACTION_AppSearch },
6398 { szBindImage, ACTION_BindImage },
6399 { szCCPSearch, ACTION_CCPSearch },
6400 { szCostFinalize, ACTION_CostFinalize },
6401 { szCostInitialize, ACTION_CostInitialize },
6402 { szCreateFolders, ACTION_CreateFolders },
6403 { szCreateShortcuts, ACTION_CreateShortcuts },
6404 { szDeleteServices, ACTION_DeleteServices },
6405 { szDisableRollback, NULL },
6406 { szDuplicateFiles, ACTION_DuplicateFiles },
6407 { szExecuteAction, ACTION_ExecuteAction },
6408 { szFileCost, ACTION_FileCost },
6409 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6410 { szForceReboot, ACTION_ForceReboot },
6411 { szInstallAdminPackage, NULL },
6412 { szInstallExecute, ACTION_InstallExecute },
6413 { szInstallExecuteAgain, ACTION_InstallExecute },
6414 { szInstallFiles, ACTION_InstallFiles},
6415 { szInstallFinalize, ACTION_InstallFinalize },
6416 { szInstallInitialize, ACTION_InstallInitialize },
6417 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6418 { szInstallValidate, ACTION_InstallValidate },
6419 { szIsolateComponents, ACTION_IsolateComponents },
6420 { szLaunchConditions, ACTION_LaunchConditions },
6421 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6422 { szMoveFiles, ACTION_MoveFiles },
6423 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6424 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6425 { szInstallODBC, ACTION_InstallODBC },
6426 { szInstallServices, ACTION_InstallServices },
6427 { szPatchFiles, ACTION_PatchFiles },
6428 { szProcessComponents, ACTION_ProcessComponents },
6429 { szPublishComponents, ACTION_PublishComponents },
6430 { szPublishFeatures, ACTION_PublishFeatures },
6431 { szPublishProduct, ACTION_PublishProduct },
6432 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6433 { szRegisterComPlus, ACTION_RegisterComPlus},
6434 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6435 { szRegisterFonts, ACTION_RegisterFonts },
6436 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6437 { szRegisterProduct, ACTION_RegisterProduct },
6438 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6439 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6440 { szRegisterUser, ACTION_RegisterUser },
6441 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6442 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6443 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6444 { szRemoveFiles, ACTION_RemoveFiles },
6445 { szRemoveFolders, ACTION_RemoveFolders },
6446 { szRemoveIniValues, ACTION_RemoveIniValues },
6447 { szRemoveODBC, ACTION_RemoveODBC },
6448 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6449 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6450 { szResolveSource, ACTION_ResolveSource },
6451 { szRMCCPSearch, ACTION_RMCCPSearch },
6452 { szScheduleReboot, NULL },
6453 { szSelfRegModules, ACTION_SelfRegModules },
6454 { szSelfUnregModules, ACTION_SelfUnregModules },
6455 { szSetODBCFolders, NULL },
6456 { szStartServices, ACTION_StartServices },
6457 { szStopServices, ACTION_StopServices },
6458 { szUnpublishComponents, ACTION_UnpublishComponents },
6459 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6460 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6461 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6462 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6463 { szUnregisterFonts, ACTION_UnregisterFonts },
6464 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6465 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6466 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6467 { szValidateProductID, ACTION_ValidateProductID },
6468 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6469 { szWriteIniValues, ACTION_WriteIniValues },
6470 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6474 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
6475 UINT* rc, BOOL force )
6481 if (!run && !package->script->CurrentlyScripting)
6486 if (strcmpW(action,szInstallFinalize) == 0 ||
6487 strcmpW(action,szInstallExecute) == 0 ||
6488 strcmpW(action,szInstallExecuteAgain) == 0)
6493 while (StandardActions[i].action != NULL)
6495 if (strcmpW(StandardActions[i].action, action)==0)
6499 ui_actioninfo(package, action, TRUE, 0);
6500 *rc = schedule_action(package,INSTALL_SCRIPT,action);
6501 ui_actioninfo(package, action, FALSE, *rc);
6505 ui_actionstart(package, action);
6506 if (StandardActions[i].handler)
6508 *rc = StandardActions[i].handler(package);
6512 FIXME("unhandled standard action %s\n",debugstr_w(action));
6513 *rc = ERROR_SUCCESS;