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 )
296 LPWSTR prop = NULL, val = NULL;
299 return ERROR_SUCCESS;
311 TRACE("Looking at %s\n",debugstr_w(ptr));
313 ptr2 = strchrW(ptr,'=');
316 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
323 prop = msi_alloc((len+1)*sizeof(WCHAR));
324 memcpy(prop,ptr,len*sizeof(WCHAR));
330 while (*ptr && (quote || (!quote && *ptr!=' ')))
343 val = msi_alloc((len+1)*sizeof(WCHAR));
344 memcpy(val,ptr2,len*sizeof(WCHAR));
347 if (lstrlenW(prop) > 0)
349 TRACE("Found commandline property (%s) = (%s)\n",
350 debugstr_w(prop), debugstr_w(val));
351 MSI_SetPropertyW(package,prop,val);
357 return ERROR_SUCCESS;
361 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
364 LPWSTR p, *ret = NULL;
370 /* count the number of substrings */
371 for ( pc = str, count = 0; pc; count++ )
373 pc = strchrW( pc, sep );
378 /* allocate space for an array of substring pointers and the substrings */
379 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
380 (lstrlenW(str)+1) * sizeof(WCHAR) );
384 /* copy the string and set the pointers */
385 p = (LPWSTR) &ret[count+1];
387 for( count = 0; (ret[count] = p); count++ )
389 p = strchrW( p, sep );
397 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
399 WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
400 LPWSTR prod_code, patch_product;
403 prod_code = msi_dup_property( package, szProductCode );
404 patch_product = msi_get_suminfo_product( patch );
406 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
408 if ( strstrW( patch_product, prod_code ) )
411 ret = ERROR_FUNCTION_FAILED;
413 msi_free( patch_product );
414 msi_free( prod_code );
419 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
420 MSIDATABASE *patch_db, LPCWSTR name )
422 UINT ret = ERROR_FUNCTION_FAILED;
423 IStorage *stg = NULL;
426 TRACE("%p %s\n", package, debugstr_w(name) );
430 ERR("expected a colon in %s\n", debugstr_w(name));
431 return ERROR_FUNCTION_FAILED;
434 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
437 ret = msi_check_transform_applicable( package, stg );
438 if (ret == ERROR_SUCCESS)
439 msi_table_apply_transform( package->db, stg );
441 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
442 IStorage_Release( stg );
445 ERR("failed to open substorage %s\n", debugstr_w(name));
447 return ERROR_SUCCESS;
450 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
452 static const WCHAR szProdCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
453 LPWSTR guid_list, *guids, product_code;
454 UINT i, ret = ERROR_FUNCTION_FAILED;
456 product_code = msi_dup_property( package, szProdCode );
459 /* FIXME: the property ProductCode should be written into the DB somewhere */
460 ERR("no product code to check\n");
461 return ERROR_SUCCESS;
464 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
465 guids = msi_split_string( guid_list, ';' );
466 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
468 if (!lstrcmpW( guids[i], product_code ))
472 msi_free( guid_list );
473 msi_free( product_code );
478 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
481 LPWSTR str, *substorage;
482 UINT i, r = ERROR_SUCCESS;
484 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
486 return ERROR_FUNCTION_FAILED;
488 msi_check_patch_applicable( package, si );
490 /* enumerate the substorage */
491 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
492 substorage = msi_split_string( str, ';' );
493 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
494 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
495 msi_free( substorage );
498 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
500 msiobj_release( &si->hdr );
505 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
507 MSIDATABASE *patch_db = NULL;
510 TRACE("%p %s\n", package, debugstr_w( file ) );
513 * We probably want to make sure we only open a patch collection here.
514 * Patch collections (.msp) and databases (.msi) have different GUIDs
515 * but currently MSI_OpenDatabaseW will accept both.
517 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
518 if ( r != ERROR_SUCCESS )
520 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
524 msi_parse_patch_summary( package, patch_db );
527 * There might be a CAB file in the patch package,
528 * so append it to the list of storage to search for streams.
530 append_storage_to_db( package->db, patch_db->storage );
532 msiobj_release( &patch_db->hdr );
534 return ERROR_SUCCESS;
537 /* get the PATCH property, and apply all the patches it specifies */
538 static UINT msi_apply_patches( MSIPACKAGE *package )
540 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
541 LPWSTR patch_list, *patches;
542 UINT i, r = ERROR_SUCCESS;
544 patch_list = msi_dup_property( package, szPatch );
546 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
548 patches = msi_split_string( patch_list, ';' );
549 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
550 r = msi_apply_patch_package( package, patches[i] );
553 msi_free( patch_list );
558 static UINT msi_apply_transforms( MSIPACKAGE *package )
560 static const WCHAR szTransforms[] = {
561 'T','R','A','N','S','F','O','R','M','S',0 };
562 LPWSTR xform_list, *xforms;
563 UINT i, r = ERROR_SUCCESS;
565 xform_list = msi_dup_property( package, szTransforms );
566 xforms = msi_split_string( xform_list, ';' );
568 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
570 if (xforms[i][0] == ':')
571 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
573 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
577 msi_free( xform_list );
582 static BOOL ui_sequence_exists( MSIPACKAGE *package )
587 static const WCHAR ExecSeqQuery [] =
588 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
589 '`','I','n','s','t','a','l','l',
590 'U','I','S','e','q','u','e','n','c','e','`',
591 ' ','W','H','E','R','E',' ',
592 '`','S','e','q','u','e','n','c','e','`',' ',
593 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
594 '`','S','e','q','u','e','n','c','e','`',0};
596 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
597 if (rc == ERROR_SUCCESS)
599 msiobj_release(&view->hdr);
606 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
609 LPWSTR source, check;
612 static const WCHAR szOriginalDatabase[] =
613 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
615 db = msi_dup_property( package, szOriginalDatabase );
617 return ERROR_OUTOFMEMORY;
619 p = strrchrW( db, '\\' );
622 p = strrchrW( db, '/' );
626 return ERROR_SUCCESS;
631 source = msi_alloc( len * sizeof(WCHAR) );
632 lstrcpynW( source, db, len );
634 check = msi_dup_property( package, cszSourceDir );
635 if (!check || replace)
636 MSI_SetPropertyW( package, cszSourceDir, source );
640 check = msi_dup_property( package, cszSOURCEDIR );
641 if (!check || replace)
642 MSI_SetPropertyW( package, cszSOURCEDIR, source );
648 return ERROR_SUCCESS;
651 static UINT msi_set_context(MSIPACKAGE *package)
658 static const WCHAR szOne[] = {'1',0};
659 static const WCHAR szAllUsers[] = {'A','L','L','U','S','E','R','S',0};
661 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
663 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
664 if (r == ERROR_SUCCESS)
667 if (num == 1 || num == 2)
668 package->Context = MSIINSTALLCONTEXT_MACHINE;
671 MSI_SetPropertyW(package, szAllUsers, szOne);
672 return ERROR_SUCCESS;
675 /****************************************************
676 * TOP level entry points
677 *****************************************************/
679 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
680 LPCWSTR szCommandLine )
683 BOOL ui = FALSE, ui_exists;
684 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
685 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
686 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
688 MSI_SetPropertyW(package, szAction, szInstall);
690 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
692 package->script->InWhatSequence = SEQUENCE_INSTALL;
699 dir = strdupW(szPackagePath);
700 p = strrchrW(dir, '\\');
704 file = szPackagePath + (p - dir);
709 dir = msi_alloc(MAX_PATH*sizeof(WCHAR));
710 GetCurrentDirectoryW(MAX_PATH, dir);
711 lstrcatW(dir, cszbs);
712 file = szPackagePath;
715 msi_free( package->PackagePath );
716 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
717 if (!package->PackagePath)
720 return ERROR_OUTOFMEMORY;
723 lstrcpyW(package->PackagePath, dir);
724 lstrcatW(package->PackagePath, file);
727 msi_set_sourcedir_props(package, FALSE);
730 msi_parse_command_line( package, szCommandLine );
732 msi_apply_transforms( package );
733 msi_apply_patches( package );
735 /* properties may have been added by a transform */
736 msi_clone_properties( package );
737 msi_set_context( package );
739 if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED )
741 package->script->InWhatSequence |= SEQUENCE_UI;
742 rc = ACTION_ProcessUISequence(package);
744 ui_exists = ui_sequence_exists(package);
745 if (rc == ERROR_SUCCESS || !ui_exists)
747 package->script->InWhatSequence |= SEQUENCE_EXEC;
748 rc = ACTION_ProcessExecSequence(package,ui_exists);
752 rc = ACTION_ProcessExecSequence(package,FALSE);
754 package->script->CurrentlyScripting= FALSE;
756 /* process the ending type action */
757 if (rc == ERROR_SUCCESS)
758 ACTION_PerformActionSequence(package,-1,ui);
759 else if (rc == ERROR_INSTALL_USEREXIT)
760 ACTION_PerformActionSequence(package,-2,ui);
761 else if (rc == ERROR_INSTALL_SUSPEND)
762 ACTION_PerformActionSequence(package,-4,ui);
764 ACTION_PerformActionSequence(package,-3,ui);
766 /* finish up running custom actions */
767 ACTION_FinishCustomActions(package);
772 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
774 UINT rc = ERROR_SUCCESS;
776 static const WCHAR ExecSeqQuery[] =
777 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
778 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
779 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
780 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
782 static const WCHAR UISeqQuery[] =
783 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
784 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
785 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
786 ' ', '=',' ','%','i',0};
789 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
791 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
795 LPCWSTR action, cond;
797 TRACE("Running the actions\n");
799 /* check conditions */
800 cond = MSI_RecordGetString(row,2);
802 /* this is a hack to skip errors in the condition code */
803 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
806 action = MSI_RecordGetString(row,1);
809 ERR("failed to fetch action\n");
810 rc = ERROR_FUNCTION_FAILED;
815 rc = ACTION_PerformUIAction(package,action,-1);
817 rc = ACTION_PerformAction(package,action,-1,FALSE);
819 msiobj_release(&row->hdr);
830 } iterate_action_param;
832 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
834 iterate_action_param *iap= (iterate_action_param*)param;
836 LPCWSTR cond, action;
838 action = MSI_RecordGetString(row,1);
841 ERR("Error is retrieving action name\n");
842 return ERROR_FUNCTION_FAILED;
845 /* check conditions */
846 cond = MSI_RecordGetString(row,2);
848 /* this is a hack to skip errors in the condition code */
849 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
851 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
852 return ERROR_SUCCESS;
856 rc = ACTION_PerformUIAction(iap->package,action,-1);
858 rc = ACTION_PerformAction(iap->package,action,-1,FALSE);
860 msi_dialog_check_messages( NULL );
862 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
863 rc = iap->package->CurrentInstallState;
865 if (rc == ERROR_FUNCTION_NOT_CALLED)
868 if (rc != ERROR_SUCCESS)
869 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
874 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
878 static const WCHAR query[] =
879 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
881 ' ','W','H','E','R','E',' ',
882 '`','S','e','q','u','e','n','c','e','`',' ',
883 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
884 '`','S','e','q','u','e','n','c','e','`',0};
885 iterate_action_param iap;
888 * FIXME: probably should be checking UILevel in the
889 * ACTION_PerformUIAction/ACTION_PerformAction
890 * rather than saving the UI level here. Those
891 * two functions can be merged too.
893 iap.package = package;
896 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
898 r = MSI_OpenQuery( package->db, &view, query, szTable );
899 if (r == ERROR_SUCCESS)
901 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
902 msiobj_release(&view->hdr);
908 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
912 static const WCHAR ExecSeqQuery[] =
913 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
914 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
915 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
916 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
917 'O','R','D','E','R',' ', 'B','Y',' ',
918 '`','S','e','q','u','e','n','c','e','`',0 };
920 static const WCHAR IVQuery[] =
921 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
922 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
923 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
924 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
925 ' ','\'', 'I','n','s','t','a','l','l',
926 'V','a','l','i','d','a','t','e','\'', 0};
928 iterate_action_param iap;
930 iap.package = package;
933 if (package->script->ExecuteSequenceRun)
935 TRACE("Execute Sequence already Run\n");
936 return ERROR_SUCCESS;
939 package->script->ExecuteSequenceRun = TRUE;
941 /* get the sequence number */
944 row = MSI_QueryGetRecord(package->db, IVQuery);
946 return ERROR_FUNCTION_FAILED;
947 seq = MSI_RecordGetInteger(row,1);
948 msiobj_release(&row->hdr);
951 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
952 if (rc == ERROR_SUCCESS)
954 TRACE("Running the actions\n");
956 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
957 msiobj_release(&view->hdr);
963 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
967 static const WCHAR ExecSeqQuery [] =
968 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
969 '`','I','n','s','t','a','l','l',
970 'U','I','S','e','q','u','e','n','c','e','`',
971 ' ','W','H','E','R','E',' ',
972 '`','S','e','q','u','e','n','c','e','`',' ',
973 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
974 '`','S','e','q','u','e','n','c','e','`',0};
975 iterate_action_param iap;
977 iap.package = package;
980 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
982 if (rc == ERROR_SUCCESS)
984 TRACE("Running the actions\n");
986 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
987 msiobj_release(&view->hdr);
993 /********************************************************
994 * ACTION helper functions and functions that perform the actions
995 *******************************************************/
996 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
997 UINT* rc, UINT script, BOOL force )
1002 arc = ACTION_CustomAction(package, action, script, force);
1004 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1013 * A lot of actions are really important even if they don't do anything
1014 * explicit... Lots of properties are set at the beginning of the installation
1015 * CostFinalize does a bunch of work to translate the directories and such
1017 * But until I get write access to the database that is hard, so I am going to
1018 * hack it to see if I can get something to run.
1020 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
1022 UINT rc = ERROR_SUCCESS;
1025 TRACE("Performing action (%s)\n",debugstr_w(action));
1027 handled = ACTION_HandleStandardAction(package, action, &rc, force);
1030 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
1034 WARN("unhandled msi action %s\n",debugstr_w(action));
1035 rc = ERROR_FUNCTION_NOT_CALLED;
1041 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
1043 UINT rc = ERROR_SUCCESS;
1044 BOOL handled = FALSE;
1046 TRACE("Performing action (%s)\n",debugstr_w(action));
1048 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1051 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
1053 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1058 WARN("unhandled msi action %s\n",debugstr_w(action));
1059 rc = ERROR_FUNCTION_NOT_CALLED;
1067 * Actual Action Handlers
1070 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1072 MSIPACKAGE *package = (MSIPACKAGE*)param;
1078 dir = MSI_RecordGetString(row,1);
1081 ERR("Unable to get folder id\n");
1082 return ERROR_SUCCESS;
1085 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1088 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1089 return ERROR_SUCCESS;
1092 TRACE("Folder is %s\n",debugstr_w(full_path));
1095 uirow = MSI_CreateRecord(1);
1096 MSI_RecordSetStringW(uirow,1,full_path);
1097 ui_actiondata(package,szCreateFolders,uirow);
1098 msiobj_release( &uirow->hdr );
1100 if (folder->State == 0)
1101 create_full_pathW(full_path);
1105 msi_free(full_path);
1106 return ERROR_SUCCESS;
1109 /* FIXME: probably should merge this with the above function */
1110 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1112 UINT rc = ERROR_SUCCESS;
1114 LPWSTR install_path;
1116 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
1118 return ERROR_FUNCTION_FAILED;
1120 /* create the path */
1121 if (folder->State == 0)
1123 create_full_pathW(install_path);
1126 msi_free(install_path);
1131 UINT msi_create_component_directories( MSIPACKAGE *package )
1135 /* create all the folders required by the components are going to install */
1136 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1138 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1140 msi_create_directory( package, comp->Directory );
1143 return ERROR_SUCCESS;
1147 * Also we cannot enable/disable components either, so for now I am just going
1148 * to do all the directories for all the components.
1150 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1152 static const WCHAR ExecSeqQuery[] =
1153 {'S','E','L','E','C','T',' ',
1154 '`','D','i','r','e','c','t','o','r','y','_','`',
1155 ' ','F','R','O','M',' ',
1156 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1160 /* create all the empty folders specified in the CreateFolder table */
1161 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1162 if (rc != ERROR_SUCCESS)
1163 return ERROR_SUCCESS;
1165 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1166 msiobj_release(&view->hdr);
1168 msi_create_component_directories( package );
1173 static UINT load_component( MSIRECORD *row, LPVOID param )
1175 MSIPACKAGE *package = param;
1178 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1180 return ERROR_FUNCTION_FAILED;
1182 list_add_tail( &package->components, &comp->entry );
1184 /* fill in the data */
1185 comp->Component = msi_dup_record_field( row, 1 );
1187 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1189 comp->ComponentId = msi_dup_record_field( row, 2 );
1190 comp->Directory = msi_dup_record_field( row, 3 );
1191 comp->Attributes = MSI_RecordGetInteger(row,4);
1192 comp->Condition = msi_dup_record_field( row, 5 );
1193 comp->KeyPath = msi_dup_record_field( row, 6 );
1195 comp->Installed = INSTALLSTATE_UNKNOWN;
1196 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
1198 return ERROR_SUCCESS;
1201 static UINT load_all_components( MSIPACKAGE *package )
1203 static const WCHAR query[] = {
1204 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1205 '`','C','o','m','p','o','n','e','n','t','`',0 };
1209 if (!list_empty(&package->components))
1210 return ERROR_SUCCESS;
1212 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1213 if (r != ERROR_SUCCESS)
1216 r = MSI_IterateRecords(view, NULL, load_component, package);
1217 msiobj_release(&view->hdr);
1222 MSIPACKAGE *package;
1223 MSIFEATURE *feature;
1226 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1230 cl = msi_alloc( sizeof (*cl) );
1232 return ERROR_NOT_ENOUGH_MEMORY;
1233 cl->component = comp;
1234 list_add_tail( &feature->Components, &cl->entry );
1236 return ERROR_SUCCESS;
1239 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1243 fl = msi_alloc( sizeof(*fl) );
1245 return ERROR_NOT_ENOUGH_MEMORY;
1246 fl->feature = child;
1247 list_add_tail( &parent->Children, &fl->entry );
1249 return ERROR_SUCCESS;
1252 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1254 _ilfs* ilfs= (_ilfs*)param;
1258 component = MSI_RecordGetString(row,1);
1260 /* check to see if the component is already loaded */
1261 comp = get_loaded_component( ilfs->package, component );
1264 ERR("unknown component %s\n", debugstr_w(component));
1265 return ERROR_FUNCTION_FAILED;
1268 add_feature_component( ilfs->feature, comp );
1269 comp->Enabled = TRUE;
1271 return ERROR_SUCCESS;
1274 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1276 MSIFEATURE *feature;
1281 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1283 if ( !lstrcmpW( feature->Feature, name ) )
1290 static UINT load_feature(MSIRECORD * row, LPVOID param)
1292 MSIPACKAGE* package = (MSIPACKAGE*)param;
1293 MSIFEATURE* feature;
1294 static const WCHAR Query1[] =
1295 {'S','E','L','E','C','T',' ',
1296 '`','C','o','m','p','o','n','e','n','t','_','`',
1297 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1298 'C','o','m','p','o','n','e','n','t','s','`',' ',
1299 'W','H','E','R','E',' ',
1300 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1305 /* fill in the data */
1307 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1309 return ERROR_NOT_ENOUGH_MEMORY;
1311 list_init( &feature->Children );
1312 list_init( &feature->Components );
1314 feature->Feature = msi_dup_record_field( row, 1 );
1316 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1318 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1319 feature->Title = msi_dup_record_field( row, 3 );
1320 feature->Description = msi_dup_record_field( row, 4 );
1322 if (!MSI_RecordIsNull(row,5))
1323 feature->Display = MSI_RecordGetInteger(row,5);
1325 feature->Level= MSI_RecordGetInteger(row,6);
1326 feature->Directory = msi_dup_record_field( row, 7 );
1327 feature->Attributes = MSI_RecordGetInteger(row,8);
1329 feature->Installed = INSTALLSTATE_UNKNOWN;
1330 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
1332 list_add_tail( &package->features, &feature->entry );
1334 /* load feature components */
1336 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1337 if (rc != ERROR_SUCCESS)
1338 return ERROR_SUCCESS;
1340 ilfs.package = package;
1341 ilfs.feature = feature;
1343 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1344 msiobj_release(&view->hdr);
1346 return ERROR_SUCCESS;
1349 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1351 MSIPACKAGE* package = (MSIPACKAGE*)param;
1352 MSIFEATURE *parent, *child;
1354 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1356 return ERROR_FUNCTION_FAILED;
1358 if (!child->Feature_Parent)
1359 return ERROR_SUCCESS;
1361 parent = find_feature_by_name( package, child->Feature_Parent );
1363 return ERROR_FUNCTION_FAILED;
1365 add_feature_child( parent, child );
1366 return ERROR_SUCCESS;
1369 static UINT load_all_features( MSIPACKAGE *package )
1371 static const WCHAR query[] = {
1372 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1373 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1374 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1378 if (!list_empty(&package->features))
1379 return ERROR_SUCCESS;
1381 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1382 if (r != ERROR_SUCCESS)
1385 r = MSI_IterateRecords( view, NULL, load_feature, package );
1386 if (r != ERROR_SUCCESS)
1389 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1390 msiobj_release( &view->hdr );
1395 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1406 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1408 static const WCHAR query[] = {
1409 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1410 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1411 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1412 MSIQUERY *view = NULL;
1413 MSIRECORD *row = NULL;
1416 TRACE("%s\n", debugstr_w(file->File));
1418 r = MSI_OpenQuery(package->db, &view, query, file->File);
1419 if (r != ERROR_SUCCESS)
1422 r = MSI_ViewExecute(view, NULL);
1423 if (r != ERROR_SUCCESS)
1426 r = MSI_ViewFetch(view, &row);
1427 if (r != ERROR_SUCCESS)
1430 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1431 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1432 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1433 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1434 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1437 if (view) msiobj_release(&view->hdr);
1438 if (row) msiobj_release(&row->hdr);
1442 static UINT load_file(MSIRECORD *row, LPVOID param)
1444 MSIPACKAGE* package = (MSIPACKAGE*)param;
1448 /* fill in the data */
1450 file = msi_alloc_zero( sizeof (MSIFILE) );
1452 return ERROR_NOT_ENOUGH_MEMORY;
1454 file->File = msi_dup_record_field( row, 1 );
1456 component = MSI_RecordGetString( row, 2 );
1457 file->Component = get_loaded_component( package, component );
1459 if (!file->Component)
1460 ERR("Unfound Component %s\n",debugstr_w(component));
1462 file->FileName = msi_dup_record_field( row, 3 );
1463 reduce_to_longfilename( file->FileName );
1465 file->ShortName = msi_dup_record_field( row, 3 );
1466 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1468 file->FileSize = MSI_RecordGetInteger( row, 4 );
1469 file->Version = msi_dup_record_field( row, 5 );
1470 file->Language = msi_dup_record_field( row, 6 );
1471 file->Attributes = MSI_RecordGetInteger( row, 7 );
1472 file->Sequence = MSI_RecordGetInteger( row, 8 );
1474 file->state = msifs_invalid;
1476 /* if the compressed bits are not set in the file attributes,
1477 * then read the information from the package word count property
1479 if (file->Attributes & msidbFileAttributesCompressed)
1481 file->IsCompressed = TRUE;
1483 else if (file->Attributes & msidbFileAttributesNoncompressed)
1485 file->IsCompressed = FALSE;
1489 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1492 if (!file->IsCompressed)
1496 p = resolve_folder(package, file->Component->Directory,
1497 TRUE, FALSE, TRUE, NULL);
1498 path = build_directory_name(2, p, file->ShortName);
1500 if (file->LongName &&
1501 GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES)
1504 path = build_directory_name(2, p, file->LongName);
1507 file->SourcePath = path;
1511 load_file_hash(package, file);
1513 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1515 list_add_tail( &package->files, &file->entry );
1517 return ERROR_SUCCESS;
1520 static UINT load_all_files(MSIPACKAGE *package)
1524 static const WCHAR Query[] =
1525 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1526 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1527 '`','S','e','q','u','e','n','c','e','`', 0};
1529 if (!list_empty(&package->files))
1530 return ERROR_SUCCESS;
1532 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1533 if (rc != ERROR_SUCCESS)
1534 return ERROR_SUCCESS;
1536 rc = MSI_IterateRecords(view, NULL, load_file, package);
1537 msiobj_release(&view->hdr);
1539 return ERROR_SUCCESS;
1542 static UINT load_folder( MSIRECORD *row, LPVOID param )
1544 MSIPACKAGE *package = param;
1545 static const WCHAR szDot[] = { '.',0 };
1546 static WCHAR szEmpty[] = { 0 };
1547 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1550 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1552 return ERROR_NOT_ENOUGH_MEMORY;
1554 folder->Directory = msi_dup_record_field( row, 1 );
1556 TRACE("%s\n", debugstr_w(folder->Directory));
1558 p = msi_dup_record_field(row, 3);
1560 /* split src and target dir */
1562 src_short = folder_split_path( p, ':' );
1564 /* split the long and short paths */
1565 tgt_long = folder_split_path( tgt_short, '|' );
1566 src_long = folder_split_path( src_short, '|' );
1568 /* check for no-op dirs */
1569 if (!lstrcmpW(szDot, tgt_short))
1570 tgt_short = szEmpty;
1571 if (!lstrcmpW(szDot, src_short))
1572 src_short = szEmpty;
1575 tgt_long = tgt_short;
1578 src_short = tgt_short;
1579 src_long = tgt_long;
1583 src_long = src_short;
1585 /* FIXME: use the target short path too */
1586 folder->TargetDefault = strdupW(tgt_long);
1587 folder->SourceShortPath = strdupW(src_short);
1588 folder->SourceLongPath = strdupW(src_long);
1591 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1592 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1593 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1595 folder->Parent = msi_dup_record_field( row, 2 );
1597 folder->Property = msi_dup_property( package, folder->Directory );
1599 list_add_tail( &package->folders, &folder->entry );
1601 TRACE("returning %p\n", folder);
1603 return ERROR_SUCCESS;
1606 static UINT load_all_folders( MSIPACKAGE *package )
1608 static const WCHAR query[] = {
1609 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1610 '`','D','i','r','e','c','t','o','r','y','`',0 };
1614 if (!list_empty(&package->folders))
1615 return ERROR_SUCCESS;
1617 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1618 if (r != ERROR_SUCCESS)
1621 r = MSI_IterateRecords(view, NULL, load_folder, package);
1622 msiobj_release(&view->hdr);
1627 * I am not doing any of the costing functionality yet.
1628 * Mostly looking at doing the Component and Feature loading
1630 * The native MSI does A LOT of modification to tables here. Mostly adding
1631 * a lot of temporary columns to the Feature and Component tables.
1633 * note: Native msi also tracks the short filename. But I am only going to
1634 * track the long ones. Also looking at this directory table
1635 * it appears that the directory table does not get the parents
1636 * resolved base on property only based on their entries in the
1639 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1641 static const WCHAR szCosting[] =
1642 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1643 static const WCHAR szZero[] = { '0', 0 };
1645 MSI_SetPropertyW(package, szCosting, szZero);
1646 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1648 load_all_folders( package );
1649 load_all_components( package );
1650 load_all_features( package );
1651 load_all_files( package );
1653 return ERROR_SUCCESS;
1656 static UINT execute_script(MSIPACKAGE *package, UINT script )
1659 UINT rc = ERROR_SUCCESS;
1661 TRACE("Executing Script %i\n",script);
1663 if (!package->script)
1665 ERR("no script!\n");
1666 return ERROR_FUNCTION_FAILED;
1669 for (i = 0; i < package->script->ActionCount[script]; i++)
1672 action = package->script->Actions[script][i];
1673 ui_actionstart(package, action);
1674 TRACE("Executing Action (%s)\n",debugstr_w(action));
1675 rc = ACTION_PerformAction(package, action, script, TRUE);
1676 if (rc != ERROR_SUCCESS)
1679 msi_free_action_script(package, script);
1683 static UINT ACTION_FileCost(MSIPACKAGE *package)
1685 return ERROR_SUCCESS;
1688 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1692 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1696 if (!comp->ComponentId)
1699 res = MsiGetComponentPathW( package->ProductCode,
1700 comp->ComponentId, NULL, NULL);
1702 res = INSTALLSTATE_ABSENT;
1703 comp->Installed = res;
1707 /* scan for and update current install states */
1708 static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1711 MSIFEATURE *feature;
1713 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1716 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1718 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1720 comp= cl->component;
1722 if (!comp->ComponentId)
1724 res = INSTALLSTATE_ABSENT;
1728 if (res == INSTALLSTATE_ABSENT)
1729 res = comp->Installed;
1732 if (res == comp->Installed)
1735 if (res != INSTALLSTATE_DEFAULT && res != INSTALLSTATE_LOCAL &&
1736 res != INSTALLSTATE_SOURCE)
1738 res = INSTALLSTATE_INCOMPLETE;
1742 feature->Installed = res;
1746 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1749 static const WCHAR all[]={'A','L','L',0};
1751 MSIFEATURE *feature;
1753 override = msi_dup_property( package, property );
1757 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1759 if (strcmpiW(override,all)==0)
1760 msi_feature_set_state( feature, state );
1763 LPWSTR ptr = override;
1764 LPWSTR ptr2 = strchrW(override,',');
1768 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1769 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1771 msi_feature_set_state( feature, state );
1777 ptr2 = strchrW(ptr,',');
1789 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1792 static const WCHAR szlevel[] =
1793 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1794 static const WCHAR szAddLocal[] =
1795 {'A','D','D','L','O','C','A','L',0};
1796 static const WCHAR szAddSource[] =
1797 {'A','D','D','S','O','U','R','C','E',0};
1798 static const WCHAR szRemove[] =
1799 {'R','E','M','O','V','E',0};
1800 static const WCHAR szReinstall[] =
1801 {'R','E','I','N','S','T','A','L','L',0};
1802 BOOL override = FALSE;
1803 MSICOMPONENT* component;
1804 MSIFEATURE *feature;
1807 /* I do not know if this is where it should happen.. but */
1809 TRACE("Checking Install Level\n");
1811 install_level = msi_get_property_int( package, szlevel, 1 );
1813 /* ok here is the _real_ rub
1814 * all these activation/deactivation things happen in order and things
1815 * later on the list override things earlier on the list.
1816 * 1) INSTALLLEVEL processing
1826 * 11) FILEADDDEFAULT
1828 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1829 * REMOVE are the big ones, since we don't handle administrative installs
1832 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1833 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1834 override |= process_state_property(package,szAddSource,INSTALLSTATE_SOURCE);
1835 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1839 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1841 BOOL feature_state = ((feature->Level > 0) &&
1842 (feature->Level <= install_level));
1844 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1846 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1847 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
1848 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1849 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
1851 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1855 /* disable child features of unselected parent features */
1856 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1860 if (feature->Level > 0 && feature->Level <= install_level)
1863 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1864 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
1869 /* set the Preselected Property */
1870 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1871 static const WCHAR szOne[] = { '1', 0 };
1873 MSI_SetPropertyW(package,szPreselected,szOne);
1877 * now we want to enable or disable components base on feature
1880 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1884 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1885 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1887 if (!feature->Level)
1890 /* features with components that have compressed files are made local */
1891 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1893 if (cl->component->Enabled &&
1894 cl->component->ForceLocalState &&
1895 feature->Action == INSTALLSTATE_SOURCE)
1897 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1902 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1904 component = cl->component;
1906 if (!component->Enabled)
1909 switch (feature->Action)
1911 case INSTALLSTATE_ABSENT:
1912 component->anyAbsent = 1;
1914 case INSTALLSTATE_ADVERTISED:
1915 component->hasAdvertiseFeature = 1;
1917 case INSTALLSTATE_SOURCE:
1918 component->hasSourceFeature = 1;
1920 case INSTALLSTATE_LOCAL:
1921 component->hasLocalFeature = 1;
1923 case INSTALLSTATE_DEFAULT:
1924 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1925 component->hasAdvertiseFeature = 1;
1926 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1927 component->hasSourceFeature = 1;
1929 component->hasLocalFeature = 1;
1937 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1939 /* if the component isn't enabled, leave it alone */
1940 if (!component->Enabled)
1943 /* check if it's local or source */
1944 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1945 (component->hasLocalFeature || component->hasSourceFeature))
1947 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1948 !component->ForceLocalState)
1949 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1951 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1955 /* if any feature is local, the component must be local too */
1956 if (component->hasLocalFeature)
1958 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1962 if (component->hasSourceFeature)
1964 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1968 if (component->hasAdvertiseFeature)
1970 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1974 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1975 if (component->anyAbsent)
1976 msi_component_set_state(component, INSTALLSTATE_ABSENT);
1979 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1981 if (component->Action == INSTALLSTATE_DEFAULT)
1983 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1984 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1987 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1988 debugstr_w(component->Component), component->Installed, component->Action);
1992 return ERROR_SUCCESS;
1995 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1997 MSIPACKAGE *package = (MSIPACKAGE*)param;
2002 name = MSI_RecordGetString(row,1);
2004 f = get_loaded_folder(package, name);
2005 if (!f) return ERROR_SUCCESS;
2007 /* reset the ResolvedTarget */
2008 msi_free(f->ResolvedTarget);
2009 f->ResolvedTarget = NULL;
2011 /* This helper function now does ALL the work */
2012 TRACE("Dir %s ...\n",debugstr_w(name));
2013 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
2014 TRACE("resolves to %s\n",debugstr_w(path));
2017 return ERROR_SUCCESS;
2020 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2022 MSIPACKAGE *package = (MSIPACKAGE*)param;
2024 MSIFEATURE *feature;
2026 name = MSI_RecordGetString( row, 1 );
2028 feature = get_loaded_feature( package, name );
2030 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2034 Condition = MSI_RecordGetString(row,3);
2036 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2038 int level = MSI_RecordGetInteger(row,2);
2039 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2040 feature->Level = level;
2043 return ERROR_SUCCESS;
2046 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
2048 static const WCHAR name_fmt[] =
2049 {'%','u','.','%','u','.','%','u','.','%','u',0};
2050 static const WCHAR name[] = {'\\',0};
2051 VS_FIXEDFILEINFO *lpVer;
2052 WCHAR filever[0x100];
2058 TRACE("%s\n", debugstr_w(filename));
2060 versize = GetFileVersionInfoSizeW( filename, &handle );
2064 version = msi_alloc( versize );
2065 GetFileVersionInfoW( filename, 0, versize, version );
2067 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
2069 msi_free( version );
2073 sprintfW( filever, name_fmt,
2074 HIWORD(lpVer->dwFileVersionMS),
2075 LOWORD(lpVer->dwFileVersionMS),
2076 HIWORD(lpVer->dwFileVersionLS),
2077 LOWORD(lpVer->dwFileVersionLS));
2079 msi_free( version );
2081 return strdupW( filever );
2084 static UINT msi_check_file_install_states( MSIPACKAGE *package )
2086 LPWSTR file_version;
2089 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2091 MSICOMPONENT* comp = file->Component;
2097 if (file->IsCompressed)
2098 comp->ForceLocalState = TRUE;
2100 /* calculate target */
2101 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2103 msi_free(file->TargetPath);
2105 TRACE("file %s is named %s\n",
2106 debugstr_w(file->File), debugstr_w(file->FileName));
2108 file->TargetPath = build_directory_name(2, p, file->FileName);
2112 TRACE("file %s resolves to %s\n",
2113 debugstr_w(file->File), debugstr_w(file->TargetPath));
2115 /* don't check files of components that aren't installed */
2116 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2117 comp->Installed == INSTALLSTATE_ABSENT)
2119 file->state = msifs_missing; /* assume files are missing */
2123 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2125 file->state = msifs_missing;
2126 comp->Cost += file->FileSize;
2127 comp->Installed = INSTALLSTATE_INCOMPLETE;
2131 if (file->Version &&
2132 (file_version = msi_get_disk_file_version( file->TargetPath )))
2134 TRACE("new %s old %s\n", debugstr_w(file->Version),
2135 debugstr_w(file_version));
2136 /* FIXME: seems like a bad way to compare version numbers */
2137 if (lstrcmpiW(file_version, file->Version)<0)
2139 file->state = msifs_overwrite;
2140 comp->Cost += file->FileSize;
2141 comp->Installed = INSTALLSTATE_INCOMPLETE;
2144 file->state = msifs_present;
2145 msi_free( file_version );
2148 file->state = msifs_present;
2151 return ERROR_SUCCESS;
2155 * A lot is done in this function aside from just the costing.
2156 * The costing needs to be implemented at some point but for now I am going
2157 * to focus on the directory building
2160 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2162 static const WCHAR ExecSeqQuery[] =
2163 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2164 '`','D','i','r','e','c','t','o','r','y','`',0};
2165 static const WCHAR ConditionQuery[] =
2166 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2167 '`','C','o','n','d','i','t','i','o','n','`',0};
2168 static const WCHAR szCosting[] =
2169 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2170 static const WCHAR szlevel[] =
2171 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2172 static const WCHAR szOutOfDiskSpace[] =
2173 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2174 static const WCHAR szOne[] = { '1', 0 };
2175 static const WCHAR szZero[] = { '0', 0 };
2181 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2182 return ERROR_SUCCESS;
2184 TRACE("Building Directory properties\n");
2186 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2187 if (rc == ERROR_SUCCESS)
2189 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2191 msiobj_release(&view->hdr);
2194 /* read components states from the registry */
2195 ACTION_GetComponentInstallStates(package);
2197 TRACE("File calculations\n");
2198 msi_check_file_install_states( package );
2200 TRACE("Evaluating Condition Table\n");
2202 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2203 if (rc == ERROR_SUCCESS)
2205 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2207 msiobj_release(&view->hdr);
2210 TRACE("Enabling or Disabling Components\n");
2211 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2213 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2215 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2216 comp->Enabled = FALSE;
2220 MSI_SetPropertyW(package,szCosting,szOne);
2221 /* set default run level if not set */
2222 level = msi_dup_property( package, szlevel );
2224 MSI_SetPropertyW(package,szlevel, szOne);
2227 /* FIXME: check volume disk space */
2228 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2230 ACTION_UpdateFeatureInstallStates(package);
2232 return MSI_SetFeatureStates(package);
2235 /* OK this value is "interpreted" and then formatted based on the
2236 first few characters */
2237 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2242 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2248 LPWSTR deformated = NULL;
2251 deformat_string(package, &value[2], &deformated);
2253 /* binary value type */
2257 *size = (strlenW(ptr)/2)+1;
2259 *size = strlenW(ptr)/2;
2261 data = msi_alloc(*size);
2267 /* if uneven pad with a zero in front */
2273 data[count] = (BYTE)strtol(byte,NULL,0);
2275 TRACE("Uneven byte count\n");
2283 data[count] = (BYTE)strtol(byte,NULL,0);
2286 msi_free(deformated);
2288 TRACE("Data %i bytes(%i)\n",*size,count);
2295 deformat_string(package, &value[1], &deformated);
2298 *size = sizeof(DWORD);
2299 data = msi_alloc(*size);
2305 if ( (*p < '0') || (*p > '9') )
2311 if (deformated[0] == '-')
2314 TRACE("DWORD %i\n",*(LPDWORD)data);
2316 msi_free(deformated);
2321 static const WCHAR szMulti[] = {'[','~',']',0};
2330 *type=REG_EXPAND_SZ;
2338 if (strstrW(value,szMulti))
2339 *type = REG_MULTI_SZ;
2341 /* remove initial delimiter */
2342 if (!strncmpW(value, szMulti, 3))
2345 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2347 /* add double NULL terminator */
2348 if (*type == REG_MULTI_SZ)
2350 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2351 data = msi_realloc_zero(data, *size);
2357 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2359 MSIPACKAGE *package = (MSIPACKAGE*)param;
2360 static const WCHAR szHCR[] =
2361 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2362 'R','O','O','T','\\',0};
2363 static const WCHAR szHCU[] =
2364 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2365 'U','S','E','R','\\',0};
2366 static const WCHAR szHLM[] =
2367 {'H','K','E','Y','_','L','O','C','A','L','_',
2368 'M','A','C','H','I','N','E','\\',0};
2369 static const WCHAR szHU[] =
2370 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2372 LPSTR value_data = NULL;
2373 HKEY root_key, hkey;
2376 LPCWSTR szRoot, component, name, key, value;
2381 BOOL check_first = FALSE;
2384 ui_progress(package,2,0,0,0);
2391 component = MSI_RecordGetString(row, 6);
2392 comp = get_loaded_component(package,component);
2394 return ERROR_SUCCESS;
2396 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2398 TRACE("Skipping write due to disabled component %s\n",
2399 debugstr_w(component));
2401 comp->Action = comp->Installed;
2403 return ERROR_SUCCESS;
2406 comp->Action = INSTALLSTATE_LOCAL;
2408 name = MSI_RecordGetString(row, 4);
2409 if( MSI_RecordIsNull(row,5) && name )
2411 /* null values can have special meanings */
2412 if (name[0]=='-' && name[1] == 0)
2413 return ERROR_SUCCESS;
2414 else if ((name[0]=='+' && name[1] == 0) ||
2415 (name[0] == '*' && name[1] == 0))
2420 root = MSI_RecordGetInteger(row,2);
2421 key = MSI_RecordGetString(row, 3);
2423 /* get the root key */
2428 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2429 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2430 if (all_users && all_users[0] == '1')
2432 root_key = HKEY_LOCAL_MACHINE;
2437 root_key = HKEY_CURRENT_USER;
2440 msi_free(all_users);
2443 case 0: root_key = HKEY_CLASSES_ROOT;
2446 case 1: root_key = HKEY_CURRENT_USER;
2449 case 2: root_key = HKEY_LOCAL_MACHINE;
2452 case 3: root_key = HKEY_USERS;
2456 ERR("Unknown root %i\n",root);
2462 return ERROR_SUCCESS;
2464 deformat_string(package, key , &deformated);
2465 size = strlenW(deformated) + strlenW(szRoot) + 1;
2466 uikey = msi_alloc(size*sizeof(WCHAR));
2467 strcpyW(uikey,szRoot);
2468 strcatW(uikey,deformated);
2470 if (RegCreateKeyW( root_key, deformated, &hkey))
2472 ERR("Could not create key %s\n",debugstr_w(deformated));
2473 msi_free(deformated);
2475 return ERROR_SUCCESS;
2477 msi_free(deformated);
2479 value = MSI_RecordGetString(row,5);
2481 value_data = parse_value(package, value, &type, &size);
2484 static const WCHAR szEmpty[] = {0};
2485 value_data = (LPSTR)strdupW(szEmpty);
2486 size = sizeof(szEmpty);
2490 deformat_string(package, name, &deformated);
2494 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2496 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2501 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2502 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2504 TRACE("value %s of %s checked already exists\n",
2505 debugstr_w(deformated), debugstr_w(uikey));
2509 TRACE("Checked and setting value %s of %s\n",
2510 debugstr_w(deformated), debugstr_w(uikey));
2511 if (deformated || size)
2512 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2517 uirow = MSI_CreateRecord(3);
2518 MSI_RecordSetStringW(uirow,2,deformated);
2519 MSI_RecordSetStringW(uirow,1,uikey);
2522 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2524 MSI_RecordSetStringW(uirow,3,value);
2526 ui_actiondata(package,szWriteRegistryValues,uirow);
2527 msiobj_release( &uirow->hdr );
2529 msi_free(value_data);
2530 msi_free(deformated);
2533 return ERROR_SUCCESS;
2536 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2540 static const WCHAR ExecSeqQuery[] =
2541 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2542 '`','R','e','g','i','s','t','r','y','`',0 };
2544 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2545 if (rc != ERROR_SUCCESS)
2546 return ERROR_SUCCESS;
2548 /* increment progress bar each time action data is sent */
2549 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2551 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2553 msiobj_release(&view->hdr);
2557 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2559 package->script->CurrentlyScripting = TRUE;
2561 return ERROR_SUCCESS;
2565 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2570 static const WCHAR q1[]=
2571 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2572 '`','R','e','g','i','s','t','r','y','`',0};
2575 MSIFEATURE *feature;
2578 TRACE("InstallValidate\n");
2580 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2581 if (rc == ERROR_SUCCESS)
2583 MSI_IterateRecords( view, &progress, NULL, package );
2584 msiobj_release( &view->hdr );
2585 total += progress * REG_PROGRESS_VALUE;
2588 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2589 total += COMPONENT_PROGRESS_VALUE;
2591 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2592 total += file->FileSize;
2594 ui_progress(package,0,total,0,0);
2596 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2598 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2599 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2600 feature->ActionRequest);
2603 return ERROR_SUCCESS;
2606 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2608 MSIPACKAGE* package = (MSIPACKAGE*)param;
2609 LPCWSTR cond = NULL;
2610 LPCWSTR message = NULL;
2613 static const WCHAR title[]=
2614 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2616 cond = MSI_RecordGetString(row,1);
2618 r = MSI_EvaluateConditionW(package,cond);
2619 if (r == MSICONDITION_FALSE)
2621 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2624 message = MSI_RecordGetString(row,2);
2625 deformat_string(package,message,&deformated);
2626 MessageBoxW(NULL,deformated,title,MB_OK);
2627 msi_free(deformated);
2630 return ERROR_INSTALL_FAILURE;
2633 return ERROR_SUCCESS;
2636 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2639 MSIQUERY * view = NULL;
2640 static const WCHAR ExecSeqQuery[] =
2641 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2642 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2644 TRACE("Checking launch conditions\n");
2646 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2647 if (rc != ERROR_SUCCESS)
2648 return ERROR_SUCCESS;
2650 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2651 msiobj_release(&view->hdr);
2656 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2660 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2662 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2664 MSIRECORD * row = 0;
2666 LPWSTR deformated,buffer,deformated_name;
2668 static const WCHAR ExecSeqQuery[] =
2669 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2670 '`','R','e','g','i','s','t','r','y','`',' ',
2671 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2672 ' ','=',' ' ,'\'','%','s','\'',0 };
2673 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2674 static const WCHAR fmt2[]=
2675 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2677 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2681 root = MSI_RecordGetInteger(row,2);
2682 key = MSI_RecordGetString(row, 3);
2683 name = MSI_RecordGetString(row, 4);
2684 deformat_string(package, key , &deformated);
2685 deformat_string(package, name, &deformated_name);
2687 len = strlenW(deformated) + 6;
2688 if (deformated_name)
2689 len+=strlenW(deformated_name);
2691 buffer = msi_alloc( len *sizeof(WCHAR));
2693 if (deformated_name)
2694 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2696 sprintfW(buffer,fmt,root,deformated);
2698 msi_free(deformated);
2699 msi_free(deformated_name);
2700 msiobj_release(&row->hdr);
2704 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2706 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2711 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2714 return strdupW( file->TargetPath );
2719 static HKEY openSharedDLLsKey(void)
2722 static const WCHAR path[] =
2723 {'S','o','f','t','w','a','r','e','\\',
2724 'M','i','c','r','o','s','o','f','t','\\',
2725 'W','i','n','d','o','w','s','\\',
2726 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2727 'S','h','a','r','e','d','D','L','L','s',0};
2729 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2733 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2738 DWORD sz = sizeof(count);
2741 hkey = openSharedDLLsKey();
2742 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2743 if (rc != ERROR_SUCCESS)
2749 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2753 hkey = openSharedDLLsKey();
2755 msi_reg_set_val_dword( hkey, path, count );
2757 RegDeleteValueW(hkey,path);
2763 * Return TRUE if the count should be written out and FALSE if not
2765 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2767 MSIFEATURE *feature;
2771 /* only refcount DLLs */
2772 if (comp->KeyPath == NULL ||
2773 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2774 comp->Attributes & msidbComponentAttributesODBCDataSource)
2778 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2779 write = (count > 0);
2781 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2785 /* increment counts */
2786 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2790 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2793 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2795 if ( cl->component == comp )
2800 /* decrement counts */
2801 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2805 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2808 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2810 if ( cl->component == comp )
2815 /* ref count all the files in the component */
2820 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2822 if (file->Component == comp)
2823 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2827 /* add a count for permanent */
2828 if (comp->Attributes & msidbComponentAttributesPermanent)
2831 comp->RefCount = count;
2834 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2838 * Ok further analysis makes me think that this work is
2839 * actually done in the PublishComponents and PublishFeatures
2840 * step, and not here. It appears like the keypath and all that is
2841 * resolved in this step, however actually written in the Publish steps.
2842 * But we will leave it here for now because it is unclear
2844 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2846 WCHAR squished_pc[GUID_SIZE];
2847 WCHAR squished_cc[GUID_SIZE];
2854 /* writes the Component values to the registry */
2856 squash_guid(package->ProductCode,squished_pc);
2857 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2859 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2863 ui_progress(package,2,0,0,0);
2864 if (!comp->ComponentId)
2867 squash_guid(comp->ComponentId,squished_cc);
2869 msi_free(comp->FullKeypath);
2870 comp->FullKeypath = resolve_keypath( package, comp );
2872 /* do the refcounting */
2873 ACTION_RefCountComponent( package, comp );
2875 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2876 debugstr_w(comp->Component),
2877 debugstr_w(squished_cc),
2878 debugstr_w(comp->FullKeypath),
2881 * Write the keypath out if the component is to be registered
2882 * and delete the key if the component is to be unregistered
2884 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2886 if (!comp->FullKeypath)
2889 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2890 rc = MSIREG_OpenLocalUserDataComponentKey(comp->ComponentId, &hkey, TRUE);
2892 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, &hkey, TRUE);
2894 if (rc != ERROR_SUCCESS)
2897 if (comp->Attributes & msidbComponentAttributesPermanent)
2899 static const WCHAR szPermKey[] =
2900 { '0','0','0','0','0','0','0','0','0','0','0','0',
2901 '0','0','0','0','0','0','0','0','0','0','0','0',
2902 '0','0','0','0','0','0','0','0',0 };
2904 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2907 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2910 else if (ACTION_VerifyComponentForAction(comp, INSTALLSTATE_ABSENT))
2912 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2913 MSIREG_DeleteLocalUserDataComponentKey(comp->ComponentId);
2915 MSIREG_DeleteUserDataComponentKey(comp->ComponentId);
2919 uirow = MSI_CreateRecord(3);
2920 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2921 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2922 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2923 ui_actiondata(package,szProcessComponents,uirow);
2924 msiobj_release( &uirow->hdr );
2927 return ERROR_SUCCESS;
2938 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2939 LPWSTR lpszName, LONG_PTR lParam)
2942 typelib_struct *tl_struct = (typelib_struct*) lParam;
2943 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2947 if (!IS_INTRESOURCE(lpszName))
2949 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2953 sz = strlenW(tl_struct->source)+4;
2954 sz *= sizeof(WCHAR);
2956 if ((INT_PTR)lpszName == 1)
2957 tl_struct->path = strdupW(tl_struct->source);
2960 tl_struct->path = msi_alloc(sz);
2961 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2964 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2965 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2966 if (!SUCCEEDED(res))
2968 msi_free(tl_struct->path);
2969 tl_struct->path = NULL;
2974 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2975 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2977 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2981 msi_free(tl_struct->path);
2982 tl_struct->path = NULL;
2984 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2985 ITypeLib_Release(tl_struct->ptLib);
2990 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2992 MSIPACKAGE* package = (MSIPACKAGE*)param;
2996 typelib_struct tl_struct;
3001 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
3003 component = MSI_RecordGetString(row,3);
3004 comp = get_loaded_component(package,component);
3006 return ERROR_SUCCESS;
3008 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3010 TRACE("Skipping typelib reg due to disabled component\n");
3012 comp->Action = comp->Installed;
3014 return ERROR_SUCCESS;
3017 comp->Action = INSTALLSTATE_LOCAL;
3019 file = get_loaded_file( package, comp->KeyPath );
3021 return ERROR_SUCCESS;
3023 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3027 guid = MSI_RecordGetString(row,1);
3028 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
3029 tl_struct.source = strdupW( file->TargetPath );
3030 tl_struct.path = NULL;
3032 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3033 (LONG_PTR)&tl_struct);
3041 helpid = MSI_RecordGetString(row,6);
3044 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3045 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3048 if (!SUCCEEDED(res))
3049 ERR("Failed to register type library %s\n",
3050 debugstr_w(tl_struct.path));
3053 ui_actiondata(package,szRegisterTypeLibraries,row);
3055 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3058 ITypeLib_Release(tl_struct.ptLib);
3059 msi_free(tl_struct.path);
3062 ERR("Failed to load type library %s\n",
3063 debugstr_w(tl_struct.source));
3065 FreeLibrary(module);
3066 msi_free(tl_struct.source);
3070 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3073 ERR("Failed to load type library: %08x\n", hr);
3074 return ERROR_FUNCTION_FAILED;
3077 ITypeLib_Release(tlib);
3080 return ERROR_SUCCESS;
3083 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3086 * OK this is a bit confusing.. I am given a _Component key and I believe
3087 * that the file that is being registered as a type library is the "key file
3088 * of that component" which I interpret to mean "The file in the KeyPath of
3093 static const WCHAR Query[] =
3094 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3095 '`','T','y','p','e','L','i','b','`',0};
3097 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3098 if (rc != ERROR_SUCCESS)
3099 return ERROR_SUCCESS;
3101 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3102 msiobj_release(&view->hdr);
3106 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3108 MSIPACKAGE *package = (MSIPACKAGE*)param;
3109 LPWSTR target_file, target_folder, filename;
3110 LPCWSTR buffer, extension;
3112 static const WCHAR szlnk[]={'.','l','n','k',0};
3113 IShellLinkW *sl = NULL;
3114 IPersistFile *pf = NULL;
3117 buffer = MSI_RecordGetString(row,4);
3118 comp = get_loaded_component(package,buffer);
3120 return ERROR_SUCCESS;
3122 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
3124 TRACE("Skipping shortcut creation due to disabled component\n");
3126 comp->Action = comp->Installed;
3128 return ERROR_SUCCESS;
3131 comp->Action = INSTALLSTATE_LOCAL;
3133 ui_actiondata(package,szCreateShortcuts,row);
3135 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3136 &IID_IShellLinkW, (LPVOID *) &sl );
3140 ERR("CLSID_ShellLink not available\n");
3144 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3147 ERR("QueryInterface(IID_IPersistFile) failed\n");
3151 buffer = MSI_RecordGetString(row,2);
3152 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
3154 /* may be needed because of a bug somewhere else */
3155 create_full_pathW(target_folder);
3157 filename = msi_dup_record_field( row, 3 );
3158 reduce_to_longfilename(filename);
3160 extension = strchrW(filename,'.');
3161 if (!extension || strcmpiW(extension,szlnk))
3163 int len = strlenW(filename);
3164 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3165 memcpy(filename + len, szlnk, sizeof(szlnk));
3167 target_file = build_directory_name(2, target_folder, filename);
3168 msi_free(target_folder);
3171 buffer = MSI_RecordGetString(row,5);
3172 if (strchrW(buffer,'['))
3175 deformat_string(package,buffer,&deformated);
3176 IShellLinkW_SetPath(sl,deformated);
3177 msi_free(deformated);
3181 FIXME("poorly handled shortcut format, advertised shortcut\n");
3182 IShellLinkW_SetPath(sl,comp->FullKeypath);
3185 if (!MSI_RecordIsNull(row,6))
3188 buffer = MSI_RecordGetString(row,6);
3189 deformat_string(package,buffer,&deformated);
3190 IShellLinkW_SetArguments(sl,deformated);
3191 msi_free(deformated);
3194 if (!MSI_RecordIsNull(row,7))
3196 buffer = MSI_RecordGetString(row,7);
3197 IShellLinkW_SetDescription(sl,buffer);
3200 if (!MSI_RecordIsNull(row,8))
3201 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3203 if (!MSI_RecordIsNull(row,9))
3208 buffer = MSI_RecordGetString(row,9);
3210 Path = build_icon_path(package,buffer);
3211 index = MSI_RecordGetInteger(row,10);
3213 /* no value means 0 */
3214 if (index == MSI_NULL_INTEGER)
3217 IShellLinkW_SetIconLocation(sl,Path,index);
3221 if (!MSI_RecordIsNull(row,11))
3222 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3224 if (!MSI_RecordIsNull(row,12))
3227 buffer = MSI_RecordGetString(row,12);
3228 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3230 IShellLinkW_SetWorkingDirectory(sl,Path);
3234 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3235 IPersistFile_Save(pf,target_file,FALSE);
3237 msi_free(target_file);
3241 IPersistFile_Release( pf );
3243 IShellLinkW_Release( sl );
3245 return ERROR_SUCCESS;
3248 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3253 static const WCHAR Query[] =
3254 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3255 '`','S','h','o','r','t','c','u','t','`',0};
3257 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3258 if (rc != ERROR_SUCCESS)
3259 return ERROR_SUCCESS;
3261 res = CoInitialize( NULL );
3264 ERR("CoInitialize failed\n");
3265 return ERROR_FUNCTION_FAILED;
3268 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3269 msiobj_release(&view->hdr);
3276 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3278 MSIPACKAGE* package = (MSIPACKAGE*)param;
3287 FileName = MSI_RecordGetString(row,1);
3290 ERR("Unable to get FileName\n");
3291 return ERROR_SUCCESS;
3294 FilePath = build_icon_path(package,FileName);
3296 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3298 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3299 FILE_ATTRIBUTE_NORMAL, NULL);
3301 if (the_file == INVALID_HANDLE_VALUE)
3303 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3305 return ERROR_SUCCESS;
3312 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3313 if (rc != ERROR_SUCCESS)
3315 ERR("Failed to get stream\n");
3316 CloseHandle(the_file);
3317 DeleteFileW(FilePath);
3320 WriteFile(the_file,buffer,sz,&write,NULL);
3321 } while (sz == 1024);
3325 CloseHandle(the_file);
3327 uirow = MSI_CreateRecord(1);
3328 MSI_RecordSetStringW(uirow,1,FileName);
3329 ui_actiondata(package,szPublishProduct,uirow);
3330 msiobj_release( &uirow->hdr );
3332 return ERROR_SUCCESS;
3335 static UINT msi_publish_icons(MSIPACKAGE *package)
3340 static const WCHAR query[]= {
3341 'S','E','L','E','C','T',' ','*',' ',
3342 'F','R','O','M',' ','`','I','c','o','n','`',0};
3344 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3345 if (r == ERROR_SUCCESS)
3347 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3348 msiobj_release(&view->hdr);
3351 return ERROR_SUCCESS;
3354 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3360 MSISOURCELISTINFO *info;
3362 static const WCHAR szEmpty[] = {0};
3363 static const WCHAR szSourceList[] = {'S','o','u','r','c','e','L','i','s','t',0};
3365 r = RegCreateKeyW(hkey, szSourceList, &source);
3366 if (r != ERROR_SUCCESS)
3369 RegCloseKey(source);
3371 buffer = strrchrW(package->PackagePath, '\\') + 1;
3372 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3373 package->Context, MSICODE_PRODUCT,
3374 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3375 if (r != ERROR_SUCCESS)
3378 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3379 package->Context, MSICODE_PRODUCT,
3380 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3381 if (r != ERROR_SUCCESS)
3384 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3385 package->Context, MSICODE_PRODUCT,
3386 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3387 if (r != ERROR_SUCCESS)
3390 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3392 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3393 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3394 info->options, info->value);
3396 MsiSourceListSetInfoW(package->ProductCode, NULL,
3397 info->context, info->options,
3398 info->property, info->value);
3401 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3403 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3404 disk->context, disk->options,
3405 disk->disk_id, disk->volume_label, disk->disk_prompt);
3408 return ERROR_SUCCESS;
3411 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3413 MSIHANDLE hdb, suminfo;
3414 WCHAR guids[MAX_PATH];
3415 WCHAR packcode[SQUISH_GUID_SIZE];
3422 static const WCHAR szProductLanguage[] =
3423 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3424 static const WCHAR szARPProductIcon[] =
3425 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3426 static const WCHAR szProductVersion[] =
3427 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3428 static const WCHAR szAssignment[] =
3429 {'A','s','s','i','g','n','m','e','n','t',0};
3430 static const WCHAR szAdvertiseFlags[] =
3431 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3432 static const WCHAR szClients[] =
3433 {'C','l','i','e','n','t','s',0};
3434 static const WCHAR szColon[] = {':',0};
3436 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3437 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3440 langid = msi_get_property_int(package, szProductLanguage, 0);
3441 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3443 ptr = strrchrW(package->PackagePath, '\\' ) + 1;
3444 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGENAMEW, ptr);
3447 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3449 buffer = msi_dup_property(package, szARPProductIcon);
3452 LPWSTR path = build_icon_path(package,buffer);
3453 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3458 buffer = msi_dup_property(package, szProductVersion);
3461 DWORD verdword = msi_version_str_to_dword(buffer);
3462 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3466 msi_reg_set_val_dword(hkey, szAssignment, 0);
3467 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3468 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3469 msi_reg_set_val_str(hkey, szClients, szColon);
3471 hdb = alloc_msihandle(&package->db->hdr);
3473 return ERROR_NOT_ENOUGH_MEMORY;
3475 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3476 MsiCloseHandle(hdb);
3477 if (r != ERROR_SUCCESS)
3481 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3482 NULL, guids, &size);
3483 if (r != ERROR_SUCCESS)
3486 ptr = strchrW(guids, ';');
3488 squash_guid(guids, packcode);
3489 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3492 MsiCloseHandle(suminfo);
3493 return ERROR_SUCCESS;
3496 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3501 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3503 static const WCHAR szUpgradeCode[] =
3504 {'U','p','g','r','a','d','e','C','o','d','e',0};
3506 upgrade = msi_dup_property(package, szUpgradeCode);
3508 return ERROR_SUCCESS;
3510 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3512 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3513 if (r != ERROR_SUCCESS)
3518 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3519 if (r != ERROR_SUCCESS)
3523 squash_guid(package->ProductCode, squashed_pc);
3524 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3533 static BOOL msi_check_publish(MSIPACKAGE *package)
3535 MSIFEATURE *feature;
3537 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3539 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3546 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3548 MSIFEATURE *feature;
3550 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3552 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3560 * 99% of the work done here is only done for
3561 * advertised installs. However this is where the
3562 * Icon table is processed and written out
3563 * so that is what I am going to do here.
3565 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3571 /* FIXME: also need to publish if the product is in advertise mode */
3572 if (!msi_check_publish(package))
3573 return ERROR_SUCCESS;
3575 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3577 rc = MSIREG_OpenLocalClassesProductKey(package->ProductCode, &hukey, TRUE);
3578 if (rc != ERROR_SUCCESS)
3581 rc = MSIREG_OpenLocalUserDataProductKey(package->ProductCode, &hudkey, TRUE);
3582 if (rc != ERROR_SUCCESS)
3587 rc = MSIREG_OpenUserProductsKey(package->ProductCode, &hukey, TRUE);
3588 if (rc != ERROR_SUCCESS)
3591 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, &hudkey, TRUE);
3592 if (rc != ERROR_SUCCESS)
3596 rc = msi_publish_upgrade_code(package);
3597 if (rc != ERROR_SUCCESS)
3600 rc = msi_publish_product_properties(package, hukey);
3601 if (rc != ERROR_SUCCESS)
3604 rc = msi_publish_sourcelist(package, hukey);
3605 if (rc != ERROR_SUCCESS)
3608 rc = msi_publish_icons(package);
3612 RegCloseKey(hudkey);
3617 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3619 MSIPACKAGE *package = (MSIPACKAGE*)param;
3620 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3621 LPWSTR deformated_section, deformated_key, deformated_value;
3622 LPWSTR folder, fullname = NULL;
3626 static const WCHAR szWindowsFolder[] =
3627 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3629 component = MSI_RecordGetString(row, 8);
3630 comp = get_loaded_component(package,component);
3632 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3634 TRACE("Skipping ini file due to disabled component %s\n",
3635 debugstr_w(component));
3637 comp->Action = comp->Installed;
3639 return ERROR_SUCCESS;
3642 comp->Action = INSTALLSTATE_LOCAL;
3644 identifier = MSI_RecordGetString(row,1);
3645 filename = MSI_RecordGetString(row,2);
3646 dirproperty = MSI_RecordGetString(row,3);
3647 section = MSI_RecordGetString(row,4);
3648 key = MSI_RecordGetString(row,5);
3649 value = MSI_RecordGetString(row,6);
3650 action = MSI_RecordGetInteger(row,7);
3652 deformat_string(package,section,&deformated_section);
3653 deformat_string(package,key,&deformated_key);
3654 deformat_string(package,value,&deformated_value);
3658 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3660 folder = msi_dup_property( package, dirproperty );
3663 folder = msi_dup_property( package, szWindowsFolder );
3667 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3671 fullname = build_directory_name(2, folder, filename);
3675 TRACE("Adding value %s to section %s in %s\n",
3676 debugstr_w(deformated_key), debugstr_w(deformated_section),
3677 debugstr_w(fullname));
3678 WritePrivateProfileStringW(deformated_section, deformated_key,
3679 deformated_value, fullname);
3681 else if (action == 1)
3684 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3685 returned, 10, fullname);
3686 if (returned[0] == 0)
3688 TRACE("Adding value %s to section %s in %s\n",
3689 debugstr_w(deformated_key), debugstr_w(deformated_section),
3690 debugstr_w(fullname));
3692 WritePrivateProfileStringW(deformated_section, deformated_key,
3693 deformated_value, fullname);
3696 else if (action == 3)
3697 FIXME("Append to existing section not yet implemented\n");
3699 uirow = MSI_CreateRecord(4);
3700 MSI_RecordSetStringW(uirow,1,identifier);
3701 MSI_RecordSetStringW(uirow,2,deformated_section);
3702 MSI_RecordSetStringW(uirow,3,deformated_key);
3703 MSI_RecordSetStringW(uirow,4,deformated_value);
3704 ui_actiondata(package,szWriteIniValues,uirow);
3705 msiobj_release( &uirow->hdr );
3709 msi_free(deformated_key);
3710 msi_free(deformated_value);
3711 msi_free(deformated_section);
3712 return ERROR_SUCCESS;
3715 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3719 static const WCHAR ExecSeqQuery[] =
3720 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3721 '`','I','n','i','F','i','l','e','`',0};
3723 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3724 if (rc != ERROR_SUCCESS)
3726 TRACE("no IniFile table\n");
3727 return ERROR_SUCCESS;
3730 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3731 msiobj_release(&view->hdr);
3735 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3737 MSIPACKAGE *package = (MSIPACKAGE*)param;
3742 static const WCHAR ExeStr[] =
3743 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3744 static const WCHAR close[] = {'\"',0};
3746 PROCESS_INFORMATION info;
3751 memset(&si,0,sizeof(STARTUPINFOW));
3753 filename = MSI_RecordGetString(row,1);
3754 file = get_loaded_file( package, filename );
3758 ERR("Unable to find file id %s\n",debugstr_w(filename));
3759 return ERROR_SUCCESS;
3762 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3764 FullName = msi_alloc(len*sizeof(WCHAR));
3765 strcpyW(FullName,ExeStr);
3766 strcatW( FullName, file->TargetPath );
3767 strcatW(FullName,close);
3769 TRACE("Registering %s\n",debugstr_w(FullName));
3770 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3774 msi_dialog_check_messages(info.hProcess);
3779 uirow = MSI_CreateRecord( 2 );
3780 uipath = strdupW( file->TargetPath );
3781 p = strrchrW(uipath,'\\');
3784 MSI_RecordSetStringW( uirow, 1, &p[1] );
3785 MSI_RecordSetStringW( uirow, 2, uipath);
3786 ui_actiondata( package, szSelfRegModules, uirow);
3787 msiobj_release( &uirow->hdr );
3789 /* FIXME: call ui_progress? */
3791 return ERROR_SUCCESS;
3794 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3798 static const WCHAR ExecSeqQuery[] =
3799 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3800 '`','S','e','l','f','R','e','g','`',0};
3802 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3803 if (rc != ERROR_SUCCESS)
3805 TRACE("no SelfReg table\n");
3806 return ERROR_SUCCESS;
3809 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3810 msiobj_release(&view->hdr);
3812 return ERROR_SUCCESS;
3815 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3817 MSIFEATURE *feature;
3822 if (!msi_check_publish(package))
3823 return ERROR_SUCCESS;
3825 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3827 rc = MSIREG_OpenLocalClassesFeaturesKey(package->ProductCode,
3829 if (rc != ERROR_SUCCESS)
3832 rc = MSIREG_OpenLocalUserDataFeaturesKey(package->ProductCode,
3834 if (rc != ERROR_SUCCESS)
3839 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode, &hkey, TRUE);
3840 if (rc != ERROR_SUCCESS)
3843 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode,
3845 if (rc != ERROR_SUCCESS)
3849 /* here the guids are base 85 encoded */
3850 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3856 BOOL absent = FALSE;
3859 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3860 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3861 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3865 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3869 if (feature->Feature_Parent)
3870 size += strlenW( feature->Feature_Parent )+2;
3872 data = msi_alloc(size * sizeof(WCHAR));
3875 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3877 MSICOMPONENT* component = cl->component;
3881 if (component->ComponentId)
3883 TRACE("From %s\n",debugstr_w(component->ComponentId));
3884 CLSIDFromString(component->ComponentId, &clsid);
3885 encode_base85_guid(&clsid,buf);
3886 TRACE("to %s\n",debugstr_w(buf));
3891 if (feature->Feature_Parent)
3893 static const WCHAR sep[] = {'\2',0};
3895 strcatW(data,feature->Feature_Parent);
3898 msi_reg_set_val_str( userdata, feature->Feature, data );
3902 if (feature->Feature_Parent)
3903 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3906 static const WCHAR emptyW[] = {0};
3907 size += sizeof(WCHAR);
3908 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3909 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : emptyW),size);
3913 size += 2*sizeof(WCHAR);
3914 data = msi_alloc(size);
3917 if (feature->Feature_Parent)
3918 strcpyW( &data[1], feature->Feature_Parent );
3919 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3925 uirow = MSI_CreateRecord( 1 );
3926 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3927 ui_actiondata( package, szPublishFeatures, uirow);
3928 msiobj_release( &uirow->hdr );
3929 /* FIXME: call ui_progress? */
3934 RegCloseKey(userdata);
3938 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
3943 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
3945 r = MSIREG_OpenUserFeaturesKey(package->ProductCode, &hkey, FALSE);
3946 if (r == ERROR_SUCCESS)
3948 RegDeleteValueW(hkey, feature->Feature);
3952 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, &hkey, FALSE);
3953 if (r == ERROR_SUCCESS)
3955 RegDeleteValueW(hkey, feature->Feature);
3959 return ERROR_SUCCESS;
3962 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
3964 MSIFEATURE *feature;
3966 if (!msi_check_unpublish(package))
3967 return ERROR_SUCCESS;
3969 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3971 msi_unpublish_feature(package, feature);
3974 return ERROR_SUCCESS;
3977 static UINT msi_get_local_package_name( LPWSTR path )
3979 static const WCHAR szInstaller[] = {
3980 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3981 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3985 time = GetTickCount();
3986 GetWindowsDirectoryW( path, MAX_PATH );
3987 lstrcatW( path, szInstaller );
3988 CreateDirectoryW( path, NULL );
3990 len = lstrlenW(path);
3991 for (i=0; i<0x10000; i++)
3993 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3994 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3995 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3996 if (handle != INVALID_HANDLE_VALUE)
3998 CloseHandle(handle);
4001 if (GetLastError() != ERROR_FILE_EXISTS &&
4002 GetLastError() != ERROR_SHARING_VIOLATION)
4003 return ERROR_FUNCTION_FAILED;
4006 return ERROR_SUCCESS;
4009 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
4011 WCHAR packagefile[MAX_PATH];
4014 r = msi_get_local_package_name( packagefile );
4015 if (r != ERROR_SUCCESS)
4018 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
4020 r = CopyFileW( package->db->path, packagefile, FALSE);
4024 ERR("Unable to copy package (%s -> %s) (error %d)\n",
4025 debugstr_w(package->db->path), debugstr_w(packagefile), GetLastError());
4026 return ERROR_FUNCTION_FAILED;
4029 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
4031 return ERROR_SUCCESS;
4034 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4036 LPWSTR prop, val, key;
4042 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4043 static const WCHAR szWindowsInstaller[] =
4044 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4045 static const WCHAR modpath_fmt[] =
4046 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4047 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4048 static const WCHAR szModifyPath[] =
4049 {'M','o','d','i','f','y','P','a','t','h',0};
4050 static const WCHAR szUninstallString[] =
4051 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4052 static const WCHAR szEstimatedSize[] =
4053 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4054 static const WCHAR szProductLanguage[] =
4055 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4056 static const WCHAR szProductVersion[] =
4057 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4058 static const WCHAR szProductName[] =
4059 {'P','r','o','d','u','c','t','N','a','m','e',0};
4060 static const WCHAR szDisplayName[] =
4061 {'D','i','s','p','l','a','y','N','a','m','e',0};
4062 static const WCHAR szDisplayVersion[] =
4063 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4064 static const WCHAR szManufacturer[] =
4065 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4067 static const LPCSTR propval[] = {
4068 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4069 "ARPCONTACT", "Contact",
4070 "ARPCOMMENTS", "Comments",
4071 "ProductName", "DisplayName",
4072 "ProductVersion", "DisplayVersion",
4073 "ARPHELPLINK", "HelpLink",
4074 "ARPHELPTELEPHONE", "HelpTelephone",
4075 "ARPINSTALLLOCATION", "InstallLocation",
4076 "SourceDir", "InstallSource",
4077 "Manufacturer", "Publisher",
4078 "ARPREADME", "Readme",
4080 "ARPURLINFOABOUT", "URLInfoAbout",
4081 "ARPURLUPDATEINFO", "URLUpdateInfo",
4084 const LPCSTR *p = propval;
4088 prop = strdupAtoW(*p++);
4089 key = strdupAtoW(*p++);
4090 val = msi_dup_property(package, prop);
4091 msi_reg_set_val_str(hkey, key, val);
4097 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4099 size = deformat_string(package, modpath_fmt, &buffer);
4100 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4101 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4104 /* FIXME: Write real Estimated Size when we have it */
4105 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4107 buffer = msi_dup_property(package, szProductName);
4108 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4111 buffer = msi_dup_property(package, cszSourceDir);
4112 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4115 buffer = msi_dup_property(package, szManufacturer);
4116 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4119 GetLocalTime(&systime);
4120 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4121 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4123 langid = msi_get_property_int(package, szProductLanguage, 0);
4124 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4126 buffer = msi_dup_property(package, szProductVersion);
4127 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4130 DWORD verdword = msi_version_str_to_dword(buffer);
4132 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4133 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4134 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4138 return ERROR_SUCCESS;
4141 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4143 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4144 LPWSTR upgrade_code;
4149 static const WCHAR szUpgradeCode[] = {
4150 'U','p','g','r','a','d','e','C','o','d','e',0};
4152 /* FIXME: also need to publish if the product is in advertise mode */
4153 if (!msi_check_publish(package))
4154 return ERROR_SUCCESS;
4156 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4157 if (rc != ERROR_SUCCESS)
4160 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4162 rc = MSIREG_OpenLocalSystemInstallProps(package->ProductCode, &props, TRUE);
4163 if (rc != ERROR_SUCCESS)
4168 rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &props, TRUE);
4169 if (rc != ERROR_SUCCESS)
4173 msi_make_package_local(package, props);
4175 rc = msi_publish_install_properties(package, hkey);
4176 if (rc != ERROR_SUCCESS)
4179 rc = msi_publish_install_properties(package, props);
4180 if (rc != ERROR_SUCCESS)
4183 upgrade_code = msi_dup_property(package, szUpgradeCode);
4186 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4187 squash_guid(package->ProductCode, squashed_pc);
4188 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4189 RegCloseKey(upgrade);
4190 msi_free(upgrade_code);
4196 return ERROR_SUCCESS;
4199 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4201 return execute_script(package,INSTALL_SCRIPT);
4204 static UINT msi_unpublish_product(MSIPACKAGE *package)
4207 LPWSTR remove = NULL;
4208 LPWSTR *features = NULL;
4209 BOOL full_uninstall = TRUE;
4210 MSIFEATURE *feature;
4212 static const WCHAR szRemove[] = {'R','E','M','O','V','E',0};
4213 static const WCHAR szAll[] = {'A','L','L',0};
4214 static const WCHAR szUpgradeCode[] =
4215 {'U','p','g','r','a','d','e','C','o','d','e',0};
4217 remove = msi_dup_property(package, szRemove);
4219 return ERROR_SUCCESS;
4221 features = msi_split_string(remove, ',');
4225 ERR("REMOVE feature list is empty!\n");
4226 return ERROR_FUNCTION_FAILED;
4229 if (!lstrcmpW(features[0], szAll))
4230 full_uninstall = TRUE;
4233 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4235 if (feature->Action != INSTALLSTATE_ABSENT)
4236 full_uninstall = FALSE;
4240 if (!full_uninstall)
4243 MSIREG_DeleteProductKey(package->ProductCode);
4244 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4245 MSIREG_DeleteUninstallKey(package->ProductCode);
4247 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4249 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4250 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4254 MSIREG_DeleteUserProductKey(package->ProductCode);
4255 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4258 upgrade = msi_dup_property(package, szUpgradeCode);
4261 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4268 return ERROR_SUCCESS;
4271 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4275 rc = msi_unpublish_product(package);
4276 if (rc != ERROR_SUCCESS)
4279 /* turn off scheduling */
4280 package->script->CurrentlyScripting= FALSE;
4282 /* first do the same as an InstallExecute */
4283 rc = ACTION_InstallExecute(package);
4284 if (rc != ERROR_SUCCESS)
4287 /* then handle Commit Actions */
4288 rc = execute_script(package,COMMIT_SCRIPT);
4293 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4295 static const WCHAR RunOnce[] = {
4296 'S','o','f','t','w','a','r','e','\\',
4297 'M','i','c','r','o','s','o','f','t','\\',
4298 'W','i','n','d','o','w','s','\\',
4299 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4300 'R','u','n','O','n','c','e',0};
4301 static const WCHAR InstallRunOnce[] = {
4302 'S','o','f','t','w','a','r','e','\\',
4303 'M','i','c','r','o','s','o','f','t','\\',
4304 'W','i','n','d','o','w','s','\\',
4305 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4306 'I','n','s','t','a','l','l','e','r','\\',
4307 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4309 static const WCHAR msiexec_fmt[] = {
4311 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4312 '\"','%','s','\"',0};
4313 static const WCHAR install_fmt[] = {
4314 '/','I',' ','\"','%','s','\"',' ',
4315 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4316 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4317 WCHAR buffer[256], sysdir[MAX_PATH];
4319 WCHAR squished_pc[100];
4321 squash_guid(package->ProductCode,squished_pc);
4323 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4324 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4325 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4328 msi_reg_set_val_str( hkey, squished_pc, buffer );
4331 TRACE("Reboot command %s\n",debugstr_w(buffer));
4333 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4334 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4336 msi_reg_set_val_str( hkey, squished_pc, buffer );
4339 return ERROR_INSTALL_SUSPEND;
4342 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4348 * We are currently doing what should be done here in the top level Install
4349 * however for Administrative and uninstalls this step will be needed
4351 if (!package->PackagePath)
4352 return ERROR_SUCCESS;
4354 msi_set_sourcedir_props(package, TRUE);
4356 attrib = GetFileAttributesW(package->db->path);
4357 if (attrib == INVALID_FILE_ATTRIBUTES)
4363 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4364 package->Context, MSICODE_PRODUCT,
4365 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4366 if (rc == ERROR_MORE_DATA)
4368 prompt = msi_alloc(size * sizeof(WCHAR));
4369 MsiSourceListGetInfoW(package->ProductCode, NULL,
4370 package->Context, MSICODE_PRODUCT,
4371 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4374 prompt = strdupW(package->db->path);
4376 msg = generate_error_string(package,1302,1,prompt);
4377 while(attrib == INVALID_FILE_ATTRIBUTES)
4379 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4382 rc = ERROR_INSTALL_USEREXIT;
4385 attrib = GetFileAttributesW(package->db->path);
4391 return ERROR_SUCCESS;
4396 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4403 static const WCHAR szPropKeys[][80] =
4405 {'P','r','o','d','u','c','t','I','D',0},
4406 {'U','S','E','R','N','A','M','E',0},
4407 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4411 static const WCHAR szRegKeys[][80] =
4413 {'P','r','o','d','u','c','t','I','D',0},
4414 {'R','e','g','O','w','n','e','r',0},
4415 {'R','e','g','C','o','m','p','a','n','y',0},
4419 if (msi_check_unpublish(package))
4421 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4422 return ERROR_SUCCESS;
4425 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4427 return ERROR_SUCCESS;
4429 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4430 rc = MSIREG_OpenLocalSystemInstallProps(package->ProductCode, &hkey, TRUE);
4432 rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &hkey, TRUE);
4434 if (rc != ERROR_SUCCESS)
4437 for( i = 0; szPropKeys[i][0]; i++ )
4439 buffer = msi_dup_property( package, szPropKeys[i] );
4440 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4445 msi_free(productid);
4448 /* FIXME: call ui_actiondata */
4454 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4458 package->script->InWhatSequence |= SEQUENCE_EXEC;
4459 rc = ACTION_ProcessExecSequence(package,FALSE);
4464 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4466 MSIPACKAGE *package = (MSIPACKAGE*)param;
4467 LPCWSTR compgroupid=NULL;
4468 LPCWSTR feature=NULL;
4469 LPCWSTR text = NULL;
4470 LPCWSTR qualifier = NULL;
4471 LPCWSTR component = NULL;
4472 LPWSTR advertise = NULL;
4473 LPWSTR output = NULL;
4475 UINT rc = ERROR_SUCCESS;
4480 component = MSI_RecordGetString(rec,3);
4481 comp = get_loaded_component(package,component);
4483 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4484 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4485 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4487 TRACE("Skipping: Component %s not scheduled for install\n",
4488 debugstr_w(component));
4490 return ERROR_SUCCESS;
4493 compgroupid = MSI_RecordGetString(rec,1);
4494 qualifier = MSI_RecordGetString(rec,2);
4496 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4497 if (rc != ERROR_SUCCESS)
4500 text = MSI_RecordGetString(rec,4);
4501 feature = MSI_RecordGetString(rec,5);
4503 advertise = create_component_advertise_string(package, comp, feature);
4505 sz = strlenW(advertise);
4508 sz += lstrlenW(text);
4511 sz *= sizeof(WCHAR);
4513 output = msi_alloc_zero(sz);
4514 strcpyW(output,advertise);
4515 msi_free(advertise);
4518 strcatW(output,text);
4520 msi_reg_set_val_multi_str( hkey, qualifier, output );
4527 uirow = MSI_CreateRecord( 2 );
4528 MSI_RecordSetStringW( uirow, 1, compgroupid );
4529 MSI_RecordSetStringW( uirow, 2, qualifier);
4530 ui_actiondata( package, szPublishComponents, uirow);
4531 msiobj_release( &uirow->hdr );
4532 /* FIXME: call ui_progress? */
4538 * At present I am ignorning the advertised components part of this and only
4539 * focusing on the qualified component sets
4541 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4545 static const WCHAR ExecSeqQuery[] =
4546 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4547 '`','P','u','b','l','i','s','h',
4548 'C','o','m','p','o','n','e','n','t','`',0};
4550 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4551 if (rc != ERROR_SUCCESS)
4552 return ERROR_SUCCESS;
4554 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4555 msiobj_release(&view->hdr);
4560 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4562 MSIPACKAGE *package = (MSIPACKAGE*)param;
4565 SC_HANDLE hscm, service = NULL;
4566 LPCWSTR comp, depends, pass;
4567 LPWSTR name = NULL, disp = NULL;
4568 LPCWSTR load_order, serv_name, key;
4569 DWORD serv_type, start_type;
4572 static const WCHAR query[] =
4573 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4574 '`','C','o','m','p','o','n','e','n','t','`',' ',
4575 'W','H','E','R','E',' ',
4576 '`','C','o','m','p','o','n','e','n','t','`',' ',
4577 '=','\'','%','s','\'',0};
4579 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4582 ERR("Failed to open the SC Manager!\n");
4586 start_type = MSI_RecordGetInteger(rec, 5);
4587 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4590 depends = MSI_RecordGetString(rec, 8);
4591 if (depends && *depends)
4592 FIXME("Dependency list unhandled!\n");
4594 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4595 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
4596 serv_type = MSI_RecordGetInteger(rec, 4);
4597 err_control = MSI_RecordGetInteger(rec, 6);
4598 load_order = MSI_RecordGetString(rec, 7);
4599 serv_name = MSI_RecordGetString(rec, 9);
4600 pass = MSI_RecordGetString(rec, 10);
4601 comp = MSI_RecordGetString(rec, 12);
4603 /* fetch the service path */
4604 row = MSI_QueryGetRecord(package->db, query, comp);
4607 ERR("Control query failed!\n");
4611 key = MSI_RecordGetString(row, 6);
4613 file = get_loaded_file(package, key);
4614 msiobj_release(&row->hdr);
4617 ERR("Failed to load the service file\n");
4621 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4622 start_type, err_control, file->TargetPath,
4623 load_order, NULL, NULL, serv_name, pass);
4626 if (GetLastError() != ERROR_SERVICE_EXISTS)
4627 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4631 CloseServiceHandle(service);
4632 CloseServiceHandle(hscm);
4636 return ERROR_SUCCESS;
4639 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4643 static const WCHAR ExecSeqQuery[] =
4644 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4645 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4647 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4648 if (rc != ERROR_SUCCESS)
4649 return ERROR_SUCCESS;
4651 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4652 msiobj_release(&view->hdr);
4657 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4658 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
4660 LPCWSTR *vector, *temp_vector;
4664 static const WCHAR separator[] = {'[','~',']',0};
4667 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4672 vector = msi_alloc(sizeof(LPWSTR));
4680 vector[*numargs - 1] = p;
4682 if ((q = strstrW(p, separator)))
4686 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4692 vector = temp_vector;
4701 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4703 MSIPACKAGE *package = (MSIPACKAGE *)param;
4705 SC_HANDLE scm, service = NULL;
4706 LPCWSTR name, *vector = NULL;
4708 DWORD event, numargs;
4709 UINT r = ERROR_FUNCTION_FAILED;
4711 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4712 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4713 return ERROR_SUCCESS;
4715 name = MSI_RecordGetString(rec, 2);
4716 event = MSI_RecordGetInteger(rec, 3);
4717 args = strdupW(MSI_RecordGetString(rec, 4));
4719 if (!(event & msidbServiceControlEventStart))
4720 return ERROR_SUCCESS;
4722 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4725 ERR("Failed to open the service control manager\n");
4729 service = OpenServiceW(scm, name, SERVICE_START);
4732 ERR("Failed to open service %s\n", debugstr_w(name));
4736 vector = msi_service_args_to_vector(args, &numargs);
4738 if (!StartServiceW(service, numargs, vector))
4740 ERR("Failed to start service %s\n", debugstr_w(name));
4747 CloseServiceHandle(service);
4748 CloseServiceHandle(scm);
4755 static UINT ACTION_StartServices( MSIPACKAGE *package )
4760 static const WCHAR query[] = {
4761 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4762 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4764 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4765 if (rc != ERROR_SUCCESS)
4766 return ERROR_SUCCESS;
4768 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4769 msiobj_release(&view->hdr);
4774 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4776 DWORD i, needed, count;
4777 ENUM_SERVICE_STATUSW *dependencies;
4781 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4782 0, &needed, &count))
4785 if (GetLastError() != ERROR_MORE_DATA)
4788 dependencies = msi_alloc(needed);
4792 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4793 needed, &needed, &count))
4796 for (i = 0; i < count; i++)
4798 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4799 SERVICE_STOP | SERVICE_QUERY_STATUS);
4803 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4810 msi_free(dependencies);
4814 static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
4816 MSIPACKAGE *package = (MSIPACKAGE *)param;
4818 SERVICE_STATUS status;
4819 SERVICE_STATUS_PROCESS ssp;
4820 SC_HANDLE scm = NULL, service = NULL;
4822 DWORD event, needed;
4824 event = MSI_RecordGetInteger(rec, 3);
4825 if (!(event & msidbServiceControlEventStop))
4826 return ERROR_SUCCESS;
4828 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4829 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4830 return ERROR_SUCCESS;
4832 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4833 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4834 args = strdupW(MSI_RecordGetString(rec, 4));
4836 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4839 WARN("Failed to open the SCM: %d\n", GetLastError());
4843 service = OpenServiceW(scm, name,
4845 SERVICE_QUERY_STATUS |
4846 SERVICE_ENUMERATE_DEPENDENTS);
4849 WARN("Failed to open service (%s): %d\n",
4850 debugstr_w(name), GetLastError());
4854 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4855 sizeof(SERVICE_STATUS_PROCESS), &needed))
4857 WARN("Failed to query service status (%s): %d\n",
4858 debugstr_w(name), GetLastError());
4862 if (ssp.dwCurrentState == SERVICE_STOPPED)
4865 stop_service_dependents(scm, service);
4867 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
4868 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
4871 CloseServiceHandle(service);
4872 CloseServiceHandle(scm);
4876 return ERROR_SUCCESS;
4879 static UINT ACTION_StopServices( MSIPACKAGE *package )
4884 static const WCHAR query[] = {
4885 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4886 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4888 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4889 if (rc != ERROR_SUCCESS)
4890 return ERROR_SUCCESS;
4892 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
4893 msiobj_release(&view->hdr);
4898 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4902 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4904 if (!lstrcmpW(file->File, filename))
4911 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4913 MSIPACKAGE *package = (MSIPACKAGE*)param;
4914 LPWSTR driver, driver_path, ptr;
4915 WCHAR outpath[MAX_PATH];
4916 MSIFILE *driver_file, *setup_file;
4919 UINT r = ERROR_SUCCESS;
4921 static const WCHAR driver_fmt[] = {
4922 'D','r','i','v','e','r','=','%','s',0};
4923 static const WCHAR setup_fmt[] = {
4924 'S','e','t','u','p','=','%','s',0};
4925 static const WCHAR usage_fmt[] = {
4926 'F','i','l','e','U','s','a','g','e','=','1',0};
4928 desc = MSI_RecordGetString(rec, 3);
4930 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4931 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4933 if (!driver_file || !setup_file)
4935 ERR("ODBC Driver entry not found!\n");
4936 return ERROR_FUNCTION_FAILED;
4939 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4940 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4941 lstrlenW(usage_fmt) + 1;
4942 driver = msi_alloc(len * sizeof(WCHAR));
4944 return ERROR_OUTOFMEMORY;
4947 lstrcpyW(ptr, desc);
4948 ptr += lstrlenW(ptr) + 1;
4950 sprintfW(ptr, driver_fmt, driver_file->FileName);
4951 ptr += lstrlenW(ptr) + 1;
4953 sprintfW(ptr, setup_fmt, setup_file->FileName);
4954 ptr += lstrlenW(ptr) + 1;
4956 lstrcpyW(ptr, usage_fmt);
4957 ptr += lstrlenW(ptr) + 1;
4960 driver_path = strdupW(driver_file->TargetPath);
4961 ptr = strrchrW(driver_path, '\\');
4962 if (ptr) *ptr = '\0';
4964 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4965 NULL, ODBC_INSTALL_COMPLETE, &usage))
4967 ERR("Failed to install SQL driver!\n");
4968 r = ERROR_FUNCTION_FAILED;
4972 msi_free(driver_path);
4977 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4979 MSIPACKAGE *package = (MSIPACKAGE*)param;
4980 LPWSTR translator, translator_path, ptr;
4981 WCHAR outpath[MAX_PATH];
4982 MSIFILE *translator_file, *setup_file;
4985 UINT r = ERROR_SUCCESS;
4987 static const WCHAR translator_fmt[] = {
4988 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4989 static const WCHAR setup_fmt[] = {
4990 'S','e','t','u','p','=','%','s',0};
4992 desc = MSI_RecordGetString(rec, 3);
4994 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4995 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4997 if (!translator_file || !setup_file)
4999 ERR("ODBC Translator entry not found!\n");
5000 return ERROR_FUNCTION_FAILED;
5003 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
5004 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
5005 translator = msi_alloc(len * sizeof(WCHAR));
5007 return ERROR_OUTOFMEMORY;
5010 lstrcpyW(ptr, desc);
5011 ptr += lstrlenW(ptr) + 1;
5013 sprintfW(ptr, translator_fmt, translator_file->FileName);
5014 ptr += lstrlenW(ptr) + 1;
5016 sprintfW(ptr, setup_fmt, setup_file->FileName);
5017 ptr += lstrlenW(ptr) + 1;
5020 translator_path = strdupW(translator_file->TargetPath);
5021 ptr = strrchrW(translator_path, '\\');
5022 if (ptr) *ptr = '\0';
5024 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5025 NULL, ODBC_INSTALL_COMPLETE, &usage))
5027 ERR("Failed to install SQL translator!\n");
5028 r = ERROR_FUNCTION_FAILED;
5031 msi_free(translator);
5032 msi_free(translator_path);
5037 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5040 LPCWSTR desc, driver;
5041 WORD request = ODBC_ADD_SYS_DSN;
5044 UINT r = ERROR_SUCCESS;
5046 static const WCHAR attrs_fmt[] = {
5047 'D','S','N','=','%','s',0 };
5049 desc = MSI_RecordGetString(rec, 3);
5050 driver = MSI_RecordGetString(rec, 4);
5051 registration = MSI_RecordGetInteger(rec, 5);
5053 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5054 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5056 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
5057 attrs = msi_alloc(len * sizeof(WCHAR));
5059 return ERROR_OUTOFMEMORY;
5061 sprintfW(attrs, attrs_fmt, desc);
5062 attrs[len - 1] = '\0';
5064 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5066 ERR("Failed to install SQL data source!\n");
5067 r = ERROR_FUNCTION_FAILED;
5075 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5080 static const WCHAR driver_query[] = {
5081 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5082 'O','D','B','C','D','r','i','v','e','r',0 };
5084 static const WCHAR translator_query[] = {
5085 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5086 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5088 static const WCHAR source_query[] = {
5089 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5090 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5092 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5093 if (rc != ERROR_SUCCESS)
5094 return ERROR_SUCCESS;
5096 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5097 msiobj_release(&view->hdr);
5099 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5100 if (rc != ERROR_SUCCESS)
5101 return ERROR_SUCCESS;
5103 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5104 msiobj_release(&view->hdr);
5106 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5107 if (rc != ERROR_SUCCESS)
5108 return ERROR_SUCCESS;
5110 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5111 msiobj_release(&view->hdr);
5116 #define ENV_ACT_SETALWAYS 0x1
5117 #define ENV_ACT_SETABSENT 0x2
5118 #define ENV_ACT_REMOVE 0x4
5119 #define ENV_ACT_REMOVEMATCH 0x8
5121 #define ENV_MOD_MACHINE 0x20000000
5122 #define ENV_MOD_APPEND 0x40000000
5123 #define ENV_MOD_PREFIX 0x80000000
5124 #define ENV_MOD_MASK 0xC0000000
5126 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5128 static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5130 LPCWSTR cptr = *name;
5131 LPCWSTR ptr = *value;
5133 static const WCHAR prefix[] = {'[','~',']',0};
5134 static const int prefix_len = 3;
5140 *flags |= ENV_ACT_SETALWAYS;
5141 else if (*cptr == '+')
5142 *flags |= ENV_ACT_SETABSENT;
5143 else if (*cptr == '-')
5144 *flags |= ENV_ACT_REMOVE;
5145 else if (*cptr == '!')
5146 *flags |= ENV_ACT_REMOVEMATCH;
5147 else if (*cptr == '*')
5148 *flags |= ENV_MOD_MACHINE;
5158 ERR("Missing environment variable\n");
5159 return ERROR_FUNCTION_FAILED;
5162 if (!strncmpW(ptr, prefix, prefix_len))
5164 *flags |= ENV_MOD_APPEND;
5165 *value += lstrlenW(prefix);
5167 else if (lstrlenW(*value) >= prefix_len)
5169 ptr += lstrlenW(ptr) - prefix_len;
5170 if (!lstrcmpW(ptr, prefix))
5172 *flags |= ENV_MOD_PREFIX;
5173 /* the "[~]" will be removed by deformat_string */;
5178 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5179 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5180 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5181 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5183 ERR("Invalid flags: %08x\n", *flags);
5184 return ERROR_FUNCTION_FAILED;
5187 return ERROR_SUCCESS;
5190 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5192 MSIPACKAGE *package = param;
5193 LPCWSTR name, value;
5194 LPWSTR data = NULL, newval = NULL;
5195 LPWSTR deformatted = NULL, ptr;
5196 DWORD flags, type, size;
5198 HKEY env = NULL, root;
5199 LPCWSTR environment;
5201 static const WCHAR user_env[] =
5202 {'E','n','v','i','r','o','n','m','e','n','t',0};
5203 static const WCHAR machine_env[] =
5204 {'S','y','s','t','e','m','\\',
5205 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5206 'C','o','n','t','r','o','l','\\',
5207 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5208 'E','n','v','i','r','o','n','m','e','n','t',0};
5209 static const WCHAR semicolon[] = {';',0};
5211 name = MSI_RecordGetString(rec, 2);
5212 value = MSI_RecordGetString(rec, 3);
5214 res = env_set_flags(&name, &value, &flags);
5215 if (res != ERROR_SUCCESS)
5218 deformat_string(package, value, &deformatted);
5221 res = ERROR_OUTOFMEMORY;
5225 value = deformatted;
5227 if (flags & ENV_MOD_MACHINE)
5229 environment = machine_env;
5230 root = HKEY_LOCAL_MACHINE;
5234 environment = user_env;
5235 root = HKEY_CURRENT_USER;
5238 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5239 KEY_ALL_ACCESS, NULL, &env, NULL);
5240 if (res != ERROR_SUCCESS)
5243 if (flags & ENV_ACT_REMOVE)
5244 FIXME("Not removing environment variable on uninstall!\n");
5247 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5248 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
5249 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
5252 if (res != ERROR_FILE_NOT_FOUND)
5254 if (flags & ENV_ACT_SETABSENT)
5256 res = ERROR_SUCCESS;
5260 data = msi_alloc(size);
5264 return ERROR_OUTOFMEMORY;
5267 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5268 if (res != ERROR_SUCCESS)
5271 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5273 res = RegDeleteKeyW(env, name);
5277 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
5278 newval = msi_alloc(size);
5282 res = ERROR_OUTOFMEMORY;
5286 if (!(flags & ENV_MOD_MASK))
5287 lstrcpyW(newval, value);
5290 if (flags & ENV_MOD_PREFIX)
5292 lstrcpyW(newval, value);
5293 lstrcatW(newval, semicolon);
5294 ptr = newval + lstrlenW(value) + 1;
5297 lstrcpyW(ptr, data);
5299 if (flags & ENV_MOD_APPEND)
5301 lstrcatW(newval, semicolon);
5302 lstrcatW(newval, value);
5308 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
5309 newval = msi_alloc(size);
5312 res = ERROR_OUTOFMEMORY;
5316 lstrcpyW(newval, value);
5319 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5320 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
5323 if (env) RegCloseKey(env);
5324 msi_free(deformatted);
5330 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5334 static const WCHAR ExecSeqQuery[] =
5335 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5336 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5337 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5338 if (rc != ERROR_SUCCESS)
5339 return ERROR_SUCCESS;
5341 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5342 msiobj_release(&view->hdr);
5347 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5358 static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5362 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5363 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5365 WARN("Source or dest is directory, not moving\n");
5369 if (options == msidbMoveFileOptionsMove)
5371 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5372 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5375 WARN("MoveFile failed: %d\n", GetLastError());
5381 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5382 ret = CopyFileW(source, dest, FALSE);
5385 WARN("CopyFile failed: %d\n", GetLastError());
5393 static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5396 DWORD dirlen, pathlen;
5398 ptr = strrchrW(wildcard, '\\');
5399 dirlen = ptr - wildcard + 1;
5401 pathlen = dirlen + lstrlenW(filename) + 1;
5402 path = msi_alloc(pathlen * sizeof(WCHAR));
5404 lstrcpynW(path, wildcard, dirlen + 1);
5405 lstrcatW(path, filename);
5410 static void free_file_entry(FILE_LIST *file)
5412 msi_free(file->source);
5413 msi_free(file->dest);
5417 static void free_list(FILE_LIST *list)
5419 while (!list_empty(&list->entry))
5421 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5423 list_remove(&file->entry);
5424 free_file_entry(file);
5428 static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5430 FILE_LIST *new, *file;
5431 LPWSTR ptr, filename;
5434 new = msi_alloc_zero(sizeof(FILE_LIST));
5438 new->source = strdupW(source);
5439 ptr = strrchrW(dest, '\\') + 1;
5440 filename = strrchrW(new->source, '\\') + 1;
5442 new->sourcename = filename;
5445 new->destname = ptr;
5447 new->destname = new->sourcename;
5449 size = (ptr - dest) + lstrlenW(filename) + 1;
5450 new->dest = msi_alloc(size * sizeof(WCHAR));
5453 free_file_entry(new);
5457 lstrcpynW(new->dest, dest, ptr - dest + 1);
5458 lstrcatW(new->dest, filename);
5460 if (list_empty(&files->entry))
5462 list_add_head(&files->entry, &new->entry);
5466 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5468 if (lstrcmpW(source, file->source) < 0)
5470 list_add_before(&file->entry, &new->entry);
5475 list_add_after(&file->entry, &new->entry);
5479 static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
5481 WIN32_FIND_DATAW wfd;
5485 FILE_LIST files, *file;
5488 hfile = FindFirstFileW(source, &wfd);
5489 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5491 list_init(&files.entry);
5493 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5495 if (is_dot_dir(wfd.cFileName)) continue;
5497 path = wildcard_to_file(source, wfd.cFileName);
5504 add_wildcard(&files, path, dest);
5508 /* no files match the wildcard */
5509 if (list_empty(&files.entry))
5512 /* only the first wildcard match gets renamed to dest */
5513 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5514 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5515 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5522 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5524 while (!list_empty(&files.entry))
5526 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5528 msi_move_file((LPCWSTR)file->source, (LPCWSTR)file->dest, options);
5530 list_remove(&file->entry);
5531 free_file_entry(file);
5542 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5544 MSIPACKAGE *package = param;
5546 LPCWSTR sourcename, destname;
5547 LPWSTR sourcedir = NULL, destdir = NULL;
5548 LPWSTR source = NULL, dest = NULL;
5551 BOOL ret, wildcards;
5553 static const WCHAR backslash[] = {'\\',0};
5555 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5556 if (!comp || !comp->Enabled ||
5557 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5559 TRACE("Component not set for install, not moving file\n");
5560 return ERROR_SUCCESS;
5563 sourcename = MSI_RecordGetString(rec, 3);
5564 destname = MSI_RecordGetString(rec, 4);
5565 options = MSI_RecordGetInteger(rec, 7);
5567 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5571 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5577 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5580 source = strdupW(sourcedir);
5586 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5587 source = msi_alloc(size * sizeof(WCHAR));
5591 lstrcpyW(source, sourcedir);
5592 if (source[lstrlenW(source) - 1] != '\\')
5593 lstrcatW(source, backslash);
5594 lstrcatW(source, sourcename);
5597 wildcards = strchrW(source, '*') || strchrW(source, '?');
5599 if (!destname && !wildcards)
5601 destname = strdupW(sourcename);
5608 size = lstrlenW(destname);
5610 size += lstrlenW(destdir) + 2;
5611 dest = msi_alloc(size * sizeof(WCHAR));
5615 lstrcpyW(dest, destdir);
5616 if (dest[lstrlenW(dest) - 1] != '\\')
5617 lstrcatW(dest, backslash);
5620 lstrcatW(dest, destname);
5622 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5624 ret = CreateDirectoryW(destdir, NULL);
5627 WARN("CreateDirectory failed: %d\n", GetLastError());
5628 return ERROR_SUCCESS;
5633 msi_move_file(source, dest, options);
5635 move_files_wildcard(source, dest, options);
5638 msi_free(sourcedir);
5643 return ERROR_SUCCESS;
5646 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5651 static const WCHAR ExecSeqQuery[] =
5652 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5653 '`','M','o','v','e','F','i','l','e','`',0};
5655 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5656 if (rc != ERROR_SUCCESS)
5657 return ERROR_SUCCESS;
5659 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5660 msiobj_release(&view->hdr);
5665 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
5667 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
5668 LPVOID pvReserved, HMODULE *phModDll);
5670 static BOOL init_functionpointers(void)
5676 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
5678 hmscoree = LoadLibraryA("mscoree.dll");
5681 WARN("mscoree.dll not available\n");
5685 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
5686 if (!pLoadLibraryShim)
5688 WARN("LoadLibraryShim not available\n");
5689 FreeLibrary(hmscoree);
5693 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
5696 WARN("fusion.dll not available\n");
5697 FreeLibrary(hmscoree);
5701 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
5703 FreeLibrary(hmscoree);
5707 static UINT install_assembly(LPWSTR path)
5709 IAssemblyCache *cache;
5711 UINT r = ERROR_FUNCTION_FAILED;
5713 if (!init_functionpointers() || !pCreateAssemblyCache)
5714 return ERROR_FUNCTION_FAILED;
5716 hr = pCreateAssemblyCache(&cache, 0);
5720 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
5722 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
5727 IAssemblyCache_Release(cache);
5731 static UINT ITERATE_PublishAssembly( MSIRECORD *rec, LPVOID param )
5733 MSIPACKAGE *package = param;
5735 MSIFEATURE *feature;
5737 WCHAR path[MAX_PATH];
5742 comp = get_loaded_component(package, MSI_RecordGetString(rec, 1));
5743 if (!comp || !comp->Enabled ||
5744 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5746 ERR("Component not set for install, not publishing assembly\n");
5747 return ERROR_SUCCESS;
5750 feature = find_feature_by_name(package, MSI_RecordGetString(rec, 2));
5752 msi_feature_set_state(feature, INSTALLSTATE_LOCAL);
5754 if (MSI_RecordGetString(rec, 3))
5755 FIXME("Manifest unhandled\n");
5757 app = MSI_RecordGetString(rec, 4);
5760 FIXME("Assembly should be privately installed\n");
5761 return ERROR_SUCCESS;
5764 attr = MSI_RecordGetInteger(rec, 5);
5765 if (attr == msidbAssemblyAttributesWin32)
5767 FIXME("Win32 assemblies not handled\n");
5768 return ERROR_SUCCESS;
5771 /* FIXME: extract all files belonging to this component */
5772 file = msi_find_file(package, comp->KeyPath);
5775 ERR("File %s not found\n", debugstr_w(comp->KeyPath));
5776 return ERROR_FUNCTION_FAILED;
5779 GetTempPathW(MAX_PATH, path);
5781 if (file->IsCompressed)
5783 r = msi_extract_file(package, file, path);
5784 if (r != ERROR_SUCCESS)
5786 ERR("Failed to extract temporary assembly\n");
5790 PathAddBackslashW(path);
5791 lstrcatW(path, file->FileName);
5795 PathAddBackslashW(path);
5796 lstrcatW(path, file->FileName);
5798 if (!CopyFileW(file->SourcePath, path, FALSE))
5800 ERR("Failed to copy temporary assembly: %d\n", GetLastError());
5801 return ERROR_FUNCTION_FAILED;
5805 r = install_assembly(path);
5806 if (r != ERROR_SUCCESS)
5807 ERR("Failed to install assembly\n");
5809 /* FIXME: write Installer assembly reg values */
5814 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
5819 static const WCHAR ExecSeqQuery[] =
5820 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5821 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
5823 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5824 if (rc != ERROR_SUCCESS)
5825 return ERROR_SUCCESS;
5827 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishAssembly, package);
5828 msiobj_release(&view->hdr);
5833 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
5834 LPCSTR action, LPCWSTR table )
5836 static const WCHAR query[] = {
5837 'S','E','L','E','C','T',' ','*',' ',
5838 'F','R','O','M',' ','`','%','s','`',0 };
5839 MSIQUERY *view = NULL;
5843 r = MSI_OpenQuery( package->db, &view, query, table );
5844 if (r == ERROR_SUCCESS)
5846 r = MSI_IterateRecords(view, &count, NULL, package);
5847 msiobj_release(&view->hdr);
5851 FIXME("%s -> %u ignored %s table values\n",
5852 action, count, debugstr_w(table));
5854 return ERROR_SUCCESS;
5857 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
5859 TRACE("%p\n", package);
5860 return ERROR_SUCCESS;
5863 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
5865 static const WCHAR table[] =
5866 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
5867 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
5870 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
5872 static const WCHAR table[] = { 'P','a','t','c','h',0 };
5873 return msi_unimplemented_action_stub( package, "PatchFiles", table );
5876 static UINT ACTION_BindImage( MSIPACKAGE *package )
5878 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
5879 return msi_unimplemented_action_stub( package, "BindImage", table );
5882 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
5884 static const WCHAR table[] = {
5885 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
5886 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
5889 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
5891 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5892 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
5895 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
5897 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
5898 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
5901 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5903 static const WCHAR table[] = {
5904 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5905 return msi_unimplemented_action_stub( package, "DeleteServices", table );
5907 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
5909 static const WCHAR table[] = {
5910 'P','r','o','d','u','c','t','I','D',0 };
5911 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
5914 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
5916 static const WCHAR table[] = {
5917 'E','n','v','i','r','o','n','m','e','n','t',0 };
5918 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
5921 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
5923 static const WCHAR table[] = {
5924 'M','s','i','A','s','s','e','m','b','l','y',0 };
5925 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
5928 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
5930 static const WCHAR table[] = { 'F','o','n','t',0 };
5931 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
5934 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
5936 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
5937 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
5940 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
5942 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
5943 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
5946 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
5948 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
5949 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
5952 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
5954 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
5955 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
5958 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
5960 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
5961 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
5964 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
5966 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5967 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
5970 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
5972 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
5973 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
5976 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5978 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
5979 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
5982 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
5984 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
5985 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
5988 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
5990 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
5991 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
5994 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5996 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
5997 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
6000 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6002 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6003 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6006 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6008 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6009 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6012 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6014 static const WCHAR table[] = { 'M','I','M','E',0 };
6015 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6018 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6020 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6021 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6024 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
6026 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
6027 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
6030 static const struct _actions StandardActions[] = {
6031 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6032 { szAppSearch, ACTION_AppSearch },
6033 { szBindImage, ACTION_BindImage },
6034 { szCCPSearch, ACTION_CCPSearch },
6035 { szCostFinalize, ACTION_CostFinalize },
6036 { szCostInitialize, ACTION_CostInitialize },
6037 { szCreateFolders, ACTION_CreateFolders },
6038 { szCreateShortcuts, ACTION_CreateShortcuts },
6039 { szDeleteServices, ACTION_DeleteServices },
6040 { szDisableRollback, NULL },
6041 { szDuplicateFiles, ACTION_DuplicateFiles },
6042 { szExecuteAction, ACTION_ExecuteAction },
6043 { szFileCost, ACTION_FileCost },
6044 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6045 { szForceReboot, ACTION_ForceReboot },
6046 { szInstallAdminPackage, NULL },
6047 { szInstallExecute, ACTION_InstallExecute },
6048 { szInstallExecuteAgain, ACTION_InstallExecute },
6049 { szInstallFiles, ACTION_InstallFiles},
6050 { szInstallFinalize, ACTION_InstallFinalize },
6051 { szInstallInitialize, ACTION_InstallInitialize },
6052 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6053 { szInstallValidate, ACTION_InstallValidate },
6054 { szIsolateComponents, ACTION_IsolateComponents },
6055 { szLaunchConditions, ACTION_LaunchConditions },
6056 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6057 { szMoveFiles, ACTION_MoveFiles },
6058 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6059 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6060 { szInstallODBC, ACTION_InstallODBC },
6061 { szInstallServices, ACTION_InstallServices },
6062 { szPatchFiles, ACTION_PatchFiles },
6063 { szProcessComponents, ACTION_ProcessComponents },
6064 { szPublishComponents, ACTION_PublishComponents },
6065 { szPublishFeatures, ACTION_PublishFeatures },
6066 { szPublishProduct, ACTION_PublishProduct },
6067 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6068 { szRegisterComPlus, ACTION_RegisterComPlus},
6069 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6070 { szRegisterFonts, ACTION_RegisterFonts },
6071 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6072 { szRegisterProduct, ACTION_RegisterProduct },
6073 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6074 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6075 { szRegisterUser, ACTION_RegisterUser },
6076 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6077 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6078 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6079 { szRemoveFiles, ACTION_RemoveFiles },
6080 { szRemoveFolders, ACTION_RemoveFolders },
6081 { szRemoveIniValues, ACTION_RemoveIniValues },
6082 { szRemoveODBC, ACTION_RemoveODBC },
6083 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6084 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6085 { szResolveSource, ACTION_ResolveSource },
6086 { szRMCCPSearch, ACTION_RMCCPSearch },
6087 { szScheduleReboot, NULL },
6088 { szSelfRegModules, ACTION_SelfRegModules },
6089 { szSelfUnregModules, ACTION_SelfUnregModules },
6090 { szSetODBCFolders, NULL },
6091 { szStartServices, ACTION_StartServices },
6092 { szStopServices, ACTION_StopServices },
6093 { szUnpublishComponents, ACTION_UnpublishComponents },
6094 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6095 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6096 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6097 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6098 { szUnregisterFonts, ACTION_UnregisterFonts },
6099 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6100 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6101 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6102 { szValidateProductID, ACTION_ValidateProductID },
6103 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6104 { szWriteIniValues, ACTION_WriteIniValues },
6105 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6109 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
6110 UINT* rc, BOOL force )
6116 if (!run && !package->script->CurrentlyScripting)
6121 if (strcmpW(action,szInstallFinalize) == 0 ||
6122 strcmpW(action,szInstallExecute) == 0 ||
6123 strcmpW(action,szInstallExecuteAgain) == 0)
6128 while (StandardActions[i].action != NULL)
6130 if (strcmpW(StandardActions[i].action, action)==0)
6134 ui_actioninfo(package, action, TRUE, 0);
6135 *rc = schedule_action(package,INSTALL_SCRIPT,action);
6136 ui_actioninfo(package, action, FALSE, *rc);
6140 ui_actionstart(package, action);
6141 if (StandardActions[i].handler)
6143 *rc = StandardActions[i].handler(package);
6147 FIXME("unhandled standard action %s\n",debugstr_w(action));
6148 *rc = ERROR_SUCCESS;