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};
1785 static const WCHAR reinstall[] = {'R','E','I','N','S','T','A','L','L',0};
1787 MSIFEATURE *feature;
1789 override = msi_dup_property( package, property );
1793 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1795 if (lstrcmpW(property, remove) &&
1796 (feature->Level <= 0 || feature->Level > level))
1799 if (!strcmpW(property, reinstall)) state = feature->Installed;
1801 if (strcmpiW(override,all)==0)
1802 msi_feature_set_state(package, feature, state);
1805 LPWSTR ptr = override;
1806 LPWSTR ptr2 = strchrW(override,',');
1810 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1811 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1813 msi_feature_set_state(package, feature, state);
1819 ptr2 = strchrW(ptr,',');
1831 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1834 static const WCHAR szlevel[] =
1835 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1836 static const WCHAR szAddLocal[] =
1837 {'A','D','D','L','O','C','A','L',0};
1838 static const WCHAR szAddSource[] =
1839 {'A','D','D','S','O','U','R','C','E',0};
1840 static const WCHAR szRemove[] =
1841 {'R','E','M','O','V','E',0};
1842 static const WCHAR szReinstall[] =
1843 {'R','E','I','N','S','T','A','L','L',0};
1844 BOOL override = FALSE;
1845 MSICOMPONENT* component;
1846 MSIFEATURE *feature;
1849 /* I do not know if this is where it should happen.. but */
1851 TRACE("Checking Install Level\n");
1853 level = msi_get_property_int(package, szlevel, 1);
1855 /* ok here is the _real_ rub
1856 * all these activation/deactivation things happen in order and things
1857 * later on the list override things earlier on the list.
1858 * 1) INSTALLLEVEL processing
1868 * 11) FILEADDDEFAULT
1870 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1871 * REMOVE are the big ones, since we don't handle administrative installs
1874 override |= process_state_property(package, level, szAddLocal, INSTALLSTATE_LOCAL);
1875 override |= process_state_property(package, level, szRemove, INSTALLSTATE_ABSENT);
1876 override |= process_state_property(package, level, szAddSource, INSTALLSTATE_SOURCE);
1877 override |= process_state_property(package, level, szReinstall, INSTALLSTATE_UNKNOWN);
1881 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1883 BOOL feature_state = ((feature->Level > 0) &&
1884 (feature->Level <= level));
1886 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1888 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1889 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1890 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1891 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1893 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1897 /* disable child features of unselected parent features */
1898 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1902 if (feature->Level > 0 && feature->Level <= level)
1905 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1906 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1911 /* set the Preselected Property */
1912 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1913 static const WCHAR szOne[] = { '1', 0 };
1915 MSI_SetPropertyW(package,szPreselected,szOne);
1919 * now we want to enable or disable components base on feature
1922 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1926 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1927 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1929 if (!feature->Level)
1932 /* features with components that have compressed files are made local */
1933 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1935 if (cl->component->Enabled &&
1936 cl->component->ForceLocalState &&
1937 feature->Action == INSTALLSTATE_SOURCE)
1939 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1944 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1946 component = cl->component;
1948 if (!component->Enabled)
1951 switch (feature->Action)
1953 case INSTALLSTATE_ABSENT:
1954 component->anyAbsent = 1;
1956 case INSTALLSTATE_ADVERTISED:
1957 component->hasAdvertiseFeature = 1;
1959 case INSTALLSTATE_SOURCE:
1960 component->hasSourceFeature = 1;
1962 case INSTALLSTATE_LOCAL:
1963 component->hasLocalFeature = 1;
1965 case INSTALLSTATE_DEFAULT:
1966 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1967 component->hasAdvertiseFeature = 1;
1968 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1969 component->hasSourceFeature = 1;
1971 component->hasLocalFeature = 1;
1979 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1981 /* if the component isn't enabled, leave it alone */
1982 if (!component->Enabled)
1985 /* check if it's local or source */
1986 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1987 (component->hasLocalFeature || component->hasSourceFeature))
1989 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1990 !component->ForceLocalState)
1991 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1993 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1997 /* if any feature is local, the component must be local too */
1998 if (component->hasLocalFeature)
2000 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2004 if (component->hasSourceFeature)
2006 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
2010 if (component->hasAdvertiseFeature)
2012 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
2016 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2017 if (component->anyAbsent)
2018 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
2021 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2023 if (component->Action == INSTALLSTATE_DEFAULT)
2025 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2026 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2029 TRACE("Result: Component %s (Installed %i, Action %i)\n",
2030 debugstr_w(component->Component), component->Installed, component->Action);
2034 return ERROR_SUCCESS;
2037 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2039 MSIPACKAGE *package = param;
2044 name = MSI_RecordGetString(row,1);
2046 f = get_loaded_folder(package, name);
2047 if (!f) return ERROR_SUCCESS;
2049 /* reset the ResolvedTarget */
2050 msi_free(f->ResolvedTarget);
2051 f->ResolvedTarget = NULL;
2053 /* This helper function now does ALL the work */
2054 TRACE("Dir %s ...\n",debugstr_w(name));
2055 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
2056 TRACE("resolves to %s\n",debugstr_w(path));
2059 return ERROR_SUCCESS;
2062 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2064 MSIPACKAGE *package = param;
2066 MSIFEATURE *feature;
2068 name = MSI_RecordGetString( row, 1 );
2070 feature = get_loaded_feature( package, name );
2072 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2076 Condition = MSI_RecordGetString(row,3);
2078 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2080 int level = MSI_RecordGetInteger(row,2);
2081 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2082 feature->Level = level;
2085 return ERROR_SUCCESS;
2088 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
2090 static const WCHAR name_fmt[] =
2091 {'%','u','.','%','u','.','%','u','.','%','u',0};
2092 static const WCHAR name[] = {'\\',0};
2093 VS_FIXEDFILEINFO *lpVer;
2094 WCHAR filever[0x100];
2100 TRACE("%s\n", debugstr_w(filename));
2102 versize = GetFileVersionInfoSizeW( filename, &handle );
2106 version = msi_alloc( versize );
2107 GetFileVersionInfoW( filename, 0, versize, version );
2109 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
2111 msi_free( version );
2115 sprintfW( filever, name_fmt,
2116 HIWORD(lpVer->dwFileVersionMS),
2117 LOWORD(lpVer->dwFileVersionMS),
2118 HIWORD(lpVer->dwFileVersionLS),
2119 LOWORD(lpVer->dwFileVersionLS));
2121 msi_free( version );
2123 return strdupW( filever );
2126 static UINT msi_check_file_install_states( MSIPACKAGE *package )
2128 LPWSTR file_version;
2131 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2133 MSICOMPONENT* comp = file->Component;
2139 if (file->IsCompressed)
2140 comp->ForceLocalState = TRUE;
2142 /* calculate target */
2143 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2145 msi_free(file->TargetPath);
2147 TRACE("file %s is named %s\n",
2148 debugstr_w(file->File), debugstr_w(file->FileName));
2150 file->TargetPath = build_directory_name(2, p, file->FileName);
2154 TRACE("file %s resolves to %s\n",
2155 debugstr_w(file->File), debugstr_w(file->TargetPath));
2157 /* don't check files of components that aren't installed */
2158 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2159 comp->Installed == INSTALLSTATE_ABSENT)
2161 file->state = msifs_missing; /* assume files are missing */
2165 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2167 file->state = msifs_missing;
2168 comp->Cost += file->FileSize;
2172 if (file->Version &&
2173 (file_version = msi_get_disk_file_version( file->TargetPath )))
2175 TRACE("new %s old %s\n", debugstr_w(file->Version),
2176 debugstr_w(file_version));
2177 /* FIXME: seems like a bad way to compare version numbers */
2178 if (lstrcmpiW(file_version, file->Version)<0)
2180 file->state = msifs_overwrite;
2181 comp->Cost += file->FileSize;
2184 file->state = msifs_present;
2185 msi_free( file_version );
2188 file->state = msifs_present;
2191 return ERROR_SUCCESS;
2195 * A lot is done in this function aside from just the costing.
2196 * The costing needs to be implemented at some point but for now I am going
2197 * to focus on the directory building
2200 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2202 static const WCHAR ExecSeqQuery[] =
2203 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2204 '`','D','i','r','e','c','t','o','r','y','`',0};
2205 static const WCHAR ConditionQuery[] =
2206 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2207 '`','C','o','n','d','i','t','i','o','n','`',0};
2208 static const WCHAR szCosting[] =
2209 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2210 static const WCHAR szlevel[] =
2211 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2212 static const WCHAR szOutOfDiskSpace[] =
2213 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2214 static const WCHAR szOne[] = { '1', 0 };
2215 static const WCHAR szZero[] = { '0', 0 };
2221 TRACE("Building Directory properties\n");
2223 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2224 if (rc == ERROR_SUCCESS)
2226 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2228 msiobj_release(&view->hdr);
2231 /* read components states from the registry */
2232 ACTION_GetComponentInstallStates(package);
2233 ACTION_GetFeatureInstallStates(package);
2235 TRACE("File calculations\n");
2236 msi_check_file_install_states( package );
2238 TRACE("Evaluating Condition Table\n");
2240 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2241 if (rc == ERROR_SUCCESS)
2243 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2245 msiobj_release(&view->hdr);
2248 TRACE("Enabling or Disabling Components\n");
2249 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2251 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2253 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2254 comp->Enabled = FALSE;
2257 comp->Enabled = TRUE;
2260 MSI_SetPropertyW(package,szCosting,szOne);
2261 /* set default run level if not set */
2262 level = msi_dup_property( package, szlevel );
2264 MSI_SetPropertyW(package,szlevel, szOne);
2267 /* FIXME: check volume disk space */
2268 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2270 return MSI_SetFeatureStates(package);
2273 /* OK this value is "interpreted" and then formatted based on the
2274 first few characters */
2275 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2280 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2286 LPWSTR deformated = NULL;
2289 deformat_string(package, &value[2], &deformated);
2291 /* binary value type */
2295 *size = (strlenW(ptr)/2)+1;
2297 *size = strlenW(ptr)/2;
2299 data = msi_alloc(*size);
2305 /* if uneven pad with a zero in front */
2311 data[count] = (BYTE)strtol(byte,NULL,0);
2313 TRACE("Uneven byte count\n");
2321 data[count] = (BYTE)strtol(byte,NULL,0);
2324 msi_free(deformated);
2326 TRACE("Data %i bytes(%i)\n",*size,count);
2333 deformat_string(package, &value[1], &deformated);
2336 *size = sizeof(DWORD);
2337 data = msi_alloc(*size);
2343 if ( (*p < '0') || (*p > '9') )
2349 if (deformated[0] == '-')
2352 TRACE("DWORD %i\n",*(LPDWORD)data);
2354 msi_free(deformated);
2359 static const WCHAR szMulti[] = {'[','~',']',0};
2368 *type=REG_EXPAND_SZ;
2376 if (strstrW(value,szMulti))
2377 *type = REG_MULTI_SZ;
2379 /* remove initial delimiter */
2380 if (!strncmpW(value, szMulti, 3))
2383 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2385 /* add double NULL terminator */
2386 if (*type == REG_MULTI_SZ)
2388 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2389 data = msi_realloc_zero(data, *size);
2395 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2397 MSIPACKAGE *package = param;
2398 static const WCHAR szHCR[] =
2399 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2400 'R','O','O','T','\\',0};
2401 static const WCHAR szHCU[] =
2402 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2403 'U','S','E','R','\\',0};
2404 static const WCHAR szHLM[] =
2405 {'H','K','E','Y','_','L','O','C','A','L','_',
2406 'M','A','C','H','I','N','E','\\',0};
2407 static const WCHAR szHU[] =
2408 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2410 LPSTR value_data = NULL;
2411 HKEY root_key, hkey;
2414 LPCWSTR szRoot, component, name, key, value;
2419 BOOL check_first = FALSE;
2422 ui_progress(package,2,0,0,0);
2429 component = MSI_RecordGetString(row, 6);
2430 comp = get_loaded_component(package,component);
2432 return ERROR_SUCCESS;
2434 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2436 TRACE("Skipping write due to disabled component %s\n",
2437 debugstr_w(component));
2439 comp->Action = comp->Installed;
2441 return ERROR_SUCCESS;
2444 comp->Action = INSTALLSTATE_LOCAL;
2446 name = MSI_RecordGetString(row, 4);
2447 if( MSI_RecordIsNull(row,5) && name )
2449 /* null values can have special meanings */
2450 if (name[0]=='-' && name[1] == 0)
2451 return ERROR_SUCCESS;
2452 else if ((name[0]=='+' && name[1] == 0) ||
2453 (name[0] == '*' && name[1] == 0))
2458 root = MSI_RecordGetInteger(row,2);
2459 key = MSI_RecordGetString(row, 3);
2461 /* get the root key */
2466 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2467 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2468 if (all_users && all_users[0] == '1')
2470 root_key = HKEY_LOCAL_MACHINE;
2475 root_key = HKEY_CURRENT_USER;
2478 msi_free(all_users);
2481 case 0: root_key = HKEY_CLASSES_ROOT;
2484 case 1: root_key = HKEY_CURRENT_USER;
2487 case 2: root_key = HKEY_LOCAL_MACHINE;
2490 case 3: root_key = HKEY_USERS;
2494 ERR("Unknown root %i\n",root);
2500 return ERROR_SUCCESS;
2502 deformat_string(package, key , &deformated);
2503 size = strlenW(deformated) + strlenW(szRoot) + 1;
2504 uikey = msi_alloc(size*sizeof(WCHAR));
2505 strcpyW(uikey,szRoot);
2506 strcatW(uikey,deformated);
2508 if (RegCreateKeyW( root_key, deformated, &hkey))
2510 ERR("Could not create key %s\n",debugstr_w(deformated));
2511 msi_free(deformated);
2513 return ERROR_SUCCESS;
2515 msi_free(deformated);
2517 value = MSI_RecordGetString(row,5);
2519 value_data = parse_value(package, value, &type, &size);
2522 static const WCHAR szEmpty[] = {0};
2523 value_data = (LPSTR)strdupW(szEmpty);
2524 size = sizeof(szEmpty);
2528 deformat_string(package, name, &deformated);
2532 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2534 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2539 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2540 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2542 TRACE("value %s of %s checked already exists\n",
2543 debugstr_w(deformated), debugstr_w(uikey));
2547 TRACE("Checked and setting value %s of %s\n",
2548 debugstr_w(deformated), debugstr_w(uikey));
2549 if (deformated || size)
2550 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2555 uirow = MSI_CreateRecord(3);
2556 MSI_RecordSetStringW(uirow,2,deformated);
2557 MSI_RecordSetStringW(uirow,1,uikey);
2560 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2562 MSI_RecordSetStringW(uirow,3,value);
2564 ui_actiondata(package,szWriteRegistryValues,uirow);
2565 msiobj_release( &uirow->hdr );
2567 msi_free(value_data);
2568 msi_free(deformated);
2571 return ERROR_SUCCESS;
2574 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2578 static const WCHAR ExecSeqQuery[] =
2579 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2580 '`','R','e','g','i','s','t','r','y','`',0 };
2582 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2583 if (rc != ERROR_SUCCESS)
2584 return ERROR_SUCCESS;
2586 /* increment progress bar each time action data is sent */
2587 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2589 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2591 msiobj_release(&view->hdr);
2595 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2597 package->script->CurrentlyScripting = TRUE;
2599 return ERROR_SUCCESS;
2603 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2608 static const WCHAR q1[]=
2609 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2610 '`','R','e','g','i','s','t','r','y','`',0};
2613 MSIFEATURE *feature;
2616 TRACE("InstallValidate\n");
2618 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2619 if (rc == ERROR_SUCCESS)
2621 MSI_IterateRecords( view, &progress, NULL, package );
2622 msiobj_release( &view->hdr );
2623 total += progress * REG_PROGRESS_VALUE;
2626 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2627 total += COMPONENT_PROGRESS_VALUE;
2629 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2630 total += file->FileSize;
2632 ui_progress(package,0,total,0,0);
2634 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2636 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2637 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2638 feature->ActionRequest);
2641 return ERROR_SUCCESS;
2644 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2646 MSIPACKAGE* package = param;
2647 LPCWSTR cond = NULL;
2648 LPCWSTR message = NULL;
2651 static const WCHAR title[]=
2652 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2654 cond = MSI_RecordGetString(row,1);
2656 r = MSI_EvaluateConditionW(package,cond);
2657 if (r == MSICONDITION_FALSE)
2659 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2662 message = MSI_RecordGetString(row,2);
2663 deformat_string(package,message,&deformated);
2664 MessageBoxW(NULL,deformated,title,MB_OK);
2665 msi_free(deformated);
2668 return ERROR_INSTALL_FAILURE;
2671 return ERROR_SUCCESS;
2674 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2677 MSIQUERY * view = NULL;
2678 static const WCHAR ExecSeqQuery[] =
2679 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2680 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2682 TRACE("Checking launch conditions\n");
2684 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2685 if (rc != ERROR_SUCCESS)
2686 return ERROR_SUCCESS;
2688 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2689 msiobj_release(&view->hdr);
2694 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2698 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2700 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2702 MSIRECORD * row = 0;
2704 LPWSTR deformated,buffer,deformated_name;
2706 static const WCHAR ExecSeqQuery[] =
2707 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2708 '`','R','e','g','i','s','t','r','y','`',' ',
2709 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2710 ' ','=',' ' ,'\'','%','s','\'',0 };
2711 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2712 static const WCHAR fmt2[]=
2713 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2715 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2719 root = MSI_RecordGetInteger(row,2);
2720 key = MSI_RecordGetString(row, 3);
2721 name = MSI_RecordGetString(row, 4);
2722 deformat_string(package, key , &deformated);
2723 deformat_string(package, name, &deformated_name);
2725 len = strlenW(deformated) + 6;
2726 if (deformated_name)
2727 len+=strlenW(deformated_name);
2729 buffer = msi_alloc( len *sizeof(WCHAR));
2731 if (deformated_name)
2732 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2734 sprintfW(buffer,fmt,root,deformated);
2736 msi_free(deformated);
2737 msi_free(deformated_name);
2738 msiobj_release(&row->hdr);
2742 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2744 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2749 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2752 return strdupW( file->TargetPath );
2757 static HKEY openSharedDLLsKey(void)
2760 static const WCHAR path[] =
2761 {'S','o','f','t','w','a','r','e','\\',
2762 'M','i','c','r','o','s','o','f','t','\\',
2763 'W','i','n','d','o','w','s','\\',
2764 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2765 'S','h','a','r','e','d','D','L','L','s',0};
2767 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2771 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2776 DWORD sz = sizeof(count);
2779 hkey = openSharedDLLsKey();
2780 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2781 if (rc != ERROR_SUCCESS)
2787 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2791 hkey = openSharedDLLsKey();
2793 msi_reg_set_val_dword( hkey, path, count );
2795 RegDeleteValueW(hkey,path);
2801 * Return TRUE if the count should be written out and FALSE if not
2803 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2805 MSIFEATURE *feature;
2809 /* only refcount DLLs */
2810 if (comp->KeyPath == NULL ||
2811 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2812 comp->Attributes & msidbComponentAttributesODBCDataSource)
2816 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2817 write = (count > 0);
2819 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2823 /* increment counts */
2824 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2828 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2831 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2833 if ( cl->component == comp )
2838 /* decrement counts */
2839 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2843 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2846 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2848 if ( cl->component == comp )
2853 /* ref count all the files in the component */
2858 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2860 if (file->Component == comp)
2861 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2865 /* add a count for permanent */
2866 if (comp->Attributes & msidbComponentAttributesPermanent)
2869 comp->RefCount = count;
2872 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2875 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2877 WCHAR squished_pc[GUID_SIZE];
2878 WCHAR squished_cc[GUID_SIZE];
2885 squash_guid(package->ProductCode,squished_pc);
2886 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2888 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2892 ui_progress(package,2,0,0,0);
2893 if (!comp->ComponentId)
2896 squash_guid(comp->ComponentId,squished_cc);
2898 msi_free(comp->FullKeypath);
2899 comp->FullKeypath = resolve_keypath( package, comp );
2901 ACTION_RefCountComponent( package, comp );
2903 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2904 debugstr_w(comp->Component),
2905 debugstr_w(squished_cc),
2906 debugstr_w(comp->FullKeypath),
2909 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL) ||
2910 ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE))
2912 if (!comp->FullKeypath)
2915 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2916 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2919 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2922 if (rc != ERROR_SUCCESS)
2925 if (comp->Attributes & msidbComponentAttributesPermanent)
2927 static const WCHAR szPermKey[] =
2928 { '0','0','0','0','0','0','0','0','0','0','0','0',
2929 '0','0','0','0','0','0','0','0','0','0','0','0',
2930 '0','0','0','0','0','0','0','0',0 };
2932 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2935 if (comp->Action == INSTALLSTATE_LOCAL)
2936 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2942 WCHAR source[MAX_PATH];
2943 WCHAR base[MAX_PATH];
2946 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2947 static const WCHAR query[] = {
2948 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2949 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2950 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2951 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2952 '`','D','i','s','k','I','d','`',0};
2954 file = get_loaded_file(package, comp->KeyPath);
2958 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2959 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2960 ptr2 = strrchrW(source, '\\') + 1;
2961 msiobj_release(&row->hdr);
2963 lstrcpyW(base, package->PackagePath);
2964 ptr = strrchrW(base, '\\');
2967 sourcepath = resolve_file_source(package, file);
2968 ptr = sourcepath + lstrlenW(base);
2969 lstrcpyW(ptr2, ptr);
2970 msi_free(sourcepath);
2972 msi_reg_set_val_str(hkey, squished_pc, source);
2976 else if (ACTION_VerifyComponentForAction(comp, INSTALLSTATE_ABSENT))
2978 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2979 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2981 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2985 uirow = MSI_CreateRecord(3);
2986 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2987 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2988 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2989 ui_actiondata(package,szProcessComponents,uirow);
2990 msiobj_release( &uirow->hdr );
2993 return ERROR_SUCCESS;
3004 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3005 LPWSTR lpszName, LONG_PTR lParam)
3008 typelib_struct *tl_struct = (typelib_struct*) lParam;
3009 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3013 if (!IS_INTRESOURCE(lpszName))
3015 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3019 sz = strlenW(tl_struct->source)+4;
3020 sz *= sizeof(WCHAR);
3022 if ((INT_PTR)lpszName == 1)
3023 tl_struct->path = strdupW(tl_struct->source);
3026 tl_struct->path = msi_alloc(sz);
3027 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3030 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3031 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3034 msi_free(tl_struct->path);
3035 tl_struct->path = NULL;
3040 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3041 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3043 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3047 msi_free(tl_struct->path);
3048 tl_struct->path = NULL;
3050 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3051 ITypeLib_Release(tl_struct->ptLib);
3056 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3058 MSIPACKAGE* package = param;
3062 typelib_struct tl_struct;
3067 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
3069 component = MSI_RecordGetString(row,3);
3070 comp = get_loaded_component(package,component);
3072 return ERROR_SUCCESS;
3074 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3076 TRACE("Skipping typelib reg due to disabled component\n");
3078 comp->Action = comp->Installed;
3080 return ERROR_SUCCESS;
3083 comp->Action = INSTALLSTATE_LOCAL;
3085 file = get_loaded_file( package, comp->KeyPath );
3087 return ERROR_SUCCESS;
3089 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3093 guid = MSI_RecordGetString(row,1);
3094 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
3095 tl_struct.source = strdupW( file->TargetPath );
3096 tl_struct.path = NULL;
3098 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3099 (LONG_PTR)&tl_struct);
3107 helpid = MSI_RecordGetString(row,6);
3110 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3111 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3115 ERR("Failed to register type library %s\n",
3116 debugstr_w(tl_struct.path));
3119 ui_actiondata(package,szRegisterTypeLibraries,row);
3121 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3124 ITypeLib_Release(tl_struct.ptLib);
3125 msi_free(tl_struct.path);
3128 ERR("Failed to load type library %s\n",
3129 debugstr_w(tl_struct.source));
3131 FreeLibrary(module);
3132 msi_free(tl_struct.source);
3136 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3139 ERR("Failed to load type library: %08x\n", hr);
3140 return ERROR_FUNCTION_FAILED;
3143 ITypeLib_Release(tlib);
3146 return ERROR_SUCCESS;
3149 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3152 * OK this is a bit confusing.. I am given a _Component key and I believe
3153 * that the file that is being registered as a type library is the "key file
3154 * of that component" which I interpret to mean "The file in the KeyPath of
3159 static const WCHAR Query[] =
3160 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3161 '`','T','y','p','e','L','i','b','`',0};
3163 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3164 if (rc != ERROR_SUCCESS)
3165 return ERROR_SUCCESS;
3167 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3168 msiobj_release(&view->hdr);
3172 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3174 MSIPACKAGE *package = param;
3175 LPWSTR target_file, target_folder, filename;
3176 LPCWSTR buffer, extension;
3178 static const WCHAR szlnk[]={'.','l','n','k',0};
3179 IShellLinkW *sl = NULL;
3180 IPersistFile *pf = NULL;
3183 buffer = MSI_RecordGetString(row,4);
3184 comp = get_loaded_component(package,buffer);
3186 return ERROR_SUCCESS;
3188 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
3190 TRACE("Skipping shortcut creation due to disabled component\n");
3192 comp->Action = comp->Installed;
3194 return ERROR_SUCCESS;
3197 comp->Action = INSTALLSTATE_LOCAL;
3199 ui_actiondata(package,szCreateShortcuts,row);
3201 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3202 &IID_IShellLinkW, (LPVOID *) &sl );
3206 ERR("CLSID_ShellLink not available\n");
3210 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3213 ERR("QueryInterface(IID_IPersistFile) failed\n");
3217 buffer = MSI_RecordGetString(row,2);
3218 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
3220 /* may be needed because of a bug somewhere else */
3221 create_full_pathW(target_folder);
3223 filename = msi_dup_record_field( row, 3 );
3224 reduce_to_longfilename(filename);
3226 extension = strchrW(filename,'.');
3227 if (!extension || strcmpiW(extension,szlnk))
3229 int len = strlenW(filename);
3230 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3231 memcpy(filename + len, szlnk, sizeof(szlnk));
3233 target_file = build_directory_name(2, target_folder, filename);
3234 msi_free(target_folder);
3237 buffer = MSI_RecordGetString(row,5);
3238 if (strchrW(buffer,'['))
3241 deformat_string(package,buffer,&deformated);
3242 IShellLinkW_SetPath(sl,deformated);
3243 msi_free(deformated);
3247 FIXME("poorly handled shortcut format, advertised shortcut\n");
3248 IShellLinkW_SetPath(sl,comp->FullKeypath);
3251 if (!MSI_RecordIsNull(row,6))
3254 buffer = MSI_RecordGetString(row,6);
3255 deformat_string(package,buffer,&deformated);
3256 IShellLinkW_SetArguments(sl,deformated);
3257 msi_free(deformated);
3260 if (!MSI_RecordIsNull(row,7))
3262 buffer = MSI_RecordGetString(row,7);
3263 IShellLinkW_SetDescription(sl,buffer);
3266 if (!MSI_RecordIsNull(row,8))
3267 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3269 if (!MSI_RecordIsNull(row,9))
3274 buffer = MSI_RecordGetString(row,9);
3276 Path = build_icon_path(package,buffer);
3277 index = MSI_RecordGetInteger(row,10);
3279 /* no value means 0 */
3280 if (index == MSI_NULL_INTEGER)
3283 IShellLinkW_SetIconLocation(sl,Path,index);
3287 if (!MSI_RecordIsNull(row,11))
3288 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3290 if (!MSI_RecordIsNull(row,12))
3293 buffer = MSI_RecordGetString(row,12);
3294 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3296 IShellLinkW_SetWorkingDirectory(sl,Path);
3300 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3301 IPersistFile_Save(pf,target_file,FALSE);
3303 msi_free(target_file);
3307 IPersistFile_Release( pf );
3309 IShellLinkW_Release( sl );
3311 return ERROR_SUCCESS;
3314 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3319 static const WCHAR Query[] =
3320 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3321 '`','S','h','o','r','t','c','u','t','`',0};
3323 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3324 if (rc != ERROR_SUCCESS)
3325 return ERROR_SUCCESS;
3327 res = CoInitialize( NULL );
3330 ERR("CoInitialize failed\n");
3331 return ERROR_FUNCTION_FAILED;
3334 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3335 msiobj_release(&view->hdr);
3342 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3344 MSIPACKAGE* package = param;
3353 FileName = MSI_RecordGetString(row,1);
3356 ERR("Unable to get FileName\n");
3357 return ERROR_SUCCESS;
3360 FilePath = build_icon_path(package,FileName);
3362 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3364 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3365 FILE_ATTRIBUTE_NORMAL, NULL);
3367 if (the_file == INVALID_HANDLE_VALUE)
3369 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3371 return ERROR_SUCCESS;
3378 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3379 if (rc != ERROR_SUCCESS)
3381 ERR("Failed to get stream\n");
3382 CloseHandle(the_file);
3383 DeleteFileW(FilePath);
3386 WriteFile(the_file,buffer,sz,&write,NULL);
3387 } while (sz == 1024);
3391 CloseHandle(the_file);
3393 uirow = MSI_CreateRecord(1);
3394 MSI_RecordSetStringW(uirow,1,FileName);
3395 ui_actiondata(package,szPublishProduct,uirow);
3396 msiobj_release( &uirow->hdr );
3398 return ERROR_SUCCESS;
3401 static UINT msi_publish_icons(MSIPACKAGE *package)
3406 static const WCHAR query[]= {
3407 'S','E','L','E','C','T',' ','*',' ',
3408 'F','R','O','M',' ','`','I','c','o','n','`',0};
3410 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3411 if (r == ERROR_SUCCESS)
3413 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3414 msiobj_release(&view->hdr);
3417 return ERROR_SUCCESS;
3420 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3426 MSISOURCELISTINFO *info;
3428 static const WCHAR szEmpty[] = {0};
3429 static const WCHAR szSourceList[] = {'S','o','u','r','c','e','L','i','s','t',0};
3431 r = RegCreateKeyW(hkey, szSourceList, &source);
3432 if (r != ERROR_SUCCESS)
3435 RegCloseKey(source);
3437 buffer = strrchrW(package->PackagePath, '\\') + 1;
3438 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3439 package->Context, MSICODE_PRODUCT,
3440 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3441 if (r != ERROR_SUCCESS)
3444 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3445 package->Context, MSICODE_PRODUCT,
3446 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3447 if (r != ERROR_SUCCESS)
3450 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3451 package->Context, MSICODE_PRODUCT,
3452 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3453 if (r != ERROR_SUCCESS)
3456 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3458 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3459 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3460 info->options, info->value);
3462 MsiSourceListSetInfoW(package->ProductCode, NULL,
3463 info->context, info->options,
3464 info->property, info->value);
3467 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3469 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3470 disk->context, disk->options,
3471 disk->disk_id, disk->volume_label, disk->disk_prompt);
3474 return ERROR_SUCCESS;
3477 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3479 MSIHANDLE hdb, suminfo;
3480 WCHAR guids[MAX_PATH];
3481 WCHAR packcode[SQUISH_GUID_SIZE];
3488 static const WCHAR szProductLanguage[] =
3489 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3490 static const WCHAR szARPProductIcon[] =
3491 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3492 static const WCHAR szProductVersion[] =
3493 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3494 static const WCHAR szAssignment[] =
3495 {'A','s','s','i','g','n','m','e','n','t',0};
3496 static const WCHAR szAdvertiseFlags[] =
3497 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3498 static const WCHAR szClients[] =
3499 {'C','l','i','e','n','t','s',0};
3500 static const WCHAR szColon[] = {':',0};
3502 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3503 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3506 langid = msi_get_property_int(package, szProductLanguage, 0);
3507 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3509 ptr = strrchrW(package->PackagePath, '\\' ) + 1;
3510 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGENAMEW, ptr);
3513 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3515 buffer = msi_dup_property(package, szARPProductIcon);
3518 LPWSTR path = build_icon_path(package,buffer);
3519 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3524 buffer = msi_dup_property(package, szProductVersion);
3527 DWORD verdword = msi_version_str_to_dword(buffer);
3528 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3532 msi_reg_set_val_dword(hkey, szAssignment, 0);
3533 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3534 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3535 msi_reg_set_val_str(hkey, szClients, szColon);
3537 hdb = alloc_msihandle(&package->db->hdr);
3539 return ERROR_NOT_ENOUGH_MEMORY;
3541 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3542 MsiCloseHandle(hdb);
3543 if (r != ERROR_SUCCESS)
3547 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3548 NULL, guids, &size);
3549 if (r != ERROR_SUCCESS)
3552 ptr = strchrW(guids, ';');
3554 squash_guid(guids, packcode);
3555 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3558 MsiCloseHandle(suminfo);
3559 return ERROR_SUCCESS;
3562 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3567 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3569 static const WCHAR szUpgradeCode[] =
3570 {'U','p','g','r','a','d','e','C','o','d','e',0};
3572 upgrade = msi_dup_property(package, szUpgradeCode);
3574 return ERROR_SUCCESS;
3576 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3578 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3579 if (r != ERROR_SUCCESS)
3584 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3585 if (r != ERROR_SUCCESS)
3589 squash_guid(package->ProductCode, squashed_pc);
3590 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3599 static BOOL msi_check_publish(MSIPACKAGE *package)
3601 MSIFEATURE *feature;
3603 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3605 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3612 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3614 MSIFEATURE *feature;
3616 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3618 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3625 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3627 WCHAR patch_squashed[GUID_SIZE];
3630 UINT r = ERROR_FUNCTION_FAILED;
3632 static const WCHAR szPatches[] = {'P','a','t','c','h','e','s',0};
3634 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3636 if (res != ERROR_SUCCESS)
3637 return ERROR_FUNCTION_FAILED;
3639 squash_guid(package->patch->patchcode, patch_squashed);
3641 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3642 (const BYTE *)patch_squashed,
3643 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3644 if (res != ERROR_SUCCESS)
3647 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3648 (const BYTE *)package->patch->transforms,
3649 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3650 if (res == ERROR_SUCCESS)
3654 RegCloseKey(patches);
3659 * 99% of the work done here is only done for
3660 * advertised installs. However this is where the
3661 * Icon table is processed and written out
3662 * so that is what I am going to do here.
3664 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3670 /* FIXME: also need to publish if the product is in advertise mode */
3671 if (!msi_check_publish(package))
3672 return ERROR_SUCCESS;
3674 rc = MSIREG_OpenProductKey(package->ProductCode, package->Context,
3676 if (rc != ERROR_SUCCESS)
3679 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3680 NULL, &hudkey, TRUE);
3681 if (rc != ERROR_SUCCESS)
3684 rc = msi_publish_upgrade_code(package);
3685 if (rc != ERROR_SUCCESS)
3690 rc = msi_publish_patch(package, hukey, hudkey);
3691 if (rc != ERROR_SUCCESS)
3695 rc = msi_publish_product_properties(package, hukey);
3696 if (rc != ERROR_SUCCESS)
3699 rc = msi_publish_sourcelist(package, hukey);
3700 if (rc != ERROR_SUCCESS)
3703 rc = msi_publish_icons(package);
3707 RegCloseKey(hudkey);
3712 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3714 MSIPACKAGE *package = param;
3715 LPCWSTR component, section, key, value, identifier, dirproperty;
3716 LPWSTR deformated_section, deformated_key, deformated_value;
3717 LPWSTR folder, filename, fullname = NULL;
3718 LPCWSTR filenameptr;
3722 static const WCHAR szWindowsFolder[] =
3723 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3725 component = MSI_RecordGetString(row, 8);
3726 comp = get_loaded_component(package,component);
3728 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3730 TRACE("Skipping ini file due to disabled component %s\n",
3731 debugstr_w(component));
3733 comp->Action = comp->Installed;
3735 return ERROR_SUCCESS;
3738 comp->Action = INSTALLSTATE_LOCAL;
3740 identifier = MSI_RecordGetString(row,1);
3741 dirproperty = MSI_RecordGetString(row,3);
3742 section = MSI_RecordGetString(row,4);
3743 key = MSI_RecordGetString(row,5);
3744 value = MSI_RecordGetString(row,6);
3745 action = MSI_RecordGetInteger(row,7);
3747 deformat_string(package,section,&deformated_section);
3748 deformat_string(package,key,&deformated_key);
3749 deformat_string(package,value,&deformated_value);
3751 filename = msi_dup_record_field(row, 2);
3752 if (filename && (filenameptr = strchrW(filename, '|')))
3755 filenameptr = filename;
3759 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3761 folder = msi_dup_property( package, dirproperty );
3764 folder = msi_dup_property( package, szWindowsFolder );
3768 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3772 fullname = build_directory_name(2, folder, filenameptr);
3776 TRACE("Adding value %s to section %s in %s\n",
3777 debugstr_w(deformated_key), debugstr_w(deformated_section),
3778 debugstr_w(fullname));
3779 WritePrivateProfileStringW(deformated_section, deformated_key,
3780 deformated_value, fullname);
3782 else if (action == 1)
3785 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3786 returned, 10, fullname);
3787 if (returned[0] == 0)
3789 TRACE("Adding value %s to section %s in %s\n",
3790 debugstr_w(deformated_key), debugstr_w(deformated_section),
3791 debugstr_w(fullname));
3793 WritePrivateProfileStringW(deformated_section, deformated_key,
3794 deformated_value, fullname);
3797 else if (action == 3)
3798 FIXME("Append to existing section not yet implemented\n");
3800 uirow = MSI_CreateRecord(4);
3801 MSI_RecordSetStringW(uirow,1,identifier);
3802 MSI_RecordSetStringW(uirow,2,deformated_section);
3803 MSI_RecordSetStringW(uirow,3,deformated_key);
3804 MSI_RecordSetStringW(uirow,4,deformated_value);
3805 ui_actiondata(package,szWriteIniValues,uirow);
3806 msiobj_release( &uirow->hdr );
3812 msi_free(deformated_key);
3813 msi_free(deformated_value);
3814 msi_free(deformated_section);
3815 return ERROR_SUCCESS;
3818 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3822 static const WCHAR ExecSeqQuery[] =
3823 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3824 '`','I','n','i','F','i','l','e','`',0};
3826 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3827 if (rc != ERROR_SUCCESS)
3829 TRACE("no IniFile table\n");
3830 return ERROR_SUCCESS;
3833 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3834 msiobj_release(&view->hdr);
3838 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3840 MSIPACKAGE *package = param;
3845 static const WCHAR ExeStr[] =
3846 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3847 static const WCHAR close[] = {'\"',0};
3849 PROCESS_INFORMATION info;
3854 memset(&si,0,sizeof(STARTUPINFOW));
3856 filename = MSI_RecordGetString(row,1);
3857 file = get_loaded_file( package, filename );
3861 ERR("Unable to find file id %s\n",debugstr_w(filename));
3862 return ERROR_SUCCESS;
3865 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3867 FullName = msi_alloc(len*sizeof(WCHAR));
3868 strcpyW(FullName,ExeStr);
3869 strcatW( FullName, file->TargetPath );
3870 strcatW(FullName,close);
3872 TRACE("Registering %s\n",debugstr_w(FullName));
3873 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3878 CloseHandle(info.hThread);
3879 msi_dialog_check_messages(info.hProcess);
3880 CloseHandle(info.hProcess);
3886 uirow = MSI_CreateRecord( 2 );
3887 uipath = strdupW( file->TargetPath );
3888 p = strrchrW(uipath,'\\');
3891 MSI_RecordSetStringW( uirow, 1, &p[1] );
3892 MSI_RecordSetStringW( uirow, 2, uipath);
3893 ui_actiondata( package, szSelfRegModules, uirow);
3894 msiobj_release( &uirow->hdr );
3896 /* FIXME: call ui_progress? */
3898 return ERROR_SUCCESS;
3901 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3905 static const WCHAR ExecSeqQuery[] =
3906 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3907 '`','S','e','l','f','R','e','g','`',0};
3909 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3910 if (rc != ERROR_SUCCESS)
3912 TRACE("no SelfReg table\n");
3913 return ERROR_SUCCESS;
3916 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3917 msiobj_release(&view->hdr);
3919 return ERROR_SUCCESS;
3922 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3924 MSIFEATURE *feature;
3927 HKEY userdata = NULL;
3929 if (!msi_check_publish(package))
3930 return ERROR_SUCCESS;
3932 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3934 if (rc != ERROR_SUCCESS)
3937 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3939 if (rc != ERROR_SUCCESS)
3942 /* here the guids are base 85 encoded */
3943 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3949 BOOL absent = FALSE;
3952 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3953 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3954 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3958 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3962 if (feature->Feature_Parent)
3963 size += strlenW( feature->Feature_Parent )+2;
3965 data = msi_alloc(size * sizeof(WCHAR));
3968 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3970 MSICOMPONENT* component = cl->component;
3974 if (component->ComponentId)
3976 TRACE("From %s\n",debugstr_w(component->ComponentId));
3977 CLSIDFromString(component->ComponentId, &clsid);
3978 encode_base85_guid(&clsid,buf);
3979 TRACE("to %s\n",debugstr_w(buf));
3984 if (feature->Feature_Parent)
3986 static const WCHAR sep[] = {'\2',0};
3988 strcatW(data,feature->Feature_Parent);
3991 msi_reg_set_val_str( userdata, feature->Feature, data );
3995 if (feature->Feature_Parent)
3996 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3999 static const WCHAR emptyW[] = {0};
4000 size += sizeof(WCHAR);
4001 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4002 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : emptyW),size);
4006 size += 2*sizeof(WCHAR);
4007 data = msi_alloc(size);
4010 if (feature->Feature_Parent)
4011 strcpyW( &data[1], feature->Feature_Parent );
4012 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4018 uirow = MSI_CreateRecord( 1 );
4019 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4020 ui_actiondata( package, szPublishFeatures, uirow);
4021 msiobj_release( &uirow->hdr );
4022 /* FIXME: call ui_progress? */
4027 RegCloseKey(userdata);
4031 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4036 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4038 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4040 if (r == ERROR_SUCCESS)
4042 RegDeleteValueW(hkey, feature->Feature);
4046 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4048 if (r == ERROR_SUCCESS)
4050 RegDeleteValueW(hkey, feature->Feature);
4054 return ERROR_SUCCESS;
4057 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4059 MSIFEATURE *feature;
4061 if (!msi_check_unpublish(package))
4062 return ERROR_SUCCESS;
4064 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4066 msi_unpublish_feature(package, feature);
4069 return ERROR_SUCCESS;
4072 static UINT msi_get_local_package_name( LPWSTR path )
4074 static const WCHAR szInstaller[] = {
4075 '\\','I','n','s','t','a','l','l','e','r','\\',0};
4076 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
4080 time = GetTickCount();
4081 GetWindowsDirectoryW( path, MAX_PATH );
4082 lstrcatW( path, szInstaller );
4083 CreateDirectoryW( path, NULL );
4085 len = lstrlenW(path);
4086 for (i=0; i<0x10000; i++)
4088 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
4089 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
4090 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
4091 if (handle != INVALID_HANDLE_VALUE)
4093 CloseHandle(handle);
4096 if (GetLastError() != ERROR_FILE_EXISTS &&
4097 GetLastError() != ERROR_SHARING_VIOLATION)
4098 return ERROR_FUNCTION_FAILED;
4101 return ERROR_SUCCESS;
4104 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
4106 WCHAR packagefile[MAX_PATH];
4109 r = msi_get_local_package_name( packagefile );
4110 if (r != ERROR_SUCCESS)
4113 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
4115 r = CopyFileW( package->db->path, packagefile, FALSE);
4119 ERR("Unable to copy package (%s -> %s) (error %d)\n",
4120 debugstr_w(package->db->path), debugstr_w(packagefile), GetLastError());
4121 return ERROR_FUNCTION_FAILED;
4124 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
4126 return ERROR_SUCCESS;
4129 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4131 LPWSTR prop, val, key;
4137 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4138 static const WCHAR szWindowsInstaller[] =
4139 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4140 static const WCHAR modpath_fmt[] =
4141 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4142 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4143 static const WCHAR szModifyPath[] =
4144 {'M','o','d','i','f','y','P','a','t','h',0};
4145 static const WCHAR szUninstallString[] =
4146 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4147 static const WCHAR szEstimatedSize[] =
4148 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4149 static const WCHAR szProductLanguage[] =
4150 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4151 static const WCHAR szProductVersion[] =
4152 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4153 static const WCHAR szProductName[] =
4154 {'P','r','o','d','u','c','t','N','a','m','e',0};
4155 static const WCHAR szDisplayName[] =
4156 {'D','i','s','p','l','a','y','N','a','m','e',0};
4157 static const WCHAR szDisplayVersion[] =
4158 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4159 static const WCHAR szManufacturer[] =
4160 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4162 static const LPCSTR propval[] = {
4163 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4164 "ARPCONTACT", "Contact",
4165 "ARPCOMMENTS", "Comments",
4166 "ProductName", "DisplayName",
4167 "ProductVersion", "DisplayVersion",
4168 "ARPHELPLINK", "HelpLink",
4169 "ARPHELPTELEPHONE", "HelpTelephone",
4170 "ARPINSTALLLOCATION", "InstallLocation",
4171 "SourceDir", "InstallSource",
4172 "Manufacturer", "Publisher",
4173 "ARPREADME", "Readme",
4175 "ARPURLINFOABOUT", "URLInfoAbout",
4176 "ARPURLUPDATEINFO", "URLUpdateInfo",
4179 const LPCSTR *p = propval;
4183 prop = strdupAtoW(*p++);
4184 key = strdupAtoW(*p++);
4185 val = msi_dup_property(package, prop);
4186 msi_reg_set_val_str(hkey, key, val);
4192 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4194 size = deformat_string(package, modpath_fmt, &buffer);
4195 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4196 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4199 /* FIXME: Write real Estimated Size when we have it */
4200 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4202 buffer = msi_dup_property(package, szProductName);
4203 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4206 buffer = msi_dup_property(package, cszSourceDir);
4207 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4210 buffer = msi_dup_property(package, szManufacturer);
4211 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4214 GetLocalTime(&systime);
4215 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4216 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4218 langid = msi_get_property_int(package, szProductLanguage, 0);
4219 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4221 buffer = msi_dup_property(package, szProductVersion);
4222 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4225 DWORD verdword = msi_version_str_to_dword(buffer);
4227 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4228 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4229 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4233 return ERROR_SUCCESS;
4236 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4238 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4239 LPWSTR upgrade_code;
4244 static const WCHAR szUpgradeCode[] = {
4245 'U','p','g','r','a','d','e','C','o','d','e',0};
4247 /* FIXME: also need to publish if the product is in advertise mode */
4248 if (!msi_check_publish(package))
4249 return ERROR_SUCCESS;
4251 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4252 if (rc != ERROR_SUCCESS)
4255 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4256 NULL, &props, TRUE);
4257 if (rc != ERROR_SUCCESS)
4260 msi_make_package_local(package, props);
4262 rc = msi_publish_install_properties(package, hkey);
4263 if (rc != ERROR_SUCCESS)
4266 rc = msi_publish_install_properties(package, props);
4267 if (rc != ERROR_SUCCESS)
4270 upgrade_code = msi_dup_property(package, szUpgradeCode);
4273 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4274 squash_guid(package->ProductCode, squashed_pc);
4275 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4276 RegCloseKey(upgrade);
4277 msi_free(upgrade_code);
4283 return ERROR_SUCCESS;
4286 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4288 return execute_script(package,INSTALL_SCRIPT);
4291 static UINT msi_unpublish_product(MSIPACKAGE *package)
4294 LPWSTR remove = NULL;
4295 LPWSTR *features = NULL;
4296 BOOL full_uninstall = TRUE;
4297 MSIFEATURE *feature;
4299 static const WCHAR szRemove[] = {'R','E','M','O','V','E',0};
4300 static const WCHAR szAll[] = {'A','L','L',0};
4301 static const WCHAR szUpgradeCode[] =
4302 {'U','p','g','r','a','d','e','C','o','d','e',0};
4304 remove = msi_dup_property(package, szRemove);
4306 return ERROR_SUCCESS;
4308 features = msi_split_string(remove, ',');
4312 ERR("REMOVE feature list is empty!\n");
4313 return ERROR_FUNCTION_FAILED;
4316 if (!lstrcmpW(features[0], szAll))
4317 full_uninstall = TRUE;
4320 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4322 if (feature->Action != INSTALLSTATE_ABSENT)
4323 full_uninstall = FALSE;
4327 if (!full_uninstall)
4330 MSIREG_DeleteProductKey(package->ProductCode);
4331 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4332 MSIREG_DeleteUninstallKey(package->ProductCode);
4334 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4336 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4337 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4341 MSIREG_DeleteUserProductKey(package->ProductCode);
4342 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4345 upgrade = msi_dup_property(package, szUpgradeCode);
4348 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4355 return ERROR_SUCCESS;
4358 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4362 rc = msi_unpublish_product(package);
4363 if (rc != ERROR_SUCCESS)
4366 /* turn off scheduling */
4367 package->script->CurrentlyScripting= FALSE;
4369 /* first do the same as an InstallExecute */
4370 rc = ACTION_InstallExecute(package);
4371 if (rc != ERROR_SUCCESS)
4374 /* then handle Commit Actions */
4375 rc = execute_script(package,COMMIT_SCRIPT);
4380 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4382 static const WCHAR RunOnce[] = {
4383 'S','o','f','t','w','a','r','e','\\',
4384 'M','i','c','r','o','s','o','f','t','\\',
4385 'W','i','n','d','o','w','s','\\',
4386 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4387 'R','u','n','O','n','c','e',0};
4388 static const WCHAR InstallRunOnce[] = {
4389 'S','o','f','t','w','a','r','e','\\',
4390 'M','i','c','r','o','s','o','f','t','\\',
4391 'W','i','n','d','o','w','s','\\',
4392 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4393 'I','n','s','t','a','l','l','e','r','\\',
4394 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4396 static const WCHAR msiexec_fmt[] = {
4398 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4399 '\"','%','s','\"',0};
4400 static const WCHAR install_fmt[] = {
4401 '/','I',' ','\"','%','s','\"',' ',
4402 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4403 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4404 WCHAR buffer[256], sysdir[MAX_PATH];
4406 WCHAR squished_pc[100];
4408 squash_guid(package->ProductCode,squished_pc);
4410 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4411 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4412 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4415 msi_reg_set_val_str( hkey, squished_pc, buffer );
4418 TRACE("Reboot command %s\n",debugstr_w(buffer));
4420 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4421 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4423 msi_reg_set_val_str( hkey, squished_pc, buffer );
4426 return ERROR_INSTALL_SUSPEND;
4429 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4435 * We are currently doing what should be done here in the top level Install
4436 * however for Administrative and uninstalls this step will be needed
4438 if (!package->PackagePath)
4439 return ERROR_SUCCESS;
4441 msi_set_sourcedir_props(package, TRUE);
4443 attrib = GetFileAttributesW(package->db->path);
4444 if (attrib == INVALID_FILE_ATTRIBUTES)
4450 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4451 package->Context, MSICODE_PRODUCT,
4452 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4453 if (rc == ERROR_MORE_DATA)
4455 prompt = msi_alloc(size * sizeof(WCHAR));
4456 MsiSourceListGetInfoW(package->ProductCode, NULL,
4457 package->Context, MSICODE_PRODUCT,
4458 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4461 prompt = strdupW(package->db->path);
4463 msg = generate_error_string(package,1302,1,prompt);
4464 while(attrib == INVALID_FILE_ATTRIBUTES)
4466 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4469 rc = ERROR_INSTALL_USEREXIT;
4472 attrib = GetFileAttributesW(package->db->path);
4478 return ERROR_SUCCESS;
4483 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4490 static const WCHAR szPropKeys[][80] =
4492 {'P','r','o','d','u','c','t','I','D',0},
4493 {'U','S','E','R','N','A','M','E',0},
4494 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4498 static const WCHAR szRegKeys[][80] =
4500 {'P','r','o','d','u','c','t','I','D',0},
4501 {'R','e','g','O','w','n','e','r',0},
4502 {'R','e','g','C','o','m','p','a','n','y',0},
4506 if (msi_check_unpublish(package))
4508 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4509 return ERROR_SUCCESS;
4512 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4514 return ERROR_SUCCESS;
4516 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4518 if (rc != ERROR_SUCCESS)
4521 for( i = 0; szPropKeys[i][0]; i++ )
4523 buffer = msi_dup_property( package, szPropKeys[i] );
4524 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4529 msi_free(productid);
4532 /* FIXME: call ui_actiondata */
4538 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4542 package->script->InWhatSequence |= SEQUENCE_EXEC;
4543 rc = ACTION_ProcessExecSequence(package,FALSE);
4548 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4550 MSIPACKAGE *package = param;
4551 LPCWSTR compgroupid=NULL;
4552 LPCWSTR feature=NULL;
4553 LPCWSTR text = NULL;
4554 LPCWSTR qualifier = NULL;
4555 LPCWSTR component = NULL;
4556 LPWSTR advertise = NULL;
4557 LPWSTR output = NULL;
4559 UINT rc = ERROR_SUCCESS;
4564 component = MSI_RecordGetString(rec,3);
4565 comp = get_loaded_component(package,component);
4567 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4568 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4569 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4571 TRACE("Skipping: Component %s not scheduled for install\n",
4572 debugstr_w(component));
4574 return ERROR_SUCCESS;
4577 compgroupid = MSI_RecordGetString(rec,1);
4578 qualifier = MSI_RecordGetString(rec,2);
4580 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4581 if (rc != ERROR_SUCCESS)
4584 text = MSI_RecordGetString(rec,4);
4585 feature = MSI_RecordGetString(rec,5);
4587 advertise = create_component_advertise_string(package, comp, feature);
4589 sz = strlenW(advertise);
4592 sz += lstrlenW(text);
4595 sz *= sizeof(WCHAR);
4597 output = msi_alloc_zero(sz);
4598 strcpyW(output,advertise);
4599 msi_free(advertise);
4602 strcatW(output,text);
4604 msi_reg_set_val_multi_str( hkey, qualifier, output );
4611 uirow = MSI_CreateRecord( 2 );
4612 MSI_RecordSetStringW( uirow, 1, compgroupid );
4613 MSI_RecordSetStringW( uirow, 2, qualifier);
4614 ui_actiondata( package, szPublishComponents, uirow);
4615 msiobj_release( &uirow->hdr );
4616 /* FIXME: call ui_progress? */
4622 * At present I am ignorning the advertised components part of this and only
4623 * focusing on the qualified component sets
4625 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4629 static const WCHAR ExecSeqQuery[] =
4630 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4631 '`','P','u','b','l','i','s','h',
4632 'C','o','m','p','o','n','e','n','t','`',0};
4634 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4635 if (rc != ERROR_SUCCESS)
4636 return ERROR_SUCCESS;
4638 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4639 msiobj_release(&view->hdr);
4644 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4646 MSIPACKAGE *package = param;
4649 SC_HANDLE hscm, service = NULL;
4650 LPCWSTR comp, depends, pass;
4651 LPWSTR name = NULL, disp = NULL;
4652 LPCWSTR load_order, serv_name, key;
4653 DWORD serv_type, start_type;
4656 static const WCHAR query[] =
4657 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4658 '`','C','o','m','p','o','n','e','n','t','`',' ',
4659 'W','H','E','R','E',' ',
4660 '`','C','o','m','p','o','n','e','n','t','`',' ',
4661 '=','\'','%','s','\'',0};
4663 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4666 ERR("Failed to open the SC Manager!\n");
4670 start_type = MSI_RecordGetInteger(rec, 5);
4671 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4674 depends = MSI_RecordGetString(rec, 8);
4675 if (depends && *depends)
4676 FIXME("Dependency list unhandled!\n");
4678 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4679 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
4680 serv_type = MSI_RecordGetInteger(rec, 4);
4681 err_control = MSI_RecordGetInteger(rec, 6);
4682 load_order = MSI_RecordGetString(rec, 7);
4683 serv_name = MSI_RecordGetString(rec, 9);
4684 pass = MSI_RecordGetString(rec, 10);
4685 comp = MSI_RecordGetString(rec, 12);
4687 /* fetch the service path */
4688 row = MSI_QueryGetRecord(package->db, query, comp);
4691 ERR("Control query failed!\n");
4695 key = MSI_RecordGetString(row, 6);
4697 file = get_loaded_file(package, key);
4698 msiobj_release(&row->hdr);
4701 ERR("Failed to load the service file\n");
4705 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4706 start_type, err_control, file->TargetPath,
4707 load_order, NULL, NULL, serv_name, pass);
4710 if (GetLastError() != ERROR_SERVICE_EXISTS)
4711 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4715 CloseServiceHandle(service);
4716 CloseServiceHandle(hscm);
4720 return ERROR_SUCCESS;
4723 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4727 static const WCHAR ExecSeqQuery[] =
4728 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4729 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4731 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4732 if (rc != ERROR_SUCCESS)
4733 return ERROR_SUCCESS;
4735 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4736 msiobj_release(&view->hdr);
4741 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4742 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
4744 LPCWSTR *vector, *temp_vector;
4748 static const WCHAR separator[] = {'[','~',']',0};
4751 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4756 vector = msi_alloc(sizeof(LPWSTR));
4764 vector[*numargs - 1] = p;
4766 if ((q = strstrW(p, separator)))
4770 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4776 vector = temp_vector;
4785 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4787 MSIPACKAGE *package = param;
4789 SC_HANDLE scm, service = NULL;
4790 LPCWSTR name, *vector = NULL;
4792 DWORD event, numargs;
4793 UINT r = ERROR_FUNCTION_FAILED;
4795 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4796 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4797 return ERROR_SUCCESS;
4799 name = MSI_RecordGetString(rec, 2);
4800 event = MSI_RecordGetInteger(rec, 3);
4801 args = strdupW(MSI_RecordGetString(rec, 4));
4803 if (!(event & msidbServiceControlEventStart))
4804 return ERROR_SUCCESS;
4806 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4809 ERR("Failed to open the service control manager\n");
4813 service = OpenServiceW(scm, name, SERVICE_START);
4816 ERR("Failed to open service %s\n", debugstr_w(name));
4820 vector = msi_service_args_to_vector(args, &numargs);
4822 if (!StartServiceW(service, numargs, vector))
4824 ERR("Failed to start service %s\n", debugstr_w(name));
4831 CloseServiceHandle(service);
4832 CloseServiceHandle(scm);
4839 static UINT ACTION_StartServices( MSIPACKAGE *package )
4844 static const WCHAR query[] = {
4845 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4846 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4848 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4849 if (rc != ERROR_SUCCESS)
4850 return ERROR_SUCCESS;
4852 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4853 msiobj_release(&view->hdr);
4858 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4860 DWORD i, needed, count;
4861 ENUM_SERVICE_STATUSW *dependencies;
4865 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4866 0, &needed, &count))
4869 if (GetLastError() != ERROR_MORE_DATA)
4872 dependencies = msi_alloc(needed);
4876 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4877 needed, &needed, &count))
4880 for (i = 0; i < count; i++)
4882 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4883 SERVICE_STOP | SERVICE_QUERY_STATUS);
4887 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4894 msi_free(dependencies);
4898 static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
4900 MSIPACKAGE *package = param;
4902 SERVICE_STATUS status;
4903 SERVICE_STATUS_PROCESS ssp;
4904 SC_HANDLE scm = NULL, service = NULL;
4906 DWORD event, needed;
4908 event = MSI_RecordGetInteger(rec, 3);
4909 if (!(event & msidbServiceControlEventStop))
4910 return ERROR_SUCCESS;
4912 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4913 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4914 return ERROR_SUCCESS;
4916 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4917 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4918 args = strdupW(MSI_RecordGetString(rec, 4));
4920 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4923 WARN("Failed to open the SCM: %d\n", GetLastError());
4927 service = OpenServiceW(scm, name,
4929 SERVICE_QUERY_STATUS |
4930 SERVICE_ENUMERATE_DEPENDENTS);
4933 WARN("Failed to open service (%s): %d\n",
4934 debugstr_w(name), GetLastError());
4938 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4939 sizeof(SERVICE_STATUS_PROCESS), &needed))
4941 WARN("Failed to query service status (%s): %d\n",
4942 debugstr_w(name), GetLastError());
4946 if (ssp.dwCurrentState == SERVICE_STOPPED)
4949 stop_service_dependents(scm, service);
4951 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
4952 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
4955 CloseServiceHandle(service);
4956 CloseServiceHandle(scm);
4960 return ERROR_SUCCESS;
4963 static UINT ACTION_StopServices( MSIPACKAGE *package )
4968 static const WCHAR query[] = {
4969 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4970 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4972 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4973 if (rc != ERROR_SUCCESS)
4974 return ERROR_SUCCESS;
4976 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
4977 msiobj_release(&view->hdr);
4982 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4986 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4988 if (!lstrcmpW(file->File, filename))
4995 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4997 MSIPACKAGE *package = param;
4998 LPWSTR driver, driver_path, ptr;
4999 WCHAR outpath[MAX_PATH];
5000 MSIFILE *driver_file, *setup_file;
5003 UINT r = ERROR_SUCCESS;
5005 static const WCHAR driver_fmt[] = {
5006 'D','r','i','v','e','r','=','%','s',0};
5007 static const WCHAR setup_fmt[] = {
5008 'S','e','t','u','p','=','%','s',0};
5009 static const WCHAR usage_fmt[] = {
5010 'F','i','l','e','U','s','a','g','e','=','1',0};
5012 desc = MSI_RecordGetString(rec, 3);
5014 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5015 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5017 if (!driver_file || !setup_file)
5019 ERR("ODBC Driver entry not found!\n");
5020 return ERROR_FUNCTION_FAILED;
5023 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
5024 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
5025 lstrlenW(usage_fmt) + 1;
5026 driver = msi_alloc(len * sizeof(WCHAR));
5028 return ERROR_OUTOFMEMORY;
5031 lstrcpyW(ptr, desc);
5032 ptr += lstrlenW(ptr) + 1;
5034 sprintfW(ptr, driver_fmt, driver_file->FileName);
5035 ptr += lstrlenW(ptr) + 1;
5037 sprintfW(ptr, setup_fmt, setup_file->FileName);
5038 ptr += lstrlenW(ptr) + 1;
5040 lstrcpyW(ptr, usage_fmt);
5041 ptr += lstrlenW(ptr) + 1;
5044 driver_path = strdupW(driver_file->TargetPath);
5045 ptr = strrchrW(driver_path, '\\');
5046 if (ptr) *ptr = '\0';
5048 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5049 NULL, ODBC_INSTALL_COMPLETE, &usage))
5051 ERR("Failed to install SQL driver!\n");
5052 r = ERROR_FUNCTION_FAILED;
5056 msi_free(driver_path);
5061 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5063 MSIPACKAGE *package = param;
5064 LPWSTR translator, translator_path, ptr;
5065 WCHAR outpath[MAX_PATH];
5066 MSIFILE *translator_file, *setup_file;
5069 UINT r = ERROR_SUCCESS;
5071 static const WCHAR translator_fmt[] = {
5072 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5073 static const WCHAR setup_fmt[] = {
5074 'S','e','t','u','p','=','%','s',0};
5076 desc = MSI_RecordGetString(rec, 3);
5078 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5079 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5081 if (!translator_file || !setup_file)
5083 ERR("ODBC Translator entry not found!\n");
5084 return ERROR_FUNCTION_FAILED;
5087 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
5088 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
5089 translator = msi_alloc(len * sizeof(WCHAR));
5091 return ERROR_OUTOFMEMORY;
5094 lstrcpyW(ptr, desc);
5095 ptr += lstrlenW(ptr) + 1;
5097 sprintfW(ptr, translator_fmt, translator_file->FileName);
5098 ptr += lstrlenW(ptr) + 1;
5100 sprintfW(ptr, setup_fmt, setup_file->FileName);
5101 ptr += lstrlenW(ptr) + 1;
5104 translator_path = strdupW(translator_file->TargetPath);
5105 ptr = strrchrW(translator_path, '\\');
5106 if (ptr) *ptr = '\0';
5108 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5109 NULL, ODBC_INSTALL_COMPLETE, &usage))
5111 ERR("Failed to install SQL translator!\n");
5112 r = ERROR_FUNCTION_FAILED;
5115 msi_free(translator);
5116 msi_free(translator_path);
5121 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5124 LPCWSTR desc, driver;
5125 WORD request = ODBC_ADD_SYS_DSN;
5128 UINT r = ERROR_SUCCESS;
5130 static const WCHAR attrs_fmt[] = {
5131 'D','S','N','=','%','s',0 };
5133 desc = MSI_RecordGetString(rec, 3);
5134 driver = MSI_RecordGetString(rec, 4);
5135 registration = MSI_RecordGetInteger(rec, 5);
5137 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5138 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5140 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
5141 attrs = msi_alloc(len * sizeof(WCHAR));
5143 return ERROR_OUTOFMEMORY;
5145 sprintfW(attrs, attrs_fmt, desc);
5146 attrs[len - 1] = '\0';
5148 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5150 ERR("Failed to install SQL data source!\n");
5151 r = ERROR_FUNCTION_FAILED;
5159 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5164 static const WCHAR driver_query[] = {
5165 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5166 'O','D','B','C','D','r','i','v','e','r',0 };
5168 static const WCHAR translator_query[] = {
5169 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5170 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5172 static const WCHAR source_query[] = {
5173 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5174 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5176 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5177 if (rc != ERROR_SUCCESS)
5178 return ERROR_SUCCESS;
5180 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5181 msiobj_release(&view->hdr);
5183 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5184 if (rc != ERROR_SUCCESS)
5185 return ERROR_SUCCESS;
5187 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5188 msiobj_release(&view->hdr);
5190 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5191 if (rc != ERROR_SUCCESS)
5192 return ERROR_SUCCESS;
5194 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5195 msiobj_release(&view->hdr);
5200 #define ENV_ACT_SETALWAYS 0x1
5201 #define ENV_ACT_SETABSENT 0x2
5202 #define ENV_ACT_REMOVE 0x4
5203 #define ENV_ACT_REMOVEMATCH 0x8
5205 #define ENV_MOD_MACHINE 0x20000000
5206 #define ENV_MOD_APPEND 0x40000000
5207 #define ENV_MOD_PREFIX 0x80000000
5208 #define ENV_MOD_MASK 0xC0000000
5210 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5212 static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5214 LPCWSTR cptr = *name;
5215 LPCWSTR ptr = *value;
5217 static const WCHAR prefix[] = {'[','~',']',0};
5218 static const int prefix_len = 3;
5224 *flags |= ENV_ACT_SETALWAYS;
5225 else if (*cptr == '+')
5226 *flags |= ENV_ACT_SETABSENT;
5227 else if (*cptr == '-')
5228 *flags |= ENV_ACT_REMOVE;
5229 else if (*cptr == '!')
5230 *flags |= ENV_ACT_REMOVEMATCH;
5231 else if (*cptr == '*')
5232 *flags |= ENV_MOD_MACHINE;
5242 ERR("Missing environment variable\n");
5243 return ERROR_FUNCTION_FAILED;
5246 if (!strncmpW(ptr, prefix, prefix_len))
5248 *flags |= ENV_MOD_APPEND;
5249 *value += lstrlenW(prefix);
5251 else if (lstrlenW(*value) >= prefix_len)
5253 ptr += lstrlenW(ptr) - prefix_len;
5254 if (!lstrcmpW(ptr, prefix))
5256 *flags |= ENV_MOD_PREFIX;
5257 /* the "[~]" will be removed by deformat_string */;
5262 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5263 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5264 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5265 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5267 ERR("Invalid flags: %08x\n", *flags);
5268 return ERROR_FUNCTION_FAILED;
5271 return ERROR_SUCCESS;
5274 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5276 MSIPACKAGE *package = param;
5277 LPCWSTR name, value;
5278 LPWSTR data = NULL, newval = NULL;
5279 LPWSTR deformatted = NULL, ptr;
5280 DWORD flags, type, size;
5282 HKEY env = NULL, root;
5283 LPCWSTR environment;
5285 static const WCHAR user_env[] =
5286 {'E','n','v','i','r','o','n','m','e','n','t',0};
5287 static const WCHAR machine_env[] =
5288 {'S','y','s','t','e','m','\\',
5289 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5290 'C','o','n','t','r','o','l','\\',
5291 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5292 'E','n','v','i','r','o','n','m','e','n','t',0};
5293 static const WCHAR semicolon[] = {';',0};
5295 name = MSI_RecordGetString(rec, 2);
5296 value = MSI_RecordGetString(rec, 3);
5298 res = env_set_flags(&name, &value, &flags);
5299 if (res != ERROR_SUCCESS)
5302 deformat_string(package, value, &deformatted);
5305 res = ERROR_OUTOFMEMORY;
5309 value = deformatted;
5311 if (flags & ENV_MOD_MACHINE)
5313 environment = machine_env;
5314 root = HKEY_LOCAL_MACHINE;
5318 environment = user_env;
5319 root = HKEY_CURRENT_USER;
5322 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5323 KEY_ALL_ACCESS, NULL, &env, NULL);
5324 if (res != ERROR_SUCCESS)
5327 if (flags & ENV_ACT_REMOVE)
5328 FIXME("Not removing environment variable on uninstall!\n");
5331 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5332 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
5333 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
5336 if (res != ERROR_FILE_NOT_FOUND)
5338 if (flags & ENV_ACT_SETABSENT)
5340 res = ERROR_SUCCESS;
5344 data = msi_alloc(size);
5348 return ERROR_OUTOFMEMORY;
5351 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5352 if (res != ERROR_SUCCESS)
5355 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5357 res = RegDeleteKeyW(env, name);
5361 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
5362 newval = msi_alloc(size);
5366 res = ERROR_OUTOFMEMORY;
5370 if (!(flags & ENV_MOD_MASK))
5371 lstrcpyW(newval, value);
5374 if (flags & ENV_MOD_PREFIX)
5376 lstrcpyW(newval, value);
5377 lstrcatW(newval, semicolon);
5378 ptr = newval + lstrlenW(value) + 1;
5381 lstrcpyW(ptr, data);
5383 if (flags & ENV_MOD_APPEND)
5385 lstrcatW(newval, semicolon);
5386 lstrcatW(newval, value);
5392 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
5393 newval = msi_alloc(size);
5396 res = ERROR_OUTOFMEMORY;
5400 lstrcpyW(newval, value);
5403 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5404 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
5407 if (env) RegCloseKey(env);
5408 msi_free(deformatted);
5414 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5418 static const WCHAR ExecSeqQuery[] =
5419 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5420 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5421 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5422 if (rc != ERROR_SUCCESS)
5423 return ERROR_SUCCESS;
5425 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5426 msiobj_release(&view->hdr);
5431 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5442 static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5446 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5447 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5449 WARN("Source or dest is directory, not moving\n");
5453 if (options == msidbMoveFileOptionsMove)
5455 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5456 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5459 WARN("MoveFile failed: %d\n", GetLastError());
5465 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5466 ret = CopyFileW(source, dest, FALSE);
5469 WARN("CopyFile failed: %d\n", GetLastError());
5477 static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5480 DWORD dirlen, pathlen;
5482 ptr = strrchrW(wildcard, '\\');
5483 dirlen = ptr - wildcard + 1;
5485 pathlen = dirlen + lstrlenW(filename) + 1;
5486 path = msi_alloc(pathlen * sizeof(WCHAR));
5488 lstrcpynW(path, wildcard, dirlen + 1);
5489 lstrcatW(path, filename);
5494 static void free_file_entry(FILE_LIST *file)
5496 msi_free(file->source);
5497 msi_free(file->dest);
5501 static void free_list(FILE_LIST *list)
5503 while (!list_empty(&list->entry))
5505 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5507 list_remove(&file->entry);
5508 free_file_entry(file);
5512 static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5514 FILE_LIST *new, *file;
5515 LPWSTR ptr, filename;
5518 new = msi_alloc_zero(sizeof(FILE_LIST));
5522 new->source = strdupW(source);
5523 ptr = strrchrW(dest, '\\') + 1;
5524 filename = strrchrW(new->source, '\\') + 1;
5526 new->sourcename = filename;
5529 new->destname = ptr;
5531 new->destname = new->sourcename;
5533 size = (ptr - dest) + lstrlenW(filename) + 1;
5534 new->dest = msi_alloc(size * sizeof(WCHAR));
5537 free_file_entry(new);
5541 lstrcpynW(new->dest, dest, ptr - dest + 1);
5542 lstrcatW(new->dest, filename);
5544 if (list_empty(&files->entry))
5546 list_add_head(&files->entry, &new->entry);
5550 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5552 if (lstrcmpW(source, file->source) < 0)
5554 list_add_before(&file->entry, &new->entry);
5559 list_add_after(&file->entry, &new->entry);
5563 static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
5565 WIN32_FIND_DATAW wfd;
5569 FILE_LIST files, *file;
5572 hfile = FindFirstFileW(source, &wfd);
5573 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5575 list_init(&files.entry);
5577 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5579 if (is_dot_dir(wfd.cFileName)) continue;
5581 path = wildcard_to_file(source, wfd.cFileName);
5588 add_wildcard(&files, path, dest);
5592 /* no files match the wildcard */
5593 if (list_empty(&files.entry))
5596 /* only the first wildcard match gets renamed to dest */
5597 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5598 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5599 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5606 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5608 while (!list_empty(&files.entry))
5610 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5612 msi_move_file(file->source, file->dest, options);
5614 list_remove(&file->entry);
5615 free_file_entry(file);
5626 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5628 MSIPACKAGE *package = param;
5631 LPWSTR destname = NULL;
5632 LPWSTR sourcedir = NULL, destdir = NULL;
5633 LPWSTR source = NULL, dest = NULL;
5636 BOOL ret, wildcards;
5638 static const WCHAR backslash[] = {'\\',0};
5640 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5641 if (!comp || !comp->Enabled ||
5642 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5644 TRACE("Component not set for install, not moving file\n");
5645 return ERROR_SUCCESS;
5648 sourcename = MSI_RecordGetString(rec, 3);
5649 options = MSI_RecordGetInteger(rec, 7);
5651 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5655 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5661 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5664 source = strdupW(sourcedir);
5670 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5671 source = msi_alloc(size * sizeof(WCHAR));
5675 lstrcpyW(source, sourcedir);
5676 if (source[lstrlenW(source) - 1] != '\\')
5677 lstrcatW(source, backslash);
5678 lstrcatW(source, sourcename);
5681 wildcards = strchrW(source, '*') || strchrW(source, '?');
5683 if (MSI_RecordIsNull(rec, 4))
5687 destname = strdupW(sourcename);
5694 destname = strdupW(MSI_RecordGetString(rec, 4));
5696 reduce_to_longfilename(destname);
5701 size = lstrlenW(destname);
5703 size += lstrlenW(destdir) + 2;
5704 dest = msi_alloc(size * sizeof(WCHAR));
5708 lstrcpyW(dest, destdir);
5709 if (dest[lstrlenW(dest) - 1] != '\\')
5710 lstrcatW(dest, backslash);
5713 lstrcatW(dest, destname);
5715 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5717 ret = CreateDirectoryW(destdir, NULL);
5720 WARN("CreateDirectory failed: %d\n", GetLastError());
5721 return ERROR_SUCCESS;
5726 msi_move_file(source, dest, options);
5728 move_files_wildcard(source, dest, options);
5731 msi_free(sourcedir);
5737 return ERROR_SUCCESS;
5740 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5745 static const WCHAR ExecSeqQuery[] =
5746 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5747 '`','M','o','v','e','F','i','l','e','`',0};
5749 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5750 if (rc != ERROR_SUCCESS)
5751 return ERROR_SUCCESS;
5753 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5754 msiobj_release(&view->hdr);
5759 typedef struct tagMSIASSEMBLY
5762 MSICOMPONENT *component;
5763 MSIFEATURE *feature;
5771 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
5773 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
5774 LPVOID pvReserved, HMODULE *phModDll);
5776 static BOOL init_functionpointers(void)
5782 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
5784 hmscoree = LoadLibraryA("mscoree.dll");
5787 WARN("mscoree.dll not available\n");
5791 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
5792 if (!pLoadLibraryShim)
5794 WARN("LoadLibraryShim not available\n");
5795 FreeLibrary(hmscoree);
5799 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
5802 WARN("fusion.dll not available\n");
5803 FreeLibrary(hmscoree);
5807 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
5809 FreeLibrary(hmscoree);
5813 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
5816 IAssemblyCache *cache;
5818 UINT r = ERROR_FUNCTION_FAILED;
5820 TRACE("installing assembly: %s\n", debugstr_w(path));
5822 if (assembly->feature)
5823 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
5825 if (assembly->manifest)
5826 FIXME("Manifest unhandled\n");
5828 if (assembly->application)
5830 FIXME("Assembly should be privately installed\n");
5831 return ERROR_SUCCESS;
5834 if (assembly->attributes == msidbAssemblyAttributesWin32)
5836 FIXME("Win32 assemblies not handled\n");
5837 return ERROR_SUCCESS;
5840 hr = pCreateAssemblyCache(&cache, 0);
5844 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
5846 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
5851 IAssemblyCache_Release(cache);
5855 typedef struct tagASSEMBLY_LIST
5857 MSIPACKAGE *package;
5858 IAssemblyCache *cache;
5859 struct list *assemblies;
5862 typedef struct tagASSEMBLY_NAME
5870 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
5872 ASSEMBLY_NAME *asmname = param;
5873 LPCWSTR name = MSI_RecordGetString(rec, 2);
5874 LPWSTR val = msi_dup_record_field(rec, 3);
5876 static const WCHAR Name[] = {'N','a','m','e',0};
5877 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
5878 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
5879 static const WCHAR PublicKeyToken[] = {
5880 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
5882 if (!strcmpiW(name, Name))
5883 asmname->name = val;
5884 else if (!strcmpiW(name, Version))
5885 asmname->version = val;
5886 else if (!strcmpiW(name, Culture))
5887 asmname->culture = val;
5888 else if (!strcmpiW(name, PublicKeyToken))
5889 asmname->pubkeytoken = val;
5893 return ERROR_SUCCESS;
5896 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
5900 *size = lstrlenW(append) + 1;
5901 *str = msi_alloc((*size) * sizeof(WCHAR));
5902 lstrcpyW(*str, append);
5906 (*size) += lstrlenW(append);
5907 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
5908 lstrcatW(*str, append);
5911 static BOOL check_assembly_installed(MSIDATABASE *db, IAssemblyCache *cache,
5914 ASSEMBLY_INFO asminfo;
5922 static const WCHAR separator[] = {',',' ',0};
5923 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
5924 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
5925 static const WCHAR PublicKeyToken[] = {
5926 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
5927 static const WCHAR query[] = {
5928 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5929 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
5930 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
5931 '=','\'','%','s','\'',0};
5935 ZeroMemory(&name, sizeof(ASSEMBLY_NAME));
5936 ZeroMemory(&asminfo, sizeof(ASSEMBLY_INFO));
5938 r = MSI_OpenQuery(db, &view, query, comp->Component);
5939 if (r != ERROR_SUCCESS)
5940 return ERROR_SUCCESS;
5942 MSI_IterateRecords(view, NULL, parse_assembly_name, &name);
5943 msiobj_release(&view->hdr);
5947 ERR("No assembly name specified!\n");
5951 append_str(&disp, &size, name.name);
5955 append_str(&disp, &size, separator);
5956 append_str(&disp, &size, Version);
5957 append_str(&disp, &size, name.version);
5962 append_str(&disp, &size, separator);
5963 append_str(&disp, &size, Culture);
5964 append_str(&disp, &size, name.culture);
5967 if (name.pubkeytoken)
5969 append_str(&disp, &size, separator);
5970 append_str(&disp, &size, PublicKeyToken);
5971 append_str(&disp, &size, name.pubkeytoken);
5974 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
5975 IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE,
5977 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
5981 msi_free(name.name);
5982 msi_free(name.version);
5983 msi_free(name.culture);
5984 msi_free(name.pubkeytoken);
5989 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
5991 ASSEMBLY_LIST *list = param;
5992 MSIASSEMBLY *assembly;
5994 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
5996 return ERROR_OUTOFMEMORY;
5998 assembly->component = get_loaded_component(list->package, MSI_RecordGetString(rec, 1));
6000 if (!assembly->component || !assembly->component->Enabled ||
6001 !(assembly->component->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
6003 TRACE("Component not set for install, not publishing assembly\n");
6005 return ERROR_SUCCESS;
6008 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6009 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6011 if (!assembly->file)
6013 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6014 return ERROR_FUNCTION_FAILED;
6017 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6018 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6019 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6020 assembly->installed = check_assembly_installed(list->package->db,
6022 assembly->component);
6024 list_add_head(list->assemblies, &assembly->entry);
6025 return ERROR_SUCCESS;
6028 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6030 IAssemblyCache *cache = NULL;
6036 static const WCHAR query[] =
6037 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6038 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6040 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6041 if (r != ERROR_SUCCESS)
6042 return ERROR_SUCCESS;
6044 hr = pCreateAssemblyCache(&cache, 0);
6046 return ERROR_FUNCTION_FAILED;
6048 list.package = package;
6050 list.assemblies = assemblies;
6052 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6053 msiobj_release(&view->hdr);
6055 IAssemblyCache_Release(cache);
6060 static void free_assemblies(struct list *assemblies)
6062 struct list *item, *cursor;
6064 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6066 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6068 list_remove(&assembly->entry);
6069 msi_free(assembly->application);
6070 msi_free(assembly->manifest);
6075 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6077 MSIASSEMBLY *assembly;
6079 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6081 if (!lstrcmpW(assembly->file->File, file))
6091 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6092 LPWSTR *path, DWORD *attrs, PVOID user)
6094 MSIASSEMBLY *assembly;
6095 WCHAR temppath[MAX_PATH];
6096 struct list *assemblies = user;
6099 if (!find_assembly(assemblies, file, &assembly))
6102 GetTempPathW(MAX_PATH, temppath);
6103 PathAddBackslashW(temppath);
6104 lstrcatW(temppath, assembly->file->FileName);
6106 if (action == MSICABEXTRACT_BEGINEXTRACT)
6108 if (assembly->installed)
6111 *path = strdupW(temppath);
6112 *attrs = assembly->file->Attributes;
6114 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6116 assembly->installed = TRUE;
6118 r = install_assembly(package, assembly, temppath);
6119 if (r != ERROR_SUCCESS)
6120 ERR("Failed to install assembly\n");
6126 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6129 struct list assemblies = LIST_INIT(assemblies);
6130 MSIASSEMBLY *assembly;
6133 if (!init_functionpointers() || !pCreateAssemblyCache)
6134 return ERROR_FUNCTION_FAILED;
6136 r = load_assemblies(package, &assemblies);
6137 if (r != ERROR_SUCCESS)
6140 if (list_empty(&assemblies))
6143 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6146 r = ERROR_OUTOFMEMORY;
6150 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6152 if (assembly->installed && !mi->is_continuous)
6155 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6156 (assembly->file->IsCompressed && !mi->is_extracted))
6160 r = ready_media(package, assembly->file, mi);
6161 if (r != ERROR_SUCCESS)
6163 ERR("Failed to ready media\n");
6168 data.package = package;
6169 data.cb = installassembly_cb;
6170 data.user = &assemblies;
6172 if (assembly->file->IsCompressed &&
6173 !msi_cabextract(package, mi, &data))
6175 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6176 r = ERROR_FUNCTION_FAILED;
6181 if (!assembly->file->IsCompressed)
6183 LPWSTR source = resolve_file_source(package, assembly->file);
6185 r = install_assembly(package, assembly, source);
6186 if (r != ERROR_SUCCESS)
6187 ERR("Failed to install assembly\n");
6192 /* FIXME: write Installer assembly reg values */
6196 free_assemblies(&assemblies);
6200 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6201 LPCSTR action, LPCWSTR table )
6203 static const WCHAR query[] = {
6204 'S','E','L','E','C','T',' ','*',' ',
6205 'F','R','O','M',' ','`','%','s','`',0 };
6206 MSIQUERY *view = NULL;
6210 r = MSI_OpenQuery( package->db, &view, query, table );
6211 if (r == ERROR_SUCCESS)
6213 r = MSI_IterateRecords(view, &count, NULL, package);
6214 msiobj_release(&view->hdr);
6218 FIXME("%s -> %u ignored %s table values\n",
6219 action, count, debugstr_w(table));
6221 return ERROR_SUCCESS;
6224 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6226 TRACE("%p\n", package);
6227 return ERROR_SUCCESS;
6230 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
6232 static const WCHAR table[] =
6233 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
6234 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
6237 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6239 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6240 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6243 static UINT ACTION_BindImage( MSIPACKAGE *package )
6245 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6246 return msi_unimplemented_action_stub( package, "BindImage", table );
6249 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6251 static const WCHAR table[] = {
6252 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
6253 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6256 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6258 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6259 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6262 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
6264 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
6265 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
6268 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6270 static const WCHAR table[] = {
6271 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6272 return msi_unimplemented_action_stub( package, "DeleteServices", table );
6274 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6276 static const WCHAR table[] = {
6277 'P','r','o','d','u','c','t','I','D',0 };
6278 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
6281 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6283 static const WCHAR table[] = {
6284 'E','n','v','i','r','o','n','m','e','n','t',0 };
6285 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
6288 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6290 static const WCHAR table[] = {
6291 'M','s','i','A','s','s','e','m','b','l','y',0 };
6292 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6295 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
6297 static const WCHAR table[] = { 'F','o','n','t',0 };
6298 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
6301 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6303 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6304 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6307 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6309 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6310 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6313 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6315 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6316 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6319 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6321 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6322 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6325 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
6327 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6328 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
6331 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6333 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6334 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6337 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
6339 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6340 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
6343 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6345 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6346 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
6349 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
6351 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6352 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
6355 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
6357 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
6358 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
6361 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
6363 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6364 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
6367 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6369 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6370 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6373 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6375 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6376 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6379 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6381 static const WCHAR table[] = { 'M','I','M','E',0 };
6382 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6385 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6387 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6388 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6391 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
6393 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
6394 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
6397 static const struct _actions StandardActions[] = {
6398 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6399 { szAppSearch, ACTION_AppSearch },
6400 { szBindImage, ACTION_BindImage },
6401 { szCCPSearch, ACTION_CCPSearch },
6402 { szCostFinalize, ACTION_CostFinalize },
6403 { szCostInitialize, ACTION_CostInitialize },
6404 { szCreateFolders, ACTION_CreateFolders },
6405 { szCreateShortcuts, ACTION_CreateShortcuts },
6406 { szDeleteServices, ACTION_DeleteServices },
6407 { szDisableRollback, NULL },
6408 { szDuplicateFiles, ACTION_DuplicateFiles },
6409 { szExecuteAction, ACTION_ExecuteAction },
6410 { szFileCost, ACTION_FileCost },
6411 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6412 { szForceReboot, ACTION_ForceReboot },
6413 { szInstallAdminPackage, NULL },
6414 { szInstallExecute, ACTION_InstallExecute },
6415 { szInstallExecuteAgain, ACTION_InstallExecute },
6416 { szInstallFiles, ACTION_InstallFiles},
6417 { szInstallFinalize, ACTION_InstallFinalize },
6418 { szInstallInitialize, ACTION_InstallInitialize },
6419 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6420 { szInstallValidate, ACTION_InstallValidate },
6421 { szIsolateComponents, ACTION_IsolateComponents },
6422 { szLaunchConditions, ACTION_LaunchConditions },
6423 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6424 { szMoveFiles, ACTION_MoveFiles },
6425 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6426 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6427 { szInstallODBC, ACTION_InstallODBC },
6428 { szInstallServices, ACTION_InstallServices },
6429 { szPatchFiles, ACTION_PatchFiles },
6430 { szProcessComponents, ACTION_ProcessComponents },
6431 { szPublishComponents, ACTION_PublishComponents },
6432 { szPublishFeatures, ACTION_PublishFeatures },
6433 { szPublishProduct, ACTION_PublishProduct },
6434 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6435 { szRegisterComPlus, ACTION_RegisterComPlus},
6436 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6437 { szRegisterFonts, ACTION_RegisterFonts },
6438 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6439 { szRegisterProduct, ACTION_RegisterProduct },
6440 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6441 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6442 { szRegisterUser, ACTION_RegisterUser },
6443 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6444 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6445 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6446 { szRemoveFiles, ACTION_RemoveFiles },
6447 { szRemoveFolders, ACTION_RemoveFolders },
6448 { szRemoveIniValues, ACTION_RemoveIniValues },
6449 { szRemoveODBC, ACTION_RemoveODBC },
6450 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6451 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6452 { szResolveSource, ACTION_ResolveSource },
6453 { szRMCCPSearch, ACTION_RMCCPSearch },
6454 { szScheduleReboot, NULL },
6455 { szSelfRegModules, ACTION_SelfRegModules },
6456 { szSelfUnregModules, ACTION_SelfUnregModules },
6457 { szSetODBCFolders, NULL },
6458 { szStartServices, ACTION_StartServices },
6459 { szStopServices, ACTION_StopServices },
6460 { szUnpublishComponents, ACTION_UnpublishComponents },
6461 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6462 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6463 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6464 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6465 { szUnregisterFonts, ACTION_UnregisterFonts },
6466 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6467 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6468 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6469 { szValidateProductID, ACTION_ValidateProductID },
6470 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6471 { szWriteIniValues, ACTION_WriteIniValues },
6472 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6476 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
6477 UINT* rc, BOOL force )
6483 if (!run && !package->script->CurrentlyScripting)
6488 if (strcmpW(action,szInstallFinalize) == 0 ||
6489 strcmpW(action,szInstallExecute) == 0 ||
6490 strcmpW(action,szInstallExecuteAgain) == 0)
6495 while (StandardActions[i].action != NULL)
6497 if (strcmpW(StandardActions[i].action, action)==0)
6501 ui_actioninfo(package, action, TRUE, 0);
6502 *rc = schedule_action(package,INSTALL_SCRIPT,action);
6503 ui_actioninfo(package, action, FALSE, *rc);
6507 ui_actionstart(package, action);
6508 if (StandardActions[i].handler)
6510 *rc = StandardActions[i].handler(package);
6514 FIXME("unhandled standard action %s\n",debugstr_w(action));
6515 *rc = ERROR_SUCCESS;