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 static const WCHAR szAdvertise[] =
1845 {'A','D','V','E','R','T','I','S','E',0};
1846 BOOL override = FALSE;
1847 MSICOMPONENT* component;
1848 MSIFEATURE *feature;
1851 /* I do not know if this is where it should happen.. but */
1853 TRACE("Checking Install Level\n");
1855 level = msi_get_property_int(package, szlevel, 1);
1857 /* ok here is the _real_ rub
1858 * all these activation/deactivation things happen in order and things
1859 * later on the list override things earlier on the list.
1860 * 0) INSTALLLEVEL processing
1871 * 11) FILEADDDEFAULT
1873 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1874 * REMOVE are the big ones, since we don't handle administrative installs
1877 override |= process_state_property(package, level, szAddLocal, INSTALLSTATE_LOCAL);
1878 override |= process_state_property(package, level, szRemove, INSTALLSTATE_ABSENT);
1879 override |= process_state_property(package, level, szAddSource, INSTALLSTATE_SOURCE);
1880 override |= process_state_property(package, level, szReinstall, INSTALLSTATE_UNKNOWN);
1881 override |= process_state_property(package, level, szAdvertise, INSTALLSTATE_ADVERTISED);
1885 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1887 BOOL feature_state = ((feature->Level > 0) &&
1888 (feature->Level <= level));
1890 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1892 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1893 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1894 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1895 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1897 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1901 /* disable child features of unselected parent features */
1902 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1906 if (feature->Level > 0 && feature->Level <= level)
1909 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1910 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1915 /* set the Preselected Property */
1916 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1917 static const WCHAR szOne[] = { '1', 0 };
1919 MSI_SetPropertyW(package,szPreselected,szOne);
1923 * now we want to enable or disable components base on feature
1926 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1930 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1931 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1933 if (!feature->Level)
1936 /* features with components that have compressed files are made local */
1937 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1939 if (cl->component->Enabled &&
1940 cl->component->ForceLocalState &&
1941 feature->Action == INSTALLSTATE_SOURCE)
1943 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1948 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1950 component = cl->component;
1952 if (!component->Enabled)
1955 switch (feature->Action)
1957 case INSTALLSTATE_ABSENT:
1958 component->anyAbsent = 1;
1960 case INSTALLSTATE_ADVERTISED:
1961 component->hasAdvertiseFeature = 1;
1963 case INSTALLSTATE_SOURCE:
1964 component->hasSourceFeature = 1;
1966 case INSTALLSTATE_LOCAL:
1967 component->hasLocalFeature = 1;
1969 case INSTALLSTATE_DEFAULT:
1970 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1971 component->hasAdvertiseFeature = 1;
1972 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1973 component->hasSourceFeature = 1;
1975 component->hasLocalFeature = 1;
1983 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1985 /* if the component isn't enabled, leave it alone */
1986 if (!component->Enabled)
1989 /* check if it's local or source */
1990 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1991 (component->hasLocalFeature || component->hasSourceFeature))
1993 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1994 !component->ForceLocalState)
1995 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1997 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2001 /* if any feature is local, the component must be local too */
2002 if (component->hasLocalFeature)
2004 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2008 if (component->hasSourceFeature)
2010 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
2014 if (component->hasAdvertiseFeature)
2016 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
2020 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2021 if (component->anyAbsent)
2022 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
2025 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2027 if (component->Action == INSTALLSTATE_DEFAULT)
2029 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2030 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2033 TRACE("Result: Component %s (Installed %i, Action %i)\n",
2034 debugstr_w(component->Component), component->Installed, component->Action);
2038 return ERROR_SUCCESS;
2041 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2043 MSIPACKAGE *package = param;
2048 name = MSI_RecordGetString(row,1);
2050 f = get_loaded_folder(package, name);
2051 if (!f) return ERROR_SUCCESS;
2053 /* reset the ResolvedTarget */
2054 msi_free(f->ResolvedTarget);
2055 f->ResolvedTarget = NULL;
2057 /* This helper function now does ALL the work */
2058 TRACE("Dir %s ...\n",debugstr_w(name));
2059 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
2060 TRACE("resolves to %s\n",debugstr_w(path));
2063 return ERROR_SUCCESS;
2066 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2068 MSIPACKAGE *package = param;
2070 MSIFEATURE *feature;
2072 name = MSI_RecordGetString( row, 1 );
2074 feature = get_loaded_feature( package, name );
2076 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2080 Condition = MSI_RecordGetString(row,3);
2082 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2084 int level = MSI_RecordGetInteger(row,2);
2085 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2086 feature->Level = level;
2089 return ERROR_SUCCESS;
2092 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
2094 static const WCHAR name_fmt[] =
2095 {'%','u','.','%','u','.','%','u','.','%','u',0};
2096 static const WCHAR name[] = {'\\',0};
2097 VS_FIXEDFILEINFO *lpVer;
2098 WCHAR filever[0x100];
2104 TRACE("%s\n", debugstr_w(filename));
2106 versize = GetFileVersionInfoSizeW( filename, &handle );
2110 version = msi_alloc( versize );
2111 GetFileVersionInfoW( filename, 0, versize, version );
2113 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
2115 msi_free( version );
2119 sprintfW( filever, name_fmt,
2120 HIWORD(lpVer->dwFileVersionMS),
2121 LOWORD(lpVer->dwFileVersionMS),
2122 HIWORD(lpVer->dwFileVersionLS),
2123 LOWORD(lpVer->dwFileVersionLS));
2125 msi_free( version );
2127 return strdupW( filever );
2130 static UINT msi_check_file_install_states( MSIPACKAGE *package )
2132 LPWSTR file_version;
2135 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2137 MSICOMPONENT* comp = file->Component;
2143 if (file->IsCompressed)
2144 comp->ForceLocalState = TRUE;
2146 /* calculate target */
2147 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2149 msi_free(file->TargetPath);
2151 TRACE("file %s is named %s\n",
2152 debugstr_w(file->File), debugstr_w(file->FileName));
2154 file->TargetPath = build_directory_name(2, p, file->FileName);
2158 TRACE("file %s resolves to %s\n",
2159 debugstr_w(file->File), debugstr_w(file->TargetPath));
2161 /* don't check files of components that aren't installed */
2162 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2163 comp->Installed == INSTALLSTATE_ABSENT)
2165 file->state = msifs_missing; /* assume files are missing */
2169 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2171 file->state = msifs_missing;
2172 comp->Cost += file->FileSize;
2176 if (file->Version &&
2177 (file_version = msi_get_disk_file_version( file->TargetPath )))
2179 TRACE("new %s old %s\n", debugstr_w(file->Version),
2180 debugstr_w(file_version));
2181 /* FIXME: seems like a bad way to compare version numbers */
2182 if (lstrcmpiW(file_version, file->Version)<0)
2184 file->state = msifs_overwrite;
2185 comp->Cost += file->FileSize;
2188 file->state = msifs_present;
2189 msi_free( file_version );
2192 file->state = msifs_present;
2195 return ERROR_SUCCESS;
2199 * A lot is done in this function aside from just the costing.
2200 * The costing needs to be implemented at some point but for now I am going
2201 * to focus on the directory building
2204 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2206 static const WCHAR ExecSeqQuery[] =
2207 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2208 '`','D','i','r','e','c','t','o','r','y','`',0};
2209 static const WCHAR ConditionQuery[] =
2210 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2211 '`','C','o','n','d','i','t','i','o','n','`',0};
2212 static const WCHAR szCosting[] =
2213 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2214 static const WCHAR szlevel[] =
2215 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2216 static const WCHAR szOutOfDiskSpace[] =
2217 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2218 static const WCHAR szOne[] = { '1', 0 };
2219 static const WCHAR szZero[] = { '0', 0 };
2225 TRACE("Building Directory properties\n");
2227 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2228 if (rc == ERROR_SUCCESS)
2230 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2232 msiobj_release(&view->hdr);
2235 /* read components states from the registry */
2236 ACTION_GetComponentInstallStates(package);
2237 ACTION_GetFeatureInstallStates(package);
2239 TRACE("File calculations\n");
2240 msi_check_file_install_states( package );
2242 TRACE("Evaluating Condition Table\n");
2244 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2245 if (rc == ERROR_SUCCESS)
2247 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2249 msiobj_release(&view->hdr);
2252 TRACE("Enabling or Disabling Components\n");
2253 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2255 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2257 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2258 comp->Enabled = FALSE;
2261 comp->Enabled = TRUE;
2264 MSI_SetPropertyW(package,szCosting,szOne);
2265 /* set default run level if not set */
2266 level = msi_dup_property( package, szlevel );
2268 MSI_SetPropertyW(package,szlevel, szOne);
2271 /* FIXME: check volume disk space */
2272 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2274 return MSI_SetFeatureStates(package);
2277 /* OK this value is "interpreted" and then formatted based on the
2278 first few characters */
2279 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2284 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2290 LPWSTR deformated = NULL;
2293 deformat_string(package, &value[2], &deformated);
2295 /* binary value type */
2299 *size = (strlenW(ptr)/2)+1;
2301 *size = strlenW(ptr)/2;
2303 data = msi_alloc(*size);
2309 /* if uneven pad with a zero in front */
2315 data[count] = (BYTE)strtol(byte,NULL,0);
2317 TRACE("Uneven byte count\n");
2325 data[count] = (BYTE)strtol(byte,NULL,0);
2328 msi_free(deformated);
2330 TRACE("Data %i bytes(%i)\n",*size,count);
2337 deformat_string(package, &value[1], &deformated);
2340 *size = sizeof(DWORD);
2341 data = msi_alloc(*size);
2347 if ( (*p < '0') || (*p > '9') )
2353 if (deformated[0] == '-')
2356 TRACE("DWORD %i\n",*(LPDWORD)data);
2358 msi_free(deformated);
2363 static const WCHAR szMulti[] = {'[','~',']',0};
2372 *type=REG_EXPAND_SZ;
2380 if (strstrW(value,szMulti))
2381 *type = REG_MULTI_SZ;
2383 /* remove initial delimiter */
2384 if (!strncmpW(value, szMulti, 3))
2387 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2389 /* add double NULL terminator */
2390 if (*type == REG_MULTI_SZ)
2392 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2393 data = msi_realloc_zero(data, *size);
2399 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2401 MSIPACKAGE *package = param;
2402 static const WCHAR szHCR[] =
2403 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2404 'R','O','O','T','\\',0};
2405 static const WCHAR szHCU[] =
2406 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2407 'U','S','E','R','\\',0};
2408 static const WCHAR szHLM[] =
2409 {'H','K','E','Y','_','L','O','C','A','L','_',
2410 'M','A','C','H','I','N','E','\\',0};
2411 static const WCHAR szHU[] =
2412 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2414 LPSTR value_data = NULL;
2415 HKEY root_key, hkey;
2418 LPCWSTR szRoot, component, name, key, value;
2423 BOOL check_first = FALSE;
2426 ui_progress(package,2,0,0,0);
2433 component = MSI_RecordGetString(row, 6);
2434 comp = get_loaded_component(package,component);
2436 return ERROR_SUCCESS;
2438 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2440 TRACE("Skipping write due to disabled component %s\n",
2441 debugstr_w(component));
2443 comp->Action = comp->Installed;
2445 return ERROR_SUCCESS;
2448 comp->Action = INSTALLSTATE_LOCAL;
2450 name = MSI_RecordGetString(row, 4);
2451 if( MSI_RecordIsNull(row,5) && name )
2453 /* null values can have special meanings */
2454 if (name[0]=='-' && name[1] == 0)
2455 return ERROR_SUCCESS;
2456 else if ((name[0]=='+' && name[1] == 0) ||
2457 (name[0] == '*' && name[1] == 0))
2462 root = MSI_RecordGetInteger(row,2);
2463 key = MSI_RecordGetString(row, 3);
2465 /* get the root key */
2470 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2471 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2472 if (all_users && all_users[0] == '1')
2474 root_key = HKEY_LOCAL_MACHINE;
2479 root_key = HKEY_CURRENT_USER;
2482 msi_free(all_users);
2485 case 0: root_key = HKEY_CLASSES_ROOT;
2488 case 1: root_key = HKEY_CURRENT_USER;
2491 case 2: root_key = HKEY_LOCAL_MACHINE;
2494 case 3: root_key = HKEY_USERS;
2498 ERR("Unknown root %i\n",root);
2504 return ERROR_SUCCESS;
2506 deformat_string(package, key , &deformated);
2507 size = strlenW(deformated) + strlenW(szRoot) + 1;
2508 uikey = msi_alloc(size*sizeof(WCHAR));
2509 strcpyW(uikey,szRoot);
2510 strcatW(uikey,deformated);
2512 if (RegCreateKeyW( root_key, deformated, &hkey))
2514 ERR("Could not create key %s\n",debugstr_w(deformated));
2515 msi_free(deformated);
2517 return ERROR_SUCCESS;
2519 msi_free(deformated);
2521 value = MSI_RecordGetString(row,5);
2523 value_data = parse_value(package, value, &type, &size);
2526 static const WCHAR szEmpty[] = {0};
2527 value_data = (LPSTR)strdupW(szEmpty);
2528 size = sizeof(szEmpty);
2532 deformat_string(package, name, &deformated);
2536 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2538 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2543 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2544 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2546 TRACE("value %s of %s checked already exists\n",
2547 debugstr_w(deformated), debugstr_w(uikey));
2551 TRACE("Checked and setting value %s of %s\n",
2552 debugstr_w(deformated), debugstr_w(uikey));
2553 if (deformated || size)
2554 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2559 uirow = MSI_CreateRecord(3);
2560 MSI_RecordSetStringW(uirow,2,deformated);
2561 MSI_RecordSetStringW(uirow,1,uikey);
2564 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2566 MSI_RecordSetStringW(uirow,3,value);
2568 ui_actiondata(package,szWriteRegistryValues,uirow);
2569 msiobj_release( &uirow->hdr );
2571 msi_free(value_data);
2572 msi_free(deformated);
2575 return ERROR_SUCCESS;
2578 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2582 static const WCHAR ExecSeqQuery[] =
2583 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2584 '`','R','e','g','i','s','t','r','y','`',0 };
2586 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2587 if (rc != ERROR_SUCCESS)
2588 return ERROR_SUCCESS;
2590 /* increment progress bar each time action data is sent */
2591 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2593 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2595 msiobj_release(&view->hdr);
2599 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2601 package->script->CurrentlyScripting = TRUE;
2603 return ERROR_SUCCESS;
2607 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2612 static const WCHAR q1[]=
2613 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2614 '`','R','e','g','i','s','t','r','y','`',0};
2617 MSIFEATURE *feature;
2620 TRACE("InstallValidate\n");
2622 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2623 if (rc == ERROR_SUCCESS)
2625 MSI_IterateRecords( view, &progress, NULL, package );
2626 msiobj_release( &view->hdr );
2627 total += progress * REG_PROGRESS_VALUE;
2630 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2631 total += COMPONENT_PROGRESS_VALUE;
2633 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2634 total += file->FileSize;
2636 ui_progress(package,0,total,0,0);
2638 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2640 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2641 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2642 feature->ActionRequest);
2645 return ERROR_SUCCESS;
2648 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2650 MSIPACKAGE* package = param;
2651 LPCWSTR cond = NULL;
2652 LPCWSTR message = NULL;
2655 static const WCHAR title[]=
2656 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2658 cond = MSI_RecordGetString(row,1);
2660 r = MSI_EvaluateConditionW(package,cond);
2661 if (r == MSICONDITION_FALSE)
2663 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2666 message = MSI_RecordGetString(row,2);
2667 deformat_string(package,message,&deformated);
2668 MessageBoxW(NULL,deformated,title,MB_OK);
2669 msi_free(deformated);
2672 return ERROR_INSTALL_FAILURE;
2675 return ERROR_SUCCESS;
2678 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2681 MSIQUERY * view = NULL;
2682 static const WCHAR ExecSeqQuery[] =
2683 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2684 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2686 TRACE("Checking launch conditions\n");
2688 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2689 if (rc != ERROR_SUCCESS)
2690 return ERROR_SUCCESS;
2692 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2693 msiobj_release(&view->hdr);
2698 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2702 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2704 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2706 MSIRECORD * row = 0;
2708 LPWSTR deformated,buffer,deformated_name;
2710 static const WCHAR ExecSeqQuery[] =
2711 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2712 '`','R','e','g','i','s','t','r','y','`',' ',
2713 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2714 ' ','=',' ' ,'\'','%','s','\'',0 };
2715 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2716 static const WCHAR fmt2[]=
2717 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2719 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2723 root = MSI_RecordGetInteger(row,2);
2724 key = MSI_RecordGetString(row, 3);
2725 name = MSI_RecordGetString(row, 4);
2726 deformat_string(package, key , &deformated);
2727 deformat_string(package, name, &deformated_name);
2729 len = strlenW(deformated) + 6;
2730 if (deformated_name)
2731 len+=strlenW(deformated_name);
2733 buffer = msi_alloc( len *sizeof(WCHAR));
2735 if (deformated_name)
2736 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2738 sprintfW(buffer,fmt,root,deformated);
2740 msi_free(deformated);
2741 msi_free(deformated_name);
2742 msiobj_release(&row->hdr);
2746 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2748 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2753 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2756 return strdupW( file->TargetPath );
2761 static HKEY openSharedDLLsKey(void)
2764 static const WCHAR path[] =
2765 {'S','o','f','t','w','a','r','e','\\',
2766 'M','i','c','r','o','s','o','f','t','\\',
2767 'W','i','n','d','o','w','s','\\',
2768 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2769 'S','h','a','r','e','d','D','L','L','s',0};
2771 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2775 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2780 DWORD sz = sizeof(count);
2783 hkey = openSharedDLLsKey();
2784 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2785 if (rc != ERROR_SUCCESS)
2791 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2795 hkey = openSharedDLLsKey();
2797 msi_reg_set_val_dword( hkey, path, count );
2799 RegDeleteValueW(hkey,path);
2805 * Return TRUE if the count should be written out and FALSE if not
2807 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2809 MSIFEATURE *feature;
2813 /* only refcount DLLs */
2814 if (comp->KeyPath == NULL ||
2815 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2816 comp->Attributes & msidbComponentAttributesODBCDataSource)
2820 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2821 write = (count > 0);
2823 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2827 /* increment counts */
2828 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2832 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2835 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2837 if ( cl->component == comp )
2842 /* decrement counts */
2843 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2847 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2850 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2852 if ( cl->component == comp )
2857 /* ref count all the files in the component */
2862 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2864 if (file->Component == comp)
2865 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2869 /* add a count for permanent */
2870 if (comp->Attributes & msidbComponentAttributesPermanent)
2873 comp->RefCount = count;
2876 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2879 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2881 WCHAR squished_pc[GUID_SIZE];
2882 WCHAR squished_cc[GUID_SIZE];
2889 squash_guid(package->ProductCode,squished_pc);
2890 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2892 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2896 ui_progress(package,2,0,0,0);
2897 if (!comp->ComponentId)
2900 squash_guid(comp->ComponentId,squished_cc);
2902 msi_free(comp->FullKeypath);
2903 comp->FullKeypath = resolve_keypath( package, comp );
2905 ACTION_RefCountComponent( package, comp );
2907 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2908 debugstr_w(comp->Component),
2909 debugstr_w(squished_cc),
2910 debugstr_w(comp->FullKeypath),
2913 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL) ||
2914 ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE))
2916 if (!comp->FullKeypath)
2919 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2920 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2923 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2926 if (rc != ERROR_SUCCESS)
2929 if (comp->Attributes & msidbComponentAttributesPermanent)
2931 static const WCHAR szPermKey[] =
2932 { '0','0','0','0','0','0','0','0','0','0','0','0',
2933 '0','0','0','0','0','0','0','0','0','0','0','0',
2934 '0','0','0','0','0','0','0','0',0 };
2936 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2939 if (comp->Action == INSTALLSTATE_LOCAL)
2940 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2946 WCHAR source[MAX_PATH];
2947 WCHAR base[MAX_PATH];
2950 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2951 static const WCHAR query[] = {
2952 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2953 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2954 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2955 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2956 '`','D','i','s','k','I','d','`',0};
2958 file = get_loaded_file(package, comp->KeyPath);
2962 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2963 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2964 ptr2 = strrchrW(source, '\\') + 1;
2965 msiobj_release(&row->hdr);
2967 lstrcpyW(base, package->PackagePath);
2968 ptr = strrchrW(base, '\\');
2971 sourcepath = resolve_file_source(package, file);
2972 ptr = sourcepath + lstrlenW(base);
2973 lstrcpyW(ptr2, ptr);
2974 msi_free(sourcepath);
2976 msi_reg_set_val_str(hkey, squished_pc, source);
2980 else if (ACTION_VerifyComponentForAction(comp, INSTALLSTATE_ABSENT))
2982 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2983 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2985 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2989 uirow = MSI_CreateRecord(3);
2990 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2991 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2992 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2993 ui_actiondata(package,szProcessComponents,uirow);
2994 msiobj_release( &uirow->hdr );
2997 return ERROR_SUCCESS;
3008 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3009 LPWSTR lpszName, LONG_PTR lParam)
3012 typelib_struct *tl_struct = (typelib_struct*) lParam;
3013 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3017 if (!IS_INTRESOURCE(lpszName))
3019 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3023 sz = strlenW(tl_struct->source)+4;
3024 sz *= sizeof(WCHAR);
3026 if ((INT_PTR)lpszName == 1)
3027 tl_struct->path = strdupW(tl_struct->source);
3030 tl_struct->path = msi_alloc(sz);
3031 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3034 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3035 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3038 msi_free(tl_struct->path);
3039 tl_struct->path = NULL;
3044 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3045 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3047 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3051 msi_free(tl_struct->path);
3052 tl_struct->path = NULL;
3054 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3055 ITypeLib_Release(tl_struct->ptLib);
3060 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3062 MSIPACKAGE* package = param;
3066 typelib_struct tl_struct;
3071 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
3073 component = MSI_RecordGetString(row,3);
3074 comp = get_loaded_component(package,component);
3076 return ERROR_SUCCESS;
3078 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3080 TRACE("Skipping typelib reg due to disabled component\n");
3082 comp->Action = comp->Installed;
3084 return ERROR_SUCCESS;
3087 comp->Action = INSTALLSTATE_LOCAL;
3089 file = get_loaded_file( package, comp->KeyPath );
3091 return ERROR_SUCCESS;
3093 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3097 guid = MSI_RecordGetString(row,1);
3098 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
3099 tl_struct.source = strdupW( file->TargetPath );
3100 tl_struct.path = NULL;
3102 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3103 (LONG_PTR)&tl_struct);
3111 helpid = MSI_RecordGetString(row,6);
3114 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3115 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3119 ERR("Failed to register type library %s\n",
3120 debugstr_w(tl_struct.path));
3123 ui_actiondata(package,szRegisterTypeLibraries,row);
3125 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3128 ITypeLib_Release(tl_struct.ptLib);
3129 msi_free(tl_struct.path);
3132 ERR("Failed to load type library %s\n",
3133 debugstr_w(tl_struct.source));
3135 FreeLibrary(module);
3136 msi_free(tl_struct.source);
3140 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3143 ERR("Failed to load type library: %08x\n", hr);
3144 return ERROR_FUNCTION_FAILED;
3147 ITypeLib_Release(tlib);
3150 return ERROR_SUCCESS;
3153 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3156 * OK this is a bit confusing.. I am given a _Component key and I believe
3157 * that the file that is being registered as a type library is the "key file
3158 * of that component" which I interpret to mean "The file in the KeyPath of
3163 static const WCHAR Query[] =
3164 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3165 '`','T','y','p','e','L','i','b','`',0};
3167 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3168 if (rc != ERROR_SUCCESS)
3169 return ERROR_SUCCESS;
3171 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3172 msiobj_release(&view->hdr);
3176 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3178 MSIPACKAGE *package = param;
3179 LPWSTR target_file, target_folder, filename;
3180 LPCWSTR buffer, extension;
3182 static const WCHAR szlnk[]={'.','l','n','k',0};
3183 IShellLinkW *sl = NULL;
3184 IPersistFile *pf = NULL;
3187 buffer = MSI_RecordGetString(row,4);
3188 comp = get_loaded_component(package,buffer);
3190 return ERROR_SUCCESS;
3192 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
3194 TRACE("Skipping shortcut creation due to disabled component\n");
3196 comp->Action = comp->Installed;
3198 return ERROR_SUCCESS;
3201 comp->Action = INSTALLSTATE_LOCAL;
3203 ui_actiondata(package,szCreateShortcuts,row);
3205 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3206 &IID_IShellLinkW, (LPVOID *) &sl );
3210 ERR("CLSID_ShellLink not available\n");
3214 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3217 ERR("QueryInterface(IID_IPersistFile) failed\n");
3221 buffer = MSI_RecordGetString(row,2);
3222 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
3224 /* may be needed because of a bug somewhere else */
3225 create_full_pathW(target_folder);
3227 filename = msi_dup_record_field( row, 3 );
3228 reduce_to_longfilename(filename);
3230 extension = strchrW(filename,'.');
3231 if (!extension || strcmpiW(extension,szlnk))
3233 int len = strlenW(filename);
3234 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3235 memcpy(filename + len, szlnk, sizeof(szlnk));
3237 target_file = build_directory_name(2, target_folder, filename);
3238 msi_free(target_folder);
3241 buffer = MSI_RecordGetString(row,5);
3242 if (strchrW(buffer,'['))
3245 deformat_string(package,buffer,&deformated);
3246 IShellLinkW_SetPath(sl,deformated);
3247 msi_free(deformated);
3251 FIXME("poorly handled shortcut format, advertised shortcut\n");
3252 IShellLinkW_SetPath(sl,comp->FullKeypath);
3255 if (!MSI_RecordIsNull(row,6))
3258 buffer = MSI_RecordGetString(row,6);
3259 deformat_string(package,buffer,&deformated);
3260 IShellLinkW_SetArguments(sl,deformated);
3261 msi_free(deformated);
3264 if (!MSI_RecordIsNull(row,7))
3266 buffer = MSI_RecordGetString(row,7);
3267 IShellLinkW_SetDescription(sl,buffer);
3270 if (!MSI_RecordIsNull(row,8))
3271 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3273 if (!MSI_RecordIsNull(row,9))
3278 buffer = MSI_RecordGetString(row,9);
3280 Path = build_icon_path(package,buffer);
3281 index = MSI_RecordGetInteger(row,10);
3283 /* no value means 0 */
3284 if (index == MSI_NULL_INTEGER)
3287 IShellLinkW_SetIconLocation(sl,Path,index);
3291 if (!MSI_RecordIsNull(row,11))
3292 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3294 if (!MSI_RecordIsNull(row,12))
3297 buffer = MSI_RecordGetString(row,12);
3298 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3300 IShellLinkW_SetWorkingDirectory(sl,Path);
3304 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3305 IPersistFile_Save(pf,target_file,FALSE);
3307 msi_free(target_file);
3311 IPersistFile_Release( pf );
3313 IShellLinkW_Release( sl );
3315 return ERROR_SUCCESS;
3318 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3323 static const WCHAR Query[] =
3324 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3325 '`','S','h','o','r','t','c','u','t','`',0};
3327 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3328 if (rc != ERROR_SUCCESS)
3329 return ERROR_SUCCESS;
3331 res = CoInitialize( NULL );
3334 ERR("CoInitialize failed\n");
3335 return ERROR_FUNCTION_FAILED;
3338 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3339 msiobj_release(&view->hdr);
3346 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3348 MSIPACKAGE* package = param;
3357 FileName = MSI_RecordGetString(row,1);
3360 ERR("Unable to get FileName\n");
3361 return ERROR_SUCCESS;
3364 FilePath = build_icon_path(package,FileName);
3366 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3368 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3369 FILE_ATTRIBUTE_NORMAL, NULL);
3371 if (the_file == INVALID_HANDLE_VALUE)
3373 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3375 return ERROR_SUCCESS;
3382 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3383 if (rc != ERROR_SUCCESS)
3385 ERR("Failed to get stream\n");
3386 CloseHandle(the_file);
3387 DeleteFileW(FilePath);
3390 WriteFile(the_file,buffer,sz,&write,NULL);
3391 } while (sz == 1024);
3395 CloseHandle(the_file);
3397 uirow = MSI_CreateRecord(1);
3398 MSI_RecordSetStringW(uirow,1,FileName);
3399 ui_actiondata(package,szPublishProduct,uirow);
3400 msiobj_release( &uirow->hdr );
3402 return ERROR_SUCCESS;
3405 static UINT msi_publish_icons(MSIPACKAGE *package)
3410 static const WCHAR query[]= {
3411 'S','E','L','E','C','T',' ','*',' ',
3412 'F','R','O','M',' ','`','I','c','o','n','`',0};
3414 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3415 if (r == ERROR_SUCCESS)
3417 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3418 msiobj_release(&view->hdr);
3421 return ERROR_SUCCESS;
3424 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3430 MSISOURCELISTINFO *info;
3432 static const WCHAR szEmpty[] = {0};
3433 static const WCHAR szSourceList[] = {'S','o','u','r','c','e','L','i','s','t',0};
3435 r = RegCreateKeyW(hkey, szSourceList, &source);
3436 if (r != ERROR_SUCCESS)
3439 RegCloseKey(source);
3441 buffer = strrchrW(package->PackagePath, '\\') + 1;
3442 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3443 package->Context, MSICODE_PRODUCT,
3444 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3445 if (r != ERROR_SUCCESS)
3448 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3449 package->Context, MSICODE_PRODUCT,
3450 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3451 if (r != ERROR_SUCCESS)
3454 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3455 package->Context, MSICODE_PRODUCT,
3456 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3457 if (r != ERROR_SUCCESS)
3460 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3462 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3463 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3464 info->options, info->value);
3466 MsiSourceListSetInfoW(package->ProductCode, NULL,
3467 info->context, info->options,
3468 info->property, info->value);
3471 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3473 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3474 disk->context, disk->options,
3475 disk->disk_id, disk->volume_label, disk->disk_prompt);
3478 return ERROR_SUCCESS;
3481 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3483 MSIHANDLE hdb, suminfo;
3484 WCHAR guids[MAX_PATH];
3485 WCHAR packcode[SQUISH_GUID_SIZE];
3492 static const WCHAR szProductLanguage[] =
3493 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3494 static const WCHAR szARPProductIcon[] =
3495 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3496 static const WCHAR szProductVersion[] =
3497 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3498 static const WCHAR szAssignment[] =
3499 {'A','s','s','i','g','n','m','e','n','t',0};
3500 static const WCHAR szAdvertiseFlags[] =
3501 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3502 static const WCHAR szClients[] =
3503 {'C','l','i','e','n','t','s',0};
3504 static const WCHAR szColon[] = {':',0};
3506 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3507 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3510 langid = msi_get_property_int(package, szProductLanguage, 0);
3511 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3513 ptr = strrchrW(package->PackagePath, '\\' ) + 1;
3514 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGENAMEW, ptr);
3517 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3519 buffer = msi_dup_property(package, szARPProductIcon);
3522 LPWSTR path = build_icon_path(package,buffer);
3523 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3528 buffer = msi_dup_property(package, szProductVersion);
3531 DWORD verdword = msi_version_str_to_dword(buffer);
3532 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3536 msi_reg_set_val_dword(hkey, szAssignment, 0);
3537 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3538 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3539 msi_reg_set_val_str(hkey, szClients, szColon);
3541 hdb = alloc_msihandle(&package->db->hdr);
3543 return ERROR_NOT_ENOUGH_MEMORY;
3545 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3546 MsiCloseHandle(hdb);
3547 if (r != ERROR_SUCCESS)
3551 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3552 NULL, guids, &size);
3553 if (r != ERROR_SUCCESS)
3556 ptr = strchrW(guids, ';');
3558 squash_guid(guids, packcode);
3559 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3562 MsiCloseHandle(suminfo);
3563 return ERROR_SUCCESS;
3566 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3571 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3573 static const WCHAR szUpgradeCode[] =
3574 {'U','p','g','r','a','d','e','C','o','d','e',0};
3576 upgrade = msi_dup_property(package, szUpgradeCode);
3578 return ERROR_SUCCESS;
3580 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3582 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3583 if (r != ERROR_SUCCESS)
3588 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3589 if (r != ERROR_SUCCESS)
3593 squash_guid(package->ProductCode, squashed_pc);
3594 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3603 static BOOL msi_check_publish(MSIPACKAGE *package)
3605 MSIFEATURE *feature;
3607 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3609 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3616 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3618 MSIFEATURE *feature;
3620 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3622 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3629 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3631 WCHAR patch_squashed[GUID_SIZE];
3634 UINT r = ERROR_FUNCTION_FAILED;
3636 static const WCHAR szPatches[] = {'P','a','t','c','h','e','s',0};
3638 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3640 if (res != ERROR_SUCCESS)
3641 return ERROR_FUNCTION_FAILED;
3643 squash_guid(package->patch->patchcode, patch_squashed);
3645 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3646 (const BYTE *)patch_squashed,
3647 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3648 if (res != ERROR_SUCCESS)
3651 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3652 (const BYTE *)package->patch->transforms,
3653 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3654 if (res == ERROR_SUCCESS)
3658 RegCloseKey(patches);
3663 * 99% of the work done here is only done for
3664 * advertised installs. However this is where the
3665 * Icon table is processed and written out
3666 * so that is what I am going to do here.
3668 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3674 /* FIXME: also need to publish if the product is in advertise mode */
3675 if (!msi_check_publish(package))
3676 return ERROR_SUCCESS;
3678 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3680 if (rc != ERROR_SUCCESS)
3683 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3684 NULL, &hudkey, TRUE);
3685 if (rc != ERROR_SUCCESS)
3688 rc = msi_publish_upgrade_code(package);
3689 if (rc != ERROR_SUCCESS)
3694 rc = msi_publish_patch(package, hukey, hudkey);
3695 if (rc != ERROR_SUCCESS)
3699 rc = msi_publish_product_properties(package, hukey);
3700 if (rc != ERROR_SUCCESS)
3703 rc = msi_publish_sourcelist(package, hukey);
3704 if (rc != ERROR_SUCCESS)
3707 rc = msi_publish_icons(package);
3711 RegCloseKey(hudkey);
3716 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3718 MSIPACKAGE *package = param;
3719 LPCWSTR component, section, key, value, identifier, dirproperty;
3720 LPWSTR deformated_section, deformated_key, deformated_value;
3721 LPWSTR folder, filename, fullname = NULL;
3722 LPCWSTR filenameptr;
3726 static const WCHAR szWindowsFolder[] =
3727 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3729 component = MSI_RecordGetString(row, 8);
3730 comp = get_loaded_component(package,component);
3732 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3734 TRACE("Skipping ini file due to disabled component %s\n",
3735 debugstr_w(component));
3737 comp->Action = comp->Installed;
3739 return ERROR_SUCCESS;
3742 comp->Action = INSTALLSTATE_LOCAL;
3744 identifier = MSI_RecordGetString(row,1);
3745 dirproperty = MSI_RecordGetString(row,3);
3746 section = MSI_RecordGetString(row,4);
3747 key = MSI_RecordGetString(row,5);
3748 value = MSI_RecordGetString(row,6);
3749 action = MSI_RecordGetInteger(row,7);
3751 deformat_string(package,section,&deformated_section);
3752 deformat_string(package,key,&deformated_key);
3753 deformat_string(package,value,&deformated_value);
3755 filename = msi_dup_record_field(row, 2);
3756 if (filename && (filenameptr = strchrW(filename, '|')))
3759 filenameptr = filename;
3763 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3765 folder = msi_dup_property( package, dirproperty );
3768 folder = msi_dup_property( package, szWindowsFolder );
3772 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3776 fullname = build_directory_name(2, folder, filenameptr);
3780 TRACE("Adding value %s to section %s in %s\n",
3781 debugstr_w(deformated_key), debugstr_w(deformated_section),
3782 debugstr_w(fullname));
3783 WritePrivateProfileStringW(deformated_section, deformated_key,
3784 deformated_value, fullname);
3786 else if (action == 1)
3789 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3790 returned, 10, fullname);
3791 if (returned[0] == 0)
3793 TRACE("Adding value %s to section %s in %s\n",
3794 debugstr_w(deformated_key), debugstr_w(deformated_section),
3795 debugstr_w(fullname));
3797 WritePrivateProfileStringW(deformated_section, deformated_key,
3798 deformated_value, fullname);
3801 else if (action == 3)
3802 FIXME("Append to existing section not yet implemented\n");
3804 uirow = MSI_CreateRecord(4);
3805 MSI_RecordSetStringW(uirow,1,identifier);
3806 MSI_RecordSetStringW(uirow,2,deformated_section);
3807 MSI_RecordSetStringW(uirow,3,deformated_key);
3808 MSI_RecordSetStringW(uirow,4,deformated_value);
3809 ui_actiondata(package,szWriteIniValues,uirow);
3810 msiobj_release( &uirow->hdr );
3816 msi_free(deformated_key);
3817 msi_free(deformated_value);
3818 msi_free(deformated_section);
3819 return ERROR_SUCCESS;
3822 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3826 static const WCHAR ExecSeqQuery[] =
3827 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3828 '`','I','n','i','F','i','l','e','`',0};
3830 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3831 if (rc != ERROR_SUCCESS)
3833 TRACE("no IniFile table\n");
3834 return ERROR_SUCCESS;
3837 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3838 msiobj_release(&view->hdr);
3842 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3844 MSIPACKAGE *package = param;
3849 static const WCHAR ExeStr[] =
3850 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3851 static const WCHAR close[] = {'\"',0};
3853 PROCESS_INFORMATION info;
3858 memset(&si,0,sizeof(STARTUPINFOW));
3860 filename = MSI_RecordGetString(row,1);
3861 file = get_loaded_file( package, filename );
3865 ERR("Unable to find file id %s\n",debugstr_w(filename));
3866 return ERROR_SUCCESS;
3869 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3871 FullName = msi_alloc(len*sizeof(WCHAR));
3872 strcpyW(FullName,ExeStr);
3873 strcatW( FullName, file->TargetPath );
3874 strcatW(FullName,close);
3876 TRACE("Registering %s\n",debugstr_w(FullName));
3877 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3882 CloseHandle(info.hThread);
3883 msi_dialog_check_messages(info.hProcess);
3884 CloseHandle(info.hProcess);
3890 uirow = MSI_CreateRecord( 2 );
3891 uipath = strdupW( file->TargetPath );
3892 p = strrchrW(uipath,'\\');
3895 MSI_RecordSetStringW( uirow, 1, &p[1] );
3896 MSI_RecordSetStringW( uirow, 2, uipath);
3897 ui_actiondata( package, szSelfRegModules, uirow);
3898 msiobj_release( &uirow->hdr );
3900 /* FIXME: call ui_progress? */
3902 return ERROR_SUCCESS;
3905 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3909 static const WCHAR ExecSeqQuery[] =
3910 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3911 '`','S','e','l','f','R','e','g','`',0};
3913 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3914 if (rc != ERROR_SUCCESS)
3916 TRACE("no SelfReg table\n");
3917 return ERROR_SUCCESS;
3920 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3921 msiobj_release(&view->hdr);
3923 return ERROR_SUCCESS;
3926 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3928 MSIFEATURE *feature;
3931 HKEY userdata = NULL;
3933 if (!msi_check_publish(package))
3934 return ERROR_SUCCESS;
3936 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3938 if (rc != ERROR_SUCCESS)
3941 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3943 if (rc != ERROR_SUCCESS)
3946 /* here the guids are base 85 encoded */
3947 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3953 BOOL absent = FALSE;
3956 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3957 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3958 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3962 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3966 if (feature->Feature_Parent)
3967 size += strlenW( feature->Feature_Parent )+2;
3969 data = msi_alloc(size * sizeof(WCHAR));
3972 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3974 MSICOMPONENT* component = cl->component;
3978 if (component->ComponentId)
3980 TRACE("From %s\n",debugstr_w(component->ComponentId));
3981 CLSIDFromString(component->ComponentId, &clsid);
3982 encode_base85_guid(&clsid,buf);
3983 TRACE("to %s\n",debugstr_w(buf));
3988 if (feature->Feature_Parent)
3990 static const WCHAR sep[] = {'\2',0};
3992 strcatW(data,feature->Feature_Parent);
3995 msi_reg_set_val_str( userdata, feature->Feature, data );
3999 if (feature->Feature_Parent)
4000 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4003 static const WCHAR emptyW[] = {0};
4004 size += sizeof(WCHAR);
4005 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4006 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : emptyW),size);
4010 size += 2*sizeof(WCHAR);
4011 data = msi_alloc(size);
4014 if (feature->Feature_Parent)
4015 strcpyW( &data[1], feature->Feature_Parent );
4016 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4022 uirow = MSI_CreateRecord( 1 );
4023 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4024 ui_actiondata( package, szPublishFeatures, uirow);
4025 msiobj_release( &uirow->hdr );
4026 /* FIXME: call ui_progress? */
4031 RegCloseKey(userdata);
4035 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4040 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4042 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4044 if (r == ERROR_SUCCESS)
4046 RegDeleteValueW(hkey, feature->Feature);
4050 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4052 if (r == ERROR_SUCCESS)
4054 RegDeleteValueW(hkey, feature->Feature);
4058 return ERROR_SUCCESS;
4061 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4063 MSIFEATURE *feature;
4065 if (!msi_check_unpublish(package))
4066 return ERROR_SUCCESS;
4068 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4070 msi_unpublish_feature(package, feature);
4073 return ERROR_SUCCESS;
4076 static UINT msi_get_local_package_name( LPWSTR path )
4078 static const WCHAR szInstaller[] = {
4079 '\\','I','n','s','t','a','l','l','e','r','\\',0};
4080 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
4084 time = GetTickCount();
4085 GetWindowsDirectoryW( path, MAX_PATH );
4086 lstrcatW( path, szInstaller );
4087 CreateDirectoryW( path, NULL );
4089 len = lstrlenW(path);
4090 for (i=0; i<0x10000; i++)
4092 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
4093 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
4094 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
4095 if (handle != INVALID_HANDLE_VALUE)
4097 CloseHandle(handle);
4100 if (GetLastError() != ERROR_FILE_EXISTS &&
4101 GetLastError() != ERROR_SHARING_VIOLATION)
4102 return ERROR_FUNCTION_FAILED;
4105 return ERROR_SUCCESS;
4108 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
4110 WCHAR packagefile[MAX_PATH];
4113 r = msi_get_local_package_name( packagefile );
4114 if (r != ERROR_SUCCESS)
4117 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
4119 r = CopyFileW( package->db->path, packagefile, FALSE);
4123 ERR("Unable to copy package (%s -> %s) (error %d)\n",
4124 debugstr_w(package->db->path), debugstr_w(packagefile), GetLastError());
4125 return ERROR_FUNCTION_FAILED;
4128 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
4130 return ERROR_SUCCESS;
4133 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4135 LPWSTR prop, val, key;
4141 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4142 static const WCHAR szWindowsInstaller[] =
4143 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4144 static const WCHAR modpath_fmt[] =
4145 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4146 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4147 static const WCHAR szModifyPath[] =
4148 {'M','o','d','i','f','y','P','a','t','h',0};
4149 static const WCHAR szUninstallString[] =
4150 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4151 static const WCHAR szEstimatedSize[] =
4152 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4153 static const WCHAR szProductLanguage[] =
4154 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4155 static const WCHAR szProductVersion[] =
4156 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4157 static const WCHAR szProductName[] =
4158 {'P','r','o','d','u','c','t','N','a','m','e',0};
4159 static const WCHAR szDisplayName[] =
4160 {'D','i','s','p','l','a','y','N','a','m','e',0};
4161 static const WCHAR szDisplayVersion[] =
4162 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4163 static const WCHAR szManufacturer[] =
4164 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4166 static const LPCSTR propval[] = {
4167 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4168 "ARPCONTACT", "Contact",
4169 "ARPCOMMENTS", "Comments",
4170 "ProductName", "DisplayName",
4171 "ProductVersion", "DisplayVersion",
4172 "ARPHELPLINK", "HelpLink",
4173 "ARPHELPTELEPHONE", "HelpTelephone",
4174 "ARPINSTALLLOCATION", "InstallLocation",
4175 "SourceDir", "InstallSource",
4176 "Manufacturer", "Publisher",
4177 "ARPREADME", "Readme",
4179 "ARPURLINFOABOUT", "URLInfoAbout",
4180 "ARPURLUPDATEINFO", "URLUpdateInfo",
4183 const LPCSTR *p = propval;
4187 prop = strdupAtoW(*p++);
4188 key = strdupAtoW(*p++);
4189 val = msi_dup_property(package, prop);
4190 msi_reg_set_val_str(hkey, key, val);
4196 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4198 size = deformat_string(package, modpath_fmt, &buffer);
4199 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4200 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4203 /* FIXME: Write real Estimated Size when we have it */
4204 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4206 buffer = msi_dup_property(package, szProductName);
4207 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4210 buffer = msi_dup_property(package, cszSourceDir);
4211 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4214 buffer = msi_dup_property(package, szManufacturer);
4215 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4218 GetLocalTime(&systime);
4219 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4220 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4222 langid = msi_get_property_int(package, szProductLanguage, 0);
4223 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4225 buffer = msi_dup_property(package, szProductVersion);
4226 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4229 DWORD verdword = msi_version_str_to_dword(buffer);
4231 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4232 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4233 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4237 return ERROR_SUCCESS;
4240 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4242 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4243 LPWSTR upgrade_code;
4248 static const WCHAR szUpgradeCode[] = {
4249 'U','p','g','r','a','d','e','C','o','d','e',0};
4251 /* FIXME: also need to publish if the product is in advertise mode */
4252 if (!msi_check_publish(package))
4253 return ERROR_SUCCESS;
4255 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4256 if (rc != ERROR_SUCCESS)
4259 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4260 NULL, &props, TRUE);
4261 if (rc != ERROR_SUCCESS)
4264 msi_make_package_local(package, props);
4266 rc = msi_publish_install_properties(package, hkey);
4267 if (rc != ERROR_SUCCESS)
4270 rc = msi_publish_install_properties(package, props);
4271 if (rc != ERROR_SUCCESS)
4274 upgrade_code = msi_dup_property(package, szUpgradeCode);
4277 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4278 squash_guid(package->ProductCode, squashed_pc);
4279 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4280 RegCloseKey(upgrade);
4281 msi_free(upgrade_code);
4287 return ERROR_SUCCESS;
4290 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4292 return execute_script(package,INSTALL_SCRIPT);
4295 static UINT msi_unpublish_product(MSIPACKAGE *package)
4298 LPWSTR remove = NULL;
4299 LPWSTR *features = NULL;
4300 BOOL full_uninstall = TRUE;
4301 MSIFEATURE *feature;
4303 static const WCHAR szRemove[] = {'R','E','M','O','V','E',0};
4304 static const WCHAR szAll[] = {'A','L','L',0};
4305 static const WCHAR szUpgradeCode[] =
4306 {'U','p','g','r','a','d','e','C','o','d','e',0};
4308 remove = msi_dup_property(package, szRemove);
4310 return ERROR_SUCCESS;
4312 features = msi_split_string(remove, ',');
4316 ERR("REMOVE feature list is empty!\n");
4317 return ERROR_FUNCTION_FAILED;
4320 if (!lstrcmpW(features[0], szAll))
4321 full_uninstall = TRUE;
4324 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4326 if (feature->Action != INSTALLSTATE_ABSENT)
4327 full_uninstall = FALSE;
4331 if (!full_uninstall)
4334 MSIREG_DeleteProductKey(package->ProductCode);
4335 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4336 MSIREG_DeleteUninstallKey(package->ProductCode);
4338 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4340 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4341 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4345 MSIREG_DeleteUserProductKey(package->ProductCode);
4346 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4349 upgrade = msi_dup_property(package, szUpgradeCode);
4352 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4359 return ERROR_SUCCESS;
4362 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4366 rc = msi_unpublish_product(package);
4367 if (rc != ERROR_SUCCESS)
4370 /* turn off scheduling */
4371 package->script->CurrentlyScripting= FALSE;
4373 /* first do the same as an InstallExecute */
4374 rc = ACTION_InstallExecute(package);
4375 if (rc != ERROR_SUCCESS)
4378 /* then handle Commit Actions */
4379 rc = execute_script(package,COMMIT_SCRIPT);
4384 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4386 static const WCHAR RunOnce[] = {
4387 'S','o','f','t','w','a','r','e','\\',
4388 'M','i','c','r','o','s','o','f','t','\\',
4389 'W','i','n','d','o','w','s','\\',
4390 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4391 'R','u','n','O','n','c','e',0};
4392 static const WCHAR InstallRunOnce[] = {
4393 'S','o','f','t','w','a','r','e','\\',
4394 'M','i','c','r','o','s','o','f','t','\\',
4395 'W','i','n','d','o','w','s','\\',
4396 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4397 'I','n','s','t','a','l','l','e','r','\\',
4398 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4400 static const WCHAR msiexec_fmt[] = {
4402 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4403 '\"','%','s','\"',0};
4404 static const WCHAR install_fmt[] = {
4405 '/','I',' ','\"','%','s','\"',' ',
4406 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4407 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4408 WCHAR buffer[256], sysdir[MAX_PATH];
4410 WCHAR squished_pc[100];
4412 squash_guid(package->ProductCode,squished_pc);
4414 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4415 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4416 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4419 msi_reg_set_val_str( hkey, squished_pc, buffer );
4422 TRACE("Reboot command %s\n",debugstr_w(buffer));
4424 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4425 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4427 msi_reg_set_val_str( hkey, squished_pc, buffer );
4430 return ERROR_INSTALL_SUSPEND;
4433 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4439 * We are currently doing what should be done here in the top level Install
4440 * however for Administrative and uninstalls this step will be needed
4442 if (!package->PackagePath)
4443 return ERROR_SUCCESS;
4445 msi_set_sourcedir_props(package, TRUE);
4447 attrib = GetFileAttributesW(package->db->path);
4448 if (attrib == INVALID_FILE_ATTRIBUTES)
4454 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4455 package->Context, MSICODE_PRODUCT,
4456 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4457 if (rc == ERROR_MORE_DATA)
4459 prompt = msi_alloc(size * sizeof(WCHAR));
4460 MsiSourceListGetInfoW(package->ProductCode, NULL,
4461 package->Context, MSICODE_PRODUCT,
4462 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4465 prompt = strdupW(package->db->path);
4467 msg = generate_error_string(package,1302,1,prompt);
4468 while(attrib == INVALID_FILE_ATTRIBUTES)
4470 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4473 rc = ERROR_INSTALL_USEREXIT;
4476 attrib = GetFileAttributesW(package->db->path);
4482 return ERROR_SUCCESS;
4487 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4494 static const WCHAR szPropKeys[][80] =
4496 {'P','r','o','d','u','c','t','I','D',0},
4497 {'U','S','E','R','N','A','M','E',0},
4498 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4502 static const WCHAR szRegKeys[][80] =
4504 {'P','r','o','d','u','c','t','I','D',0},
4505 {'R','e','g','O','w','n','e','r',0},
4506 {'R','e','g','C','o','m','p','a','n','y',0},
4510 if (msi_check_unpublish(package))
4512 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4513 return ERROR_SUCCESS;
4516 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4518 return ERROR_SUCCESS;
4520 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4522 if (rc != ERROR_SUCCESS)
4525 for( i = 0; szPropKeys[i][0]; i++ )
4527 buffer = msi_dup_property( package, szPropKeys[i] );
4528 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4533 msi_free(productid);
4536 /* FIXME: call ui_actiondata */
4542 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4546 package->script->InWhatSequence |= SEQUENCE_EXEC;
4547 rc = ACTION_ProcessExecSequence(package,FALSE);
4552 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4554 MSIPACKAGE *package = param;
4555 LPCWSTR compgroupid=NULL;
4556 LPCWSTR feature=NULL;
4557 LPCWSTR text = NULL;
4558 LPCWSTR qualifier = NULL;
4559 LPCWSTR component = NULL;
4560 LPWSTR advertise = NULL;
4561 LPWSTR output = NULL;
4563 UINT rc = ERROR_SUCCESS;
4568 component = MSI_RecordGetString(rec,3);
4569 comp = get_loaded_component(package,component);
4571 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4572 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4573 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4575 TRACE("Skipping: Component %s not scheduled for install\n",
4576 debugstr_w(component));
4578 return ERROR_SUCCESS;
4581 compgroupid = MSI_RecordGetString(rec,1);
4582 qualifier = MSI_RecordGetString(rec,2);
4584 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4585 if (rc != ERROR_SUCCESS)
4588 text = MSI_RecordGetString(rec,4);
4589 feature = MSI_RecordGetString(rec,5);
4591 advertise = create_component_advertise_string(package, comp, feature);
4593 sz = strlenW(advertise);
4596 sz += lstrlenW(text);
4599 sz *= sizeof(WCHAR);
4601 output = msi_alloc_zero(sz);
4602 strcpyW(output,advertise);
4603 msi_free(advertise);
4606 strcatW(output,text);
4608 msi_reg_set_val_multi_str( hkey, qualifier, output );
4615 uirow = MSI_CreateRecord( 2 );
4616 MSI_RecordSetStringW( uirow, 1, compgroupid );
4617 MSI_RecordSetStringW( uirow, 2, qualifier);
4618 ui_actiondata( package, szPublishComponents, uirow);
4619 msiobj_release( &uirow->hdr );
4620 /* FIXME: call ui_progress? */
4626 * At present I am ignorning the advertised components part of this and only
4627 * focusing on the qualified component sets
4629 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4633 static const WCHAR ExecSeqQuery[] =
4634 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4635 '`','P','u','b','l','i','s','h',
4636 'C','o','m','p','o','n','e','n','t','`',0};
4638 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4639 if (rc != ERROR_SUCCESS)
4640 return ERROR_SUCCESS;
4642 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4643 msiobj_release(&view->hdr);
4648 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4650 MSIPACKAGE *package = param;
4653 SC_HANDLE hscm, service = NULL;
4654 LPCWSTR comp, depends, pass;
4655 LPWSTR name = NULL, disp = NULL;
4656 LPCWSTR load_order, serv_name, key;
4657 DWORD serv_type, start_type;
4660 static const WCHAR query[] =
4661 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4662 '`','C','o','m','p','o','n','e','n','t','`',' ',
4663 'W','H','E','R','E',' ',
4664 '`','C','o','m','p','o','n','e','n','t','`',' ',
4665 '=','\'','%','s','\'',0};
4667 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4670 ERR("Failed to open the SC Manager!\n");
4674 start_type = MSI_RecordGetInteger(rec, 5);
4675 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4678 depends = MSI_RecordGetString(rec, 8);
4679 if (depends && *depends)
4680 FIXME("Dependency list unhandled!\n");
4682 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4683 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
4684 serv_type = MSI_RecordGetInteger(rec, 4);
4685 err_control = MSI_RecordGetInteger(rec, 6);
4686 load_order = MSI_RecordGetString(rec, 7);
4687 serv_name = MSI_RecordGetString(rec, 9);
4688 pass = MSI_RecordGetString(rec, 10);
4689 comp = MSI_RecordGetString(rec, 12);
4691 /* fetch the service path */
4692 row = MSI_QueryGetRecord(package->db, query, comp);
4695 ERR("Control query failed!\n");
4699 key = MSI_RecordGetString(row, 6);
4701 file = get_loaded_file(package, key);
4702 msiobj_release(&row->hdr);
4705 ERR("Failed to load the service file\n");
4709 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4710 start_type, err_control, file->TargetPath,
4711 load_order, NULL, NULL, serv_name, pass);
4714 if (GetLastError() != ERROR_SERVICE_EXISTS)
4715 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4719 CloseServiceHandle(service);
4720 CloseServiceHandle(hscm);
4724 return ERROR_SUCCESS;
4727 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4731 static const WCHAR ExecSeqQuery[] =
4732 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4733 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4735 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4736 if (rc != ERROR_SUCCESS)
4737 return ERROR_SUCCESS;
4739 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4740 msiobj_release(&view->hdr);
4745 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4746 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
4748 LPCWSTR *vector, *temp_vector;
4752 static const WCHAR separator[] = {'[','~',']',0};
4755 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4760 vector = msi_alloc(sizeof(LPWSTR));
4768 vector[*numargs - 1] = p;
4770 if ((q = strstrW(p, separator)))
4774 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4780 vector = temp_vector;
4789 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4791 MSIPACKAGE *package = param;
4793 SC_HANDLE scm, service = NULL;
4794 LPCWSTR name, *vector = NULL;
4796 DWORD event, numargs;
4797 UINT r = ERROR_FUNCTION_FAILED;
4799 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4800 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4801 return ERROR_SUCCESS;
4803 name = MSI_RecordGetString(rec, 2);
4804 event = MSI_RecordGetInteger(rec, 3);
4805 args = strdupW(MSI_RecordGetString(rec, 4));
4807 if (!(event & msidbServiceControlEventStart))
4808 return ERROR_SUCCESS;
4810 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4813 ERR("Failed to open the service control manager\n");
4817 service = OpenServiceW(scm, name, SERVICE_START);
4820 ERR("Failed to open service %s\n", debugstr_w(name));
4824 vector = msi_service_args_to_vector(args, &numargs);
4826 if (!StartServiceW(service, numargs, vector))
4828 ERR("Failed to start service %s\n", debugstr_w(name));
4835 CloseServiceHandle(service);
4836 CloseServiceHandle(scm);
4843 static UINT ACTION_StartServices( MSIPACKAGE *package )
4848 static const WCHAR query[] = {
4849 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4850 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4852 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4853 if (rc != ERROR_SUCCESS)
4854 return ERROR_SUCCESS;
4856 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4857 msiobj_release(&view->hdr);
4862 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4864 DWORD i, needed, count;
4865 ENUM_SERVICE_STATUSW *dependencies;
4869 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4870 0, &needed, &count))
4873 if (GetLastError() != ERROR_MORE_DATA)
4876 dependencies = msi_alloc(needed);
4880 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4881 needed, &needed, &count))
4884 for (i = 0; i < count; i++)
4886 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4887 SERVICE_STOP | SERVICE_QUERY_STATUS);
4891 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4898 msi_free(dependencies);
4902 static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
4904 MSIPACKAGE *package = param;
4906 SERVICE_STATUS status;
4907 SERVICE_STATUS_PROCESS ssp;
4908 SC_HANDLE scm = NULL, service = NULL;
4910 DWORD event, needed;
4912 event = MSI_RecordGetInteger(rec, 3);
4913 if (!(event & msidbServiceControlEventStop))
4914 return ERROR_SUCCESS;
4916 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4917 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4918 return ERROR_SUCCESS;
4920 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4921 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4922 args = strdupW(MSI_RecordGetString(rec, 4));
4924 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4927 WARN("Failed to open the SCM: %d\n", GetLastError());
4931 service = OpenServiceW(scm, name,
4933 SERVICE_QUERY_STATUS |
4934 SERVICE_ENUMERATE_DEPENDENTS);
4937 WARN("Failed to open service (%s): %d\n",
4938 debugstr_w(name), GetLastError());
4942 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4943 sizeof(SERVICE_STATUS_PROCESS), &needed))
4945 WARN("Failed to query service status (%s): %d\n",
4946 debugstr_w(name), GetLastError());
4950 if (ssp.dwCurrentState == SERVICE_STOPPED)
4953 stop_service_dependents(scm, service);
4955 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
4956 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
4959 CloseServiceHandle(service);
4960 CloseServiceHandle(scm);
4964 return ERROR_SUCCESS;
4967 static UINT ACTION_StopServices( MSIPACKAGE *package )
4972 static const WCHAR query[] = {
4973 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4974 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4976 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4977 if (rc != ERROR_SUCCESS)
4978 return ERROR_SUCCESS;
4980 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
4981 msiobj_release(&view->hdr);
4986 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4990 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4992 if (!lstrcmpW(file->File, filename))
4999 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5001 MSIPACKAGE *package = param;
5002 LPWSTR driver, driver_path, ptr;
5003 WCHAR outpath[MAX_PATH];
5004 MSIFILE *driver_file, *setup_file;
5007 UINT r = ERROR_SUCCESS;
5009 static const WCHAR driver_fmt[] = {
5010 'D','r','i','v','e','r','=','%','s',0};
5011 static const WCHAR setup_fmt[] = {
5012 'S','e','t','u','p','=','%','s',0};
5013 static const WCHAR usage_fmt[] = {
5014 'F','i','l','e','U','s','a','g','e','=','1',0};
5016 desc = MSI_RecordGetString(rec, 3);
5018 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5019 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5021 if (!driver_file || !setup_file)
5023 ERR("ODBC Driver entry not found!\n");
5024 return ERROR_FUNCTION_FAILED;
5027 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
5028 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
5029 lstrlenW(usage_fmt) + 1;
5030 driver = msi_alloc(len * sizeof(WCHAR));
5032 return ERROR_OUTOFMEMORY;
5035 lstrcpyW(ptr, desc);
5036 ptr += lstrlenW(ptr) + 1;
5038 sprintfW(ptr, driver_fmt, driver_file->FileName);
5039 ptr += lstrlenW(ptr) + 1;
5041 sprintfW(ptr, setup_fmt, setup_file->FileName);
5042 ptr += lstrlenW(ptr) + 1;
5044 lstrcpyW(ptr, usage_fmt);
5045 ptr += lstrlenW(ptr) + 1;
5048 driver_path = strdupW(driver_file->TargetPath);
5049 ptr = strrchrW(driver_path, '\\');
5050 if (ptr) *ptr = '\0';
5052 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5053 NULL, ODBC_INSTALL_COMPLETE, &usage))
5055 ERR("Failed to install SQL driver!\n");
5056 r = ERROR_FUNCTION_FAILED;
5060 msi_free(driver_path);
5065 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5067 MSIPACKAGE *package = param;
5068 LPWSTR translator, translator_path, ptr;
5069 WCHAR outpath[MAX_PATH];
5070 MSIFILE *translator_file, *setup_file;
5073 UINT r = ERROR_SUCCESS;
5075 static const WCHAR translator_fmt[] = {
5076 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5077 static const WCHAR setup_fmt[] = {
5078 'S','e','t','u','p','=','%','s',0};
5080 desc = MSI_RecordGetString(rec, 3);
5082 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5083 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5085 if (!translator_file || !setup_file)
5087 ERR("ODBC Translator entry not found!\n");
5088 return ERROR_FUNCTION_FAILED;
5091 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
5092 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
5093 translator = msi_alloc(len * sizeof(WCHAR));
5095 return ERROR_OUTOFMEMORY;
5098 lstrcpyW(ptr, desc);
5099 ptr += lstrlenW(ptr) + 1;
5101 sprintfW(ptr, translator_fmt, translator_file->FileName);
5102 ptr += lstrlenW(ptr) + 1;
5104 sprintfW(ptr, setup_fmt, setup_file->FileName);
5105 ptr += lstrlenW(ptr) + 1;
5108 translator_path = strdupW(translator_file->TargetPath);
5109 ptr = strrchrW(translator_path, '\\');
5110 if (ptr) *ptr = '\0';
5112 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5113 NULL, ODBC_INSTALL_COMPLETE, &usage))
5115 ERR("Failed to install SQL translator!\n");
5116 r = ERROR_FUNCTION_FAILED;
5119 msi_free(translator);
5120 msi_free(translator_path);
5125 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5128 LPCWSTR desc, driver;
5129 WORD request = ODBC_ADD_SYS_DSN;
5132 UINT r = ERROR_SUCCESS;
5134 static const WCHAR attrs_fmt[] = {
5135 'D','S','N','=','%','s',0 };
5137 desc = MSI_RecordGetString(rec, 3);
5138 driver = MSI_RecordGetString(rec, 4);
5139 registration = MSI_RecordGetInteger(rec, 5);
5141 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5142 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5144 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
5145 attrs = msi_alloc(len * sizeof(WCHAR));
5147 return ERROR_OUTOFMEMORY;
5149 sprintfW(attrs, attrs_fmt, desc);
5150 attrs[len - 1] = '\0';
5152 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5154 ERR("Failed to install SQL data source!\n");
5155 r = ERROR_FUNCTION_FAILED;
5163 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5168 static const WCHAR driver_query[] = {
5169 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5170 'O','D','B','C','D','r','i','v','e','r',0 };
5172 static const WCHAR translator_query[] = {
5173 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5174 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5176 static const WCHAR source_query[] = {
5177 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5178 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5180 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5181 if (rc != ERROR_SUCCESS)
5182 return ERROR_SUCCESS;
5184 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5185 msiobj_release(&view->hdr);
5187 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5188 if (rc != ERROR_SUCCESS)
5189 return ERROR_SUCCESS;
5191 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5192 msiobj_release(&view->hdr);
5194 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5195 if (rc != ERROR_SUCCESS)
5196 return ERROR_SUCCESS;
5198 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5199 msiobj_release(&view->hdr);
5204 #define ENV_ACT_SETALWAYS 0x1
5205 #define ENV_ACT_SETABSENT 0x2
5206 #define ENV_ACT_REMOVE 0x4
5207 #define ENV_ACT_REMOVEMATCH 0x8
5209 #define ENV_MOD_MACHINE 0x20000000
5210 #define ENV_MOD_APPEND 0x40000000
5211 #define ENV_MOD_PREFIX 0x80000000
5212 #define ENV_MOD_MASK 0xC0000000
5214 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5216 static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5218 LPCWSTR cptr = *name;
5219 LPCWSTR ptr = *value;
5221 static const WCHAR prefix[] = {'[','~',']',0};
5222 static const int prefix_len = 3;
5228 *flags |= ENV_ACT_SETALWAYS;
5229 else if (*cptr == '+')
5230 *flags |= ENV_ACT_SETABSENT;
5231 else if (*cptr == '-')
5232 *flags |= ENV_ACT_REMOVE;
5233 else if (*cptr == '!')
5234 *flags |= ENV_ACT_REMOVEMATCH;
5235 else if (*cptr == '*')
5236 *flags |= ENV_MOD_MACHINE;
5246 ERR("Missing environment variable\n");
5247 return ERROR_FUNCTION_FAILED;
5250 if (!strncmpW(ptr, prefix, prefix_len))
5252 *flags |= ENV_MOD_APPEND;
5253 *value += lstrlenW(prefix);
5255 else if (lstrlenW(*value) >= prefix_len)
5257 ptr += lstrlenW(ptr) - prefix_len;
5258 if (!lstrcmpW(ptr, prefix))
5260 *flags |= ENV_MOD_PREFIX;
5261 /* the "[~]" will be removed by deformat_string */;
5266 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5267 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5268 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5269 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5271 ERR("Invalid flags: %08x\n", *flags);
5272 return ERROR_FUNCTION_FAILED;
5275 return ERROR_SUCCESS;
5278 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5280 MSIPACKAGE *package = param;
5281 LPCWSTR name, value;
5282 LPWSTR data = NULL, newval = NULL;
5283 LPWSTR deformatted = NULL, ptr;
5284 DWORD flags, type, size;
5286 HKEY env = NULL, root;
5287 LPCWSTR environment;
5289 static const WCHAR user_env[] =
5290 {'E','n','v','i','r','o','n','m','e','n','t',0};
5291 static const WCHAR machine_env[] =
5292 {'S','y','s','t','e','m','\\',
5293 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5294 'C','o','n','t','r','o','l','\\',
5295 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5296 'E','n','v','i','r','o','n','m','e','n','t',0};
5297 static const WCHAR semicolon[] = {';',0};
5299 name = MSI_RecordGetString(rec, 2);
5300 value = MSI_RecordGetString(rec, 3);
5302 res = env_set_flags(&name, &value, &flags);
5303 if (res != ERROR_SUCCESS)
5306 deformat_string(package, value, &deformatted);
5309 res = ERROR_OUTOFMEMORY;
5313 value = deformatted;
5315 if (flags & ENV_MOD_MACHINE)
5317 environment = machine_env;
5318 root = HKEY_LOCAL_MACHINE;
5322 environment = user_env;
5323 root = HKEY_CURRENT_USER;
5326 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5327 KEY_ALL_ACCESS, NULL, &env, NULL);
5328 if (res != ERROR_SUCCESS)
5331 if (flags & ENV_ACT_REMOVE)
5332 FIXME("Not removing environment variable on uninstall!\n");
5335 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5336 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
5337 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
5340 if (res != ERROR_FILE_NOT_FOUND)
5342 if (flags & ENV_ACT_SETABSENT)
5344 res = ERROR_SUCCESS;
5348 data = msi_alloc(size);
5352 return ERROR_OUTOFMEMORY;
5355 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5356 if (res != ERROR_SUCCESS)
5359 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5361 res = RegDeleteKeyW(env, name);
5365 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
5366 newval = msi_alloc(size);
5370 res = ERROR_OUTOFMEMORY;
5374 if (!(flags & ENV_MOD_MASK))
5375 lstrcpyW(newval, value);
5378 if (flags & ENV_MOD_PREFIX)
5380 lstrcpyW(newval, value);
5381 lstrcatW(newval, semicolon);
5382 ptr = newval + lstrlenW(value) + 1;
5385 lstrcpyW(ptr, data);
5387 if (flags & ENV_MOD_APPEND)
5389 lstrcatW(newval, semicolon);
5390 lstrcatW(newval, value);
5396 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
5397 newval = msi_alloc(size);
5400 res = ERROR_OUTOFMEMORY;
5404 lstrcpyW(newval, value);
5407 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5408 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
5411 if (env) RegCloseKey(env);
5412 msi_free(deformatted);
5418 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5422 static const WCHAR ExecSeqQuery[] =
5423 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5424 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5425 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5426 if (rc != ERROR_SUCCESS)
5427 return ERROR_SUCCESS;
5429 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5430 msiobj_release(&view->hdr);
5435 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5446 static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5450 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5451 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5453 WARN("Source or dest is directory, not moving\n");
5457 if (options == msidbMoveFileOptionsMove)
5459 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5460 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5463 WARN("MoveFile failed: %d\n", GetLastError());
5469 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5470 ret = CopyFileW(source, dest, FALSE);
5473 WARN("CopyFile failed: %d\n", GetLastError());
5481 static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5484 DWORD dirlen, pathlen;
5486 ptr = strrchrW(wildcard, '\\');
5487 dirlen = ptr - wildcard + 1;
5489 pathlen = dirlen + lstrlenW(filename) + 1;
5490 path = msi_alloc(pathlen * sizeof(WCHAR));
5492 lstrcpynW(path, wildcard, dirlen + 1);
5493 lstrcatW(path, filename);
5498 static void free_file_entry(FILE_LIST *file)
5500 msi_free(file->source);
5501 msi_free(file->dest);
5505 static void free_list(FILE_LIST *list)
5507 while (!list_empty(&list->entry))
5509 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5511 list_remove(&file->entry);
5512 free_file_entry(file);
5516 static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5518 FILE_LIST *new, *file;
5519 LPWSTR ptr, filename;
5522 new = msi_alloc_zero(sizeof(FILE_LIST));
5526 new->source = strdupW(source);
5527 ptr = strrchrW(dest, '\\') + 1;
5528 filename = strrchrW(new->source, '\\') + 1;
5530 new->sourcename = filename;
5533 new->destname = ptr;
5535 new->destname = new->sourcename;
5537 size = (ptr - dest) + lstrlenW(filename) + 1;
5538 new->dest = msi_alloc(size * sizeof(WCHAR));
5541 free_file_entry(new);
5545 lstrcpynW(new->dest, dest, ptr - dest + 1);
5546 lstrcatW(new->dest, filename);
5548 if (list_empty(&files->entry))
5550 list_add_head(&files->entry, &new->entry);
5554 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5556 if (lstrcmpW(source, file->source) < 0)
5558 list_add_before(&file->entry, &new->entry);
5563 list_add_after(&file->entry, &new->entry);
5567 static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
5569 WIN32_FIND_DATAW wfd;
5573 FILE_LIST files, *file;
5576 hfile = FindFirstFileW(source, &wfd);
5577 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5579 list_init(&files.entry);
5581 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5583 if (is_dot_dir(wfd.cFileName)) continue;
5585 path = wildcard_to_file(source, wfd.cFileName);
5592 add_wildcard(&files, path, dest);
5596 /* no files match the wildcard */
5597 if (list_empty(&files.entry))
5600 /* only the first wildcard match gets renamed to dest */
5601 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5602 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5603 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5610 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5612 while (!list_empty(&files.entry))
5614 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5616 msi_move_file(file->source, file->dest, options);
5618 list_remove(&file->entry);
5619 free_file_entry(file);
5630 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5632 MSIPACKAGE *package = param;
5635 LPWSTR destname = NULL;
5636 LPWSTR sourcedir = NULL, destdir = NULL;
5637 LPWSTR source = NULL, dest = NULL;
5640 BOOL ret, wildcards;
5642 static const WCHAR backslash[] = {'\\',0};
5644 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5645 if (!comp || !comp->Enabled ||
5646 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5648 TRACE("Component not set for install, not moving file\n");
5649 return ERROR_SUCCESS;
5652 sourcename = MSI_RecordGetString(rec, 3);
5653 options = MSI_RecordGetInteger(rec, 7);
5655 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5659 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5665 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5668 source = strdupW(sourcedir);
5674 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5675 source = msi_alloc(size * sizeof(WCHAR));
5679 lstrcpyW(source, sourcedir);
5680 if (source[lstrlenW(source) - 1] != '\\')
5681 lstrcatW(source, backslash);
5682 lstrcatW(source, sourcename);
5685 wildcards = strchrW(source, '*') || strchrW(source, '?');
5687 if (MSI_RecordIsNull(rec, 4))
5691 destname = strdupW(sourcename);
5698 destname = strdupW(MSI_RecordGetString(rec, 4));
5700 reduce_to_longfilename(destname);
5705 size = lstrlenW(destname);
5707 size += lstrlenW(destdir) + 2;
5708 dest = msi_alloc(size * sizeof(WCHAR));
5712 lstrcpyW(dest, destdir);
5713 if (dest[lstrlenW(dest) - 1] != '\\')
5714 lstrcatW(dest, backslash);
5717 lstrcatW(dest, destname);
5719 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5721 ret = CreateDirectoryW(destdir, NULL);
5724 WARN("CreateDirectory failed: %d\n", GetLastError());
5725 return ERROR_SUCCESS;
5730 msi_move_file(source, dest, options);
5732 move_files_wildcard(source, dest, options);
5735 msi_free(sourcedir);
5741 return ERROR_SUCCESS;
5744 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5749 static const WCHAR ExecSeqQuery[] =
5750 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5751 '`','M','o','v','e','F','i','l','e','`',0};
5753 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5754 if (rc != ERROR_SUCCESS)
5755 return ERROR_SUCCESS;
5757 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5758 msiobj_release(&view->hdr);
5763 typedef struct tagMSIASSEMBLY
5766 MSICOMPONENT *component;
5767 MSIFEATURE *feature;
5775 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
5777 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
5778 LPVOID pvReserved, HMODULE *phModDll);
5780 static BOOL init_functionpointers(void)
5786 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
5788 hmscoree = LoadLibraryA("mscoree.dll");
5791 WARN("mscoree.dll not available\n");
5795 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
5796 if (!pLoadLibraryShim)
5798 WARN("LoadLibraryShim not available\n");
5799 FreeLibrary(hmscoree);
5803 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
5806 WARN("fusion.dll not available\n");
5807 FreeLibrary(hmscoree);
5811 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
5813 FreeLibrary(hmscoree);
5817 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
5820 IAssemblyCache *cache;
5822 UINT r = ERROR_FUNCTION_FAILED;
5824 TRACE("installing assembly: %s\n", debugstr_w(path));
5826 if (assembly->feature)
5827 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
5829 if (assembly->manifest)
5830 FIXME("Manifest unhandled\n");
5832 if (assembly->application)
5834 FIXME("Assembly should be privately installed\n");
5835 return ERROR_SUCCESS;
5838 if (assembly->attributes == msidbAssemblyAttributesWin32)
5840 FIXME("Win32 assemblies not handled\n");
5841 return ERROR_SUCCESS;
5844 hr = pCreateAssemblyCache(&cache, 0);
5848 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
5850 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
5855 IAssemblyCache_Release(cache);
5859 typedef struct tagASSEMBLY_LIST
5861 MSIPACKAGE *package;
5862 IAssemblyCache *cache;
5863 struct list *assemblies;
5866 typedef struct tagASSEMBLY_NAME
5874 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
5876 ASSEMBLY_NAME *asmname = param;
5877 LPCWSTR name = MSI_RecordGetString(rec, 2);
5878 LPWSTR val = msi_dup_record_field(rec, 3);
5880 static const WCHAR Name[] = {'N','a','m','e',0};
5881 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
5882 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
5883 static const WCHAR PublicKeyToken[] = {
5884 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
5886 if (!strcmpiW(name, Name))
5887 asmname->name = val;
5888 else if (!strcmpiW(name, Version))
5889 asmname->version = val;
5890 else if (!strcmpiW(name, Culture))
5891 asmname->culture = val;
5892 else if (!strcmpiW(name, PublicKeyToken))
5893 asmname->pubkeytoken = val;
5897 return ERROR_SUCCESS;
5900 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
5904 *size = lstrlenW(append) + 1;
5905 *str = msi_alloc((*size) * sizeof(WCHAR));
5906 lstrcpyW(*str, append);
5910 (*size) += lstrlenW(append);
5911 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
5912 lstrcatW(*str, append);
5915 static BOOL check_assembly_installed(MSIDATABASE *db, IAssemblyCache *cache,
5918 ASSEMBLY_INFO asminfo;
5926 static const WCHAR separator[] = {',',' ',0};
5927 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
5928 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
5929 static const WCHAR PublicKeyToken[] = {
5930 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
5931 static const WCHAR query[] = {
5932 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5933 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
5934 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
5935 '=','\'','%','s','\'',0};
5939 ZeroMemory(&name, sizeof(ASSEMBLY_NAME));
5940 ZeroMemory(&asminfo, sizeof(ASSEMBLY_INFO));
5942 r = MSI_OpenQuery(db, &view, query, comp->Component);
5943 if (r != ERROR_SUCCESS)
5944 return ERROR_SUCCESS;
5946 MSI_IterateRecords(view, NULL, parse_assembly_name, &name);
5947 msiobj_release(&view->hdr);
5951 ERR("No assembly name specified!\n");
5955 append_str(&disp, &size, name.name);
5959 append_str(&disp, &size, separator);
5960 append_str(&disp, &size, Version);
5961 append_str(&disp, &size, name.version);
5966 append_str(&disp, &size, separator);
5967 append_str(&disp, &size, Culture);
5968 append_str(&disp, &size, name.culture);
5971 if (name.pubkeytoken)
5973 append_str(&disp, &size, separator);
5974 append_str(&disp, &size, PublicKeyToken);
5975 append_str(&disp, &size, name.pubkeytoken);
5978 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
5979 IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE,
5981 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
5985 msi_free(name.name);
5986 msi_free(name.version);
5987 msi_free(name.culture);
5988 msi_free(name.pubkeytoken);
5993 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
5995 ASSEMBLY_LIST *list = param;
5996 MSIASSEMBLY *assembly;
5998 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6000 return ERROR_OUTOFMEMORY;
6002 assembly->component = get_loaded_component(list->package, MSI_RecordGetString(rec, 1));
6004 if (!assembly->component || !assembly->component->Enabled ||
6005 !(assembly->component->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
6007 TRACE("Component not set for install, not publishing assembly\n");
6009 return ERROR_SUCCESS;
6012 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6013 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6015 if (!assembly->file)
6017 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6018 return ERROR_FUNCTION_FAILED;
6021 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6022 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6023 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6024 assembly->installed = check_assembly_installed(list->package->db,
6026 assembly->component);
6028 list_add_head(list->assemblies, &assembly->entry);
6029 return ERROR_SUCCESS;
6032 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6034 IAssemblyCache *cache = NULL;
6040 static const WCHAR query[] =
6041 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6042 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6044 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6045 if (r != ERROR_SUCCESS)
6046 return ERROR_SUCCESS;
6048 hr = pCreateAssemblyCache(&cache, 0);
6050 return ERROR_FUNCTION_FAILED;
6052 list.package = package;
6054 list.assemblies = assemblies;
6056 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6057 msiobj_release(&view->hdr);
6059 IAssemblyCache_Release(cache);
6064 static void free_assemblies(struct list *assemblies)
6066 struct list *item, *cursor;
6068 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6070 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6072 list_remove(&assembly->entry);
6073 msi_free(assembly->application);
6074 msi_free(assembly->manifest);
6079 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6081 MSIASSEMBLY *assembly;
6083 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6085 if (!lstrcmpW(assembly->file->File, file))
6095 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6096 LPWSTR *path, DWORD *attrs, PVOID user)
6098 MSIASSEMBLY *assembly;
6099 WCHAR temppath[MAX_PATH];
6100 struct list *assemblies = user;
6103 if (!find_assembly(assemblies, file, &assembly))
6106 GetTempPathW(MAX_PATH, temppath);
6107 PathAddBackslashW(temppath);
6108 lstrcatW(temppath, assembly->file->FileName);
6110 if (action == MSICABEXTRACT_BEGINEXTRACT)
6112 if (assembly->installed)
6115 *path = strdupW(temppath);
6116 *attrs = assembly->file->Attributes;
6118 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6120 assembly->installed = TRUE;
6122 r = install_assembly(package, assembly, temppath);
6123 if (r != ERROR_SUCCESS)
6124 ERR("Failed to install assembly\n");
6130 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6133 struct list assemblies = LIST_INIT(assemblies);
6134 MSIASSEMBLY *assembly;
6137 if (!init_functionpointers() || !pCreateAssemblyCache)
6138 return ERROR_FUNCTION_FAILED;
6140 r = load_assemblies(package, &assemblies);
6141 if (r != ERROR_SUCCESS)
6144 if (list_empty(&assemblies))
6147 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6150 r = ERROR_OUTOFMEMORY;
6154 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6156 if (assembly->installed && !mi->is_continuous)
6159 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6160 (assembly->file->IsCompressed && !mi->is_extracted))
6164 r = ready_media(package, assembly->file, mi);
6165 if (r != ERROR_SUCCESS)
6167 ERR("Failed to ready media\n");
6172 data.package = package;
6173 data.cb = installassembly_cb;
6174 data.user = &assemblies;
6176 if (assembly->file->IsCompressed &&
6177 !msi_cabextract(package, mi, &data))
6179 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6180 r = ERROR_FUNCTION_FAILED;
6185 if (!assembly->file->IsCompressed)
6187 LPWSTR source = resolve_file_source(package, assembly->file);
6189 r = install_assembly(package, assembly, source);
6190 if (r != ERROR_SUCCESS)
6191 ERR("Failed to install assembly\n");
6196 /* FIXME: write Installer assembly reg values */
6200 free_assemblies(&assemblies);
6204 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6205 LPCSTR action, LPCWSTR table )
6207 static const WCHAR query[] = {
6208 'S','E','L','E','C','T',' ','*',' ',
6209 'F','R','O','M',' ','`','%','s','`',0 };
6210 MSIQUERY *view = NULL;
6214 r = MSI_OpenQuery( package->db, &view, query, table );
6215 if (r == ERROR_SUCCESS)
6217 r = MSI_IterateRecords(view, &count, NULL, package);
6218 msiobj_release(&view->hdr);
6222 FIXME("%s -> %u ignored %s table values\n",
6223 action, count, debugstr_w(table));
6225 return ERROR_SUCCESS;
6228 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6230 TRACE("%p\n", package);
6231 return ERROR_SUCCESS;
6234 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
6236 static const WCHAR table[] =
6237 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
6238 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
6241 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6243 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6244 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6247 static UINT ACTION_BindImage( MSIPACKAGE *package )
6249 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6250 return msi_unimplemented_action_stub( package, "BindImage", table );
6253 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6255 static const WCHAR table[] = {
6256 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
6257 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6260 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6262 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6263 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6266 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
6268 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
6269 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
6272 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6274 static const WCHAR table[] = {
6275 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6276 return msi_unimplemented_action_stub( package, "DeleteServices", table );
6278 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6280 static const WCHAR table[] = {
6281 'P','r','o','d','u','c','t','I','D',0 };
6282 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
6285 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6287 static const WCHAR table[] = {
6288 'E','n','v','i','r','o','n','m','e','n','t',0 };
6289 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
6292 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6294 static const WCHAR table[] = {
6295 'M','s','i','A','s','s','e','m','b','l','y',0 };
6296 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6299 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
6301 static const WCHAR table[] = { 'F','o','n','t',0 };
6302 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
6305 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6307 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6308 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6311 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6313 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6314 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6317 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6319 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6320 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6323 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6325 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6326 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6329 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
6331 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6332 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
6335 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6337 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6338 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6341 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
6343 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6344 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
6347 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6349 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6350 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
6353 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
6355 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6356 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
6359 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
6361 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
6362 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
6365 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
6367 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6368 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
6371 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6373 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6374 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6377 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6379 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6380 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6383 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6385 static const WCHAR table[] = { 'M','I','M','E',0 };
6386 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6389 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6391 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6392 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6395 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
6397 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
6398 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
6401 static const struct _actions StandardActions[] = {
6402 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6403 { szAppSearch, ACTION_AppSearch },
6404 { szBindImage, ACTION_BindImage },
6405 { szCCPSearch, ACTION_CCPSearch },
6406 { szCostFinalize, ACTION_CostFinalize },
6407 { szCostInitialize, ACTION_CostInitialize },
6408 { szCreateFolders, ACTION_CreateFolders },
6409 { szCreateShortcuts, ACTION_CreateShortcuts },
6410 { szDeleteServices, ACTION_DeleteServices },
6411 { szDisableRollback, NULL },
6412 { szDuplicateFiles, ACTION_DuplicateFiles },
6413 { szExecuteAction, ACTION_ExecuteAction },
6414 { szFileCost, ACTION_FileCost },
6415 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6416 { szForceReboot, ACTION_ForceReboot },
6417 { szInstallAdminPackage, NULL },
6418 { szInstallExecute, ACTION_InstallExecute },
6419 { szInstallExecuteAgain, ACTION_InstallExecute },
6420 { szInstallFiles, ACTION_InstallFiles},
6421 { szInstallFinalize, ACTION_InstallFinalize },
6422 { szInstallInitialize, ACTION_InstallInitialize },
6423 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6424 { szInstallValidate, ACTION_InstallValidate },
6425 { szIsolateComponents, ACTION_IsolateComponents },
6426 { szLaunchConditions, ACTION_LaunchConditions },
6427 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6428 { szMoveFiles, ACTION_MoveFiles },
6429 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6430 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6431 { szInstallODBC, ACTION_InstallODBC },
6432 { szInstallServices, ACTION_InstallServices },
6433 { szPatchFiles, ACTION_PatchFiles },
6434 { szProcessComponents, ACTION_ProcessComponents },
6435 { szPublishComponents, ACTION_PublishComponents },
6436 { szPublishFeatures, ACTION_PublishFeatures },
6437 { szPublishProduct, ACTION_PublishProduct },
6438 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6439 { szRegisterComPlus, ACTION_RegisterComPlus},
6440 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6441 { szRegisterFonts, ACTION_RegisterFonts },
6442 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6443 { szRegisterProduct, ACTION_RegisterProduct },
6444 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6445 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6446 { szRegisterUser, ACTION_RegisterUser },
6447 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6448 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6449 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6450 { szRemoveFiles, ACTION_RemoveFiles },
6451 { szRemoveFolders, ACTION_RemoveFolders },
6452 { szRemoveIniValues, ACTION_RemoveIniValues },
6453 { szRemoveODBC, ACTION_RemoveODBC },
6454 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6455 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6456 { szResolveSource, ACTION_ResolveSource },
6457 { szRMCCPSearch, ACTION_RMCCPSearch },
6458 { szScheduleReboot, NULL },
6459 { szSelfRegModules, ACTION_SelfRegModules },
6460 { szSelfUnregModules, ACTION_SelfUnregModules },
6461 { szSetODBCFolders, NULL },
6462 { szStartServices, ACTION_StartServices },
6463 { szStopServices, ACTION_StopServices },
6464 { szUnpublishComponents, ACTION_UnpublishComponents },
6465 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6466 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6467 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6468 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6469 { szUnregisterFonts, ACTION_UnregisterFonts },
6470 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6471 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6472 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6473 { szValidateProductID, ACTION_ValidateProductID },
6474 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6475 { szWriteIniValues, ACTION_WriteIniValues },
6476 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6480 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
6481 UINT* rc, BOOL force )
6487 if (!run && !package->script->CurrentlyScripting)
6492 if (strcmpW(action,szInstallFinalize) == 0 ||
6493 strcmpW(action,szInstallExecute) == 0 ||
6494 strcmpW(action,szInstallExecuteAgain) == 0)
6499 while (StandardActions[i].action != NULL)
6501 if (strcmpW(StandardActions[i].action, action)==0)
6505 ui_actioninfo(package, action, TRUE, 0);
6506 *rc = schedule_action(package,INSTALL_SCRIPT,action);
6507 ui_actioninfo(package, action, FALSE, *rc);
6511 ui_actionstart(package, action);
6512 if (StandardActions[i].handler)
6514 *rc = StandardActions[i].handler(package);
6518 FIXME("unhandled standard action %s\n",debugstr_w(action));
6519 *rc = ERROR_SUCCESS;