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 & MSIWORDCOUNT_COMPRESSED;
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;
2998 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
3000 component = MSI_RecordGetString(row,3);
3001 comp = get_loaded_component(package,component);
3003 return ERROR_SUCCESS;
3005 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3007 TRACE("Skipping typelib reg due to disabled component\n");
3009 comp->Action = comp->Installed;
3011 return ERROR_SUCCESS;
3014 comp->Action = INSTALLSTATE_LOCAL;
3016 file = get_loaded_file( package, comp->KeyPath );
3018 return ERROR_SUCCESS;
3020 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3024 guid = MSI_RecordGetString(row,1);
3025 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
3026 tl_struct.source = strdupW( file->TargetPath );
3027 tl_struct.path = NULL;
3029 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3030 (LONG_PTR)&tl_struct);
3038 helpid = MSI_RecordGetString(row,6);
3041 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3042 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3045 if (!SUCCEEDED(res))
3046 ERR("Failed to register type library %s\n",
3047 debugstr_w(tl_struct.path));
3050 ui_actiondata(package,szRegisterTypeLibraries,row);
3052 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3055 ITypeLib_Release(tl_struct.ptLib);
3056 msi_free(tl_struct.path);
3059 ERR("Failed to load type library %s\n",
3060 debugstr_w(tl_struct.source));
3062 FreeLibrary(module);
3063 msi_free(tl_struct.source);
3066 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
3068 return ERROR_SUCCESS;
3071 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3074 * OK this is a bit confusing.. I am given a _Component key and I believe
3075 * that the file that is being registered as a type library is the "key file
3076 * of that component" which I interpret to mean "The file in the KeyPath of
3081 static const WCHAR Query[] =
3082 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3083 '`','T','y','p','e','L','i','b','`',0};
3085 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3086 if (rc != ERROR_SUCCESS)
3087 return ERROR_SUCCESS;
3089 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3090 msiobj_release(&view->hdr);
3094 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3096 MSIPACKAGE *package = (MSIPACKAGE*)param;
3097 LPWSTR target_file, target_folder, filename;
3098 LPCWSTR buffer, extension;
3100 static const WCHAR szlnk[]={'.','l','n','k',0};
3101 IShellLinkW *sl = NULL;
3102 IPersistFile *pf = NULL;
3105 buffer = MSI_RecordGetString(row,4);
3106 comp = get_loaded_component(package,buffer);
3108 return ERROR_SUCCESS;
3110 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
3112 TRACE("Skipping shortcut creation due to disabled component\n");
3114 comp->Action = comp->Installed;
3116 return ERROR_SUCCESS;
3119 comp->Action = INSTALLSTATE_LOCAL;
3121 ui_actiondata(package,szCreateShortcuts,row);
3123 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3124 &IID_IShellLinkW, (LPVOID *) &sl );
3128 ERR("CLSID_ShellLink not available\n");
3132 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3135 ERR("QueryInterface(IID_IPersistFile) failed\n");
3139 buffer = MSI_RecordGetString(row,2);
3140 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
3142 /* may be needed because of a bug somewhere else */
3143 create_full_pathW(target_folder);
3145 filename = msi_dup_record_field( row, 3 );
3146 reduce_to_longfilename(filename);
3148 extension = strchrW(filename,'.');
3149 if (!extension || strcmpiW(extension,szlnk))
3151 int len = strlenW(filename);
3152 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3153 memcpy(filename + len, szlnk, sizeof(szlnk));
3155 target_file = build_directory_name(2, target_folder, filename);
3156 msi_free(target_folder);
3159 buffer = MSI_RecordGetString(row,5);
3160 if (strchrW(buffer,'['))
3163 deformat_string(package,buffer,&deformated);
3164 IShellLinkW_SetPath(sl,deformated);
3165 msi_free(deformated);
3169 FIXME("poorly handled shortcut format, advertised shortcut\n");
3170 IShellLinkW_SetPath(sl,comp->FullKeypath);
3173 if (!MSI_RecordIsNull(row,6))
3176 buffer = MSI_RecordGetString(row,6);
3177 deformat_string(package,buffer,&deformated);
3178 IShellLinkW_SetArguments(sl,deformated);
3179 msi_free(deformated);
3182 if (!MSI_RecordIsNull(row,7))
3184 buffer = MSI_RecordGetString(row,7);
3185 IShellLinkW_SetDescription(sl,buffer);
3188 if (!MSI_RecordIsNull(row,8))
3189 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3191 if (!MSI_RecordIsNull(row,9))
3196 buffer = MSI_RecordGetString(row,9);
3198 Path = build_icon_path(package,buffer);
3199 index = MSI_RecordGetInteger(row,10);
3201 /* no value means 0 */
3202 if (index == MSI_NULL_INTEGER)
3205 IShellLinkW_SetIconLocation(sl,Path,index);
3209 if (!MSI_RecordIsNull(row,11))
3210 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3212 if (!MSI_RecordIsNull(row,12))
3215 buffer = MSI_RecordGetString(row,12);
3216 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3218 IShellLinkW_SetWorkingDirectory(sl,Path);
3222 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3223 IPersistFile_Save(pf,target_file,FALSE);
3225 msi_free(target_file);
3229 IPersistFile_Release( pf );
3231 IShellLinkW_Release( sl );
3233 return ERROR_SUCCESS;
3236 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3241 static const WCHAR Query[] =
3242 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3243 '`','S','h','o','r','t','c','u','t','`',0};
3245 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3246 if (rc != ERROR_SUCCESS)
3247 return ERROR_SUCCESS;
3249 res = CoInitialize( NULL );
3252 ERR("CoInitialize failed\n");
3253 return ERROR_FUNCTION_FAILED;
3256 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3257 msiobj_release(&view->hdr);
3264 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3266 MSIPACKAGE* package = (MSIPACKAGE*)param;
3275 FileName = MSI_RecordGetString(row,1);
3278 ERR("Unable to get FileName\n");
3279 return ERROR_SUCCESS;
3282 FilePath = build_icon_path(package,FileName);
3284 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3286 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3287 FILE_ATTRIBUTE_NORMAL, NULL);
3289 if (the_file == INVALID_HANDLE_VALUE)
3291 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3293 return ERROR_SUCCESS;
3300 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3301 if (rc != ERROR_SUCCESS)
3303 ERR("Failed to get stream\n");
3304 CloseHandle(the_file);
3305 DeleteFileW(FilePath);
3308 WriteFile(the_file,buffer,sz,&write,NULL);
3309 } while (sz == 1024);
3313 CloseHandle(the_file);
3315 uirow = MSI_CreateRecord(1);
3316 MSI_RecordSetStringW(uirow,1,FileName);
3317 ui_actiondata(package,szPublishProduct,uirow);
3318 msiobj_release( &uirow->hdr );
3320 return ERROR_SUCCESS;
3323 static UINT msi_publish_icons(MSIPACKAGE *package)
3328 static const WCHAR query[]= {
3329 'S','E','L','E','C','T',' ','*',' ',
3330 'F','R','O','M',' ','`','I','c','o','n','`',0};
3332 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3333 if (r == ERROR_SUCCESS)
3335 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3336 msiobj_release(&view->hdr);
3339 return ERROR_SUCCESS;
3342 static UINT msi_publish_sourcelist(MSIPACKAGE *package)
3347 MSISOURCELISTINFO *info;
3349 static const WCHAR szEmpty[] = {0};
3351 buffer = strrchrW(package->PackagePath, '\\') + 1;
3352 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3353 package->Context, MSICODE_PRODUCT,
3354 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3355 if (r != ERROR_SUCCESS)
3358 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3359 package->Context, MSICODE_PRODUCT,
3360 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3361 if (r != ERROR_SUCCESS)
3364 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3365 package->Context, MSICODE_PRODUCT,
3366 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3367 if (r != ERROR_SUCCESS)
3370 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3372 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3373 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3374 info->options, info->value);
3376 MsiSourceListSetInfoW(package->ProductCode, NULL,
3377 info->context, info->options,
3378 info->property, info->value);
3381 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3383 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3384 disk->context, disk->options,
3385 disk->disk_id, disk->volume_label, disk->disk_prompt);
3388 return ERROR_SUCCESS;
3391 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3393 MSIHANDLE hdb, suminfo;
3394 WCHAR guids[MAX_PATH];
3395 WCHAR packcode[SQUISH_GUID_SIZE];
3402 static const WCHAR szProductLanguage[] =
3403 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3404 static const WCHAR szARPProductIcon[] =
3405 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3406 static const WCHAR szProductVersion[] =
3407 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3408 static const WCHAR szAssignment[] =
3409 {'A','s','s','i','g','n','m','e','n','t',0};
3410 static const WCHAR szAdvertiseFlags[] =
3411 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3412 static const WCHAR szClients[] =
3413 {'C','l','i','e','n','t','s',0};
3414 static const WCHAR szColon[] = {':',0};
3416 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3417 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3420 langid = msi_get_property_int(package, szProductLanguage, 0);
3421 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3423 ptr = strrchrW(package->PackagePath, '\\' ) + 1;
3424 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGENAMEW, ptr);
3427 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3429 buffer = msi_dup_property(package, szARPProductIcon);
3432 LPWSTR path = build_icon_path(package,buffer);
3433 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3438 buffer = msi_dup_property(package, szProductVersion);
3441 DWORD verdword = msi_version_str_to_dword(buffer);
3442 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3446 msi_reg_set_val_dword(hkey, szAssignment, 0);
3447 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3448 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3449 msi_reg_set_val_str(hkey, szClients, szColon);
3451 hdb = alloc_msihandle(&package->db->hdr);
3453 return ERROR_NOT_ENOUGH_MEMORY;
3455 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3456 MsiCloseHandle(hdb);
3457 if (r != ERROR_SUCCESS)
3461 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3462 NULL, guids, &size);
3463 if (r != ERROR_SUCCESS)
3466 ptr = strchrW(guids, ';');
3468 squash_guid(guids, packcode);
3469 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3472 MsiCloseHandle(suminfo);
3473 return ERROR_SUCCESS;
3476 static BOOL msi_check_publish(MSIPACKAGE *package)
3478 MSIFEATURE *feature;
3480 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3482 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3490 * 99% of the work done here is only done for
3491 * advertised installs. However this is where the
3492 * Icon table is processed and written out
3493 * so that is what I am going to do here.
3495 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3502 static const WCHAR szSourceList[] =
3503 {'S','o','u','r','c','e','L','i','s','t',0};
3505 /* FIXME: also need to publish if the product is in advertise mode */
3506 if (!msi_check_publish(package))
3507 return ERROR_SUCCESS;
3509 /* ok there is a lot more done here but i need to figure out what */
3511 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3513 rc = MSIREG_OpenLocalClassesProductKey(package->ProductCode, &hukey, TRUE);
3514 if (rc != ERROR_SUCCESS)
3519 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3520 if (rc != ERROR_SUCCESS)
3524 rc = RegCreateKeyW(hukey, szSourceList, &source);
3525 if (rc != ERROR_SUCCESS)
3528 RegCloseKey(source);
3530 rc = MSIREG_OpenUserDataProductKey(package->ProductCode,&hudkey,TRUE);
3531 if (rc != ERROR_SUCCESS)
3534 /* FIXME: Need to write more keys to the user registry */
3536 rc = msi_publish_product_properties(package, hukey);
3537 if (rc != ERROR_SUCCESS)
3540 rc = msi_publish_sourcelist(package);
3541 if (rc != ERROR_SUCCESS)
3544 rc = msi_publish_icons(package);
3548 RegCloseKey(hudkey);
3553 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3555 MSIPACKAGE *package = (MSIPACKAGE*)param;
3556 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3557 LPWSTR deformated_section, deformated_key, deformated_value;
3558 LPWSTR folder, fullname = NULL;
3562 static const WCHAR szWindowsFolder[] =
3563 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3565 component = MSI_RecordGetString(row, 8);
3566 comp = get_loaded_component(package,component);
3568 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3570 TRACE("Skipping ini file due to disabled component %s\n",
3571 debugstr_w(component));
3573 comp->Action = comp->Installed;
3575 return ERROR_SUCCESS;
3578 comp->Action = INSTALLSTATE_LOCAL;
3580 identifier = MSI_RecordGetString(row,1);
3581 filename = MSI_RecordGetString(row,2);
3582 dirproperty = MSI_RecordGetString(row,3);
3583 section = MSI_RecordGetString(row,4);
3584 key = MSI_RecordGetString(row,5);
3585 value = MSI_RecordGetString(row,6);
3586 action = MSI_RecordGetInteger(row,7);
3588 deformat_string(package,section,&deformated_section);
3589 deformat_string(package,key,&deformated_key);
3590 deformat_string(package,value,&deformated_value);
3594 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3596 folder = msi_dup_property( package, dirproperty );
3599 folder = msi_dup_property( package, szWindowsFolder );
3603 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3607 fullname = build_directory_name(2, folder, filename);
3611 TRACE("Adding value %s to section %s in %s\n",
3612 debugstr_w(deformated_key), debugstr_w(deformated_section),
3613 debugstr_w(fullname));
3614 WritePrivateProfileStringW(deformated_section, deformated_key,
3615 deformated_value, fullname);
3617 else if (action == 1)
3620 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3621 returned, 10, fullname);
3622 if (returned[0] == 0)
3624 TRACE("Adding value %s to section %s in %s\n",
3625 debugstr_w(deformated_key), debugstr_w(deformated_section),
3626 debugstr_w(fullname));
3628 WritePrivateProfileStringW(deformated_section, deformated_key,
3629 deformated_value, fullname);
3632 else if (action == 3)
3633 FIXME("Append to existing section not yet implemented\n");
3635 uirow = MSI_CreateRecord(4);
3636 MSI_RecordSetStringW(uirow,1,identifier);
3637 MSI_RecordSetStringW(uirow,2,deformated_section);
3638 MSI_RecordSetStringW(uirow,3,deformated_key);
3639 MSI_RecordSetStringW(uirow,4,deformated_value);
3640 ui_actiondata(package,szWriteIniValues,uirow);
3641 msiobj_release( &uirow->hdr );
3645 msi_free(deformated_key);
3646 msi_free(deformated_value);
3647 msi_free(deformated_section);
3648 return ERROR_SUCCESS;
3651 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3655 static const WCHAR ExecSeqQuery[] =
3656 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3657 '`','I','n','i','F','i','l','e','`',0};
3659 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3660 if (rc != ERROR_SUCCESS)
3662 TRACE("no IniFile table\n");
3663 return ERROR_SUCCESS;
3666 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3667 msiobj_release(&view->hdr);
3671 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3673 MSIPACKAGE *package = (MSIPACKAGE*)param;
3678 static const WCHAR ExeStr[] =
3679 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3680 static const WCHAR close[] = {'\"',0};
3682 PROCESS_INFORMATION info;
3687 memset(&si,0,sizeof(STARTUPINFOW));
3689 filename = MSI_RecordGetString(row,1);
3690 file = get_loaded_file( package, filename );
3694 ERR("Unable to find file id %s\n",debugstr_w(filename));
3695 return ERROR_SUCCESS;
3698 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3700 FullName = msi_alloc(len*sizeof(WCHAR));
3701 strcpyW(FullName,ExeStr);
3702 strcatW( FullName, file->TargetPath );
3703 strcatW(FullName,close);
3705 TRACE("Registering %s\n",debugstr_w(FullName));
3706 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3710 msi_dialog_check_messages(info.hProcess);
3715 uirow = MSI_CreateRecord( 2 );
3716 uipath = strdupW( file->TargetPath );
3717 p = strrchrW(uipath,'\\');
3720 MSI_RecordSetStringW( uirow, 1, &p[1] );
3721 MSI_RecordSetStringW( uirow, 2, uipath);
3722 ui_actiondata( package, szSelfRegModules, uirow);
3723 msiobj_release( &uirow->hdr );
3725 /* FIXME: call ui_progress? */
3727 return ERROR_SUCCESS;
3730 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3734 static const WCHAR ExecSeqQuery[] =
3735 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3736 '`','S','e','l','f','R','e','g','`',0};
3738 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3739 if (rc != ERROR_SUCCESS)
3741 TRACE("no SelfReg table\n");
3742 return ERROR_SUCCESS;
3745 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3746 msiobj_release(&view->hdr);
3748 return ERROR_SUCCESS;
3751 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3753 MSIFEATURE *feature;
3758 if (!msi_check_publish(package))
3759 return ERROR_SUCCESS;
3761 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3763 rc = MSIREG_OpenLocalClassesFeaturesKey(package->ProductCode,
3765 if (rc != ERROR_SUCCESS)
3768 rc = MSIREG_OpenLocalUserDataFeaturesKey(package->ProductCode,
3770 if (rc != ERROR_SUCCESS)
3775 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode, &hkey, TRUE);
3776 if (rc != ERROR_SUCCESS)
3779 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode,
3781 if (rc != ERROR_SUCCESS)
3785 /* here the guids are base 85 encoded */
3786 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3792 BOOL absent = FALSE;
3795 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3796 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3797 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3801 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3805 if (feature->Feature_Parent)
3806 size += strlenW( feature->Feature_Parent )+2;
3808 data = msi_alloc(size * sizeof(WCHAR));
3811 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3813 MSICOMPONENT* component = cl->component;
3817 if (component->ComponentId)
3819 TRACE("From %s\n",debugstr_w(component->ComponentId));
3820 CLSIDFromString(component->ComponentId, &clsid);
3821 encode_base85_guid(&clsid,buf);
3822 TRACE("to %s\n",debugstr_w(buf));
3827 if (feature->Feature_Parent)
3829 static const WCHAR sep[] = {'\2',0};
3831 strcatW(data,feature->Feature_Parent);
3834 msi_reg_set_val_str( userdata, feature->Feature, data );
3838 if (feature->Feature_Parent)
3839 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3842 static const WCHAR emptyW[] = {0};
3843 size += sizeof(WCHAR);
3844 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3845 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : emptyW),size);
3849 size += 2*sizeof(WCHAR);
3850 data = msi_alloc(size);
3853 if (feature->Feature_Parent)
3854 strcpyW( &data[1], feature->Feature_Parent );
3855 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3861 uirow = MSI_CreateRecord( 1 );
3862 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3863 ui_actiondata( package, szPublishFeatures, uirow);
3864 msiobj_release( &uirow->hdr );
3865 /* FIXME: call ui_progress? */
3870 RegCloseKey(userdata);
3874 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
3879 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
3881 r = MSIREG_OpenUserFeaturesKey(package->ProductCode, &hkey, FALSE);
3882 if (r == ERROR_SUCCESS)
3884 RegDeleteValueW(hkey, feature->Feature);
3888 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, &hkey, FALSE);
3889 if (r == ERROR_SUCCESS)
3891 RegDeleteValueW(hkey, feature->Feature);
3895 return ERROR_SUCCESS;
3898 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3900 MSIFEATURE *feature;
3902 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3904 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3911 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
3913 MSIFEATURE *feature;
3915 if (!msi_check_unpublish(package))
3916 return ERROR_SUCCESS;
3918 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3920 msi_unpublish_feature(package, feature);
3923 return ERROR_SUCCESS;
3926 static UINT msi_get_local_package_name( LPWSTR path )
3928 static const WCHAR szInstaller[] = {
3929 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3930 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3934 time = GetTickCount();
3935 GetWindowsDirectoryW( path, MAX_PATH );
3936 lstrcatW( path, szInstaller );
3937 CreateDirectoryW( path, NULL );
3939 len = lstrlenW(path);
3940 for (i=0; i<0x10000; i++)
3942 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3943 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3944 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3945 if (handle != INVALID_HANDLE_VALUE)
3947 CloseHandle(handle);
3950 if (GetLastError() != ERROR_FILE_EXISTS &&
3951 GetLastError() != ERROR_SHARING_VIOLATION)
3952 return ERROR_FUNCTION_FAILED;
3955 return ERROR_SUCCESS;
3958 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3960 WCHAR packagefile[MAX_PATH];
3963 r = msi_get_local_package_name( packagefile );
3964 if (r != ERROR_SUCCESS)
3967 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3969 r = CopyFileW( package->db->path, packagefile, FALSE);
3973 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3974 debugstr_w(package->db->path), debugstr_w(packagefile), GetLastError());
3975 return ERROR_FUNCTION_FAILED;
3978 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3980 return ERROR_SUCCESS;
3983 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
3985 LPWSTR prop, val, key;
3991 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
3992 static const WCHAR szWindowsInstaller[] =
3993 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3994 static const WCHAR modpath_fmt[] =
3995 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3996 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3997 static const WCHAR szModifyPath[] =
3998 {'M','o','d','i','f','y','P','a','t','h',0};
3999 static const WCHAR szUninstallString[] =
4000 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4001 static const WCHAR szEstimatedSize[] =
4002 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4003 static const WCHAR szProductLanguage[] =
4004 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4005 static const WCHAR szProductVersion[] =
4006 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4007 static const WCHAR szProductName[] =
4008 {'P','r','o','d','u','c','t','N','a','m','e',0};
4009 static const WCHAR szDisplayName[] =
4010 {'D','i','s','p','l','a','y','N','a','m','e',0};
4011 static const WCHAR szDisplayVersion[] =
4012 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4013 static const WCHAR szManufacturer[] =
4014 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4016 static const LPCSTR propval[] = {
4017 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4018 "ARPCONTACT", "Contact",
4019 "ARPCOMMENTS", "Comments",
4020 "ProductName", "DisplayName",
4021 "ProductVersion", "DisplayVersion",
4022 "ARPHELPLINK", "HelpLink",
4023 "ARPHELPTELEPHONE", "HelpTelephone",
4024 "ARPINSTALLLOCATION", "InstallLocation",
4025 "SourceDir", "InstallSource",
4026 "Manufacturer", "Publisher",
4027 "ARPREADME", "Readme",
4029 "ARPURLINFOABOUT", "URLInfoAbout",
4030 "ARPURLUPDATEINFO", "URLUpdateInfo",
4033 const LPCSTR *p = propval;
4037 prop = strdupAtoW(*p++);
4038 key = strdupAtoW(*p++);
4039 val = msi_dup_property(package, prop);
4040 msi_reg_set_val_str(hkey, key, val);
4046 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4048 size = deformat_string(package, modpath_fmt, &buffer);
4049 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4050 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4053 /* FIXME: Write real Estimated Size when we have it */
4054 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4056 buffer = msi_dup_property(package, szProductName);
4057 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4060 buffer = msi_dup_property(package, cszSourceDir);
4061 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4064 buffer = msi_dup_property(package, szManufacturer);
4065 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4068 GetLocalTime(&systime);
4069 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4070 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4072 langid = msi_get_property_int(package, szProductLanguage, 0);
4073 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4075 buffer = msi_dup_property(package, szProductVersion);
4076 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4079 DWORD verdword = msi_version_str_to_dword(buffer);
4081 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4082 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4083 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4087 return ERROR_SUCCESS;
4090 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4092 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4093 LPWSTR upgrade_code;
4098 static const WCHAR szUpgradeCode[] = {
4099 'U','p','g','r','a','d','e','C','o','d','e',0};
4101 /* FIXME: also need to publish if the product is in advertise mode */
4102 if (!msi_check_publish(package))
4103 return ERROR_SUCCESS;
4105 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4106 if (rc != ERROR_SUCCESS)
4109 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4111 rc = MSIREG_OpenLocalSystemInstallProps(package->ProductCode, &props, TRUE);
4112 if (rc != ERROR_SUCCESS)
4117 rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &props, TRUE);
4118 if (rc != ERROR_SUCCESS)
4122 msi_make_package_local(package, props);
4124 rc = msi_publish_install_properties(package, hkey);
4125 if (rc != ERROR_SUCCESS)
4128 rc = msi_publish_install_properties(package, props);
4129 if (rc != ERROR_SUCCESS)
4132 upgrade_code = msi_dup_property(package, szUpgradeCode);
4135 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4136 squash_guid(package->ProductCode, squashed_pc);
4137 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4138 RegCloseKey(upgrade);
4139 msi_free(upgrade_code);
4145 return ERROR_SUCCESS;
4148 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4150 return execute_script(package,INSTALL_SCRIPT);
4153 static UINT msi_unpublish_product(MSIPACKAGE *package)
4155 LPWSTR remove = NULL;
4156 LPWSTR *features = NULL;
4157 BOOL full_uninstall = TRUE;
4158 MSIFEATURE *feature;
4160 static const WCHAR szRemove[] = {'R','E','M','O','V','E',0};
4161 static const WCHAR szAll[] = {'A','L','L',0};
4163 remove = msi_dup_property(package, szRemove);
4165 return ERROR_SUCCESS;
4167 features = msi_split_string(remove, ',');
4171 ERR("REMOVE feature list is empty!\n");
4172 return ERROR_FUNCTION_FAILED;
4175 if (!lstrcmpW(features[0], szAll))
4176 full_uninstall = TRUE;
4179 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4181 if (feature->Action != INSTALLSTATE_ABSENT)
4182 full_uninstall = FALSE;
4186 if (!full_uninstall)
4189 MSIREG_DeleteProductKey(package->ProductCode);
4190 MSIREG_DeleteUserProductKey(package->ProductCode);
4191 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4192 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4193 MSIREG_DeleteUninstallKey(package->ProductCode);
4198 return ERROR_SUCCESS;
4201 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4205 rc = msi_unpublish_product(package);
4206 if (rc != ERROR_SUCCESS)
4209 /* turn off scheduling */
4210 package->script->CurrentlyScripting= FALSE;
4212 /* first do the same as an InstallExecute */
4213 rc = ACTION_InstallExecute(package);
4214 if (rc != ERROR_SUCCESS)
4217 /* then handle Commit Actions */
4218 rc = execute_script(package,COMMIT_SCRIPT);
4223 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4225 static const WCHAR RunOnce[] = {
4226 'S','o','f','t','w','a','r','e','\\',
4227 'M','i','c','r','o','s','o','f','t','\\',
4228 'W','i','n','d','o','w','s','\\',
4229 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4230 'R','u','n','O','n','c','e',0};
4231 static const WCHAR InstallRunOnce[] = {
4232 'S','o','f','t','w','a','r','e','\\',
4233 'M','i','c','r','o','s','o','f','t','\\',
4234 'W','i','n','d','o','w','s','\\',
4235 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4236 'I','n','s','t','a','l','l','e','r','\\',
4237 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4239 static const WCHAR msiexec_fmt[] = {
4241 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4242 '\"','%','s','\"',0};
4243 static const WCHAR install_fmt[] = {
4244 '/','I',' ','\"','%','s','\"',' ',
4245 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4246 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4247 WCHAR buffer[256], sysdir[MAX_PATH];
4249 WCHAR squished_pc[100];
4251 squash_guid(package->ProductCode,squished_pc);
4253 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4254 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4255 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4258 msi_reg_set_val_str( hkey, squished_pc, buffer );
4261 TRACE("Reboot command %s\n",debugstr_w(buffer));
4263 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4264 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4266 msi_reg_set_val_str( hkey, squished_pc, buffer );
4269 return ERROR_INSTALL_SUSPEND;
4272 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4278 * We are currently doing what should be done here in the top level Install
4279 * however for Administrative and uninstalls this step will be needed
4281 if (!package->PackagePath)
4282 return ERROR_SUCCESS;
4284 msi_set_sourcedir_props(package, TRUE);
4286 attrib = GetFileAttributesW(package->db->path);
4287 if (attrib == INVALID_FILE_ATTRIBUTES)
4293 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4294 package->Context, MSICODE_PRODUCT,
4295 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4296 if (rc == ERROR_MORE_DATA)
4298 prompt = msi_alloc(size * sizeof(WCHAR));
4299 MsiSourceListGetInfoW(package->ProductCode, NULL,
4300 package->Context, MSICODE_PRODUCT,
4301 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4304 prompt = strdupW(package->db->path);
4306 msg = generate_error_string(package,1302,1,prompt);
4307 while(attrib == INVALID_FILE_ATTRIBUTES)
4309 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4312 rc = ERROR_INSTALL_USEREXIT;
4315 attrib = GetFileAttributesW(package->db->path);
4321 return ERROR_SUCCESS;
4326 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4333 static const WCHAR szPropKeys[][80] =
4335 {'P','r','o','d','u','c','t','I','D',0},
4336 {'U','S','E','R','N','A','M','E',0},
4337 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4341 static const WCHAR szRegKeys[][80] =
4343 {'P','r','o','d','u','c','t','I','D',0},
4344 {'R','e','g','O','w','n','e','r',0},
4345 {'R','e','g','C','o','m','p','a','n','y',0},
4349 if (msi_check_unpublish(package))
4351 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4352 return ERROR_SUCCESS;
4355 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4357 return ERROR_SUCCESS;
4359 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4360 rc = MSIREG_OpenLocalSystemInstallProps(package->ProductCode, &hkey, TRUE);
4362 rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &hkey, TRUE);
4364 if (rc != ERROR_SUCCESS)
4367 for( i = 0; szPropKeys[i][0]; i++ )
4369 buffer = msi_dup_property( package, szPropKeys[i] );
4370 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4375 msi_free(productid);
4378 /* FIXME: call ui_actiondata */
4384 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4388 package->script->InWhatSequence |= SEQUENCE_EXEC;
4389 rc = ACTION_ProcessExecSequence(package,FALSE);
4394 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4396 MSIPACKAGE *package = (MSIPACKAGE*)param;
4397 LPCWSTR compgroupid=NULL;
4398 LPCWSTR feature=NULL;
4399 LPCWSTR text = NULL;
4400 LPCWSTR qualifier = NULL;
4401 LPCWSTR component = NULL;
4402 LPWSTR advertise = NULL;
4403 LPWSTR output = NULL;
4405 UINT rc = ERROR_SUCCESS;
4410 component = MSI_RecordGetString(rec,3);
4411 comp = get_loaded_component(package,component);
4413 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4414 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4415 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4417 TRACE("Skipping: Component %s not scheduled for install\n",
4418 debugstr_w(component));
4420 return ERROR_SUCCESS;
4423 compgroupid = MSI_RecordGetString(rec,1);
4424 qualifier = MSI_RecordGetString(rec,2);
4426 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4427 if (rc != ERROR_SUCCESS)
4430 text = MSI_RecordGetString(rec,4);
4431 feature = MSI_RecordGetString(rec,5);
4433 advertise = create_component_advertise_string(package, comp, feature);
4435 sz = strlenW(advertise);
4438 sz += lstrlenW(text);
4441 sz *= sizeof(WCHAR);
4443 output = msi_alloc_zero(sz);
4444 strcpyW(output,advertise);
4445 msi_free(advertise);
4448 strcatW(output,text);
4450 msi_reg_set_val_multi_str( hkey, qualifier, output );
4457 uirow = MSI_CreateRecord( 2 );
4458 MSI_RecordSetStringW( uirow, 1, compgroupid );
4459 MSI_RecordSetStringW( uirow, 2, qualifier);
4460 ui_actiondata( package, szPublishComponents, uirow);
4461 msiobj_release( &uirow->hdr );
4462 /* FIXME: call ui_progress? */
4468 * At present I am ignorning the advertised components part of this and only
4469 * focusing on the qualified component sets
4471 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4475 static const WCHAR ExecSeqQuery[] =
4476 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4477 '`','P','u','b','l','i','s','h',
4478 'C','o','m','p','o','n','e','n','t','`',0};
4480 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4481 if (rc != ERROR_SUCCESS)
4482 return ERROR_SUCCESS;
4484 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4485 msiobj_release(&view->hdr);
4490 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4492 MSIPACKAGE *package = (MSIPACKAGE*)param;
4495 SC_HANDLE hscm, service = NULL;
4496 LPCWSTR comp, depends, pass;
4497 LPWSTR name = NULL, disp = NULL;
4498 LPCWSTR load_order, serv_name, key;
4499 DWORD serv_type, start_type;
4502 static const WCHAR query[] =
4503 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4504 '`','C','o','m','p','o','n','e','n','t','`',' ',
4505 'W','H','E','R','E',' ',
4506 '`','C','o','m','p','o','n','e','n','t','`',' ',
4507 '=','\'','%','s','\'',0};
4509 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4512 ERR("Failed to open the SC Manager!\n");
4516 start_type = MSI_RecordGetInteger(rec, 5);
4517 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4520 depends = MSI_RecordGetString(rec, 8);
4521 if (depends && *depends)
4522 FIXME("Dependency list unhandled!\n");
4524 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4525 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
4526 serv_type = MSI_RecordGetInteger(rec, 4);
4527 err_control = MSI_RecordGetInteger(rec, 6);
4528 load_order = MSI_RecordGetString(rec, 7);
4529 serv_name = MSI_RecordGetString(rec, 9);
4530 pass = MSI_RecordGetString(rec, 10);
4531 comp = MSI_RecordGetString(rec, 12);
4533 /* fetch the service path */
4534 row = MSI_QueryGetRecord(package->db, query, comp);
4537 ERR("Control query failed!\n");
4541 key = MSI_RecordGetString(row, 6);
4543 file = get_loaded_file(package, key);
4544 msiobj_release(&row->hdr);
4547 ERR("Failed to load the service file\n");
4551 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4552 start_type, err_control, file->TargetPath,
4553 load_order, NULL, NULL, serv_name, pass);
4556 if (GetLastError() != ERROR_SERVICE_EXISTS)
4557 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4561 CloseServiceHandle(service);
4562 CloseServiceHandle(hscm);
4566 return ERROR_SUCCESS;
4569 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4573 static const WCHAR ExecSeqQuery[] =
4574 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4575 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4577 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4578 if (rc != ERROR_SUCCESS)
4579 return ERROR_SUCCESS;
4581 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4582 msiobj_release(&view->hdr);
4587 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4588 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
4590 LPCWSTR *vector, *temp_vector;
4594 static const WCHAR separator[] = {'[','~',']',0};
4597 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4602 vector = msi_alloc(sizeof(LPWSTR));
4610 vector[*numargs - 1] = p;
4612 if ((q = strstrW(p, separator)))
4616 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4622 vector = temp_vector;
4631 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4633 MSIPACKAGE *package = (MSIPACKAGE *)param;
4635 SC_HANDLE scm, service = NULL;
4636 LPCWSTR name, *vector = NULL;
4638 DWORD event, numargs;
4639 UINT r = ERROR_FUNCTION_FAILED;
4641 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4642 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4643 return ERROR_SUCCESS;
4645 name = MSI_RecordGetString(rec, 2);
4646 event = MSI_RecordGetInteger(rec, 3);
4647 args = strdupW(MSI_RecordGetString(rec, 4));
4649 if (!(event & msidbServiceControlEventStart))
4650 return ERROR_SUCCESS;
4652 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4655 ERR("Failed to open the service control manager\n");
4659 service = OpenServiceW(scm, name, SERVICE_START);
4662 ERR("Failed to open service %s\n", debugstr_w(name));
4666 vector = msi_service_args_to_vector(args, &numargs);
4668 if (!StartServiceW(service, numargs, vector))
4670 ERR("Failed to start service %s\n", debugstr_w(name));
4677 CloseServiceHandle(service);
4678 CloseServiceHandle(scm);
4685 static UINT ACTION_StartServices( MSIPACKAGE *package )
4690 static const WCHAR query[] = {
4691 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4692 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4694 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4695 if (rc != ERROR_SUCCESS)
4696 return ERROR_SUCCESS;
4698 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4699 msiobj_release(&view->hdr);
4704 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4706 DWORD i, needed, count;
4707 ENUM_SERVICE_STATUSW *dependencies;
4711 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4712 0, &needed, &count))
4715 if (GetLastError() != ERROR_MORE_DATA)
4718 dependencies = msi_alloc(needed);
4722 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4723 needed, &needed, &count))
4726 for (i = 0; i < count; i++)
4728 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4729 SERVICE_STOP | SERVICE_QUERY_STATUS);
4733 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4740 msi_free(dependencies);
4744 static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
4746 MSIPACKAGE *package = (MSIPACKAGE *)param;
4748 SERVICE_STATUS status;
4749 SERVICE_STATUS_PROCESS ssp;
4750 SC_HANDLE scm = NULL, service = NULL;
4752 DWORD event, needed;
4754 event = MSI_RecordGetInteger(rec, 3);
4755 if (!(event & msidbServiceControlEventStop))
4756 return ERROR_SUCCESS;
4758 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4759 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4760 return ERROR_SUCCESS;
4762 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4763 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4764 args = strdupW(MSI_RecordGetString(rec, 4));
4766 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4769 WARN("Failed to open the SCM: %d\n", GetLastError());
4773 service = OpenServiceW(scm, name,
4775 SERVICE_QUERY_STATUS |
4776 SERVICE_ENUMERATE_DEPENDENTS);
4779 WARN("Failed to open service (%s): %d\n",
4780 debugstr_w(name), GetLastError());
4784 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4785 sizeof(SERVICE_STATUS_PROCESS), &needed))
4787 WARN("Failed to query service status (%s): %d\n",
4788 debugstr_w(name), GetLastError());
4792 if (ssp.dwCurrentState == SERVICE_STOPPED)
4795 stop_service_dependents(scm, service);
4797 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
4798 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
4801 CloseServiceHandle(service);
4802 CloseServiceHandle(scm);
4806 return ERROR_SUCCESS;
4809 static UINT ACTION_StopServices( MSIPACKAGE *package )
4814 static const WCHAR query[] = {
4815 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4816 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4818 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4819 if (rc != ERROR_SUCCESS)
4820 return ERROR_SUCCESS;
4822 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
4823 msiobj_release(&view->hdr);
4828 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4832 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4834 if (!lstrcmpW(file->File, filename))
4841 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4843 MSIPACKAGE *package = (MSIPACKAGE*)param;
4844 LPWSTR driver, driver_path, ptr;
4845 WCHAR outpath[MAX_PATH];
4846 MSIFILE *driver_file, *setup_file;
4849 UINT r = ERROR_SUCCESS;
4851 static const WCHAR driver_fmt[] = {
4852 'D','r','i','v','e','r','=','%','s',0};
4853 static const WCHAR setup_fmt[] = {
4854 'S','e','t','u','p','=','%','s',0};
4855 static const WCHAR usage_fmt[] = {
4856 'F','i','l','e','U','s','a','g','e','=','1',0};
4858 desc = MSI_RecordGetString(rec, 3);
4860 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4861 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4863 if (!driver_file || !setup_file)
4865 ERR("ODBC Driver entry not found!\n");
4866 return ERROR_FUNCTION_FAILED;
4869 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4870 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4871 lstrlenW(usage_fmt) + 1;
4872 driver = msi_alloc(len * sizeof(WCHAR));
4874 return ERROR_OUTOFMEMORY;
4877 lstrcpyW(ptr, desc);
4878 ptr += lstrlenW(ptr) + 1;
4880 sprintfW(ptr, driver_fmt, driver_file->FileName);
4881 ptr += lstrlenW(ptr) + 1;
4883 sprintfW(ptr, setup_fmt, setup_file->FileName);
4884 ptr += lstrlenW(ptr) + 1;
4886 lstrcpyW(ptr, usage_fmt);
4887 ptr += lstrlenW(ptr) + 1;
4890 driver_path = strdupW(driver_file->TargetPath);
4891 ptr = strrchrW(driver_path, '\\');
4892 if (ptr) *ptr = '\0';
4894 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4895 NULL, ODBC_INSTALL_COMPLETE, &usage))
4897 ERR("Failed to install SQL driver!\n");
4898 r = ERROR_FUNCTION_FAILED;
4902 msi_free(driver_path);
4907 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4909 MSIPACKAGE *package = (MSIPACKAGE*)param;
4910 LPWSTR translator, translator_path, ptr;
4911 WCHAR outpath[MAX_PATH];
4912 MSIFILE *translator_file, *setup_file;
4915 UINT r = ERROR_SUCCESS;
4917 static const WCHAR translator_fmt[] = {
4918 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4919 static const WCHAR setup_fmt[] = {
4920 'S','e','t','u','p','=','%','s',0};
4922 desc = MSI_RecordGetString(rec, 3);
4924 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4925 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4927 if (!translator_file || !setup_file)
4929 ERR("ODBC Translator entry not found!\n");
4930 return ERROR_FUNCTION_FAILED;
4933 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
4934 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
4935 translator = msi_alloc(len * sizeof(WCHAR));
4937 return ERROR_OUTOFMEMORY;
4940 lstrcpyW(ptr, desc);
4941 ptr += lstrlenW(ptr) + 1;
4943 sprintfW(ptr, translator_fmt, translator_file->FileName);
4944 ptr += lstrlenW(ptr) + 1;
4946 sprintfW(ptr, setup_fmt, setup_file->FileName);
4947 ptr += lstrlenW(ptr) + 1;
4950 translator_path = strdupW(translator_file->TargetPath);
4951 ptr = strrchrW(translator_path, '\\');
4952 if (ptr) *ptr = '\0';
4954 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
4955 NULL, ODBC_INSTALL_COMPLETE, &usage))
4957 ERR("Failed to install SQL translator!\n");
4958 r = ERROR_FUNCTION_FAILED;
4961 msi_free(translator);
4962 msi_free(translator_path);
4967 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
4970 LPCWSTR desc, driver;
4971 WORD request = ODBC_ADD_SYS_DSN;
4974 UINT r = ERROR_SUCCESS;
4976 static const WCHAR attrs_fmt[] = {
4977 'D','S','N','=','%','s',0 };
4979 desc = MSI_RecordGetString(rec, 3);
4980 driver = MSI_RecordGetString(rec, 4);
4981 registration = MSI_RecordGetInteger(rec, 5);
4983 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
4984 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
4986 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
4987 attrs = msi_alloc(len * sizeof(WCHAR));
4989 return ERROR_OUTOFMEMORY;
4991 sprintfW(attrs, attrs_fmt, desc);
4992 attrs[len - 1] = '\0';
4994 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
4996 ERR("Failed to install SQL data source!\n");
4997 r = ERROR_FUNCTION_FAILED;
5005 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5010 static const WCHAR driver_query[] = {
5011 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5012 'O','D','B','C','D','r','i','v','e','r',0 };
5014 static const WCHAR translator_query[] = {
5015 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5016 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5018 static const WCHAR source_query[] = {
5019 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5020 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5022 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5023 if (rc != ERROR_SUCCESS)
5024 return ERROR_SUCCESS;
5026 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5027 msiobj_release(&view->hdr);
5029 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5030 if (rc != ERROR_SUCCESS)
5031 return ERROR_SUCCESS;
5033 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5034 msiobj_release(&view->hdr);
5036 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5037 if (rc != ERROR_SUCCESS)
5038 return ERROR_SUCCESS;
5040 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5041 msiobj_release(&view->hdr);
5046 #define ENV_ACT_SETALWAYS 0x1
5047 #define ENV_ACT_SETABSENT 0x2
5048 #define ENV_ACT_REMOVE 0x4
5049 #define ENV_ACT_REMOVEMATCH 0x8
5051 #define ENV_MOD_MACHINE 0x20000000
5052 #define ENV_MOD_APPEND 0x40000000
5053 #define ENV_MOD_PREFIX 0x80000000
5054 #define ENV_MOD_MASK 0xC0000000
5056 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5058 static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5060 LPCWSTR cptr = *name;
5061 LPCWSTR ptr = *value;
5063 static const WCHAR prefix[] = {'[','~',']',0};
5064 static const int prefix_len = 3;
5070 *flags |= ENV_ACT_SETALWAYS;
5071 else if (*cptr == '+')
5072 *flags |= ENV_ACT_SETABSENT;
5073 else if (*cptr == '-')
5074 *flags |= ENV_ACT_REMOVE;
5075 else if (*cptr == '!')
5076 *flags |= ENV_ACT_REMOVEMATCH;
5077 else if (*cptr == '*')
5078 *flags |= ENV_MOD_MACHINE;
5088 ERR("Missing environment variable\n");
5089 return ERROR_FUNCTION_FAILED;
5092 if (!strncmpW(ptr, prefix, prefix_len))
5094 *flags |= ENV_MOD_APPEND;
5095 *value += lstrlenW(prefix);
5097 else if (lstrlenW(*value) >= prefix_len)
5099 ptr += lstrlenW(ptr) - prefix_len;
5100 if (!lstrcmpW(ptr, prefix))
5102 *flags |= ENV_MOD_PREFIX;
5103 /* the "[~]" will be removed by deformat_string */;
5108 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5109 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5110 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5111 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5113 ERR("Invalid flags: %08x\n", *flags);
5114 return ERROR_FUNCTION_FAILED;
5117 return ERROR_SUCCESS;
5120 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5122 MSIPACKAGE *package = param;
5123 LPCWSTR name, value;
5124 LPWSTR data = NULL, newval = NULL;
5125 LPWSTR deformatted = NULL, ptr;
5126 DWORD flags, type, size;
5128 HKEY env = NULL, root;
5129 LPCWSTR environment;
5131 static const WCHAR user_env[] =
5132 {'E','n','v','i','r','o','n','m','e','n','t',0};
5133 static const WCHAR machine_env[] =
5134 {'S','y','s','t','e','m','\\',
5135 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5136 'C','o','n','t','r','o','l','\\',
5137 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5138 'E','n','v','i','r','o','n','m','e','n','t',0};
5139 static const WCHAR semicolon[] = {';',0};
5141 name = MSI_RecordGetString(rec, 2);
5142 value = MSI_RecordGetString(rec, 3);
5144 res = env_set_flags(&name, &value, &flags);
5145 if (res != ERROR_SUCCESS)
5148 deformat_string(package, value, &deformatted);
5151 res = ERROR_OUTOFMEMORY;
5155 value = deformatted;
5157 if (flags & ENV_MOD_MACHINE)
5159 environment = machine_env;
5160 root = HKEY_LOCAL_MACHINE;
5164 environment = user_env;
5165 root = HKEY_CURRENT_USER;
5168 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5169 KEY_ALL_ACCESS, NULL, &env, NULL);
5170 if (res != ERROR_SUCCESS)
5173 if (flags & ENV_ACT_REMOVE)
5174 FIXME("Not removing environment variable on uninstall!\n");
5177 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5178 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
5179 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
5182 if (res != ERROR_FILE_NOT_FOUND)
5184 if (flags & ENV_ACT_SETABSENT)
5186 res = ERROR_SUCCESS;
5190 data = msi_alloc(size);
5194 return ERROR_OUTOFMEMORY;
5197 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5198 if (res != ERROR_SUCCESS)
5201 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5203 res = RegDeleteKeyW(env, name);
5207 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
5208 newval = msi_alloc(size);
5212 res = ERROR_OUTOFMEMORY;
5216 if (!(flags & ENV_MOD_MASK))
5217 lstrcpyW(newval, value);
5220 if (flags & ENV_MOD_PREFIX)
5222 lstrcpyW(newval, value);
5223 lstrcatW(newval, semicolon);
5224 ptr = newval + lstrlenW(value) + 1;
5227 lstrcpyW(ptr, data);
5229 if (flags & ENV_MOD_APPEND)
5231 lstrcatW(newval, semicolon);
5232 lstrcatW(newval, value);
5238 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
5239 newval = msi_alloc(size);
5242 res = ERROR_OUTOFMEMORY;
5246 lstrcpyW(newval, value);
5249 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5250 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
5253 if (env) RegCloseKey(env);
5254 msi_free(deformatted);
5260 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5264 static const WCHAR ExecSeqQuery[] =
5265 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5266 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5267 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5268 if (rc != ERROR_SUCCESS)
5269 return ERROR_SUCCESS;
5271 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5272 msiobj_release(&view->hdr);
5277 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5288 static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5292 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5293 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5295 WARN("Source or dest is directory, not moving\n");
5299 if (options == msidbMoveFileOptionsMove)
5301 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5302 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5305 WARN("MoveFile failed: %d\n", GetLastError());
5311 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5312 ret = CopyFileW(source, dest, FALSE);
5315 WARN("CopyFile failed: %d\n", GetLastError());
5323 static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5326 DWORD dirlen, pathlen;
5328 ptr = strrchrW(wildcard, '\\');
5329 dirlen = ptr - wildcard + 1;
5331 pathlen = dirlen + lstrlenW(filename) + 1;
5332 path = msi_alloc(pathlen * sizeof(WCHAR));
5334 lstrcpynW(path, wildcard, dirlen + 1);
5335 lstrcatW(path, filename);
5340 static void free_file_entry(FILE_LIST *file)
5342 msi_free(file->source);
5343 msi_free(file->dest);
5347 static void free_list(FILE_LIST *list)
5349 while (!list_empty(&list->entry))
5351 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5353 list_remove(&file->entry);
5354 free_file_entry(file);
5358 static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5360 FILE_LIST *new, *file;
5361 LPWSTR ptr, filename;
5364 new = msi_alloc_zero(sizeof(FILE_LIST));
5368 new->source = strdupW(source);
5369 ptr = strrchrW(dest, '\\') + 1;
5370 filename = strrchrW(new->source, '\\') + 1;
5372 new->sourcename = filename;
5375 new->destname = ptr;
5377 new->destname = new->sourcename;
5379 size = (ptr - dest) + lstrlenW(filename) + 1;
5380 new->dest = msi_alloc(size * sizeof(WCHAR));
5383 free_file_entry(new);
5387 lstrcpynW(new->dest, dest, ptr - dest + 1);
5388 lstrcatW(new->dest, filename);
5390 if (list_empty(&files->entry))
5392 list_add_head(&files->entry, &new->entry);
5396 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5398 if (lstrcmpW(source, file->source) < 0)
5400 list_add_before(&file->entry, &new->entry);
5405 list_add_after(&file->entry, &new->entry);
5409 static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
5411 WIN32_FIND_DATAW wfd;
5415 FILE_LIST files, *file;
5418 hfile = FindFirstFileW(source, &wfd);
5419 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5421 list_init(&files.entry);
5423 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5425 if (is_dot_dir(wfd.cFileName)) continue;
5427 path = wildcard_to_file(source, wfd.cFileName);
5434 add_wildcard(&files, path, dest);
5438 /* no files match the wildcard */
5439 if (list_empty(&files.entry))
5442 /* only the first wildcard match gets renamed to dest */
5443 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5444 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5445 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5452 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5454 while (!list_empty(&files.entry))
5456 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5458 msi_move_file((LPCWSTR)file->source, (LPCWSTR)file->dest, options);
5460 list_remove(&file->entry);
5461 free_file_entry(file);
5472 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5474 MSIPACKAGE *package = param;
5476 LPCWSTR sourcename, destname;
5477 LPWSTR sourcedir = NULL, destdir = NULL;
5478 LPWSTR source = NULL, dest = NULL;
5481 BOOL ret, wildcards;
5483 static const WCHAR backslash[] = {'\\',0};
5485 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5486 if (!comp || !comp->Enabled ||
5487 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5489 TRACE("Component not set for install, not moving file\n");
5490 return ERROR_SUCCESS;
5493 sourcename = MSI_RecordGetString(rec, 3);
5494 destname = MSI_RecordGetString(rec, 4);
5495 options = MSI_RecordGetInteger(rec, 7);
5497 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5501 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5507 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5510 source = strdupW(sourcedir);
5516 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5517 source = msi_alloc(size * sizeof(WCHAR));
5521 lstrcpyW(source, sourcedir);
5522 if (source[lstrlenW(source) - 1] != '\\')
5523 lstrcatW(source, backslash);
5524 lstrcatW(source, sourcename);
5527 wildcards = strchrW(source, '*') || strchrW(source, '?');
5529 if (!destname && !wildcards)
5531 destname = strdupW(sourcename);
5538 size = lstrlenW(destname);
5540 size += lstrlenW(destdir) + 2;
5541 dest = msi_alloc(size * sizeof(WCHAR));
5545 lstrcpyW(dest, destdir);
5546 if (dest[lstrlenW(dest) - 1] != '\\')
5547 lstrcatW(dest, backslash);
5550 lstrcatW(dest, destname);
5552 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5554 ret = CreateDirectoryW(destdir, NULL);
5557 WARN("CreateDirectory failed: %d\n", GetLastError());
5558 return ERROR_SUCCESS;
5563 msi_move_file(source, dest, options);
5565 move_files_wildcard(source, dest, options);
5568 msi_free(sourcedir);
5573 return ERROR_SUCCESS;
5576 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5581 static const WCHAR ExecSeqQuery[] =
5582 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5583 '`','M','o','v','e','F','i','l','e','`',0};
5585 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5586 if (rc != ERROR_SUCCESS)
5587 return ERROR_SUCCESS;
5589 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5590 msiobj_release(&view->hdr);
5595 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
5597 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
5598 LPVOID pvReserved, HMODULE *phModDll);
5600 static BOOL init_functionpointers(void)
5606 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
5608 hmscoree = LoadLibraryA("mscoree.dll");
5611 WARN("mscoree.dll not available\n");
5615 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
5616 if (!pLoadLibraryShim)
5618 WARN("LoadLibraryShim not available\n");
5619 FreeLibrary(hmscoree);
5623 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
5626 WARN("fusion.dll not available\n");
5627 FreeLibrary(hmscoree);
5631 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
5633 FreeLibrary(hmscoree);
5637 static UINT install_assembly(LPWSTR path)
5639 IAssemblyCache *cache;
5641 UINT r = ERROR_FUNCTION_FAILED;
5643 if (!init_functionpointers() || !pCreateAssemblyCache)
5644 return ERROR_FUNCTION_FAILED;
5646 hr = pCreateAssemblyCache(&cache, 0);
5650 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
5652 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
5657 IAssemblyCache_Release(cache);
5661 static UINT ITERATE_PublishAssembly( MSIRECORD *rec, LPVOID param )
5663 MSIPACKAGE *package = param;
5665 MSIFEATURE *feature;
5667 WCHAR path[MAX_PATH];
5672 comp = get_loaded_component(package, MSI_RecordGetString(rec, 1));
5673 if (!comp || !comp->Enabled ||
5674 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5676 ERR("Component not set for install, not publishing assembly\n");
5677 return ERROR_SUCCESS;
5680 feature = find_feature_by_name(package, MSI_RecordGetString(rec, 2));
5682 msi_feature_set_state(feature, INSTALLSTATE_LOCAL);
5684 if (MSI_RecordGetString(rec, 3))
5685 FIXME("Manifest unhandled\n");
5687 app = MSI_RecordGetString(rec, 4);
5690 FIXME("Assembly should be privately installed\n");
5691 return ERROR_SUCCESS;
5694 attr = MSI_RecordGetInteger(rec, 5);
5695 if (attr == msidbAssemblyAttributesWin32)
5697 FIXME("Win32 assemblies not handled\n");
5698 return ERROR_SUCCESS;
5701 /* FIXME: extract all files belonging to this component */
5702 file = msi_find_file(package, comp->KeyPath);
5705 ERR("File %s not found\n", debugstr_w(comp->KeyPath));
5706 return ERROR_FUNCTION_FAILED;
5709 GetTempPathW(MAX_PATH, path);
5711 if (file->IsCompressed)
5713 r = msi_extract_file(package, file, path);
5714 if (r != ERROR_SUCCESS)
5716 ERR("Failed to extract temporary assembly\n");
5720 PathAddBackslashW(path);
5721 lstrcatW(path, file->FileName);
5725 PathAddBackslashW(path);
5726 lstrcatW(path, file->FileName);
5728 if (!CopyFileW(file->SourcePath, path, FALSE))
5730 ERR("Failed to copy temporary assembly: %d\n", GetLastError());
5731 return ERROR_FUNCTION_FAILED;
5735 r = install_assembly(path);
5736 if (r != ERROR_SUCCESS)
5737 ERR("Failed to install assembly\n");
5739 /* FIXME: write Installer assembly reg values */
5744 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
5749 static const WCHAR ExecSeqQuery[] =
5750 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5751 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
5753 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5754 if (rc != ERROR_SUCCESS)
5755 return ERROR_SUCCESS;
5757 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishAssembly, package);
5758 msiobj_release(&view->hdr);
5763 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
5764 LPCSTR action, LPCWSTR table )
5766 static const WCHAR query[] = {
5767 'S','E','L','E','C','T',' ','*',' ',
5768 'F','R','O','M',' ','`','%','s','`',0 };
5769 MSIQUERY *view = NULL;
5773 r = MSI_OpenQuery( package->db, &view, query, table );
5774 if (r == ERROR_SUCCESS)
5776 r = MSI_IterateRecords(view, &count, NULL, package);
5777 msiobj_release(&view->hdr);
5781 FIXME("%s -> %u ignored %s table values\n",
5782 action, count, debugstr_w(table));
5784 return ERROR_SUCCESS;
5787 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
5789 TRACE("%p\n", package);
5790 return ERROR_SUCCESS;
5793 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
5795 static const WCHAR table[] =
5796 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
5797 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
5800 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
5802 static const WCHAR table[] = { 'P','a','t','c','h',0 };
5803 return msi_unimplemented_action_stub( package, "PatchFiles", table );
5806 static UINT ACTION_BindImage( MSIPACKAGE *package )
5808 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
5809 return msi_unimplemented_action_stub( package, "BindImage", table );
5812 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
5814 static const WCHAR table[] = {
5815 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
5816 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
5819 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
5821 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5822 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
5825 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
5827 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
5828 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
5831 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5833 static const WCHAR table[] = {
5834 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5835 return msi_unimplemented_action_stub( package, "DeleteServices", table );
5837 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
5839 static const WCHAR table[] = {
5840 'P','r','o','d','u','c','t','I','D',0 };
5841 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
5844 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
5846 static const WCHAR table[] = {
5847 'E','n','v','i','r','o','n','m','e','n','t',0 };
5848 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
5851 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
5853 static const WCHAR table[] = {
5854 'M','s','i','A','s','s','e','m','b','l','y',0 };
5855 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
5858 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
5860 static const WCHAR table[] = { 'F','o','n','t',0 };
5861 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
5864 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
5866 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
5867 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
5870 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
5872 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
5873 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
5876 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
5878 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
5879 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
5882 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
5884 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
5885 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
5888 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
5890 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
5891 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
5894 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
5896 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5897 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
5900 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
5902 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
5903 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
5906 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5908 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
5909 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
5912 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
5914 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
5915 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
5918 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
5920 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
5921 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
5924 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5926 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
5927 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
5930 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
5932 static const WCHAR table[] = { 'A','p','p','I','d',0 };
5933 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
5936 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
5938 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
5939 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
5942 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
5944 static const WCHAR table[] = { 'M','I','M','E',0 };
5945 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
5948 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
5950 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
5951 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
5954 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
5956 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
5957 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
5960 static const struct _actions StandardActions[] = {
5961 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
5962 { szAppSearch, ACTION_AppSearch },
5963 { szBindImage, ACTION_BindImage },
5964 { szCCPSearch, ACTION_CCPSearch },
5965 { szCostFinalize, ACTION_CostFinalize },
5966 { szCostInitialize, ACTION_CostInitialize },
5967 { szCreateFolders, ACTION_CreateFolders },
5968 { szCreateShortcuts, ACTION_CreateShortcuts },
5969 { szDeleteServices, ACTION_DeleteServices },
5970 { szDisableRollback, NULL },
5971 { szDuplicateFiles, ACTION_DuplicateFiles },
5972 { szExecuteAction, ACTION_ExecuteAction },
5973 { szFileCost, ACTION_FileCost },
5974 { szFindRelatedProducts, ACTION_FindRelatedProducts },
5975 { szForceReboot, ACTION_ForceReboot },
5976 { szInstallAdminPackage, NULL },
5977 { szInstallExecute, ACTION_InstallExecute },
5978 { szInstallExecuteAgain, ACTION_InstallExecute },
5979 { szInstallFiles, ACTION_InstallFiles},
5980 { szInstallFinalize, ACTION_InstallFinalize },
5981 { szInstallInitialize, ACTION_InstallInitialize },
5982 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
5983 { szInstallValidate, ACTION_InstallValidate },
5984 { szIsolateComponents, ACTION_IsolateComponents },
5985 { szLaunchConditions, ACTION_LaunchConditions },
5986 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
5987 { szMoveFiles, ACTION_MoveFiles },
5988 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
5989 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
5990 { szInstallODBC, ACTION_InstallODBC },
5991 { szInstallServices, ACTION_InstallServices },
5992 { szPatchFiles, ACTION_PatchFiles },
5993 { szProcessComponents, ACTION_ProcessComponents },
5994 { szPublishComponents, ACTION_PublishComponents },
5995 { szPublishFeatures, ACTION_PublishFeatures },
5996 { szPublishProduct, ACTION_PublishProduct },
5997 { szRegisterClassInfo, ACTION_RegisterClassInfo },
5998 { szRegisterComPlus, ACTION_RegisterComPlus},
5999 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6000 { szRegisterFonts, ACTION_RegisterFonts },
6001 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6002 { szRegisterProduct, ACTION_RegisterProduct },
6003 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6004 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6005 { szRegisterUser, ACTION_RegisterUser },
6006 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6007 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6008 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6009 { szRemoveFiles, ACTION_RemoveFiles },
6010 { szRemoveFolders, ACTION_RemoveFolders },
6011 { szRemoveIniValues, ACTION_RemoveIniValues },
6012 { szRemoveODBC, ACTION_RemoveODBC },
6013 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6014 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6015 { szResolveSource, ACTION_ResolveSource },
6016 { szRMCCPSearch, ACTION_RMCCPSearch },
6017 { szScheduleReboot, NULL },
6018 { szSelfRegModules, ACTION_SelfRegModules },
6019 { szSelfUnregModules, ACTION_SelfUnregModules },
6020 { szSetODBCFolders, NULL },
6021 { szStartServices, ACTION_StartServices },
6022 { szStopServices, ACTION_StopServices },
6023 { szUnpublishComponents, ACTION_UnpublishComponents },
6024 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6025 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6026 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6027 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6028 { szUnregisterFonts, ACTION_UnregisterFonts },
6029 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6030 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6031 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6032 { szValidateProductID, ACTION_ValidateProductID },
6033 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6034 { szWriteIniValues, ACTION_WriteIniValues },
6035 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6039 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
6040 UINT* rc, BOOL force )
6046 if (!run && !package->script->CurrentlyScripting)
6051 if (strcmpW(action,szInstallFinalize) == 0 ||
6052 strcmpW(action,szInstallExecute) == 0 ||
6053 strcmpW(action,szInstallExecuteAgain) == 0)
6058 while (StandardActions[i].action != NULL)
6060 if (strcmpW(StandardActions[i].action, action)==0)
6064 ui_actioninfo(package, action, TRUE, 0);
6065 *rc = schedule_action(package,INSTALL_SCRIPT,action);
6066 ui_actioninfo(package, action, FALSE, *rc);
6070 ui_actionstart(package, action);
6071 if (StandardActions[i].handler)
6073 *rc = StandardActions[i].handler(package);
6077 FIXME("unhandled standard action %s\n",debugstr_w(action));
6078 *rc = ERROR_SUCCESS;