push 17e2dc55811cd90cc188e62454531c17ba44e341
[wine/hacks.git] / dlls / msi / action.c
blob3a11c616a82356d4bd74eeaebcbe4c1edd83c712
1 /*
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
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "winreg.h"
29 #include "winsvc.h"
30 #include "odbcinst.h"
31 #include "wine/debug.h"
32 #include "msidefs.h"
33 #include "msipriv.h"
34 #include "winuser.h"
35 #include "shlobj.h"
36 #include "objbase.h"
37 #include "mscoree.h"
38 #include "fusion.h"
39 #include "shlwapi.h"
40 #include "wine/unicode.h"
41 #include "winver.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
49 * consts and values used
51 static const WCHAR c_colon[] = {'C',':','\\',0};
53 static const WCHAR szCreateFolders[] =
54 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
55 static const WCHAR szCostFinalize[] =
56 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
57 static const WCHAR szWriteRegistryValues[] =
58 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
59 static const WCHAR szCostInitialize[] =
60 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
61 static const WCHAR szFileCost[] =
62 {'F','i','l','e','C','o','s','t',0};
63 static const WCHAR szInstallInitialize[] =
64 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
65 static const WCHAR szInstallValidate[] =
66 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
67 static const WCHAR szLaunchConditions[] =
68 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
69 static const WCHAR szProcessComponents[] =
70 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
71 static const WCHAR szRegisterTypeLibraries[] =
72 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
73 static const WCHAR szCreateShortcuts[] =
74 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
75 static const WCHAR szPublishProduct[] =
76 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
77 static const WCHAR szWriteIniValues[] =
78 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
79 static const WCHAR szSelfRegModules[] =
80 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
81 static const WCHAR szPublishFeatures[] =
82 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
83 static const WCHAR szRegisterProduct[] =
84 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
85 static const WCHAR szInstallExecute[] =
86 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
87 static const WCHAR szInstallExecuteAgain[] =
88 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
89 static const WCHAR szInstallFinalize[] =
90 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
91 static const WCHAR szForceReboot[] =
92 {'F','o','r','c','e','R','e','b','o','o','t',0};
93 static const WCHAR szResolveSource[] =
94 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
95 static const WCHAR szAppSearch[] =
96 {'A','p','p','S','e','a','r','c','h',0};
97 static const WCHAR szAllocateRegistrySpace[] =
98 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
99 static const WCHAR szBindImage[] =
100 {'B','i','n','d','I','m','a','g','e',0};
101 static const WCHAR szCCPSearch[] =
102 {'C','C','P','S','e','a','r','c','h',0};
103 static const WCHAR szDeleteServices[] =
104 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
105 static const WCHAR szDisableRollback[] =
106 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
107 static const WCHAR szExecuteAction[] =
108 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
109 static const WCHAR szInstallAdminPackage[] =
110 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
111 static const WCHAR szInstallSFPCatalogFile[] =
112 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
113 static const WCHAR szIsolateComponents[] =
114 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
115 static const WCHAR szMigrateFeatureStates[] =
116 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
117 static const WCHAR szMoveFiles[] =
118 {'M','o','v','e','F','i','l','e','s',0};
119 static const WCHAR szMsiPublishAssemblies[] =
120 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
121 static const WCHAR szMsiUnpublishAssemblies[] =
122 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
123 static const WCHAR szInstallODBC[] =
124 {'I','n','s','t','a','l','l','O','D','B','C',0};
125 static const WCHAR szInstallServices[] =
126 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szPatchFiles[] =
128 {'P','a','t','c','h','F','i','l','e','s',0};
129 static const WCHAR szPublishComponents[] =
130 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
131 static const WCHAR szRegisterComPlus[] =
132 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
133 static const WCHAR szRegisterFonts[] =
134 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
135 static const WCHAR szRegisterUser[] =
136 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
137 static const WCHAR szRemoveDuplicateFiles[] =
138 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
139 static const WCHAR szRemoveEnvironmentStrings[] =
140 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
141 static const WCHAR szRemoveExistingProducts[] =
142 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
143 static const WCHAR szRemoveFolders[] =
144 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
145 static const WCHAR szRemoveIniValues[] =
146 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
147 static const WCHAR szRemoveODBC[] =
148 {'R','e','m','o','v','e','O','D','B','C',0};
149 static const WCHAR szRemoveRegistryValues[] =
150 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
151 static const WCHAR szRemoveShortcuts[] =
152 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
153 static const WCHAR szRMCCPSearch[] =
154 {'R','M','C','C','P','S','e','a','r','c','h',0};
155 static const WCHAR szScheduleReboot[] =
156 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
157 static const WCHAR szSelfUnregModules[] =
158 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
159 static const WCHAR szSetODBCFolders[] =
160 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
161 static const WCHAR szStartServices[] =
162 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
163 static const WCHAR szStopServices[] =
164 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
165 static const WCHAR szUnpublishComponents[] =
166 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
167 static const WCHAR szUnpublishFeatures[] =
168 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
169 static const WCHAR szUnregisterClassInfo[] =
170 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
171 static const WCHAR szUnregisterComPlus[] =
172 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
173 static const WCHAR szUnregisterExtensionInfo[] =
174 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
175 static const WCHAR szUnregisterFonts[] =
176 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
177 static const WCHAR szUnregisterMIMEInfo[] =
178 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
179 static const WCHAR szUnregisterProgIdInfo[] =
180 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
181 static const WCHAR szUnregisterTypeLibraries[] =
182 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
183 static const WCHAR szValidateProductID[] =
184 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
185 static const WCHAR szWriteEnvironmentStrings[] =
186 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
188 /********************************************************
189 * helper functions
190 ********************************************************/
192 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
194 static const WCHAR Query_t[] =
195 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
196 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
197 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
198 ' ','\'','%','s','\'',0};
199 MSIRECORD * row;
201 row = MSI_QueryGetRecord( package->db, Query_t, action );
202 if (!row)
203 return;
204 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
205 msiobj_release(&row->hdr);
208 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
209 UINT rc)
211 MSIRECORD * row;
212 static const WCHAR template_s[]=
213 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
214 '%','s', '.',0};
215 static const WCHAR template_e[]=
216 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
217 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
218 '%','i','.',0};
219 static const WCHAR format[] =
220 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
221 WCHAR message[1024];
222 WCHAR timet[0x100];
224 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
225 if (start)
226 sprintfW(message,template_s,timet,action);
227 else
228 sprintfW(message,template_e,timet,action,rc);
230 row = MSI_CreateRecord(1);
231 MSI_RecordSetStringW(row,1,message);
233 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
234 msiobj_release(&row->hdr);
237 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
238 BOOL preserve_case )
240 LPCWSTR ptr,ptr2;
241 BOOL quote;
242 DWORD len;
243 LPWSTR prop = NULL, val = NULL;
245 if (!szCommandLine)
246 return ERROR_SUCCESS;
248 ptr = szCommandLine;
250 while (*ptr)
252 if (*ptr==' ')
254 ptr++;
255 continue;
258 TRACE("Looking at %s\n",debugstr_w(ptr));
260 ptr2 = strchrW(ptr,'=');
261 if (!ptr2)
263 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
264 break;
267 quote = FALSE;
269 len = ptr2-ptr;
270 prop = msi_alloc((len+1)*sizeof(WCHAR));
271 memcpy(prop,ptr,len*sizeof(WCHAR));
272 prop[len]=0;
274 if (!preserve_case)
275 struprW(prop);
277 ptr2++;
279 len = 0;
280 ptr = ptr2;
281 while (*ptr && (quote || (!quote && *ptr!=' ')))
283 if (*ptr == '"')
284 quote = !quote;
285 ptr++;
286 len++;
289 if (*ptr2=='"')
291 ptr2++;
292 len -= 2;
294 val = msi_alloc((len+1)*sizeof(WCHAR));
295 memcpy(val,ptr2,len*sizeof(WCHAR));
296 val[len] = 0;
298 if (lstrlenW(prop) > 0)
300 TRACE("Found commandline property (%s) = (%s)\n",
301 debugstr_w(prop), debugstr_w(val));
302 MSI_SetPropertyW(package,prop,val);
304 msi_free(val);
305 msi_free(prop);
308 return ERROR_SUCCESS;
312 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
314 LPCWSTR pc;
315 LPWSTR p, *ret = NULL;
316 UINT count = 0;
318 if (!str)
319 return ret;
321 /* count the number of substrings */
322 for ( pc = str, count = 0; pc; count++ )
324 pc = strchrW( pc, sep );
325 if (pc)
326 pc++;
329 /* allocate space for an array of substring pointers and the substrings */
330 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
331 (lstrlenW(str)+1) * sizeof(WCHAR) );
332 if (!ret)
333 return ret;
335 /* copy the string and set the pointers */
336 p = (LPWSTR) &ret[count+1];
337 lstrcpyW( p, str );
338 for( count = 0; (ret[count] = p); count++ )
340 p = strchrW( p, sep );
341 if (p)
342 *p++ = 0;
345 return ret;
348 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
350 static const WCHAR szSystemLanguageID[] =
351 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
353 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
354 UINT ret = ERROR_FUNCTION_FAILED;
356 prod_code = msi_dup_property( package, szProductCode );
357 patch_product = msi_get_suminfo_product( patch );
359 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
361 if ( strstrW( patch_product, prod_code ) )
363 MSISUMMARYINFO *si;
364 const WCHAR *p;
366 si = MSI_GetSummaryInformationW( patch, 0 );
367 if (!si)
369 ERR("no summary information!\n");
370 goto end;
373 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
374 if (!template)
376 ERR("no template property!\n");
377 msiobj_release( &si->hdr );
378 goto end;
381 if (!template[0])
383 ret = ERROR_SUCCESS;
384 msiobj_release( &si->hdr );
385 goto end;
388 langid = msi_dup_property( package, szSystemLanguageID );
389 if (!langid)
391 msiobj_release( &si->hdr );
392 goto end;
395 p = strchrW( template, ';' );
396 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
398 TRACE("applicable transform\n");
399 ret = ERROR_SUCCESS;
402 /* FIXME: check platform */
404 msiobj_release( &si->hdr );
407 end:
408 msi_free( patch_product );
409 msi_free( prod_code );
410 msi_free( template );
411 msi_free( langid );
413 return ret;
416 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
417 MSIDATABASE *patch_db, LPCWSTR name )
419 UINT ret = ERROR_FUNCTION_FAILED;
420 IStorage *stg = NULL;
421 HRESULT r;
423 TRACE("%p %s\n", package, debugstr_w(name) );
425 if (*name++ != ':')
427 ERR("expected a colon in %s\n", debugstr_w(name));
428 return ERROR_FUNCTION_FAILED;
431 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
432 if (SUCCEEDED(r))
434 ret = msi_check_transform_applicable( package, stg );
435 if (ret == ERROR_SUCCESS)
436 msi_table_apply_transform( package->db, stg );
437 else
438 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
439 IStorage_Release( stg );
441 else
442 ERR("failed to open substorage %s\n", debugstr_w(name));
444 return ERROR_SUCCESS;
447 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
449 LPWSTR guid_list, *guids, product_code;
450 UINT i, ret = ERROR_FUNCTION_FAILED;
452 product_code = msi_dup_property( package, szProductCode );
453 if (!product_code)
455 /* FIXME: the property ProductCode should be written into the DB somewhere */
456 ERR("no product code to check\n");
457 return ERROR_SUCCESS;
460 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
461 guids = msi_split_string( guid_list, ';' );
462 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
464 if (!lstrcmpW( guids[i], product_code ))
465 ret = ERROR_SUCCESS;
467 msi_free( guids );
468 msi_free( guid_list );
469 msi_free( product_code );
471 return ret;
474 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
476 MSIQUERY *view;
477 MSIRECORD *rec = NULL;
478 LPWSTR patch;
479 LPCWSTR prop;
480 UINT r;
482 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
483 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
484 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
485 '`','S','o','u','r','c','e','`',' ','I','S',' ',
486 'N','O','T',' ','N','U','L','L',0};
488 r = MSI_DatabaseOpenViewW(package->db, query, &view);
489 if (r != ERROR_SUCCESS)
490 return r;
492 r = MSI_ViewExecute(view, 0);
493 if (r != ERROR_SUCCESS)
494 goto done;
496 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
498 prop = MSI_RecordGetString(rec, 1);
499 patch = msi_dup_property(package, szPatch);
500 MSI_SetPropertyW(package, prop, patch);
501 msi_free(patch);
504 done:
505 if (rec) msiobj_release(&rec->hdr);
506 msiobj_release(&view->hdr);
508 return r;
511 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
513 MSISUMMARYINFO *si;
514 LPWSTR str, *substorage;
515 UINT i, r = ERROR_SUCCESS;
517 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
518 if (!si)
519 return ERROR_FUNCTION_FAILED;
521 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
523 TRACE("Patch not applicable\n");
524 return ERROR_SUCCESS;
527 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
528 if (!package->patch)
529 return ERROR_OUTOFMEMORY;
531 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
532 if (!package->patch->patchcode)
533 return ERROR_OUTOFMEMORY;
535 /* enumerate the substorage */
536 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
537 package->patch->transforms = str;
539 substorage = msi_split_string( str, ';' );
540 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
541 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
543 msi_free( substorage );
544 msiobj_release( &si->hdr );
546 msi_set_media_source_prop(package);
548 return r;
551 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
553 MSIDATABASE *patch_db = NULL;
554 UINT r;
556 TRACE("%p %s\n", package, debugstr_w( file ) );
558 /* FIXME:
559 * We probably want to make sure we only open a patch collection here.
560 * Patch collections (.msp) and databases (.msi) have different GUIDs
561 * but currently MSI_OpenDatabaseW will accept both.
563 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
564 if ( r != ERROR_SUCCESS )
566 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
567 return r;
570 msi_parse_patch_summary( package, patch_db );
573 * There might be a CAB file in the patch package,
574 * so append it to the list of storage to search for streams.
576 append_storage_to_db( package->db, patch_db->storage );
578 msiobj_release( &patch_db->hdr );
580 return ERROR_SUCCESS;
583 /* get the PATCH property, and apply all the patches it specifies */
584 static UINT msi_apply_patches( MSIPACKAGE *package )
586 LPWSTR patch_list, *patches;
587 UINT i, r = ERROR_SUCCESS;
589 patch_list = msi_dup_property( package, szPatch );
591 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
593 patches = msi_split_string( patch_list, ';' );
594 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
595 r = msi_apply_patch_package( package, patches[i] );
597 msi_free( patches );
598 msi_free( patch_list );
600 return r;
603 static UINT msi_apply_transforms( MSIPACKAGE *package )
605 static const WCHAR szTransforms[] = {
606 'T','R','A','N','S','F','O','R','M','S',0 };
607 LPWSTR xform_list, *xforms;
608 UINT i, r = ERROR_SUCCESS;
610 xform_list = msi_dup_property( package, szTransforms );
611 xforms = msi_split_string( xform_list, ';' );
613 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
615 if (xforms[i][0] == ':')
616 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
617 else
618 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
621 msi_free( xforms );
622 msi_free( xform_list );
624 return r;
627 static BOOL ui_sequence_exists( MSIPACKAGE *package )
629 MSIQUERY *view;
630 UINT rc;
632 static const WCHAR ExecSeqQuery [] =
633 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
634 '`','I','n','s','t','a','l','l',
635 'U','I','S','e','q','u','e','n','c','e','`',
636 ' ','W','H','E','R','E',' ',
637 '`','S','e','q','u','e','n','c','e','`',' ',
638 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
639 '`','S','e','q','u','e','n','c','e','`',0};
641 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
642 if (rc == ERROR_SUCCESS)
644 msiobj_release(&view->hdr);
645 return TRUE;
648 return FALSE;
651 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
653 LPWSTR p, db;
654 LPWSTR source, check;
655 DWORD len;
657 static const WCHAR szOriginalDatabase[] =
658 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
660 db = msi_dup_property( package, szOriginalDatabase );
661 if (!db)
662 return ERROR_OUTOFMEMORY;
664 p = strrchrW( db, '\\' );
665 if (!p)
667 p = strrchrW( db, '/' );
668 if (!p)
670 msi_free(db);
671 return ERROR_SUCCESS;
675 len = p - db + 2;
676 source = msi_alloc( len * sizeof(WCHAR) );
677 lstrcpynW( source, db, len );
679 check = msi_dup_property( package, cszSourceDir );
680 if (!check || replace)
681 MSI_SetPropertyW( package, cszSourceDir, source );
683 msi_free( check );
685 check = msi_dup_property( package, cszSOURCEDIR );
686 if (!check || replace)
687 MSI_SetPropertyW( package, cszSOURCEDIR, source );
689 msi_free( check );
690 msi_free( source );
691 msi_free( db );
693 return ERROR_SUCCESS;
696 static BOOL needs_ui_sequence(MSIPACKAGE *package)
698 INT level = msi_get_property_int(package, szUILevel, 0);
699 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
702 static UINT msi_set_context(MSIPACKAGE *package)
704 WCHAR val[10];
705 DWORD sz = 10;
706 DWORD num;
707 UINT r;
709 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
711 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
712 if (r == ERROR_SUCCESS)
714 num = atolW(val);
715 if (num == 1 || num == 2)
716 package->Context = MSIINSTALLCONTEXT_MACHINE;
719 MSI_SetPropertyW(package, szAllUsers, szOne);
720 return ERROR_SUCCESS;
723 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
725 UINT rc;
726 LPCWSTR cond, action;
727 MSIPACKAGE *package = param;
729 action = MSI_RecordGetString(row,1);
730 if (!action)
732 ERR("Error is retrieving action name\n");
733 return ERROR_FUNCTION_FAILED;
736 /* check conditions */
737 cond = MSI_RecordGetString(row,2);
739 /* this is a hack to skip errors in the condition code */
740 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
742 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
743 return ERROR_SUCCESS;
746 if (needs_ui_sequence(package))
747 rc = ACTION_PerformUIAction(package, action, -1);
748 else
749 rc = ACTION_PerformAction(package, action, -1, FALSE);
751 msi_dialog_check_messages( NULL );
753 if (package->CurrentInstallState != ERROR_SUCCESS)
754 rc = package->CurrentInstallState;
756 if (rc == ERROR_FUNCTION_NOT_CALLED)
757 rc = ERROR_SUCCESS;
759 if (rc != ERROR_SUCCESS)
760 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
762 return rc;
765 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
767 MSIQUERY * view;
768 UINT r;
769 static const WCHAR query[] =
770 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
771 '`','%','s','`',
772 ' ','W','H','E','R','E',' ',
773 '`','S','e','q','u','e','n','c','e','`',' ',
774 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
775 '`','S','e','q','u','e','n','c','e','`',0};
777 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
779 r = MSI_OpenQuery( package->db, &view, query, szTable );
780 if (r == ERROR_SUCCESS)
782 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
783 msiobj_release(&view->hdr);
786 return r;
789 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
791 MSIQUERY * view;
792 UINT rc;
793 static const WCHAR ExecSeqQuery[] =
794 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
795 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
796 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
797 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
798 'O','R','D','E','R',' ', 'B','Y',' ',
799 '`','S','e','q','u','e','n','c','e','`',0 };
800 static const WCHAR IVQuery[] =
801 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
802 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
803 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
804 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
805 ' ','\'', 'I','n','s','t','a','l','l',
806 'V','a','l','i','d','a','t','e','\'', 0};
807 INT seq = 0;
809 if (package->script->ExecuteSequenceRun)
811 TRACE("Execute Sequence already Run\n");
812 return ERROR_SUCCESS;
815 package->script->ExecuteSequenceRun = TRUE;
817 /* get the sequence number */
818 if (UIran)
820 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
821 if( !row )
822 return ERROR_FUNCTION_FAILED;
823 seq = MSI_RecordGetInteger(row,1);
824 msiobj_release(&row->hdr);
827 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
828 if (rc == ERROR_SUCCESS)
830 TRACE("Running the actions\n");
832 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
833 msiobj_release(&view->hdr);
836 return rc;
839 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
841 MSIQUERY * view;
842 UINT rc;
843 static const WCHAR ExecSeqQuery [] =
844 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
845 '`','I','n','s','t','a','l','l',
846 'U','I','S','e','q','u','e','n','c','e','`',
847 ' ','W','H','E','R','E',' ',
848 '`','S','e','q','u','e','n','c','e','`',' ',
849 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
850 '`','S','e','q','u','e','n','c','e','`',0};
852 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
853 if (rc == ERROR_SUCCESS)
855 TRACE("Running the actions\n");
857 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
858 msiobj_release(&view->hdr);
861 return rc;
864 /********************************************************
865 * ACTION helper functions and functions that perform the actions
866 *******************************************************/
867 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
868 UINT* rc, UINT script, BOOL force )
870 BOOL ret=FALSE;
871 UINT arc;
873 arc = ACTION_CustomAction(package, action, script, force);
875 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
877 *rc = arc;
878 ret = TRUE;
880 return ret;
884 * Actual Action Handlers
887 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
889 MSIPACKAGE *package = param;
890 LPCWSTR dir;
891 LPWSTR full_path;
892 MSIRECORD *uirow;
893 MSIFOLDER *folder;
895 dir = MSI_RecordGetString(row,1);
896 if (!dir)
898 ERR("Unable to get folder id\n");
899 return ERROR_SUCCESS;
902 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
903 if (!full_path)
905 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
906 return ERROR_SUCCESS;
909 TRACE("Folder is %s\n",debugstr_w(full_path));
911 /* UI stuff */
912 uirow = MSI_CreateRecord(1);
913 MSI_RecordSetStringW(uirow,1,full_path);
914 ui_actiondata(package,szCreateFolders,uirow);
915 msiobj_release( &uirow->hdr );
917 if (folder->State == 0)
918 create_full_pathW(full_path);
920 folder->State = 3;
922 msi_free(full_path);
923 return ERROR_SUCCESS;
926 /* FIXME: probably should merge this with the above function */
927 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
929 UINT rc = ERROR_SUCCESS;
930 MSIFOLDER *folder;
931 LPWSTR install_path;
933 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
934 if (!install_path)
935 return ERROR_FUNCTION_FAILED;
937 /* create the path */
938 if (folder->State == 0)
940 create_full_pathW(install_path);
941 folder->State = 2;
943 msi_free(install_path);
945 return rc;
948 UINT msi_create_component_directories( MSIPACKAGE *package )
950 MSICOMPONENT *comp;
952 /* create all the folders required by the components are going to install */
953 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
955 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
956 continue;
957 msi_create_directory( package, comp->Directory );
960 return ERROR_SUCCESS;
964 * Also we cannot enable/disable components either, so for now I am just going
965 * to do all the directories for all the components.
967 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
969 static const WCHAR ExecSeqQuery[] =
970 {'S','E','L','E','C','T',' ',
971 '`','D','i','r','e','c','t','o','r','y','_','`',
972 ' ','F','R','O','M',' ',
973 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
974 UINT rc;
975 MSIQUERY *view;
977 /* create all the empty folders specified in the CreateFolder table */
978 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
979 if (rc != ERROR_SUCCESS)
980 return ERROR_SUCCESS;
982 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
983 msiobj_release(&view->hdr);
985 msi_create_component_directories( package );
987 return rc;
990 static UINT load_component( MSIRECORD *row, LPVOID param )
992 MSIPACKAGE *package = param;
993 MSICOMPONENT *comp;
995 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
996 if (!comp)
997 return ERROR_FUNCTION_FAILED;
999 list_add_tail( &package->components, &comp->entry );
1001 /* fill in the data */
1002 comp->Component = msi_dup_record_field( row, 1 );
1004 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1006 comp->ComponentId = msi_dup_record_field( row, 2 );
1007 comp->Directory = msi_dup_record_field( row, 3 );
1008 comp->Attributes = MSI_RecordGetInteger(row,4);
1009 comp->Condition = msi_dup_record_field( row, 5 );
1010 comp->KeyPath = msi_dup_record_field( row, 6 );
1012 comp->Installed = INSTALLSTATE_UNKNOWN;
1013 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1015 return ERROR_SUCCESS;
1018 static UINT load_all_components( MSIPACKAGE *package )
1020 static const WCHAR query[] = {
1021 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1022 '`','C','o','m','p','o','n','e','n','t','`',0 };
1023 MSIQUERY *view;
1024 UINT r;
1026 if (!list_empty(&package->components))
1027 return ERROR_SUCCESS;
1029 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1030 if (r != ERROR_SUCCESS)
1031 return r;
1033 r = MSI_IterateRecords(view, NULL, load_component, package);
1034 msiobj_release(&view->hdr);
1035 return r;
1038 typedef struct {
1039 MSIPACKAGE *package;
1040 MSIFEATURE *feature;
1041 } _ilfs;
1043 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1045 ComponentList *cl;
1047 cl = msi_alloc( sizeof (*cl) );
1048 if ( !cl )
1049 return ERROR_NOT_ENOUGH_MEMORY;
1050 cl->component = comp;
1051 list_add_tail( &feature->Components, &cl->entry );
1053 return ERROR_SUCCESS;
1056 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1058 FeatureList *fl;
1060 fl = msi_alloc( sizeof(*fl) );
1061 if ( !fl )
1062 return ERROR_NOT_ENOUGH_MEMORY;
1063 fl->feature = child;
1064 list_add_tail( &parent->Children, &fl->entry );
1066 return ERROR_SUCCESS;
1069 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1071 _ilfs* ilfs = param;
1072 LPCWSTR component;
1073 MSICOMPONENT *comp;
1075 component = MSI_RecordGetString(row,1);
1077 /* check to see if the component is already loaded */
1078 comp = get_loaded_component( ilfs->package, component );
1079 if (!comp)
1081 ERR("unknown component %s\n", debugstr_w(component));
1082 return ERROR_FUNCTION_FAILED;
1085 add_feature_component( ilfs->feature, comp );
1086 comp->Enabled = TRUE;
1088 return ERROR_SUCCESS;
1091 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1093 MSIFEATURE *feature;
1095 if ( !name )
1096 return NULL;
1098 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1100 if ( !lstrcmpW( feature->Feature, name ) )
1101 return feature;
1104 return NULL;
1107 static UINT load_feature(MSIRECORD * row, LPVOID param)
1109 MSIPACKAGE* package = param;
1110 MSIFEATURE* feature;
1111 static const WCHAR Query1[] =
1112 {'S','E','L','E','C','T',' ',
1113 '`','C','o','m','p','o','n','e','n','t','_','`',
1114 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1115 'C','o','m','p','o','n','e','n','t','s','`',' ',
1116 'W','H','E','R','E',' ',
1117 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1118 MSIQUERY * view;
1119 UINT rc;
1120 _ilfs ilfs;
1122 /* fill in the data */
1124 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1125 if (!feature)
1126 return ERROR_NOT_ENOUGH_MEMORY;
1128 list_init( &feature->Children );
1129 list_init( &feature->Components );
1131 feature->Feature = msi_dup_record_field( row, 1 );
1133 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1135 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1136 feature->Title = msi_dup_record_field( row, 3 );
1137 feature->Description = msi_dup_record_field( row, 4 );
1139 if (!MSI_RecordIsNull(row,5))
1140 feature->Display = MSI_RecordGetInteger(row,5);
1142 feature->Level= MSI_RecordGetInteger(row,6);
1143 feature->Directory = msi_dup_record_field( row, 7 );
1144 feature->Attributes = MSI_RecordGetInteger(row,8);
1146 feature->Installed = INSTALLSTATE_UNKNOWN;
1147 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1149 list_add_tail( &package->features, &feature->entry );
1151 /* load feature components */
1153 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1154 if (rc != ERROR_SUCCESS)
1155 return ERROR_SUCCESS;
1157 ilfs.package = package;
1158 ilfs.feature = feature;
1160 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1161 msiobj_release(&view->hdr);
1163 return ERROR_SUCCESS;
1166 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1168 MSIPACKAGE* package = param;
1169 MSIFEATURE *parent, *child;
1171 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1172 if (!child)
1173 return ERROR_FUNCTION_FAILED;
1175 if (!child->Feature_Parent)
1176 return ERROR_SUCCESS;
1178 parent = find_feature_by_name( package, child->Feature_Parent );
1179 if (!parent)
1180 return ERROR_FUNCTION_FAILED;
1182 add_feature_child( parent, child );
1183 return ERROR_SUCCESS;
1186 static UINT load_all_features( MSIPACKAGE *package )
1188 static const WCHAR query[] = {
1189 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1190 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1191 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1192 MSIQUERY *view;
1193 UINT r;
1195 if (!list_empty(&package->features))
1196 return ERROR_SUCCESS;
1198 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1199 if (r != ERROR_SUCCESS)
1200 return r;
1202 r = MSI_IterateRecords( view, NULL, load_feature, package );
1203 if (r != ERROR_SUCCESS)
1204 return r;
1206 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1207 msiobj_release( &view->hdr );
1209 return r;
1212 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1214 if (!p)
1215 return p;
1216 p = strchrW(p, ch);
1217 if (!p)
1218 return p;
1219 *p = 0;
1220 return p+1;
1223 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1225 static const WCHAR query[] = {
1226 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1227 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1228 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1229 MSIQUERY *view = NULL;
1230 MSIRECORD *row = NULL;
1231 UINT r;
1233 TRACE("%s\n", debugstr_w(file->File));
1235 r = MSI_OpenQuery(package->db, &view, query, file->File);
1236 if (r != ERROR_SUCCESS)
1237 goto done;
1239 r = MSI_ViewExecute(view, NULL);
1240 if (r != ERROR_SUCCESS)
1241 goto done;
1243 r = MSI_ViewFetch(view, &row);
1244 if (r != ERROR_SUCCESS)
1245 goto done;
1247 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1248 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1249 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1250 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1251 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1253 done:
1254 if (view) msiobj_release(&view->hdr);
1255 if (row) msiobj_release(&row->hdr);
1256 return r;
1259 static UINT load_file(MSIRECORD *row, LPVOID param)
1261 MSIPACKAGE* package = param;
1262 LPCWSTR component;
1263 MSIFILE *file;
1265 /* fill in the data */
1267 file = msi_alloc_zero( sizeof (MSIFILE) );
1268 if (!file)
1269 return ERROR_NOT_ENOUGH_MEMORY;
1271 file->File = msi_dup_record_field( row, 1 );
1273 component = MSI_RecordGetString( row, 2 );
1274 file->Component = get_loaded_component( package, component );
1276 if (!file->Component)
1278 WARN("Component not found: %s\n", debugstr_w(component));
1279 msi_free(file->File);
1280 msi_free(file);
1281 return ERROR_SUCCESS;
1284 file->FileName = msi_dup_record_field( row, 3 );
1285 reduce_to_longfilename( file->FileName );
1287 file->ShortName = msi_dup_record_field( row, 3 );
1288 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1290 file->FileSize = MSI_RecordGetInteger( row, 4 );
1291 file->Version = msi_dup_record_field( row, 5 );
1292 file->Language = msi_dup_record_field( row, 6 );
1293 file->Attributes = MSI_RecordGetInteger( row, 7 );
1294 file->Sequence = MSI_RecordGetInteger( row, 8 );
1296 file->state = msifs_invalid;
1298 /* if the compressed bits are not set in the file attributes,
1299 * then read the information from the package word count property
1301 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1303 file->IsCompressed = FALSE;
1305 else if (file->Attributes &
1306 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1308 file->IsCompressed = TRUE;
1310 else if (file->Attributes & msidbFileAttributesNoncompressed)
1312 file->IsCompressed = FALSE;
1314 else
1316 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1319 load_file_hash(package, file);
1321 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1323 list_add_tail( &package->files, &file->entry );
1325 return ERROR_SUCCESS;
1328 static UINT load_all_files(MSIPACKAGE *package)
1330 MSIQUERY * view;
1331 UINT rc;
1332 static const WCHAR Query[] =
1333 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1334 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1335 '`','S','e','q','u','e','n','c','e','`', 0};
1337 if (!list_empty(&package->files))
1338 return ERROR_SUCCESS;
1340 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1341 if (rc != ERROR_SUCCESS)
1342 return ERROR_SUCCESS;
1344 rc = MSI_IterateRecords(view, NULL, load_file, package);
1345 msiobj_release(&view->hdr);
1347 return ERROR_SUCCESS;
1350 static UINT load_folder( MSIRECORD *row, LPVOID param )
1352 MSIPACKAGE *package = param;
1353 static WCHAR szEmpty[] = { 0 };
1354 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1355 MSIFOLDER *folder;
1357 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1358 if (!folder)
1359 return ERROR_NOT_ENOUGH_MEMORY;
1361 folder->Directory = msi_dup_record_field( row, 1 );
1363 TRACE("%s\n", debugstr_w(folder->Directory));
1365 p = msi_dup_record_field(row, 3);
1367 /* split src and target dir */
1368 tgt_short = p;
1369 src_short = folder_split_path( p, ':' );
1371 /* split the long and short paths */
1372 tgt_long = folder_split_path( tgt_short, '|' );
1373 src_long = folder_split_path( src_short, '|' );
1375 /* check for no-op dirs */
1376 if (!lstrcmpW(szDot, tgt_short))
1377 tgt_short = szEmpty;
1378 if (!lstrcmpW(szDot, src_short))
1379 src_short = szEmpty;
1381 if (!tgt_long)
1382 tgt_long = tgt_short;
1384 if (!src_short) {
1385 src_short = tgt_short;
1386 src_long = tgt_long;
1389 if (!src_long)
1390 src_long = src_short;
1392 /* FIXME: use the target short path too */
1393 folder->TargetDefault = strdupW(tgt_long);
1394 folder->SourceShortPath = strdupW(src_short);
1395 folder->SourceLongPath = strdupW(src_long);
1396 msi_free(p);
1398 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1399 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1400 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1402 folder->Parent = msi_dup_record_field( row, 2 );
1404 folder->Property = msi_dup_property( package, folder->Directory );
1406 list_add_tail( &package->folders, &folder->entry );
1408 TRACE("returning %p\n", folder);
1410 return ERROR_SUCCESS;
1413 static UINT load_all_folders( MSIPACKAGE *package )
1415 static const WCHAR query[] = {
1416 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1417 '`','D','i','r','e','c','t','o','r','y','`',0 };
1418 MSIQUERY *view;
1419 UINT r;
1421 if (!list_empty(&package->folders))
1422 return ERROR_SUCCESS;
1424 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1425 if (r != ERROR_SUCCESS)
1426 return r;
1428 r = MSI_IterateRecords(view, NULL, load_folder, package);
1429 msiobj_release(&view->hdr);
1430 return r;
1434 * I am not doing any of the costing functionality yet.
1435 * Mostly looking at doing the Component and Feature loading
1437 * The native MSI does A LOT of modification to tables here. Mostly adding
1438 * a lot of temporary columns to the Feature and Component tables.
1440 * note: Native msi also tracks the short filename. But I am only going to
1441 * track the long ones. Also looking at this directory table
1442 * it appears that the directory table does not get the parents
1443 * resolved base on property only based on their entries in the
1444 * directory table.
1446 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1448 static const WCHAR szCosting[] =
1449 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1451 MSI_SetPropertyW(package, szCosting, szZero);
1452 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1454 load_all_folders( package );
1455 load_all_components( package );
1456 load_all_features( package );
1457 load_all_files( package );
1459 return ERROR_SUCCESS;
1462 static UINT execute_script(MSIPACKAGE *package, UINT script )
1464 UINT i;
1465 UINT rc = ERROR_SUCCESS;
1467 TRACE("Executing Script %i\n",script);
1469 if (!package->script)
1471 ERR("no script!\n");
1472 return ERROR_FUNCTION_FAILED;
1475 for (i = 0; i < package->script->ActionCount[script]; i++)
1477 LPWSTR action;
1478 action = package->script->Actions[script][i];
1479 ui_actionstart(package, action);
1480 TRACE("Executing Action (%s)\n",debugstr_w(action));
1481 rc = ACTION_PerformAction(package, action, script, TRUE);
1482 if (rc != ERROR_SUCCESS)
1483 break;
1485 msi_free_action_script(package, script);
1486 return rc;
1489 static UINT ACTION_FileCost(MSIPACKAGE *package)
1491 return ERROR_SUCCESS;
1494 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1496 MSICOMPONENT *comp;
1497 INSTALLSTATE state;
1498 UINT r;
1500 state = MsiQueryProductStateW(package->ProductCode);
1502 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1504 if (!comp->ComponentId)
1505 continue;
1507 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1508 comp->Installed = INSTALLSTATE_ABSENT;
1509 else
1511 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1512 package->Context, comp->ComponentId,
1513 &comp->Installed);
1514 if (r != ERROR_SUCCESS)
1515 comp->Installed = INSTALLSTATE_ABSENT;
1520 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1522 MSIFEATURE *feature;
1523 INSTALLSTATE state;
1525 state = MsiQueryProductStateW(package->ProductCode);
1527 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1529 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1530 feature->Installed = INSTALLSTATE_ABSENT;
1531 else
1533 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1534 feature->Feature);
1539 static BOOL process_state_property(MSIPACKAGE* package, int level,
1540 LPCWSTR property, INSTALLSTATE state)
1542 LPWSTR override;
1543 MSIFEATURE *feature;
1545 override = msi_dup_property( package, property );
1546 if (!override)
1547 return FALSE;
1549 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1551 if (lstrcmpW(property, szRemove) &&
1552 (feature->Level <= 0 || feature->Level > level))
1553 continue;
1555 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1557 if (strcmpiW(override, szAll)==0)
1558 msi_feature_set_state(package, feature, state);
1559 else
1561 LPWSTR ptr = override;
1562 LPWSTR ptr2 = strchrW(override,',');
1564 while (ptr)
1566 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1567 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1569 msi_feature_set_state(package, feature, state);
1570 break;
1572 if (ptr2)
1574 ptr=ptr2+1;
1575 ptr2 = strchrW(ptr,',');
1577 else
1578 break;
1582 msi_free(override);
1584 return TRUE;
1587 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1589 int level;
1590 static const WCHAR szlevel[] =
1591 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1592 static const WCHAR szAddLocal[] =
1593 {'A','D','D','L','O','C','A','L',0};
1594 static const WCHAR szAddSource[] =
1595 {'A','D','D','S','O','U','R','C','E',0};
1596 static const WCHAR szAdvertise[] =
1597 {'A','D','V','E','R','T','I','S','E',0};
1598 BOOL override = FALSE;
1599 MSICOMPONENT* component;
1600 MSIFEATURE *feature;
1603 /* I do not know if this is where it should happen.. but */
1605 TRACE("Checking Install Level\n");
1607 level = msi_get_property_int(package, szlevel, 1);
1609 /* ok here is the _real_ rub
1610 * all these activation/deactivation things happen in order and things
1611 * later on the list override things earlier on the list.
1612 * 0) INSTALLLEVEL processing
1613 * 1) ADDLOCAL
1614 * 2) REMOVE
1615 * 3) ADDSOURCE
1616 * 4) ADDDEFAULT
1617 * 5) REINSTALL
1618 * 6) ADVERTISE
1619 * 7) COMPADDLOCAL
1620 * 8) COMPADDSOURCE
1621 * 9) FILEADDLOCAL
1622 * 10) FILEADDSOURCE
1623 * 11) FILEADDDEFAULT
1625 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1626 * REMOVE are the big ones, since we don't handle administrative installs
1627 * yet anyway.
1629 override |= process_state_property(package, level, szAddLocal, INSTALLSTATE_LOCAL);
1630 override |= process_state_property(package, level, szRemove, INSTALLSTATE_ABSENT);
1631 override |= process_state_property(package, level, szAddSource, INSTALLSTATE_SOURCE);
1632 override |= process_state_property(package, level, szReinstall, INSTALLSTATE_UNKNOWN);
1633 override |= process_state_property(package, level, szAdvertise, INSTALLSTATE_ADVERTISED);
1635 if (!override)
1637 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1639 BOOL feature_state = ((feature->Level > 0) &&
1640 (feature->Level <= level));
1642 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1644 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1645 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1646 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1647 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1648 else
1649 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1653 /* disable child features of unselected parent features */
1654 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1656 FeatureList *fl;
1658 if (feature->Level > 0 && feature->Level <= level)
1659 continue;
1661 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1662 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1665 else
1666 MSI_SetPropertyW(package, szPreselected, szOne);
1669 * now we want to enable or disable components base on feature
1672 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1674 ComponentList *cl;
1676 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1677 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1679 if (!feature->Level)
1680 continue;
1682 /* features with components that have compressed files are made local */
1683 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1685 if (cl->component->Enabled &&
1686 cl->component->ForceLocalState &&
1687 feature->Action == INSTALLSTATE_SOURCE)
1689 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1690 break;
1694 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1696 component = cl->component;
1698 if (!component->Enabled)
1699 continue;
1701 switch (feature->Action)
1703 case INSTALLSTATE_ABSENT:
1704 component->anyAbsent = 1;
1705 break;
1706 case INSTALLSTATE_ADVERTISED:
1707 component->hasAdvertiseFeature = 1;
1708 break;
1709 case INSTALLSTATE_SOURCE:
1710 component->hasSourceFeature = 1;
1711 break;
1712 case INSTALLSTATE_LOCAL:
1713 component->hasLocalFeature = 1;
1714 break;
1715 case INSTALLSTATE_DEFAULT:
1716 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1717 component->hasAdvertiseFeature = 1;
1718 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1719 component->hasSourceFeature = 1;
1720 else
1721 component->hasLocalFeature = 1;
1722 break;
1723 default:
1724 break;
1729 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1731 /* if the component isn't enabled, leave it alone */
1732 if (!component->Enabled)
1733 continue;
1735 /* check if it's local or source */
1736 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1737 (component->hasLocalFeature || component->hasSourceFeature))
1739 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1740 !component->ForceLocalState)
1741 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1742 else
1743 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1744 continue;
1747 /* if any feature is local, the component must be local too */
1748 if (component->hasLocalFeature)
1750 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1751 continue;
1754 if (component->hasSourceFeature)
1756 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1757 continue;
1760 if (component->hasAdvertiseFeature)
1762 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1763 continue;
1766 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1767 if (component->anyAbsent)
1768 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1771 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1773 if (component->Action == INSTALLSTATE_DEFAULT)
1775 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1776 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1779 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1780 debugstr_w(component->Component), component->Installed, component->Action);
1784 return ERROR_SUCCESS;
1787 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1789 MSIPACKAGE *package = param;
1790 LPCWSTR name;
1791 LPWSTR path;
1792 MSIFOLDER *f;
1794 name = MSI_RecordGetString(row,1);
1796 f = get_loaded_folder(package, name);
1797 if (!f) return ERROR_SUCCESS;
1799 /* reset the ResolvedTarget */
1800 msi_free(f->ResolvedTarget);
1801 f->ResolvedTarget = NULL;
1803 /* This helper function now does ALL the work */
1804 TRACE("Dir %s ...\n",debugstr_w(name));
1805 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1806 TRACE("resolves to %s\n",debugstr_w(path));
1807 msi_free(path);
1809 return ERROR_SUCCESS;
1812 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1814 MSIPACKAGE *package = param;
1815 LPCWSTR name;
1816 MSIFEATURE *feature;
1818 name = MSI_RecordGetString( row, 1 );
1820 feature = get_loaded_feature( package, name );
1821 if (!feature)
1822 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1823 else
1825 LPCWSTR Condition;
1826 Condition = MSI_RecordGetString(row,3);
1828 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1830 int level = MSI_RecordGetInteger(row,2);
1831 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1832 feature->Level = level;
1835 return ERROR_SUCCESS;
1838 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1840 static const WCHAR name_fmt[] =
1841 {'%','u','.','%','u','.','%','u','.','%','u',0};
1842 static const WCHAR name[] = {'\\',0};
1843 VS_FIXEDFILEINFO *lpVer;
1844 WCHAR filever[0x100];
1845 LPVOID version;
1846 DWORD versize;
1847 DWORD handle;
1848 UINT sz;
1850 TRACE("%s\n", debugstr_w(filename));
1852 versize = GetFileVersionInfoSizeW( filename, &handle );
1853 if (!versize)
1854 return NULL;
1856 version = msi_alloc( versize );
1857 GetFileVersionInfoW( filename, 0, versize, version );
1859 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1861 msi_free( version );
1862 return NULL;
1865 sprintfW( filever, name_fmt,
1866 HIWORD(lpVer->dwFileVersionMS),
1867 LOWORD(lpVer->dwFileVersionMS),
1868 HIWORD(lpVer->dwFileVersionLS),
1869 LOWORD(lpVer->dwFileVersionLS));
1871 msi_free( version );
1873 return strdupW( filever );
1876 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1878 LPWSTR file_version;
1879 MSIFILE *file;
1881 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1883 MSICOMPONENT* comp = file->Component;
1884 LPWSTR p;
1886 if (!comp)
1887 continue;
1889 if (file->IsCompressed)
1890 comp->ForceLocalState = TRUE;
1892 /* calculate target */
1893 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1895 msi_free(file->TargetPath);
1897 TRACE("file %s is named %s\n",
1898 debugstr_w(file->File), debugstr_w(file->FileName));
1900 file->TargetPath = build_directory_name(2, p, file->FileName);
1902 msi_free(p);
1904 TRACE("file %s resolves to %s\n",
1905 debugstr_w(file->File), debugstr_w(file->TargetPath));
1907 /* don't check files of components that aren't installed */
1908 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1909 comp->Installed == INSTALLSTATE_ABSENT)
1911 file->state = msifs_missing; /* assume files are missing */
1912 continue;
1915 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1917 file->state = msifs_missing;
1918 comp->Cost += file->FileSize;
1919 continue;
1922 if (file->Version &&
1923 (file_version = msi_get_disk_file_version( file->TargetPath )))
1925 TRACE("new %s old %s\n", debugstr_w(file->Version),
1926 debugstr_w(file_version));
1927 /* FIXME: seems like a bad way to compare version numbers */
1928 if (lstrcmpiW(file_version, file->Version)<0)
1930 file->state = msifs_overwrite;
1931 comp->Cost += file->FileSize;
1933 else
1934 file->state = msifs_present;
1935 msi_free( file_version );
1937 else
1938 file->state = msifs_present;
1941 return ERROR_SUCCESS;
1945 * A lot is done in this function aside from just the costing.
1946 * The costing needs to be implemented at some point but for now I am going
1947 * to focus on the directory building
1950 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1952 static const WCHAR ExecSeqQuery[] =
1953 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1954 '`','D','i','r','e','c','t','o','r','y','`',0};
1955 static const WCHAR ConditionQuery[] =
1956 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1957 '`','C','o','n','d','i','t','i','o','n','`',0};
1958 static const WCHAR szCosting[] =
1959 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1960 static const WCHAR szlevel[] =
1961 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1962 static const WCHAR szOutOfDiskSpace[] =
1963 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
1964 MSICOMPONENT *comp;
1965 UINT rc;
1966 MSIQUERY * view;
1967 LPWSTR level;
1969 TRACE("Building Directory properties\n");
1971 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1972 if (rc == ERROR_SUCCESS)
1974 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1975 package);
1976 msiobj_release(&view->hdr);
1979 /* read components states from the registry */
1980 ACTION_GetComponentInstallStates(package);
1981 ACTION_GetFeatureInstallStates(package);
1983 TRACE("File calculations\n");
1984 msi_check_file_install_states( package );
1986 TRACE("Evaluating Condition Table\n");
1988 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1989 if (rc == ERROR_SUCCESS)
1991 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1992 package);
1993 msiobj_release(&view->hdr);
1996 TRACE("Enabling or Disabling Components\n");
1997 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1999 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2001 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2002 comp->Enabled = FALSE;
2004 else
2005 comp->Enabled = TRUE;
2008 MSI_SetPropertyW(package,szCosting,szOne);
2009 /* set default run level if not set */
2010 level = msi_dup_property( package, szlevel );
2011 if (!level)
2012 MSI_SetPropertyW(package,szlevel, szOne);
2013 msi_free(level);
2015 /* FIXME: check volume disk space */
2016 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2018 return MSI_SetFeatureStates(package);
2021 /* OK this value is "interpreted" and then formatted based on the
2022 first few characters */
2023 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2024 DWORD *size)
2026 LPSTR data = NULL;
2028 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2030 if (value[1]=='x')
2032 LPWSTR ptr;
2033 CHAR byte[5];
2034 LPWSTR deformated = NULL;
2035 int count;
2037 deformat_string(package, &value[2], &deformated);
2039 /* binary value type */
2040 ptr = deformated;
2041 *type = REG_BINARY;
2042 if (strlenW(ptr)%2)
2043 *size = (strlenW(ptr)/2)+1;
2044 else
2045 *size = strlenW(ptr)/2;
2047 data = msi_alloc(*size);
2049 byte[0] = '0';
2050 byte[1] = 'x';
2051 byte[4] = 0;
2052 count = 0;
2053 /* if uneven pad with a zero in front */
2054 if (strlenW(ptr)%2)
2056 byte[2]= '0';
2057 byte[3]= *ptr;
2058 ptr++;
2059 data[count] = (BYTE)strtol(byte,NULL,0);
2060 count ++;
2061 TRACE("Uneven byte count\n");
2063 while (*ptr)
2065 byte[2]= *ptr;
2066 ptr++;
2067 byte[3]= *ptr;
2068 ptr++;
2069 data[count] = (BYTE)strtol(byte,NULL,0);
2070 count ++;
2072 msi_free(deformated);
2074 TRACE("Data %i bytes(%i)\n",*size,count);
2076 else
2078 LPWSTR deformated;
2079 LPWSTR p;
2080 DWORD d = 0;
2081 deformat_string(package, &value[1], &deformated);
2083 *type=REG_DWORD;
2084 *size = sizeof(DWORD);
2085 data = msi_alloc(*size);
2086 p = deformated;
2087 if (*p == '-')
2088 p++;
2089 while (*p)
2091 if ( (*p < '0') || (*p > '9') )
2092 break;
2093 d *= 10;
2094 d += (*p - '0');
2095 p++;
2097 if (deformated[0] == '-')
2098 d = -d;
2099 *(LPDWORD)data = d;
2100 TRACE("DWORD %i\n",*(LPDWORD)data);
2102 msi_free(deformated);
2105 else
2107 static const WCHAR szMulti[] = {'[','~',']',0};
2108 LPCWSTR ptr;
2109 *type=REG_SZ;
2111 if (value[0]=='#')
2113 if (value[1]=='%')
2115 ptr = &value[2];
2116 *type=REG_EXPAND_SZ;
2118 else
2119 ptr = &value[1];
2121 else
2122 ptr=value;
2124 if (strstrW(value,szMulti))
2125 *type = REG_MULTI_SZ;
2127 /* remove initial delimiter */
2128 if (!strncmpW(value, szMulti, 3))
2129 ptr = value + 3;
2131 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2133 /* add double NULL terminator */
2134 if (*type == REG_MULTI_SZ)
2136 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2137 data = msi_realloc_zero(data, *size);
2140 return data;
2143 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2145 MSIPACKAGE *package = param;
2146 static const WCHAR szHCR[] =
2147 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2148 'R','O','O','T','\\',0};
2149 static const WCHAR szHCU[] =
2150 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2151 'U','S','E','R','\\',0};
2152 static const WCHAR szHLM[] =
2153 {'H','K','E','Y','_','L','O','C','A','L','_',
2154 'M','A','C','H','I','N','E','\\',0};
2155 static const WCHAR szHU[] =
2156 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2158 LPSTR value_data = NULL;
2159 HKEY root_key, hkey;
2160 DWORD type,size;
2161 LPWSTR deformated;
2162 LPCWSTR szRoot, component, name, key, value;
2163 MSICOMPONENT *comp;
2164 MSIRECORD * uirow;
2165 LPWSTR uikey;
2166 INT root;
2167 BOOL check_first = FALSE;
2168 UINT rc;
2170 ui_progress(package,2,0,0,0);
2172 value = NULL;
2173 key = NULL;
2174 uikey = NULL;
2175 name = NULL;
2177 component = MSI_RecordGetString(row, 6);
2178 comp = get_loaded_component(package,component);
2179 if (!comp)
2180 return ERROR_SUCCESS;
2182 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2184 TRACE("Skipping write due to disabled component %s\n",
2185 debugstr_w(component));
2187 comp->Action = comp->Installed;
2189 return ERROR_SUCCESS;
2192 comp->Action = INSTALLSTATE_LOCAL;
2194 name = MSI_RecordGetString(row, 4);
2195 if( MSI_RecordIsNull(row,5) && name )
2197 /* null values can have special meanings */
2198 if (name[0]=='-' && name[1] == 0)
2199 return ERROR_SUCCESS;
2200 else if ((name[0]=='+' && name[1] == 0) ||
2201 (name[0] == '*' && name[1] == 0))
2202 name = NULL;
2203 check_first = TRUE;
2206 root = MSI_RecordGetInteger(row,2);
2207 key = MSI_RecordGetString(row, 3);
2209 /* get the root key */
2210 switch (root)
2212 case -1:
2214 LPWSTR all_users = msi_dup_property( package, szAllUsers );
2215 if (all_users && all_users[0] == '1')
2217 root_key = HKEY_LOCAL_MACHINE;
2218 szRoot = szHLM;
2220 else
2222 root_key = HKEY_CURRENT_USER;
2223 szRoot = szHCU;
2225 msi_free(all_users);
2227 break;
2228 case 0: root_key = HKEY_CLASSES_ROOT;
2229 szRoot = szHCR;
2230 break;
2231 case 1: root_key = HKEY_CURRENT_USER;
2232 szRoot = szHCU;
2233 break;
2234 case 2: root_key = HKEY_LOCAL_MACHINE;
2235 szRoot = szHLM;
2236 break;
2237 case 3: root_key = HKEY_USERS;
2238 szRoot = szHU;
2239 break;
2240 default:
2241 ERR("Unknown root %i\n",root);
2242 root_key=NULL;
2243 szRoot = NULL;
2244 break;
2246 if (!root_key)
2247 return ERROR_SUCCESS;
2249 deformat_string(package, key , &deformated);
2250 size = strlenW(deformated) + strlenW(szRoot) + 1;
2251 uikey = msi_alloc(size*sizeof(WCHAR));
2252 strcpyW(uikey,szRoot);
2253 strcatW(uikey,deformated);
2255 if (RegCreateKeyW( root_key, deformated, &hkey))
2257 ERR("Could not create key %s\n",debugstr_w(deformated));
2258 msi_free(deformated);
2259 msi_free(uikey);
2260 return ERROR_SUCCESS;
2262 msi_free(deformated);
2264 value = MSI_RecordGetString(row,5);
2265 if (value)
2266 value_data = parse_value(package, value, &type, &size);
2267 else
2269 value_data = (LPSTR)strdupW(szEmpty);
2270 size = sizeof(szEmpty);
2271 type = REG_SZ;
2274 deformat_string(package, name, &deformated);
2276 if (!check_first)
2278 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2279 debugstr_w(uikey));
2280 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2282 else
2284 DWORD sz = 0;
2285 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2286 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2288 TRACE("value %s of %s checked already exists\n",
2289 debugstr_w(deformated), debugstr_w(uikey));
2291 else
2293 TRACE("Checked and setting value %s of %s\n",
2294 debugstr_w(deformated), debugstr_w(uikey));
2295 if (deformated || size)
2296 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2299 RegCloseKey(hkey);
2301 uirow = MSI_CreateRecord(3);
2302 MSI_RecordSetStringW(uirow,2,deformated);
2303 MSI_RecordSetStringW(uirow,1,uikey);
2305 if (type == REG_SZ)
2306 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2307 else
2308 MSI_RecordSetStringW(uirow,3,value);
2310 ui_actiondata(package,szWriteRegistryValues,uirow);
2311 msiobj_release( &uirow->hdr );
2313 msi_free(value_data);
2314 msi_free(deformated);
2315 msi_free(uikey);
2317 return ERROR_SUCCESS;
2320 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2322 UINT rc;
2323 MSIQUERY * view;
2324 static const WCHAR ExecSeqQuery[] =
2325 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2326 '`','R','e','g','i','s','t','r','y','`',0 };
2328 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2329 if (rc != ERROR_SUCCESS)
2330 return ERROR_SUCCESS;
2332 /* increment progress bar each time action data is sent */
2333 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2335 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2337 msiobj_release(&view->hdr);
2338 return rc;
2341 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2343 package->script->CurrentlyScripting = TRUE;
2345 return ERROR_SUCCESS;
2349 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2351 MSICOMPONENT *comp;
2352 DWORD progress = 0;
2353 DWORD total = 0;
2354 static const WCHAR q1[]=
2355 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2356 '`','R','e','g','i','s','t','r','y','`',0};
2357 UINT rc;
2358 MSIQUERY * view;
2359 MSIFEATURE *feature;
2360 MSIFILE *file;
2362 TRACE("InstallValidate\n");
2364 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2365 if (rc == ERROR_SUCCESS)
2367 MSI_IterateRecords( view, &progress, NULL, package );
2368 msiobj_release( &view->hdr );
2369 total += progress * REG_PROGRESS_VALUE;
2372 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2373 total += COMPONENT_PROGRESS_VALUE;
2375 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2376 total += file->FileSize;
2378 ui_progress(package,0,total,0,0);
2380 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2382 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2383 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2384 feature->ActionRequest);
2387 return ERROR_SUCCESS;
2390 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2392 MSIPACKAGE* package = param;
2393 LPCWSTR cond = NULL;
2394 LPCWSTR message = NULL;
2395 UINT r;
2397 static const WCHAR title[]=
2398 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2400 cond = MSI_RecordGetString(row,1);
2402 r = MSI_EvaluateConditionW(package,cond);
2403 if (r == MSICONDITION_FALSE)
2405 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2407 LPWSTR deformated;
2408 message = MSI_RecordGetString(row,2);
2409 deformat_string(package,message,&deformated);
2410 MessageBoxW(NULL,deformated,title,MB_OK);
2411 msi_free(deformated);
2414 return ERROR_INSTALL_FAILURE;
2417 return ERROR_SUCCESS;
2420 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2422 UINT rc;
2423 MSIQUERY * view = NULL;
2424 static const WCHAR ExecSeqQuery[] =
2425 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2426 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2428 TRACE("Checking launch conditions\n");
2430 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2431 if (rc != ERROR_SUCCESS)
2432 return ERROR_SUCCESS;
2434 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2435 msiobj_release(&view->hdr);
2437 return rc;
2440 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2443 if (!cmp->KeyPath)
2444 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2446 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2448 MSIRECORD * row = 0;
2449 UINT root,len;
2450 LPWSTR deformated,buffer,deformated_name;
2451 LPCWSTR key,name;
2452 static const WCHAR ExecSeqQuery[] =
2453 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2454 '`','R','e','g','i','s','t','r','y','`',' ',
2455 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2456 ' ','=',' ' ,'\'','%','s','\'',0 };
2457 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2458 static const WCHAR fmt2[]=
2459 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2461 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2462 if (!row)
2463 return NULL;
2465 root = MSI_RecordGetInteger(row,2);
2466 key = MSI_RecordGetString(row, 3);
2467 name = MSI_RecordGetString(row, 4);
2468 deformat_string(package, key , &deformated);
2469 deformat_string(package, name, &deformated_name);
2471 len = strlenW(deformated) + 6;
2472 if (deformated_name)
2473 len+=strlenW(deformated_name);
2475 buffer = msi_alloc( len *sizeof(WCHAR));
2477 if (deformated_name)
2478 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2479 else
2480 sprintfW(buffer,fmt,root,deformated);
2482 msi_free(deformated);
2483 msi_free(deformated_name);
2484 msiobj_release(&row->hdr);
2486 return buffer;
2488 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2490 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2491 return NULL;
2493 else
2495 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2497 if (file)
2498 return strdupW( file->TargetPath );
2500 return NULL;
2503 static HKEY openSharedDLLsKey(void)
2505 HKEY hkey=0;
2506 static const WCHAR path[] =
2507 {'S','o','f','t','w','a','r','e','\\',
2508 'M','i','c','r','o','s','o','f','t','\\',
2509 'W','i','n','d','o','w','s','\\',
2510 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2511 'S','h','a','r','e','d','D','L','L','s',0};
2513 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2514 return hkey;
2517 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2519 HKEY hkey;
2520 DWORD count=0;
2521 DWORD type;
2522 DWORD sz = sizeof(count);
2523 DWORD rc;
2525 hkey = openSharedDLLsKey();
2526 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2527 if (rc != ERROR_SUCCESS)
2528 count = 0;
2529 RegCloseKey(hkey);
2530 return count;
2533 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2535 HKEY hkey;
2537 hkey = openSharedDLLsKey();
2538 if (count > 0)
2539 msi_reg_set_val_dword( hkey, path, count );
2540 else
2541 RegDeleteValueW(hkey,path);
2542 RegCloseKey(hkey);
2543 return count;
2547 * Return TRUE if the count should be written out and FALSE if not
2549 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2551 MSIFEATURE *feature;
2552 INT count = 0;
2553 BOOL write = FALSE;
2555 /* only refcount DLLs */
2556 if (comp->KeyPath == NULL ||
2557 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2558 comp->Attributes & msidbComponentAttributesODBCDataSource)
2559 write = FALSE;
2560 else
2562 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2563 write = (count > 0);
2565 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2566 write = TRUE;
2569 /* increment counts */
2570 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2572 ComponentList *cl;
2574 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2575 continue;
2577 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2579 if ( cl->component == comp )
2580 count++;
2584 /* decrement counts */
2585 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2587 ComponentList *cl;
2589 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2590 continue;
2592 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2594 if ( cl->component == comp )
2595 count--;
2599 /* ref count all the files in the component */
2600 if (write)
2602 MSIFILE *file;
2604 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2606 if (file->Component == comp)
2607 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2611 /* add a count for permanent */
2612 if (comp->Attributes & msidbComponentAttributesPermanent)
2613 count ++;
2615 comp->RefCount = count;
2617 if (write)
2618 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2621 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2623 WCHAR squished_pc[GUID_SIZE];
2624 WCHAR squished_cc[GUID_SIZE];
2625 UINT rc;
2626 MSICOMPONENT *comp;
2627 HKEY hkey;
2629 TRACE("\n");
2631 squash_guid(package->ProductCode,squished_pc);
2632 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2634 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2636 MSIRECORD * uirow;
2638 ui_progress(package,2,0,0,0);
2639 if (!comp->ComponentId)
2640 continue;
2642 squash_guid(comp->ComponentId,squished_cc);
2644 msi_free(comp->FullKeypath);
2645 comp->FullKeypath = resolve_keypath( package, comp );
2647 ACTION_RefCountComponent( package, comp );
2649 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2650 debugstr_w(comp->Component),
2651 debugstr_w(squished_cc),
2652 debugstr_w(comp->FullKeypath),
2653 comp->RefCount);
2655 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL) ||
2656 ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE))
2658 if (!comp->FullKeypath)
2659 continue;
2661 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2662 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2663 &hkey, TRUE);
2664 else
2665 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2666 &hkey, TRUE);
2668 if (rc != ERROR_SUCCESS)
2669 continue;
2671 if (comp->Attributes & msidbComponentAttributesPermanent)
2673 static const WCHAR szPermKey[] =
2674 { '0','0','0','0','0','0','0','0','0','0','0','0',
2675 '0','0','0','0','0','0','0','0','0','0','0','0',
2676 '0','0','0','0','0','0','0','0',0 };
2678 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2681 if (comp->Action == INSTALLSTATE_LOCAL)
2682 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2683 else
2685 MSIFILE *file;
2686 MSIRECORD *row;
2687 LPWSTR ptr, ptr2;
2688 WCHAR source[MAX_PATH];
2689 WCHAR base[MAX_PATH];
2690 LPWSTR sourcepath;
2692 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2693 static const WCHAR query[] = {
2694 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2695 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2696 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2697 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2698 '`','D','i','s','k','I','d','`',0};
2700 file = get_loaded_file(package, comp->KeyPath);
2701 if (!file)
2702 continue;
2704 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2705 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2706 ptr2 = strrchrW(source, '\\') + 1;
2707 msiobj_release(&row->hdr);
2709 lstrcpyW(base, package->PackagePath);
2710 ptr = strrchrW(base, '\\');
2711 *(ptr + 1) = '\0';
2713 sourcepath = resolve_file_source(package, file);
2714 ptr = sourcepath + lstrlenW(base);
2715 lstrcpyW(ptr2, ptr);
2716 msi_free(sourcepath);
2718 msi_reg_set_val_str(hkey, squished_pc, source);
2720 RegCloseKey(hkey);
2722 else if (ACTION_VerifyComponentForAction(comp, INSTALLSTATE_ABSENT))
2724 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2725 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2726 else
2727 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2730 /* UI stuff */
2731 uirow = MSI_CreateRecord(3);
2732 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2733 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2734 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2735 ui_actiondata(package,szProcessComponents,uirow);
2736 msiobj_release( &uirow->hdr );
2739 return ERROR_SUCCESS;
2742 typedef struct {
2743 CLSID clsid;
2744 LPWSTR source;
2746 LPWSTR path;
2747 ITypeLib *ptLib;
2748 } typelib_struct;
2750 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2751 LPWSTR lpszName, LONG_PTR lParam)
2753 TLIBATTR *attr;
2754 typelib_struct *tl_struct = (typelib_struct*) lParam;
2755 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2756 int sz;
2757 HRESULT res;
2759 if (!IS_INTRESOURCE(lpszName))
2761 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2762 return TRUE;
2765 sz = strlenW(tl_struct->source)+4;
2766 sz *= sizeof(WCHAR);
2768 if ((INT_PTR)lpszName == 1)
2769 tl_struct->path = strdupW(tl_struct->source);
2770 else
2772 tl_struct->path = msi_alloc(sz);
2773 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2776 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2777 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2778 if (FAILED(res))
2780 msi_free(tl_struct->path);
2781 tl_struct->path = NULL;
2783 return TRUE;
2786 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2787 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2789 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2790 return FALSE;
2793 msi_free(tl_struct->path);
2794 tl_struct->path = NULL;
2796 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2797 ITypeLib_Release(tl_struct->ptLib);
2799 return TRUE;
2802 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2804 MSIPACKAGE* package = param;
2805 LPCWSTR component;
2806 MSICOMPONENT *comp;
2807 MSIFILE *file;
2808 typelib_struct tl_struct;
2809 ITypeLib *tlib;
2810 HMODULE module;
2811 HRESULT hr;
2813 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2815 component = MSI_RecordGetString(row,3);
2816 comp = get_loaded_component(package,component);
2817 if (!comp)
2818 return ERROR_SUCCESS;
2820 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2822 TRACE("Skipping typelib reg due to disabled component\n");
2824 comp->Action = comp->Installed;
2826 return ERROR_SUCCESS;
2829 comp->Action = INSTALLSTATE_LOCAL;
2831 file = get_loaded_file( package, comp->KeyPath );
2832 if (!file)
2833 return ERROR_SUCCESS;
2835 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2836 if (module)
2838 LPCWSTR guid;
2839 guid = MSI_RecordGetString(row,1);
2840 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2841 tl_struct.source = strdupW( file->TargetPath );
2842 tl_struct.path = NULL;
2844 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2845 (LONG_PTR)&tl_struct);
2847 if (tl_struct.path)
2849 LPWSTR help = NULL;
2850 LPCWSTR helpid;
2851 HRESULT res;
2853 helpid = MSI_RecordGetString(row,6);
2855 if (helpid)
2856 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
2857 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2858 msi_free(help);
2860 if (FAILED(res))
2861 ERR("Failed to register type library %s\n",
2862 debugstr_w(tl_struct.path));
2863 else
2865 ui_actiondata(package,szRegisterTypeLibraries,row);
2867 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2870 ITypeLib_Release(tl_struct.ptLib);
2871 msi_free(tl_struct.path);
2873 else
2874 ERR("Failed to load type library %s\n",
2875 debugstr_w(tl_struct.source));
2877 FreeLibrary(module);
2878 msi_free(tl_struct.source);
2880 else
2882 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
2883 if (FAILED(hr))
2885 ERR("Failed to load type library: %08x\n", hr);
2886 return ERROR_FUNCTION_FAILED;
2889 ITypeLib_Release(tlib);
2892 return ERROR_SUCCESS;
2895 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2898 * OK this is a bit confusing.. I am given a _Component key and I believe
2899 * that the file that is being registered as a type library is the "key file
2900 * of that component" which I interpret to mean "The file in the KeyPath of
2901 * that component".
2903 UINT rc;
2904 MSIQUERY * view;
2905 static const WCHAR Query[] =
2906 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2907 '`','T','y','p','e','L','i','b','`',0};
2909 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2910 if (rc != ERROR_SUCCESS)
2911 return ERROR_SUCCESS;
2913 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2914 msiobj_release(&view->hdr);
2915 return rc;
2918 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2920 MSIPACKAGE *package = param;
2921 LPWSTR target_file, target_folder, filename;
2922 LPCWSTR buffer, extension;
2923 MSICOMPONENT *comp;
2924 static const WCHAR szlnk[]={'.','l','n','k',0};
2925 IShellLinkW *sl = NULL;
2926 IPersistFile *pf = NULL;
2927 HRESULT res;
2929 buffer = MSI_RecordGetString(row,4);
2930 comp = get_loaded_component(package,buffer);
2931 if (!comp)
2932 return ERROR_SUCCESS;
2934 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2936 TRACE("Skipping shortcut creation due to disabled component\n");
2938 comp->Action = comp->Installed;
2940 return ERROR_SUCCESS;
2943 comp->Action = INSTALLSTATE_LOCAL;
2945 ui_actiondata(package,szCreateShortcuts,row);
2947 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2948 &IID_IShellLinkW, (LPVOID *) &sl );
2950 if (FAILED( res ))
2952 ERR("CLSID_ShellLink not available\n");
2953 goto err;
2956 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2957 if (FAILED( res ))
2959 ERR("QueryInterface(IID_IPersistFile) failed\n");
2960 goto err;
2963 buffer = MSI_RecordGetString(row,2);
2964 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
2966 /* may be needed because of a bug somewhere else */
2967 create_full_pathW(target_folder);
2969 filename = msi_dup_record_field( row, 3 );
2970 reduce_to_longfilename(filename);
2972 extension = strchrW(filename,'.');
2973 if (!extension || strcmpiW(extension,szlnk))
2975 int len = strlenW(filename);
2976 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2977 memcpy(filename + len, szlnk, sizeof(szlnk));
2979 target_file = build_directory_name(2, target_folder, filename);
2980 msi_free(target_folder);
2981 msi_free(filename);
2983 buffer = MSI_RecordGetString(row,5);
2984 if (strchrW(buffer,'['))
2986 LPWSTR deformated;
2987 deformat_string(package,buffer,&deformated);
2988 IShellLinkW_SetPath(sl,deformated);
2989 msi_free(deformated);
2991 else
2993 FIXME("poorly handled shortcut format, advertised shortcut\n");
2994 IShellLinkW_SetPath(sl,comp->FullKeypath);
2997 if (!MSI_RecordIsNull(row,6))
2999 LPWSTR deformated;
3000 buffer = MSI_RecordGetString(row,6);
3001 deformat_string(package,buffer,&deformated);
3002 IShellLinkW_SetArguments(sl,deformated);
3003 msi_free(deformated);
3006 if (!MSI_RecordIsNull(row,7))
3008 buffer = MSI_RecordGetString(row,7);
3009 IShellLinkW_SetDescription(sl,buffer);
3012 if (!MSI_RecordIsNull(row,8))
3013 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3015 if (!MSI_RecordIsNull(row,9))
3017 LPWSTR Path;
3018 INT index;
3020 buffer = MSI_RecordGetString(row,9);
3022 Path = build_icon_path(package,buffer);
3023 index = MSI_RecordGetInteger(row,10);
3025 /* no value means 0 */
3026 if (index == MSI_NULL_INTEGER)
3027 index = 0;
3029 IShellLinkW_SetIconLocation(sl,Path,index);
3030 msi_free(Path);
3033 if (!MSI_RecordIsNull(row,11))
3034 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3036 if (!MSI_RecordIsNull(row,12))
3038 LPWSTR Path;
3039 buffer = MSI_RecordGetString(row,12);
3040 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3041 if (Path)
3042 IShellLinkW_SetWorkingDirectory(sl,Path);
3043 msi_free(Path);
3046 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3047 IPersistFile_Save(pf,target_file,FALSE);
3049 msi_free(target_file);
3051 err:
3052 if (pf)
3053 IPersistFile_Release( pf );
3054 if (sl)
3055 IShellLinkW_Release( sl );
3057 return ERROR_SUCCESS;
3060 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3062 UINT rc;
3063 HRESULT res;
3064 MSIQUERY * view;
3065 static const WCHAR Query[] =
3066 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3067 '`','S','h','o','r','t','c','u','t','`',0};
3069 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3070 if (rc != ERROR_SUCCESS)
3071 return ERROR_SUCCESS;
3073 res = CoInitialize( NULL );
3075 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3076 msiobj_release(&view->hdr);
3078 if (SUCCEEDED(res))
3079 CoUninitialize();
3081 return rc;
3084 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3086 MSIPACKAGE* package = param;
3087 HANDLE the_file;
3088 LPWSTR FilePath;
3089 LPCWSTR FileName;
3090 CHAR buffer[1024];
3091 DWORD sz;
3092 UINT rc;
3093 MSIRECORD *uirow;
3095 FileName = MSI_RecordGetString(row,1);
3096 if (!FileName)
3098 ERR("Unable to get FileName\n");
3099 return ERROR_SUCCESS;
3102 FilePath = build_icon_path(package,FileName);
3104 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3106 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3107 FILE_ATTRIBUTE_NORMAL, NULL);
3109 if (the_file == INVALID_HANDLE_VALUE)
3111 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3112 msi_free(FilePath);
3113 return ERROR_SUCCESS;
3118 DWORD write;
3119 sz = 1024;
3120 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3121 if (rc != ERROR_SUCCESS)
3123 ERR("Failed to get stream\n");
3124 CloseHandle(the_file);
3125 DeleteFileW(FilePath);
3126 break;
3128 WriteFile(the_file,buffer,sz,&write,NULL);
3129 } while (sz == 1024);
3131 msi_free(FilePath);
3133 CloseHandle(the_file);
3135 uirow = MSI_CreateRecord(1);
3136 MSI_RecordSetStringW(uirow,1,FileName);
3137 ui_actiondata(package,szPublishProduct,uirow);
3138 msiobj_release( &uirow->hdr );
3140 return ERROR_SUCCESS;
3143 static UINT msi_publish_icons(MSIPACKAGE *package)
3145 UINT r;
3146 MSIQUERY *view;
3148 static const WCHAR query[]= {
3149 'S','E','L','E','C','T',' ','*',' ',
3150 'F','R','O','M',' ','`','I','c','o','n','`',0};
3152 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3153 if (r == ERROR_SUCCESS)
3155 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3156 msiobj_release(&view->hdr);
3159 return ERROR_SUCCESS;
3162 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3164 UINT r;
3165 HKEY source;
3166 LPWSTR buffer;
3167 MSIMEDIADISK *disk;
3168 MSISOURCELISTINFO *info;
3170 r = RegCreateKeyW(hkey, szSourceList, &source);
3171 if (r != ERROR_SUCCESS)
3172 return r;
3174 RegCloseKey(source);
3176 buffer = strrchrW(package->PackagePath, '\\') + 1;
3177 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3178 package->Context, MSICODE_PRODUCT,
3179 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3180 if (r != ERROR_SUCCESS)
3181 return r;
3183 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3184 package->Context, MSICODE_PRODUCT,
3185 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3186 if (r != ERROR_SUCCESS)
3187 return r;
3189 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3190 package->Context, MSICODE_PRODUCT,
3191 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3192 if (r != ERROR_SUCCESS)
3193 return r;
3195 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3197 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3198 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3199 info->options, info->value);
3200 else
3201 MsiSourceListSetInfoW(package->ProductCode, NULL,
3202 info->context, info->options,
3203 info->property, info->value);
3206 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3208 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3209 disk->context, disk->options,
3210 disk->disk_id, disk->volume_label, disk->disk_prompt);
3213 return ERROR_SUCCESS;
3216 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3218 MSIHANDLE hdb, suminfo;
3219 WCHAR guids[MAX_PATH];
3220 WCHAR packcode[SQUISH_GUID_SIZE];
3221 LPWSTR buffer;
3222 LPWSTR ptr;
3223 DWORD langid;
3224 DWORD size;
3225 UINT r;
3227 static const WCHAR szProductLanguage[] =
3228 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3229 static const WCHAR szARPProductIcon[] =
3230 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3231 static const WCHAR szProductVersion[] =
3232 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3233 static const WCHAR szAssignment[] =
3234 {'A','s','s','i','g','n','m','e','n','t',0};
3235 static const WCHAR szAdvertiseFlags[] =
3236 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3237 static const WCHAR szClients[] =
3238 {'C','l','i','e','n','t','s',0};
3239 static const WCHAR szColon[] = {':',0};
3241 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3242 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3243 msi_free(buffer);
3245 langid = msi_get_property_int(package, szProductLanguage, 0);
3246 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3248 /* FIXME */
3249 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3251 buffer = msi_dup_property(package, szARPProductIcon);
3252 if (buffer)
3254 LPWSTR path = build_icon_path(package,buffer);
3255 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3256 msi_free(path);
3257 msi_free(buffer);
3260 buffer = msi_dup_property(package, szProductVersion);
3261 if (buffer)
3263 DWORD verdword = msi_version_str_to_dword(buffer);
3264 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3265 msi_free(buffer);
3268 msi_reg_set_val_dword(hkey, szAssignment, 0);
3269 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3270 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3271 msi_reg_set_val_str(hkey, szClients, szColon);
3273 hdb = alloc_msihandle(&package->db->hdr);
3274 if (!hdb)
3275 return ERROR_NOT_ENOUGH_MEMORY;
3277 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3278 MsiCloseHandle(hdb);
3279 if (r != ERROR_SUCCESS)
3280 goto done;
3282 size = MAX_PATH;
3283 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3284 NULL, guids, &size);
3285 if (r != ERROR_SUCCESS)
3286 goto done;
3288 ptr = strchrW(guids, ';');
3289 if (ptr) *ptr = 0;
3290 squash_guid(guids, packcode);
3291 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3293 done:
3294 MsiCloseHandle(suminfo);
3295 return ERROR_SUCCESS;
3298 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3300 UINT r;
3301 HKEY hkey;
3302 LPWSTR upgrade;
3303 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3305 static const WCHAR szUpgradeCode[] =
3306 {'U','p','g','r','a','d','e','C','o','d','e',0};
3308 upgrade = msi_dup_property(package, szUpgradeCode);
3309 if (!upgrade)
3310 return ERROR_SUCCESS;
3312 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3314 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3315 if (r != ERROR_SUCCESS)
3316 goto done;
3318 else
3320 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3321 if (r != ERROR_SUCCESS)
3322 goto done;
3325 squash_guid(package->ProductCode, squashed_pc);
3326 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3328 RegCloseKey(hkey);
3330 done:
3331 msi_free(upgrade);
3332 return r;
3335 static BOOL msi_check_publish(MSIPACKAGE *package)
3337 MSIFEATURE *feature;
3339 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3341 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3342 return TRUE;
3345 return FALSE;
3348 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3350 MSIFEATURE *feature;
3352 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3354 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3355 return FALSE;
3358 return TRUE;
3361 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3363 WCHAR patch_squashed[GUID_SIZE];
3364 HKEY patches;
3365 LONG res;
3366 UINT r = ERROR_FUNCTION_FAILED;
3368 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3369 &patches, NULL);
3370 if (res != ERROR_SUCCESS)
3371 return ERROR_FUNCTION_FAILED;
3373 squash_guid(package->patch->patchcode, patch_squashed);
3375 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3376 (const BYTE *)patch_squashed,
3377 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3378 if (res != ERROR_SUCCESS)
3379 goto done;
3381 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3382 (const BYTE *)package->patch->transforms,
3383 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3384 if (res == ERROR_SUCCESS)
3385 r = ERROR_SUCCESS;
3387 done:
3388 RegCloseKey(patches);
3389 return r;
3393 * 99% of the work done here is only done for
3394 * advertised installs. However this is where the
3395 * Icon table is processed and written out
3396 * so that is what I am going to do here.
3398 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3400 UINT rc;
3401 HKEY hukey=0;
3402 HKEY hudkey=0;
3404 /* FIXME: also need to publish if the product is in advertise mode */
3405 if (!msi_check_publish(package))
3406 return ERROR_SUCCESS;
3408 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3409 &hukey, TRUE);
3410 if (rc != ERROR_SUCCESS)
3411 goto end;
3413 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3414 NULL, &hudkey, TRUE);
3415 if (rc != ERROR_SUCCESS)
3416 goto end;
3418 rc = msi_publish_upgrade_code(package);
3419 if (rc != ERROR_SUCCESS)
3420 goto end;
3422 if (package->patch)
3424 rc = msi_publish_patch(package, hukey, hudkey);
3425 if (rc != ERROR_SUCCESS)
3426 goto end;
3429 rc = msi_publish_product_properties(package, hukey);
3430 if (rc != ERROR_SUCCESS)
3431 goto end;
3433 rc = msi_publish_sourcelist(package, hukey);
3434 if (rc != ERROR_SUCCESS)
3435 goto end;
3437 rc = msi_publish_icons(package);
3439 end:
3440 RegCloseKey(hukey);
3441 RegCloseKey(hudkey);
3443 return rc;
3446 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3448 MSIPACKAGE *package = param;
3449 LPCWSTR component, section, key, value, identifier, dirproperty;
3450 LPWSTR deformated_section, deformated_key, deformated_value;
3451 LPWSTR folder, filename, fullname = NULL;
3452 LPCWSTR filenameptr;
3453 MSIRECORD * uirow;
3454 INT action;
3455 MSICOMPONENT *comp;
3456 static const WCHAR szWindowsFolder[] =
3457 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3459 component = MSI_RecordGetString(row, 8);
3460 comp = get_loaded_component(package,component);
3462 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3464 TRACE("Skipping ini file due to disabled component %s\n",
3465 debugstr_w(component));
3467 comp->Action = comp->Installed;
3469 return ERROR_SUCCESS;
3472 comp->Action = INSTALLSTATE_LOCAL;
3474 identifier = MSI_RecordGetString(row,1);
3475 dirproperty = MSI_RecordGetString(row,3);
3476 section = MSI_RecordGetString(row,4);
3477 key = MSI_RecordGetString(row,5);
3478 value = MSI_RecordGetString(row,6);
3479 action = MSI_RecordGetInteger(row,7);
3481 deformat_string(package,section,&deformated_section);
3482 deformat_string(package,key,&deformated_key);
3483 deformat_string(package,value,&deformated_value);
3485 filename = msi_dup_record_field(row, 2);
3486 if (filename && (filenameptr = strchrW(filename, '|')))
3487 filenameptr++;
3488 else
3489 filenameptr = filename;
3491 if (dirproperty)
3493 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3494 if (!folder)
3495 folder = msi_dup_property( package, dirproperty );
3497 else
3498 folder = msi_dup_property( package, szWindowsFolder );
3500 if (!folder)
3502 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3503 goto cleanup;
3506 fullname = build_directory_name(2, folder, filenameptr);
3508 if (action == 0)
3510 TRACE("Adding value %s to section %s in %s\n",
3511 debugstr_w(deformated_key), debugstr_w(deformated_section),
3512 debugstr_w(fullname));
3513 WritePrivateProfileStringW(deformated_section, deformated_key,
3514 deformated_value, fullname);
3516 else if (action == 1)
3518 WCHAR returned[10];
3519 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3520 returned, 10, fullname);
3521 if (returned[0] == 0)
3523 TRACE("Adding value %s to section %s in %s\n",
3524 debugstr_w(deformated_key), debugstr_w(deformated_section),
3525 debugstr_w(fullname));
3527 WritePrivateProfileStringW(deformated_section, deformated_key,
3528 deformated_value, fullname);
3531 else if (action == 3)
3532 FIXME("Append to existing section not yet implemented\n");
3534 uirow = MSI_CreateRecord(4);
3535 MSI_RecordSetStringW(uirow,1,identifier);
3536 MSI_RecordSetStringW(uirow,2,deformated_section);
3537 MSI_RecordSetStringW(uirow,3,deformated_key);
3538 MSI_RecordSetStringW(uirow,4,deformated_value);
3539 ui_actiondata(package,szWriteIniValues,uirow);
3540 msiobj_release( &uirow->hdr );
3542 cleanup:
3543 msi_free(filename);
3544 msi_free(fullname);
3545 msi_free(folder);
3546 msi_free(deformated_key);
3547 msi_free(deformated_value);
3548 msi_free(deformated_section);
3549 return ERROR_SUCCESS;
3552 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3554 UINT rc;
3555 MSIQUERY * view;
3556 static const WCHAR ExecSeqQuery[] =
3557 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3558 '`','I','n','i','F','i','l','e','`',0};
3560 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3561 if (rc != ERROR_SUCCESS)
3563 TRACE("no IniFile table\n");
3564 return ERROR_SUCCESS;
3567 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3568 msiobj_release(&view->hdr);
3569 return rc;
3572 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3574 MSIPACKAGE *package = param;
3575 LPCWSTR filename;
3576 LPWSTR FullName;
3577 MSIFILE *file;
3578 DWORD len;
3579 static const WCHAR ExeStr[] =
3580 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3581 static const WCHAR close[] = {'\"',0};
3582 STARTUPINFOW si;
3583 PROCESS_INFORMATION info;
3584 BOOL brc;
3585 MSIRECORD *uirow;
3586 LPWSTR uipath, p;
3588 memset(&si,0,sizeof(STARTUPINFOW));
3590 filename = MSI_RecordGetString(row,1);
3591 file = get_loaded_file( package, filename );
3593 if (!file)
3595 ERR("Unable to find file id %s\n",debugstr_w(filename));
3596 return ERROR_SUCCESS;
3599 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3601 FullName = msi_alloc(len*sizeof(WCHAR));
3602 strcpyW(FullName,ExeStr);
3603 strcatW( FullName, file->TargetPath );
3604 strcatW(FullName,close);
3606 TRACE("Registering %s\n",debugstr_w(FullName));
3607 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3608 &si, &info);
3610 if (brc)
3612 CloseHandle(info.hThread);
3613 msi_dialog_check_messages(info.hProcess);
3614 CloseHandle(info.hProcess);
3617 msi_free(FullName);
3619 /* the UI chunk */
3620 uirow = MSI_CreateRecord( 2 );
3621 uipath = strdupW( file->TargetPath );
3622 p = strrchrW(uipath,'\\');
3623 if (p)
3624 p[0]=0;
3625 MSI_RecordSetStringW( uirow, 1, &p[1] );
3626 MSI_RecordSetStringW( uirow, 2, uipath);
3627 ui_actiondata( package, szSelfRegModules, uirow);
3628 msiobj_release( &uirow->hdr );
3629 msi_free( uipath );
3630 /* FIXME: call ui_progress? */
3632 return ERROR_SUCCESS;
3635 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3637 UINT rc;
3638 MSIQUERY * view;
3639 static const WCHAR ExecSeqQuery[] =
3640 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3641 '`','S','e','l','f','R','e','g','`',0};
3643 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3644 if (rc != ERROR_SUCCESS)
3646 TRACE("no SelfReg table\n");
3647 return ERROR_SUCCESS;
3650 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3651 msiobj_release(&view->hdr);
3653 return ERROR_SUCCESS;
3656 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3658 MSIFEATURE *feature;
3659 UINT rc;
3660 HKEY hkey;
3661 HKEY userdata = NULL;
3663 if (!msi_check_publish(package))
3664 return ERROR_SUCCESS;
3666 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3667 &hkey, TRUE);
3668 if (rc != ERROR_SUCCESS)
3669 goto end;
3671 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3672 &userdata, TRUE);
3673 if (rc != ERROR_SUCCESS)
3674 goto end;
3676 /* here the guids are base 85 encoded */
3677 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3679 ComponentList *cl;
3680 LPWSTR data = NULL;
3681 GUID clsid;
3682 INT size;
3683 BOOL absent = FALSE;
3684 MSIRECORD *uirow;
3686 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3687 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3688 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3689 absent = TRUE;
3691 size = 1;
3692 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3694 size += 21;
3696 if (feature->Feature_Parent)
3697 size += strlenW( feature->Feature_Parent )+2;
3699 data = msi_alloc(size * sizeof(WCHAR));
3701 data[0] = 0;
3702 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3704 MSICOMPONENT* component = cl->component;
3705 WCHAR buf[21];
3707 buf[0] = 0;
3708 if (component->ComponentId)
3710 TRACE("From %s\n",debugstr_w(component->ComponentId));
3711 CLSIDFromString(component->ComponentId, &clsid);
3712 encode_base85_guid(&clsid,buf);
3713 TRACE("to %s\n",debugstr_w(buf));
3714 strcatW(data,buf);
3718 if (feature->Feature_Parent)
3720 static const WCHAR sep[] = {'\2',0};
3721 strcatW(data,sep);
3722 strcatW(data,feature->Feature_Parent);
3725 msi_reg_set_val_str( userdata, feature->Feature, data );
3726 msi_free(data);
3728 size = 0;
3729 if (feature->Feature_Parent)
3730 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3731 if (!absent)
3733 size += sizeof(WCHAR);
3734 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3735 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
3737 else
3739 size += 2*sizeof(WCHAR);
3740 data = msi_alloc(size);
3741 data[0] = 0x6;
3742 data[1] = 0;
3743 if (feature->Feature_Parent)
3744 strcpyW( &data[1], feature->Feature_Parent );
3745 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3746 (LPBYTE)data,size);
3747 msi_free(data);
3750 /* the UI chunk */
3751 uirow = MSI_CreateRecord( 1 );
3752 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3753 ui_actiondata( package, szPublishFeatures, uirow);
3754 msiobj_release( &uirow->hdr );
3755 /* FIXME: call ui_progress? */
3758 end:
3759 RegCloseKey(hkey);
3760 RegCloseKey(userdata);
3761 return rc;
3764 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
3766 UINT r;
3767 HKEY hkey;
3769 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
3771 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3772 &hkey, FALSE);
3773 if (r == ERROR_SUCCESS)
3775 RegDeleteValueW(hkey, feature->Feature);
3776 RegCloseKey(hkey);
3779 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3780 &hkey, FALSE);
3781 if (r == ERROR_SUCCESS)
3783 RegDeleteValueW(hkey, feature->Feature);
3784 RegCloseKey(hkey);
3787 return ERROR_SUCCESS;
3790 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
3792 MSIFEATURE *feature;
3794 if (!msi_check_unpublish(package))
3795 return ERROR_SUCCESS;
3797 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3799 msi_unpublish_feature(package, feature);
3802 return ERROR_SUCCESS;
3805 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
3807 LPWSTR prop, val, key;
3808 SYSTEMTIME systime;
3809 DWORD size, langid;
3810 WCHAR date[9];
3811 LPWSTR buffer;
3813 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
3814 static const WCHAR szWindowsInstaller[] =
3815 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3816 static const WCHAR modpath_fmt[] =
3817 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3818 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3819 static const WCHAR szModifyPath[] =
3820 {'M','o','d','i','f','y','P','a','t','h',0};
3821 static const WCHAR szUninstallString[] =
3822 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3823 static const WCHAR szEstimatedSize[] =
3824 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3825 static const WCHAR szProductLanguage[] =
3826 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3827 static const WCHAR szProductVersion[] =
3828 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3829 static const WCHAR szProductName[] =
3830 {'P','r','o','d','u','c','t','N','a','m','e',0};
3831 static const WCHAR szDisplayName[] =
3832 {'D','i','s','p','l','a','y','N','a','m','e',0};
3833 static const WCHAR szDisplayVersion[] =
3834 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
3835 static const WCHAR szManufacturer[] =
3836 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
3838 static const LPCSTR propval[] = {
3839 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3840 "ARPCONTACT", "Contact",
3841 "ARPCOMMENTS", "Comments",
3842 "ProductName", "DisplayName",
3843 "ProductVersion", "DisplayVersion",
3844 "ARPHELPLINK", "HelpLink",
3845 "ARPHELPTELEPHONE", "HelpTelephone",
3846 "ARPINSTALLLOCATION", "InstallLocation",
3847 "SourceDir", "InstallSource",
3848 "Manufacturer", "Publisher",
3849 "ARPREADME", "Readme",
3850 "ARPSIZE", "Size",
3851 "ARPURLINFOABOUT", "URLInfoAbout",
3852 "ARPURLUPDATEINFO", "URLUpdateInfo",
3853 NULL,
3855 const LPCSTR *p = propval;
3857 while (*p)
3859 prop = strdupAtoW(*p++);
3860 key = strdupAtoW(*p++);
3861 val = msi_dup_property(package, prop);
3862 msi_reg_set_val_str(hkey, key, val);
3863 msi_free(val);
3864 msi_free(key);
3865 msi_free(prop);
3868 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
3870 size = deformat_string(package, modpath_fmt, &buffer);
3871 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
3872 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
3873 msi_free(buffer);
3875 /* FIXME: Write real Estimated Size when we have it */
3876 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
3878 buffer = msi_dup_property(package, szProductName);
3879 msi_reg_set_val_str(hkey, szDisplayName, buffer);
3880 msi_free(buffer);
3882 buffer = msi_dup_property(package, cszSourceDir);
3883 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
3884 msi_free(buffer);
3886 buffer = msi_dup_property(package, szManufacturer);
3887 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
3888 msi_free(buffer);
3890 GetLocalTime(&systime);
3891 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
3892 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
3894 langid = msi_get_property_int(package, szProductLanguage, 0);
3895 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3897 buffer = msi_dup_property(package, szProductVersion);
3898 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
3899 if (buffer)
3901 DWORD verdword = msi_version_str_to_dword(buffer);
3903 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3904 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
3905 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
3906 msi_free(buffer);
3909 return ERROR_SUCCESS;
3912 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3914 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3915 LPWSTR upgrade_code;
3916 HKEY hkey, props;
3917 HKEY upgrade;
3918 UINT rc;
3920 static const WCHAR szUpgradeCode[] = {
3921 'U','p','g','r','a','d','e','C','o','d','e',0};
3923 /* FIXME: also need to publish if the product is in advertise mode */
3924 if (!msi_check_publish(package))
3925 return ERROR_SUCCESS;
3927 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
3928 if (rc != ERROR_SUCCESS)
3929 return rc;
3931 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
3932 NULL, &props, TRUE);
3933 if (rc != ERROR_SUCCESS)
3934 goto done;
3936 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
3937 msi_free( package->db->localfile );
3938 package->db->localfile = NULL;
3940 rc = msi_publish_install_properties(package, hkey);
3941 if (rc != ERROR_SUCCESS)
3942 goto done;
3944 rc = msi_publish_install_properties(package, props);
3945 if (rc != ERROR_SUCCESS)
3946 goto done;
3948 upgrade_code = msi_dup_property(package, szUpgradeCode);
3949 if (upgrade_code)
3951 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
3952 squash_guid(package->ProductCode, squashed_pc);
3953 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
3954 RegCloseKey(upgrade);
3955 msi_free(upgrade_code);
3958 done:
3959 RegCloseKey(hkey);
3961 return ERROR_SUCCESS;
3964 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3966 return execute_script(package,INSTALL_SCRIPT);
3969 static UINT msi_unpublish_product(MSIPACKAGE *package)
3971 LPWSTR upgrade;
3972 LPWSTR remove = NULL;
3973 LPWSTR *features = NULL;
3974 BOOL full_uninstall = TRUE;
3975 MSIFEATURE *feature;
3977 static const WCHAR szUpgradeCode[] =
3978 {'U','p','g','r','a','d','e','C','o','d','e',0};
3980 remove = msi_dup_property(package, szRemove);
3981 if (!remove)
3982 return ERROR_SUCCESS;
3984 features = msi_split_string(remove, ',');
3985 if (!features)
3987 msi_free(remove);
3988 ERR("REMOVE feature list is empty!\n");
3989 return ERROR_FUNCTION_FAILED;
3992 if (!lstrcmpW(features[0], szAll))
3993 full_uninstall = TRUE;
3994 else
3996 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3998 if (feature->Action != INSTALLSTATE_ABSENT)
3999 full_uninstall = FALSE;
4003 if (!full_uninstall)
4004 goto done;
4006 MSIREG_DeleteProductKey(package->ProductCode);
4007 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4008 MSIREG_DeleteUninstallKey(package->ProductCode);
4010 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4012 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4013 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4015 else
4017 MSIREG_DeleteUserProductKey(package->ProductCode);
4018 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4021 upgrade = msi_dup_property(package, szUpgradeCode);
4022 if (upgrade)
4024 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4025 msi_free(upgrade);
4028 done:
4029 msi_free(remove);
4030 msi_free(features);
4031 return ERROR_SUCCESS;
4034 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4036 UINT rc;
4038 rc = msi_unpublish_product(package);
4039 if (rc != ERROR_SUCCESS)
4040 return rc;
4042 /* turn off scheduling */
4043 package->script->CurrentlyScripting= FALSE;
4045 /* first do the same as an InstallExecute */
4046 rc = ACTION_InstallExecute(package);
4047 if (rc != ERROR_SUCCESS)
4048 return rc;
4050 /* then handle Commit Actions */
4051 rc = execute_script(package,COMMIT_SCRIPT);
4053 return rc;
4056 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4058 static const WCHAR RunOnce[] = {
4059 'S','o','f','t','w','a','r','e','\\',
4060 'M','i','c','r','o','s','o','f','t','\\',
4061 'W','i','n','d','o','w','s','\\',
4062 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4063 'R','u','n','O','n','c','e',0};
4064 static const WCHAR InstallRunOnce[] = {
4065 'S','o','f','t','w','a','r','e','\\',
4066 'M','i','c','r','o','s','o','f','t','\\',
4067 'W','i','n','d','o','w','s','\\',
4068 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4069 'I','n','s','t','a','l','l','e','r','\\',
4070 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4072 static const WCHAR msiexec_fmt[] = {
4073 '%','s',
4074 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4075 '\"','%','s','\"',0};
4076 static const WCHAR install_fmt[] = {
4077 '/','I',' ','\"','%','s','\"',' ',
4078 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4079 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4080 WCHAR buffer[256], sysdir[MAX_PATH];
4081 HKEY hkey;
4082 WCHAR squished_pc[100];
4084 squash_guid(package->ProductCode,squished_pc);
4086 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4087 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4088 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4089 squished_pc);
4091 msi_reg_set_val_str( hkey, squished_pc, buffer );
4092 RegCloseKey(hkey);
4094 TRACE("Reboot command %s\n",debugstr_w(buffer));
4096 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4097 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4099 msi_reg_set_val_str( hkey, squished_pc, buffer );
4100 RegCloseKey(hkey);
4102 return ERROR_INSTALL_SUSPEND;
4105 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4107 DWORD attrib;
4108 UINT rc;
4111 * We are currently doing what should be done here in the top level Install
4112 * however for Administrative and uninstalls this step will be needed
4114 if (!package->PackagePath)
4115 return ERROR_SUCCESS;
4117 msi_set_sourcedir_props(package, TRUE);
4119 attrib = GetFileAttributesW(package->db->path);
4120 if (attrib == INVALID_FILE_ATTRIBUTES)
4122 LPWSTR prompt;
4123 LPWSTR msg;
4124 DWORD size = 0;
4126 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4127 package->Context, MSICODE_PRODUCT,
4128 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4129 if (rc == ERROR_MORE_DATA)
4131 prompt = msi_alloc(size * sizeof(WCHAR));
4132 MsiSourceListGetInfoW(package->ProductCode, NULL,
4133 package->Context, MSICODE_PRODUCT,
4134 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4136 else
4137 prompt = strdupW(package->db->path);
4139 msg = generate_error_string(package,1302,1,prompt);
4140 while(attrib == INVALID_FILE_ATTRIBUTES)
4142 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4143 if (rc == IDCANCEL)
4145 rc = ERROR_INSTALL_USEREXIT;
4146 break;
4148 attrib = GetFileAttributesW(package->db->path);
4150 msi_free(prompt);
4151 rc = ERROR_SUCCESS;
4153 else
4154 return ERROR_SUCCESS;
4156 return rc;
4159 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4161 HKEY hkey=0;
4162 LPWSTR buffer;
4163 LPWSTR productid;
4164 UINT rc,i;
4166 static const WCHAR szPropKeys[][80] =
4168 {'P','r','o','d','u','c','t','I','D',0},
4169 {'U','S','E','R','N','A','M','E',0},
4170 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4171 {0},
4174 static const WCHAR szRegKeys[][80] =
4176 {'P','r','o','d','u','c','t','I','D',0},
4177 {'R','e','g','O','w','n','e','r',0},
4178 {'R','e','g','C','o','m','p','a','n','y',0},
4179 {0},
4182 if (msi_check_unpublish(package))
4184 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4185 return ERROR_SUCCESS;
4188 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4189 if (!productid)
4190 return ERROR_SUCCESS;
4192 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4193 NULL, &hkey, TRUE);
4194 if (rc != ERROR_SUCCESS)
4195 goto end;
4197 for( i = 0; szPropKeys[i][0]; i++ )
4199 buffer = msi_dup_property( package, szPropKeys[i] );
4200 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4201 msi_free( buffer );
4204 end:
4205 msi_free(productid);
4206 RegCloseKey(hkey);
4208 /* FIXME: call ui_actiondata */
4210 return rc;
4214 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4216 UINT rc;
4218 package->script->InWhatSequence |= SEQUENCE_EXEC;
4219 rc = ACTION_ProcessExecSequence(package,FALSE);
4220 return rc;
4224 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4226 MSIPACKAGE *package = param;
4227 LPCWSTR compgroupid=NULL;
4228 LPCWSTR feature=NULL;
4229 LPCWSTR text = NULL;
4230 LPCWSTR qualifier = NULL;
4231 LPCWSTR component = NULL;
4232 LPWSTR advertise = NULL;
4233 LPWSTR output = NULL;
4234 HKEY hkey;
4235 UINT rc = ERROR_SUCCESS;
4236 MSICOMPONENT *comp;
4237 DWORD sz = 0;
4238 MSIRECORD *uirow;
4240 component = MSI_RecordGetString(rec,3);
4241 comp = get_loaded_component(package,component);
4243 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4244 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4245 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4247 TRACE("Skipping: Component %s not scheduled for install\n",
4248 debugstr_w(component));
4250 return ERROR_SUCCESS;
4253 compgroupid = MSI_RecordGetString(rec,1);
4254 qualifier = MSI_RecordGetString(rec,2);
4256 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4257 if (rc != ERROR_SUCCESS)
4258 goto end;
4260 text = MSI_RecordGetString(rec,4);
4261 feature = MSI_RecordGetString(rec,5);
4263 advertise = create_component_advertise_string(package, comp, feature);
4265 sz = strlenW(advertise);
4267 if (text)
4268 sz += lstrlenW(text);
4270 sz+=3;
4271 sz *= sizeof(WCHAR);
4273 output = msi_alloc_zero(sz);
4274 strcpyW(output,advertise);
4275 msi_free(advertise);
4277 if (text)
4278 strcatW(output,text);
4280 msi_reg_set_val_multi_str( hkey, qualifier, output );
4282 end:
4283 RegCloseKey(hkey);
4284 msi_free(output);
4286 /* the UI chunk */
4287 uirow = MSI_CreateRecord( 2 );
4288 MSI_RecordSetStringW( uirow, 1, compgroupid );
4289 MSI_RecordSetStringW( uirow, 2, qualifier);
4290 ui_actiondata( package, szPublishComponents, uirow);
4291 msiobj_release( &uirow->hdr );
4292 /* FIXME: call ui_progress? */
4294 return rc;
4298 * At present I am ignorning the advertised components part of this and only
4299 * focusing on the qualified component sets
4301 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4303 UINT rc;
4304 MSIQUERY * view;
4305 static const WCHAR ExecSeqQuery[] =
4306 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4307 '`','P','u','b','l','i','s','h',
4308 'C','o','m','p','o','n','e','n','t','`',0};
4310 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4311 if (rc != ERROR_SUCCESS)
4312 return ERROR_SUCCESS;
4314 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4315 msiobj_release(&view->hdr);
4317 return rc;
4320 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4322 MSIPACKAGE *package = param;
4323 MSIRECORD *row;
4324 MSIFILE *file;
4325 SC_HANDLE hscm, service = NULL;
4326 LPCWSTR comp, depends, pass;
4327 LPWSTR name = NULL, disp = NULL;
4328 LPCWSTR load_order, serv_name, key;
4329 DWORD serv_type, start_type;
4330 DWORD err_control;
4332 static const WCHAR query[] =
4333 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4334 '`','C','o','m','p','o','n','e','n','t','`',' ',
4335 'W','H','E','R','E',' ',
4336 '`','C','o','m','p','o','n','e','n','t','`',' ',
4337 '=','\'','%','s','\'',0};
4339 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4340 if (!hscm)
4342 ERR("Failed to open the SC Manager!\n");
4343 goto done;
4346 start_type = MSI_RecordGetInteger(rec, 5);
4347 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4348 goto done;
4350 depends = MSI_RecordGetString(rec, 8);
4351 if (depends && *depends)
4352 FIXME("Dependency list unhandled!\n");
4354 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4355 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
4356 serv_type = MSI_RecordGetInteger(rec, 4);
4357 err_control = MSI_RecordGetInteger(rec, 6);
4358 load_order = MSI_RecordGetString(rec, 7);
4359 serv_name = MSI_RecordGetString(rec, 9);
4360 pass = MSI_RecordGetString(rec, 10);
4361 comp = MSI_RecordGetString(rec, 12);
4363 /* fetch the service path */
4364 row = MSI_QueryGetRecord(package->db, query, comp);
4365 if (!row)
4367 ERR("Control query failed!\n");
4368 goto done;
4371 key = MSI_RecordGetString(row, 6);
4373 file = get_loaded_file(package, key);
4374 msiobj_release(&row->hdr);
4375 if (!file)
4377 ERR("Failed to load the service file\n");
4378 goto done;
4381 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4382 start_type, err_control, file->TargetPath,
4383 load_order, NULL, NULL, serv_name, pass);
4384 if (!service)
4386 if (GetLastError() != ERROR_SERVICE_EXISTS)
4387 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4390 done:
4391 CloseServiceHandle(service);
4392 CloseServiceHandle(hscm);
4393 msi_free(name);
4394 msi_free(disp);
4396 return ERROR_SUCCESS;
4399 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4401 UINT rc;
4402 MSIQUERY * view;
4403 static const WCHAR ExecSeqQuery[] =
4404 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4405 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4407 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4408 if (rc != ERROR_SUCCESS)
4409 return ERROR_SUCCESS;
4411 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4412 msiobj_release(&view->hdr);
4414 return rc;
4417 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4418 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
4420 LPCWSTR *vector, *temp_vector;
4421 LPWSTR p, q;
4422 DWORD sep_len;
4424 static const WCHAR separator[] = {'[','~',']',0};
4426 *numargs = 0;
4427 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4429 if (!args)
4430 return NULL;
4432 vector = msi_alloc(sizeof(LPWSTR));
4433 if (!vector)
4434 return NULL;
4436 p = args;
4439 (*numargs)++;
4440 vector[*numargs - 1] = p;
4442 if ((q = strstrW(p, separator)))
4444 *q = '\0';
4446 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4447 if (!temp_vector)
4449 msi_free(vector);
4450 return NULL;
4452 vector = temp_vector;
4454 p = q + sep_len;
4456 } while (q);
4458 return vector;
4461 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4463 MSIPACKAGE *package = param;
4464 MSICOMPONENT *comp;
4465 SC_HANDLE scm, service = NULL;
4466 LPCWSTR name, *vector = NULL;
4467 LPWSTR args;
4468 DWORD event, numargs;
4469 UINT r = ERROR_FUNCTION_FAILED;
4471 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4472 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4473 return ERROR_SUCCESS;
4475 name = MSI_RecordGetString(rec, 2);
4476 event = MSI_RecordGetInteger(rec, 3);
4477 args = strdupW(MSI_RecordGetString(rec, 4));
4479 if (!(event & msidbServiceControlEventStart))
4480 return ERROR_SUCCESS;
4482 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4483 if (!scm)
4485 ERR("Failed to open the service control manager\n");
4486 goto done;
4489 service = OpenServiceW(scm, name, SERVICE_START);
4490 if (!service)
4492 ERR("Failed to open service %s\n", debugstr_w(name));
4493 goto done;
4496 vector = msi_service_args_to_vector(args, &numargs);
4498 if (!StartServiceW(service, numargs, vector))
4500 ERR("Failed to start service %s\n", debugstr_w(name));
4501 goto done;
4504 r = ERROR_SUCCESS;
4506 done:
4507 CloseServiceHandle(service);
4508 CloseServiceHandle(scm);
4510 msi_free(args);
4511 msi_free(vector);
4512 return r;
4515 static UINT ACTION_StartServices( MSIPACKAGE *package )
4517 UINT rc;
4518 MSIQUERY *view;
4520 static const WCHAR query[] = {
4521 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4522 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4524 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4525 if (rc != ERROR_SUCCESS)
4526 return ERROR_SUCCESS;
4528 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4529 msiobj_release(&view->hdr);
4531 return rc;
4534 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4536 DWORD i, needed, count;
4537 ENUM_SERVICE_STATUSW *dependencies;
4538 SERVICE_STATUS ss;
4539 SC_HANDLE depserv;
4541 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4542 0, &needed, &count))
4543 return TRUE;
4545 if (GetLastError() != ERROR_MORE_DATA)
4546 return FALSE;
4548 dependencies = msi_alloc(needed);
4549 if (!dependencies)
4550 return FALSE;
4552 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4553 needed, &needed, &count))
4554 goto error;
4556 for (i = 0; i < count; i++)
4558 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4559 SERVICE_STOP | SERVICE_QUERY_STATUS);
4560 if (!depserv)
4561 goto error;
4563 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4564 goto error;
4567 return TRUE;
4569 error:
4570 msi_free(dependencies);
4571 return FALSE;
4574 static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
4576 MSIPACKAGE *package = param;
4577 MSICOMPONENT *comp;
4578 SERVICE_STATUS status;
4579 SERVICE_STATUS_PROCESS ssp;
4580 SC_HANDLE scm = NULL, service = NULL;
4581 LPWSTR name, args;
4582 DWORD event, needed;
4584 event = MSI_RecordGetInteger(rec, 3);
4585 if (!(event & msidbServiceControlEventStop))
4586 return ERROR_SUCCESS;
4588 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4589 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4590 return ERROR_SUCCESS;
4592 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4593 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4594 args = strdupW(MSI_RecordGetString(rec, 4));
4596 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4597 if (!scm)
4599 WARN("Failed to open the SCM: %d\n", GetLastError());
4600 goto done;
4603 service = OpenServiceW(scm, name,
4604 SERVICE_STOP |
4605 SERVICE_QUERY_STATUS |
4606 SERVICE_ENUMERATE_DEPENDENTS);
4607 if (!service)
4609 WARN("Failed to open service (%s): %d\n",
4610 debugstr_w(name), GetLastError());
4611 goto done;
4614 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4615 sizeof(SERVICE_STATUS_PROCESS), &needed))
4617 WARN("Failed to query service status (%s): %d\n",
4618 debugstr_w(name), GetLastError());
4619 goto done;
4622 if (ssp.dwCurrentState == SERVICE_STOPPED)
4623 goto done;
4625 stop_service_dependents(scm, service);
4627 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
4628 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
4630 done:
4631 CloseServiceHandle(service);
4632 CloseServiceHandle(scm);
4633 msi_free(name);
4634 msi_free(args);
4636 return ERROR_SUCCESS;
4639 static UINT ACTION_StopServices( MSIPACKAGE *package )
4641 UINT rc;
4642 MSIQUERY *view;
4644 static const WCHAR query[] = {
4645 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4646 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4648 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4649 if (rc != ERROR_SUCCESS)
4650 return ERROR_SUCCESS;
4652 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
4653 msiobj_release(&view->hdr);
4655 return rc;
4658 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4660 MSIFILE *file;
4662 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4664 if (!lstrcmpW(file->File, filename))
4665 return file;
4668 return NULL;
4671 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4673 MSIPACKAGE *package = param;
4674 LPWSTR driver, driver_path, ptr;
4675 WCHAR outpath[MAX_PATH];
4676 MSIFILE *driver_file, *setup_file;
4677 LPCWSTR desc;
4678 DWORD len, usage;
4679 UINT r = ERROR_SUCCESS;
4681 static const WCHAR driver_fmt[] = {
4682 'D','r','i','v','e','r','=','%','s',0};
4683 static const WCHAR setup_fmt[] = {
4684 'S','e','t','u','p','=','%','s',0};
4685 static const WCHAR usage_fmt[] = {
4686 'F','i','l','e','U','s','a','g','e','=','1',0};
4688 desc = MSI_RecordGetString(rec, 3);
4690 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4691 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4693 if (!driver_file || !setup_file)
4695 ERR("ODBC Driver entry not found!\n");
4696 return ERROR_FUNCTION_FAILED;
4699 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4700 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4701 lstrlenW(usage_fmt) + 1;
4702 driver = msi_alloc(len * sizeof(WCHAR));
4703 if (!driver)
4704 return ERROR_OUTOFMEMORY;
4706 ptr = driver;
4707 lstrcpyW(ptr, desc);
4708 ptr += lstrlenW(ptr) + 1;
4710 sprintfW(ptr, driver_fmt, driver_file->FileName);
4711 ptr += lstrlenW(ptr) + 1;
4713 sprintfW(ptr, setup_fmt, setup_file->FileName);
4714 ptr += lstrlenW(ptr) + 1;
4716 lstrcpyW(ptr, usage_fmt);
4717 ptr += lstrlenW(ptr) + 1;
4718 *ptr = '\0';
4720 driver_path = strdupW(driver_file->TargetPath);
4721 ptr = strrchrW(driver_path, '\\');
4722 if (ptr) *ptr = '\0';
4724 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4725 NULL, ODBC_INSTALL_COMPLETE, &usage))
4727 ERR("Failed to install SQL driver!\n");
4728 r = ERROR_FUNCTION_FAILED;
4731 msi_free(driver);
4732 msi_free(driver_path);
4734 return r;
4737 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4739 MSIPACKAGE *package = param;
4740 LPWSTR translator, translator_path, ptr;
4741 WCHAR outpath[MAX_PATH];
4742 MSIFILE *translator_file, *setup_file;
4743 LPCWSTR desc;
4744 DWORD len, usage;
4745 UINT r = ERROR_SUCCESS;
4747 static const WCHAR translator_fmt[] = {
4748 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4749 static const WCHAR setup_fmt[] = {
4750 'S','e','t','u','p','=','%','s',0};
4752 desc = MSI_RecordGetString(rec, 3);
4754 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4755 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4757 if (!translator_file || !setup_file)
4759 ERR("ODBC Translator entry not found!\n");
4760 return ERROR_FUNCTION_FAILED;
4763 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
4764 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
4765 translator = msi_alloc(len * sizeof(WCHAR));
4766 if (!translator)
4767 return ERROR_OUTOFMEMORY;
4769 ptr = translator;
4770 lstrcpyW(ptr, desc);
4771 ptr += lstrlenW(ptr) + 1;
4773 sprintfW(ptr, translator_fmt, translator_file->FileName);
4774 ptr += lstrlenW(ptr) + 1;
4776 sprintfW(ptr, setup_fmt, setup_file->FileName);
4777 ptr += lstrlenW(ptr) + 1;
4778 *ptr = '\0';
4780 translator_path = strdupW(translator_file->TargetPath);
4781 ptr = strrchrW(translator_path, '\\');
4782 if (ptr) *ptr = '\0';
4784 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
4785 NULL, ODBC_INSTALL_COMPLETE, &usage))
4787 ERR("Failed to install SQL translator!\n");
4788 r = ERROR_FUNCTION_FAILED;
4791 msi_free(translator);
4792 msi_free(translator_path);
4794 return r;
4797 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
4799 LPWSTR attrs;
4800 LPCWSTR desc, driver;
4801 WORD request = ODBC_ADD_SYS_DSN;
4802 INT registration;
4803 DWORD len;
4804 UINT r = ERROR_SUCCESS;
4806 static const WCHAR attrs_fmt[] = {
4807 'D','S','N','=','%','s',0 };
4809 desc = MSI_RecordGetString(rec, 3);
4810 driver = MSI_RecordGetString(rec, 4);
4811 registration = MSI_RecordGetInteger(rec, 5);
4813 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
4814 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
4816 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
4817 attrs = msi_alloc(len * sizeof(WCHAR));
4818 if (!attrs)
4819 return ERROR_OUTOFMEMORY;
4821 sprintfW(attrs, attrs_fmt, desc);
4822 attrs[len - 1] = '\0';
4824 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
4826 ERR("Failed to install SQL data source!\n");
4827 r = ERROR_FUNCTION_FAILED;
4830 msi_free(attrs);
4832 return r;
4835 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
4837 UINT rc;
4838 MSIQUERY *view;
4840 static const WCHAR driver_query[] = {
4841 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4842 'O','D','B','C','D','r','i','v','e','r',0 };
4844 static const WCHAR translator_query[] = {
4845 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4846 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4848 static const WCHAR source_query[] = {
4849 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4850 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4852 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
4853 if (rc != ERROR_SUCCESS)
4854 return ERROR_SUCCESS;
4856 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
4857 msiobj_release(&view->hdr);
4859 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
4860 if (rc != ERROR_SUCCESS)
4861 return ERROR_SUCCESS;
4863 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
4864 msiobj_release(&view->hdr);
4866 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
4867 if (rc != ERROR_SUCCESS)
4868 return ERROR_SUCCESS;
4870 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
4871 msiobj_release(&view->hdr);
4873 return rc;
4876 #define ENV_ACT_SETALWAYS 0x1
4877 #define ENV_ACT_SETABSENT 0x2
4878 #define ENV_ACT_REMOVE 0x4
4879 #define ENV_ACT_REMOVEMATCH 0x8
4881 #define ENV_MOD_MACHINE 0x20000000
4882 #define ENV_MOD_APPEND 0x40000000
4883 #define ENV_MOD_PREFIX 0x80000000
4884 #define ENV_MOD_MASK 0xC0000000
4886 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
4888 static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
4890 LPCWSTR cptr = *name;
4892 static const WCHAR prefix[] = {'[','~',']',0};
4893 static const int prefix_len = 3;
4895 *flags = 0;
4896 while (*cptr)
4898 if (*cptr == '=')
4899 *flags |= ENV_ACT_SETALWAYS;
4900 else if (*cptr == '+')
4901 *flags |= ENV_ACT_SETABSENT;
4902 else if (*cptr == '-')
4903 *flags |= ENV_ACT_REMOVE;
4904 else if (*cptr == '!')
4905 *flags |= ENV_ACT_REMOVEMATCH;
4906 else if (*cptr == '*')
4907 *flags |= ENV_MOD_MACHINE;
4908 else
4909 break;
4911 cptr++;
4912 (*name)++;
4915 if (!*cptr)
4917 ERR("Missing environment variable\n");
4918 return ERROR_FUNCTION_FAILED;
4921 if (*value)
4923 LPCWSTR ptr = *value;
4924 if (!strncmpW(ptr, prefix, prefix_len))
4926 *flags |= ENV_MOD_APPEND;
4927 *value += lstrlenW(prefix);
4929 else if (lstrlenW(*value) >= prefix_len)
4931 ptr += lstrlenW(ptr) - prefix_len;
4932 if (!lstrcmpW(ptr, prefix))
4934 *flags |= ENV_MOD_PREFIX;
4935 /* the "[~]" will be removed by deformat_string */;
4940 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
4941 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
4942 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
4943 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
4945 ERR("Invalid flags: %08x\n", *flags);
4946 return ERROR_FUNCTION_FAILED;
4949 if (!*flags)
4950 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
4952 return ERROR_SUCCESS;
4955 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
4957 MSIPACKAGE *package = param;
4958 LPCWSTR name, value;
4959 LPWSTR data = NULL, newval = NULL;
4960 LPWSTR deformatted = NULL, ptr;
4961 DWORD flags, type, size;
4962 LONG res;
4963 HKEY env = NULL, root;
4964 LPCWSTR environment;
4966 static const WCHAR user_env[] =
4967 {'E','n','v','i','r','o','n','m','e','n','t',0};
4968 static const WCHAR machine_env[] =
4969 {'S','y','s','t','e','m','\\',
4970 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
4971 'C','o','n','t','r','o','l','\\',
4972 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
4973 'E','n','v','i','r','o','n','m','e','n','t',0};
4975 name = MSI_RecordGetString(rec, 2);
4976 value = MSI_RecordGetString(rec, 3);
4978 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
4980 res = env_set_flags(&name, &value, &flags);
4981 if (res != ERROR_SUCCESS)
4982 goto done;
4984 if (value && !deformat_string(package, value, &deformatted))
4986 res = ERROR_OUTOFMEMORY;
4987 goto done;
4990 value = deformatted;
4992 if (flags & ENV_MOD_MACHINE)
4994 environment = machine_env;
4995 root = HKEY_LOCAL_MACHINE;
4997 else
4999 environment = user_env;
5000 root = HKEY_CURRENT_USER;
5003 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5004 KEY_ALL_ACCESS, NULL, &env, NULL);
5005 if (res != ERROR_SUCCESS)
5006 goto done;
5008 if (flags & ENV_ACT_REMOVE)
5009 FIXME("Not removing environment variable on uninstall!\n");
5011 size = 0;
5012 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5013 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
5014 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
5015 goto done;
5017 if (res != ERROR_FILE_NOT_FOUND)
5019 if (flags & ENV_ACT_SETABSENT)
5021 res = ERROR_SUCCESS;
5022 goto done;
5025 data = msi_alloc(size);
5026 if (!data)
5028 RegCloseKey(env);
5029 return ERROR_OUTOFMEMORY;
5032 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5033 if (res != ERROR_SUCCESS)
5034 goto done;
5036 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5038 res = RegDeleteKeyW(env, name);
5039 goto done;
5042 size += (lstrlenW(value) + 1) * sizeof(WCHAR);
5043 newval = msi_alloc(size);
5044 ptr = newval;
5045 if (!newval)
5047 res = ERROR_OUTOFMEMORY;
5048 goto done;
5051 if (!(flags & ENV_MOD_MASK))
5052 lstrcpyW(newval, value);
5053 else
5055 if (flags & ENV_MOD_PREFIX)
5057 lstrcpyW(newval, value);
5058 lstrcatW(newval, szSemiColon);
5059 ptr = newval + lstrlenW(value) + 1;
5062 lstrcpyW(ptr, data);
5064 if (flags & ENV_MOD_APPEND)
5066 lstrcatW(newval, szSemiColon);
5067 lstrcatW(newval, value);
5071 else if (value)
5073 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
5074 newval = msi_alloc(size);
5075 if (!newval)
5077 res = ERROR_OUTOFMEMORY;
5078 goto done;
5081 lstrcpyW(newval, value);
5084 if (newval)
5086 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5087 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
5089 else
5090 res = ERROR_SUCCESS;
5092 done:
5093 if (env) RegCloseKey(env);
5094 msi_free(deformatted);
5095 msi_free(data);
5096 msi_free(newval);
5097 return res;
5100 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5102 UINT rc;
5103 MSIQUERY * view;
5104 static const WCHAR ExecSeqQuery[] =
5105 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5106 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5107 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5108 if (rc != ERROR_SUCCESS)
5109 return ERROR_SUCCESS;
5111 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5112 msiobj_release(&view->hdr);
5114 return rc;
5117 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5119 typedef struct
5121 struct list entry;
5122 LPWSTR sourcename;
5123 LPWSTR destname;
5124 LPWSTR source;
5125 LPWSTR dest;
5126 } FILE_LIST;
5128 static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5130 BOOL ret;
5132 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5133 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5135 WARN("Source or dest is directory, not moving\n");
5136 return FALSE;
5139 if (options == msidbMoveFileOptionsMove)
5141 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5142 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5143 if (!ret)
5145 WARN("MoveFile failed: %d\n", GetLastError());
5146 return FALSE;
5149 else
5151 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5152 ret = CopyFileW(source, dest, FALSE);
5153 if (!ret)
5155 WARN("CopyFile failed: %d\n", GetLastError());
5156 return FALSE;
5160 return TRUE;
5163 static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5165 LPWSTR path, ptr;
5166 DWORD dirlen, pathlen;
5168 ptr = strrchrW(wildcard, '\\');
5169 dirlen = ptr - wildcard + 1;
5171 pathlen = dirlen + lstrlenW(filename) + 1;
5172 path = msi_alloc(pathlen * sizeof(WCHAR));
5174 lstrcpynW(path, wildcard, dirlen + 1);
5175 lstrcatW(path, filename);
5177 return path;
5180 static void free_file_entry(FILE_LIST *file)
5182 msi_free(file->source);
5183 msi_free(file->dest);
5184 msi_free(file);
5187 static void free_list(FILE_LIST *list)
5189 while (!list_empty(&list->entry))
5191 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5193 list_remove(&file->entry);
5194 free_file_entry(file);
5198 static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5200 FILE_LIST *new, *file;
5201 LPWSTR ptr, filename;
5202 DWORD size;
5204 new = msi_alloc_zero(sizeof(FILE_LIST));
5205 if (!new)
5206 return FALSE;
5208 new->source = strdupW(source);
5209 ptr = strrchrW(dest, '\\') + 1;
5210 filename = strrchrW(new->source, '\\') + 1;
5212 new->sourcename = filename;
5214 if (*ptr)
5215 new->destname = ptr;
5216 else
5217 new->destname = new->sourcename;
5219 size = (ptr - dest) + lstrlenW(filename) + 1;
5220 new->dest = msi_alloc(size * sizeof(WCHAR));
5221 if (!new->dest)
5223 free_file_entry(new);
5224 return FALSE;
5227 lstrcpynW(new->dest, dest, ptr - dest + 1);
5228 lstrcatW(new->dest, filename);
5230 if (list_empty(&files->entry))
5232 list_add_head(&files->entry, &new->entry);
5233 return TRUE;
5236 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5238 if (lstrcmpW(source, file->source) < 0)
5240 list_add_before(&file->entry, &new->entry);
5241 return TRUE;
5245 list_add_after(&file->entry, &new->entry);
5246 return TRUE;
5249 static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
5251 WIN32_FIND_DATAW wfd;
5252 HANDLE hfile;
5253 LPWSTR path;
5254 BOOL res;
5255 FILE_LIST files, *file;
5256 DWORD size;
5258 hfile = FindFirstFileW(source, &wfd);
5259 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5261 list_init(&files.entry);
5263 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5265 if (is_dot_dir(wfd.cFileName)) continue;
5267 path = wildcard_to_file(source, wfd.cFileName);
5268 if (!path)
5270 res = FALSE;
5271 goto done;
5274 add_wildcard(&files, path, dest);
5275 msi_free(path);
5278 /* no files match the wildcard */
5279 if (list_empty(&files.entry))
5280 goto done;
5282 /* only the first wildcard match gets renamed to dest */
5283 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5284 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5285 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5286 if (!file->dest)
5288 res = FALSE;
5289 goto done;
5292 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5294 while (!list_empty(&files.entry))
5296 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5298 msi_move_file(file->source, file->dest, options);
5300 list_remove(&file->entry);
5301 free_file_entry(file);
5304 res = TRUE;
5306 done:
5307 free_list(&files);
5308 FindClose(hfile);
5309 return res;
5312 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5314 MSIPACKAGE *package = param;
5315 MSICOMPONENT *comp;
5316 LPCWSTR sourcename;
5317 LPWSTR destname = NULL;
5318 LPWSTR sourcedir = NULL, destdir = NULL;
5319 LPWSTR source = NULL, dest = NULL;
5320 int options;
5321 DWORD size;
5322 BOOL ret, wildcards;
5324 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5325 if (!comp || !comp->Enabled ||
5326 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5328 TRACE("Component not set for install, not moving file\n");
5329 return ERROR_SUCCESS;
5332 sourcename = MSI_RecordGetString(rec, 3);
5333 options = MSI_RecordGetInteger(rec, 7);
5335 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5336 if (!sourcedir)
5337 goto done;
5339 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5340 if (!destdir)
5341 goto done;
5343 if (!sourcename)
5345 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5346 goto done;
5348 source = strdupW(sourcedir);
5349 if (!source)
5350 goto done;
5352 else
5354 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5355 source = msi_alloc(size * sizeof(WCHAR));
5356 if (!source)
5357 goto done;
5359 lstrcpyW(source, sourcedir);
5360 if (source[lstrlenW(source) - 1] != '\\')
5361 lstrcatW(source, szBackSlash);
5362 lstrcatW(source, sourcename);
5365 wildcards = strchrW(source, '*') || strchrW(source, '?');
5367 if (MSI_RecordIsNull(rec, 4))
5369 if (!wildcards)
5371 destname = strdupW(sourcename);
5372 if (!destname)
5373 goto done;
5376 else
5378 destname = strdupW(MSI_RecordGetString(rec, 4));
5379 if (destname)
5380 reduce_to_longfilename(destname);
5383 size = 0;
5384 if (destname)
5385 size = lstrlenW(destname);
5387 size += lstrlenW(destdir) + 2;
5388 dest = msi_alloc(size * sizeof(WCHAR));
5389 if (!dest)
5390 goto done;
5392 lstrcpyW(dest, destdir);
5393 if (dest[lstrlenW(dest) - 1] != '\\')
5394 lstrcatW(dest, szBackSlash);
5396 if (destname)
5397 lstrcatW(dest, destname);
5399 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5401 ret = CreateDirectoryW(destdir, NULL);
5402 if (!ret)
5404 WARN("CreateDirectory failed: %d\n", GetLastError());
5405 return ERROR_SUCCESS;
5409 if (!wildcards)
5410 msi_move_file(source, dest, options);
5411 else
5412 move_files_wildcard(source, dest, options);
5414 done:
5415 msi_free(sourcedir);
5416 msi_free(destdir);
5417 msi_free(destname);
5418 msi_free(source);
5419 msi_free(dest);
5421 return ERROR_SUCCESS;
5424 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5426 UINT rc;
5427 MSIQUERY *view;
5429 static const WCHAR ExecSeqQuery[] =
5430 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5431 '`','M','o','v','e','F','i','l','e','`',0};
5433 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5434 if (rc != ERROR_SUCCESS)
5435 return ERROR_SUCCESS;
5437 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5438 msiobj_release(&view->hdr);
5440 return rc;
5443 typedef struct tagMSIASSEMBLY
5445 struct list entry;
5446 MSICOMPONENT *component;
5447 MSIFEATURE *feature;
5448 MSIFILE *file;
5449 LPWSTR manifest;
5450 LPWSTR application;
5451 DWORD attributes;
5452 BOOL installed;
5453 } MSIASSEMBLY;
5455 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
5456 DWORD dwReserved);
5457 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
5458 LPVOID pvReserved, HMODULE *phModDll);
5460 static BOOL init_functionpointers(void)
5462 HRESULT hr;
5463 HMODULE hfusion;
5464 HMODULE hmscoree;
5466 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
5468 hmscoree = LoadLibraryA("mscoree.dll");
5469 if (!hmscoree)
5471 WARN("mscoree.dll not available\n");
5472 return FALSE;
5475 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
5476 if (!pLoadLibraryShim)
5478 WARN("LoadLibraryShim not available\n");
5479 FreeLibrary(hmscoree);
5480 return FALSE;
5483 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
5484 if (FAILED(hr))
5486 WARN("fusion.dll not available\n");
5487 FreeLibrary(hmscoree);
5488 return FALSE;
5491 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
5493 FreeLibrary(hmscoree);
5494 return TRUE;
5497 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
5498 LPWSTR path)
5500 IAssemblyCache *cache;
5501 HRESULT hr;
5502 UINT r = ERROR_FUNCTION_FAILED;
5504 TRACE("installing assembly: %s\n", debugstr_w(path));
5506 if (assembly->feature)
5507 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
5509 if (assembly->manifest)
5510 FIXME("Manifest unhandled\n");
5512 if (assembly->application)
5514 FIXME("Assembly should be privately installed\n");
5515 return ERROR_SUCCESS;
5518 if (assembly->attributes == msidbAssemblyAttributesWin32)
5520 FIXME("Win32 assemblies not handled\n");
5521 return ERROR_SUCCESS;
5524 hr = pCreateAssemblyCache(&cache, 0);
5525 if (FAILED(hr))
5526 goto done;
5528 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
5529 if (FAILED(hr))
5530 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
5532 r = ERROR_SUCCESS;
5534 done:
5535 IAssemblyCache_Release(cache);
5536 return r;
5539 typedef struct tagASSEMBLY_LIST
5541 MSIPACKAGE *package;
5542 IAssemblyCache *cache;
5543 struct list *assemblies;
5544 } ASSEMBLY_LIST;
5546 typedef struct tagASSEMBLY_NAME
5548 LPWSTR name;
5549 LPWSTR version;
5550 LPWSTR culture;
5551 LPWSTR pubkeytoken;
5552 } ASSEMBLY_NAME;
5554 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
5556 ASSEMBLY_NAME *asmname = param;
5557 LPCWSTR name = MSI_RecordGetString(rec, 2);
5558 LPWSTR val = msi_dup_record_field(rec, 3);
5560 static const WCHAR Name[] = {'N','a','m','e',0};
5561 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
5562 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
5563 static const WCHAR PublicKeyToken[] = {
5564 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
5566 if (!strcmpiW(name, Name))
5567 asmname->name = val;
5568 else if (!strcmpiW(name, Version))
5569 asmname->version = val;
5570 else if (!strcmpiW(name, Culture))
5571 asmname->culture = val;
5572 else if (!strcmpiW(name, PublicKeyToken))
5573 asmname->pubkeytoken = val;
5574 else
5575 msi_free(val);
5577 return ERROR_SUCCESS;
5580 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
5582 if (!*str)
5584 *size = lstrlenW(append) + 1;
5585 *str = msi_alloc((*size) * sizeof(WCHAR));
5586 lstrcpyW(*str, append);
5587 return;
5590 (*size) += lstrlenW(append);
5591 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
5592 lstrcatW(*str, append);
5595 static BOOL check_assembly_installed(MSIDATABASE *db, IAssemblyCache *cache,
5596 MSICOMPONENT *comp)
5598 ASSEMBLY_INFO asminfo;
5599 ASSEMBLY_NAME name;
5600 MSIQUERY *view;
5601 LPWSTR disp;
5602 DWORD size;
5603 BOOL found;
5604 UINT r;
5606 static const WCHAR separator[] = {',',' ',0};
5607 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
5608 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
5609 static const WCHAR PublicKeyToken[] = {
5610 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
5611 static const WCHAR query[] = {
5612 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5613 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
5614 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
5615 '=','\'','%','s','\'',0};
5617 disp = NULL;
5618 found = FALSE;
5619 ZeroMemory(&name, sizeof(ASSEMBLY_NAME));
5620 ZeroMemory(&asminfo, sizeof(ASSEMBLY_INFO));
5622 r = MSI_OpenQuery(db, &view, query, comp->Component);
5623 if (r != ERROR_SUCCESS)
5624 return ERROR_SUCCESS;
5626 MSI_IterateRecords(view, NULL, parse_assembly_name, &name);
5627 msiobj_release(&view->hdr);
5629 if (!name.name)
5631 ERR("No assembly name specified!\n");
5632 goto done;
5635 append_str(&disp, &size, name.name);
5637 if (name.version)
5639 append_str(&disp, &size, separator);
5640 append_str(&disp, &size, Version);
5641 append_str(&disp, &size, name.version);
5644 if (name.culture)
5646 append_str(&disp, &size, separator);
5647 append_str(&disp, &size, Culture);
5648 append_str(&disp, &size, name.culture);
5651 if (name.pubkeytoken)
5653 append_str(&disp, &size, separator);
5654 append_str(&disp, &size, PublicKeyToken);
5655 append_str(&disp, &size, name.pubkeytoken);
5658 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
5659 IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE,
5660 disp, &asminfo);
5661 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
5663 done:
5664 msi_free(disp);
5665 msi_free(name.name);
5666 msi_free(name.version);
5667 msi_free(name.culture);
5668 msi_free(name.pubkeytoken);
5670 return found;
5673 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
5675 ASSEMBLY_LIST *list = param;
5676 MSIASSEMBLY *assembly;
5678 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
5679 if (!assembly)
5680 return ERROR_OUTOFMEMORY;
5682 assembly->component = get_loaded_component(list->package, MSI_RecordGetString(rec, 1));
5684 if (!assembly->component || !assembly->component->Enabled ||
5685 !(assembly->component->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5687 TRACE("Component not set for install, not publishing assembly\n");
5688 msi_free(assembly);
5689 return ERROR_SUCCESS;
5692 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
5693 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
5695 if (!assembly->file)
5697 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
5698 return ERROR_FUNCTION_FAILED;
5701 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
5702 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
5703 assembly->attributes = MSI_RecordGetInteger(rec, 5);
5705 if (assembly->application)
5707 WCHAR version[24];
5708 DWORD size = sizeof(version)/sizeof(WCHAR);
5710 /* FIXME: we should probably check the manifest file here */
5712 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
5713 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
5715 assembly->installed = TRUE;
5718 else
5719 assembly->installed = check_assembly_installed(list->package->db,
5720 list->cache,
5721 assembly->component);
5723 list_add_head(list->assemblies, &assembly->entry);
5724 return ERROR_SUCCESS;
5727 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
5729 IAssemblyCache *cache = NULL;
5730 ASSEMBLY_LIST list;
5731 MSIQUERY *view;
5732 HRESULT hr;
5733 UINT r;
5735 static const WCHAR query[] =
5736 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5737 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
5739 r = MSI_DatabaseOpenViewW(package->db, query, &view);
5740 if (r != ERROR_SUCCESS)
5741 return ERROR_SUCCESS;
5743 hr = pCreateAssemblyCache(&cache, 0);
5744 if (FAILED(hr))
5745 return ERROR_FUNCTION_FAILED;
5747 list.package = package;
5748 list.cache = cache;
5749 list.assemblies = assemblies;
5751 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
5752 msiobj_release(&view->hdr);
5754 IAssemblyCache_Release(cache);
5756 return r;
5759 static void free_assemblies(struct list *assemblies)
5761 struct list *item, *cursor;
5763 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
5765 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
5767 list_remove(&assembly->entry);
5768 msi_free(assembly->application);
5769 msi_free(assembly->manifest);
5770 msi_free(assembly);
5774 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
5776 MSIASSEMBLY *assembly;
5778 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
5780 if (!lstrcmpW(assembly->file->File, file))
5782 *out = assembly;
5783 return TRUE;
5787 return FALSE;
5790 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
5791 LPWSTR *path, DWORD *attrs, PVOID user)
5793 MSIASSEMBLY *assembly;
5794 WCHAR temppath[MAX_PATH];
5795 struct list *assemblies = user;
5796 UINT r;
5798 if (!find_assembly(assemblies, file, &assembly))
5799 return FALSE;
5801 GetTempPathW(MAX_PATH, temppath);
5802 PathAddBackslashW(temppath);
5803 lstrcatW(temppath, assembly->file->FileName);
5805 if (action == MSICABEXTRACT_BEGINEXTRACT)
5807 if (assembly->installed)
5808 return FALSE;
5810 *path = strdupW(temppath);
5811 *attrs = assembly->file->Attributes;
5813 else if (action == MSICABEXTRACT_FILEEXTRACTED)
5815 assembly->installed = TRUE;
5817 r = install_assembly(package, assembly, temppath);
5818 if (r != ERROR_SUCCESS)
5819 ERR("Failed to install assembly\n");
5822 return TRUE;
5825 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
5827 UINT r;
5828 struct list assemblies = LIST_INIT(assemblies);
5829 MSIASSEMBLY *assembly;
5830 MSIMEDIAINFO *mi;
5832 if (!init_functionpointers() || !pCreateAssemblyCache)
5833 return ERROR_FUNCTION_FAILED;
5835 r = load_assemblies(package, &assemblies);
5836 if (r != ERROR_SUCCESS)
5837 goto done;
5839 if (list_empty(&assemblies))
5840 goto done;
5842 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
5843 if (!mi)
5845 r = ERROR_OUTOFMEMORY;
5846 goto done;
5849 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
5851 if (assembly->installed && !mi->is_continuous)
5852 continue;
5854 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
5855 (assembly->file->IsCompressed && !mi->is_extracted))
5857 MSICABDATA data;
5859 r = ready_media(package, assembly->file, mi);
5860 if (r != ERROR_SUCCESS)
5862 ERR("Failed to ready media\n");
5863 break;
5866 data.mi = mi;
5867 data.package = package;
5868 data.cb = installassembly_cb;
5869 data.user = &assemblies;
5871 if (assembly->file->IsCompressed &&
5872 !msi_cabextract(package, mi, &data))
5874 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
5875 r = ERROR_FUNCTION_FAILED;
5876 break;
5880 if (!assembly->file->IsCompressed)
5882 LPWSTR source = resolve_file_source(package, assembly->file);
5884 r = install_assembly(package, assembly, source);
5885 if (r != ERROR_SUCCESS)
5886 ERR("Failed to install assembly\n");
5888 msi_free(source);
5891 /* FIXME: write Installer assembly reg values */
5894 done:
5895 free_assemblies(&assemblies);
5896 return r;
5899 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
5900 LPCSTR action, LPCWSTR table )
5902 static const WCHAR query[] = {
5903 'S','E','L','E','C','T',' ','*',' ',
5904 'F','R','O','M',' ','`','%','s','`',0 };
5905 MSIQUERY *view = NULL;
5906 DWORD count = 0;
5907 UINT r;
5909 r = MSI_OpenQuery( package->db, &view, query, table );
5910 if (r == ERROR_SUCCESS)
5912 r = MSI_IterateRecords(view, &count, NULL, package);
5913 msiobj_release(&view->hdr);
5916 if (count)
5917 FIXME("%s -> %u ignored %s table values\n",
5918 action, count, debugstr_w(table));
5920 return ERROR_SUCCESS;
5923 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
5925 TRACE("%p\n", package);
5926 return ERROR_SUCCESS;
5929 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
5931 static const WCHAR table[] =
5932 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
5933 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
5936 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
5938 static const WCHAR table[] = { 'P','a','t','c','h',0 };
5939 return msi_unimplemented_action_stub( package, "PatchFiles", table );
5942 static UINT ACTION_BindImage( MSIPACKAGE *package )
5944 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
5945 return msi_unimplemented_action_stub( package, "BindImage", table );
5948 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
5950 static const WCHAR table[] = {
5951 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
5952 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
5955 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
5957 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5958 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
5961 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
5963 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
5964 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
5967 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5969 static const WCHAR table[] = {
5970 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5971 return msi_unimplemented_action_stub( package, "DeleteServices", table );
5973 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
5975 static const WCHAR table[] = {
5976 'P','r','o','d','u','c','t','I','D',0 };
5977 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
5980 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
5982 static const WCHAR table[] = {
5983 'E','n','v','i','r','o','n','m','e','n','t',0 };
5984 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
5987 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
5989 static const WCHAR table[] = {
5990 'M','s','i','A','s','s','e','m','b','l','y',0 };
5991 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
5994 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
5996 static const WCHAR table[] = { 'F','o','n','t',0 };
5997 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
6000 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6002 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6003 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6006 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6008 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6009 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6012 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6014 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6015 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6018 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6020 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6021 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6024 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
6026 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6027 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
6030 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6032 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6033 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6036 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
6038 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6039 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
6042 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6044 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6045 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
6048 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
6050 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6051 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
6054 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
6056 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
6057 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
6060 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
6062 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6063 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
6066 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6068 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6069 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6072 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6074 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6075 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6078 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6080 static const WCHAR table[] = { 'M','I','M','E',0 };
6081 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6084 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6086 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6087 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6090 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
6092 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
6093 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
6096 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6098 static const struct
6100 const WCHAR *action;
6101 UINT (*handler)(MSIPACKAGE *);
6103 StandardActions[] =
6105 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6106 { szAppSearch, ACTION_AppSearch },
6107 { szBindImage, ACTION_BindImage },
6108 { szCCPSearch, ACTION_CCPSearch },
6109 { szCostFinalize, ACTION_CostFinalize },
6110 { szCostInitialize, ACTION_CostInitialize },
6111 { szCreateFolders, ACTION_CreateFolders },
6112 { szCreateShortcuts, ACTION_CreateShortcuts },
6113 { szDeleteServices, ACTION_DeleteServices },
6114 { szDisableRollback, NULL },
6115 { szDuplicateFiles, ACTION_DuplicateFiles },
6116 { szExecuteAction, ACTION_ExecuteAction },
6117 { szFileCost, ACTION_FileCost },
6118 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6119 { szForceReboot, ACTION_ForceReboot },
6120 { szInstallAdminPackage, NULL },
6121 { szInstallExecute, ACTION_InstallExecute },
6122 { szInstallExecuteAgain, ACTION_InstallExecute },
6123 { szInstallFiles, ACTION_InstallFiles},
6124 { szInstallFinalize, ACTION_InstallFinalize },
6125 { szInstallInitialize, ACTION_InstallInitialize },
6126 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6127 { szInstallValidate, ACTION_InstallValidate },
6128 { szIsolateComponents, ACTION_IsolateComponents },
6129 { szLaunchConditions, ACTION_LaunchConditions },
6130 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6131 { szMoveFiles, ACTION_MoveFiles },
6132 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6133 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6134 { szInstallODBC, ACTION_InstallODBC },
6135 { szInstallServices, ACTION_InstallServices },
6136 { szPatchFiles, ACTION_PatchFiles },
6137 { szProcessComponents, ACTION_ProcessComponents },
6138 { szPublishComponents, ACTION_PublishComponents },
6139 { szPublishFeatures, ACTION_PublishFeatures },
6140 { szPublishProduct, ACTION_PublishProduct },
6141 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6142 { szRegisterComPlus, ACTION_RegisterComPlus},
6143 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6144 { szRegisterFonts, ACTION_RegisterFonts },
6145 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6146 { szRegisterProduct, ACTION_RegisterProduct },
6147 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6148 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6149 { szRegisterUser, ACTION_RegisterUser },
6150 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6151 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6152 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6153 { szRemoveFiles, ACTION_RemoveFiles },
6154 { szRemoveFolders, ACTION_RemoveFolders },
6155 { szRemoveIniValues, ACTION_RemoveIniValues },
6156 { szRemoveODBC, ACTION_RemoveODBC },
6157 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6158 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6159 { szResolveSource, ACTION_ResolveSource },
6160 { szRMCCPSearch, ACTION_RMCCPSearch },
6161 { szScheduleReboot, NULL },
6162 { szSelfRegModules, ACTION_SelfRegModules },
6163 { szSelfUnregModules, ACTION_SelfUnregModules },
6164 { szSetODBCFolders, NULL },
6165 { szStartServices, ACTION_StartServices },
6166 { szStopServices, ACTION_StopServices },
6167 { szUnpublishComponents, ACTION_UnpublishComponents },
6168 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6169 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6170 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6171 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6172 { szUnregisterFonts, ACTION_UnregisterFonts },
6173 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6174 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6175 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6176 { szValidateProductID, ACTION_ValidateProductID },
6177 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6178 { szWriteIniValues, ACTION_WriteIniValues },
6179 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6180 { NULL, NULL },
6183 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
6184 UINT* rc, BOOL force )
6186 BOOL ret = FALSE;
6187 BOOL run = force;
6188 int i;
6190 if (!run && !package->script->CurrentlyScripting)
6191 run = TRUE;
6193 if (!run)
6195 if (strcmpW(action,szInstallFinalize) == 0 ||
6196 strcmpW(action,szInstallExecute) == 0 ||
6197 strcmpW(action,szInstallExecuteAgain) == 0)
6198 run = TRUE;
6201 i = 0;
6202 while (StandardActions[i].action != NULL)
6204 if (strcmpW(StandardActions[i].action, action)==0)
6206 if (!run)
6208 ui_actioninfo(package, action, TRUE, 0);
6209 *rc = schedule_action(package,INSTALL_SCRIPT,action);
6210 ui_actioninfo(package, action, FALSE, *rc);
6212 else
6214 ui_actionstart(package, action);
6215 if (StandardActions[i].handler)
6217 *rc = StandardActions[i].handler(package);
6219 else
6221 FIXME("unhandled standard action %s\n",debugstr_w(action));
6222 *rc = ERROR_SUCCESS;
6225 ret = TRUE;
6226 break;
6228 i++;
6230 return ret;
6233 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
6235 UINT rc = ERROR_SUCCESS;
6236 BOOL handled;
6238 TRACE("Performing action (%s)\n", debugstr_w(action));
6240 handled = ACTION_HandleStandardAction(package, action, &rc, force);
6242 if (!handled)
6243 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
6245 if (!handled)
6247 WARN("unhandled msi action %s\n", debugstr_w(action));
6248 rc = ERROR_FUNCTION_NOT_CALLED;
6251 return rc;
6254 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
6256 UINT rc = ERROR_SUCCESS;
6257 BOOL handled = FALSE;
6259 TRACE("Performing action (%s)\n", debugstr_w(action));
6261 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
6263 if (!handled)
6264 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
6266 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
6267 handled = TRUE;
6269 if (!handled)
6271 WARN("unhandled msi action %s\n", debugstr_w(action));
6272 rc = ERROR_FUNCTION_NOT_CALLED;
6275 return rc;
6278 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
6280 UINT rc = ERROR_SUCCESS;
6281 MSIRECORD *row;
6283 static const WCHAR ExecSeqQuery[] =
6284 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6285 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
6286 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
6287 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
6288 static const WCHAR UISeqQuery[] =
6289 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6290 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
6291 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
6292 ' ', '=',' ','%','i',0};
6294 if (needs_ui_sequence(package))
6295 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
6296 else
6297 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
6299 if (row)
6301 LPCWSTR action, cond;
6303 TRACE("Running the actions\n");
6305 /* check conditions */
6306 cond = MSI_RecordGetString(row, 2);
6308 /* this is a hack to skip errors in the condition code */
6309 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
6311 msiobj_release(&row->hdr);
6312 return ERROR_SUCCESS;
6315 action = MSI_RecordGetString(row, 1);
6316 if (!action)
6318 ERR("failed to fetch action\n");
6319 msiobj_release(&row->hdr);
6320 return ERROR_FUNCTION_FAILED;
6323 if (needs_ui_sequence(package))
6324 rc = ACTION_PerformUIAction(package, action, -1);
6325 else
6326 rc = ACTION_PerformAction(package, action, -1, FALSE);
6328 msiobj_release(&row->hdr);
6331 return rc;
6334 /****************************************************
6335 * TOP level entry points
6336 *****************************************************/
6338 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
6339 LPCWSTR szCommandLine )
6341 UINT rc;
6342 BOOL ui_exists;
6344 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
6345 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
6347 MSI_SetPropertyW(package, szAction, szInstall);
6349 package->script->InWhatSequence = SEQUENCE_INSTALL;
6351 if (szPackagePath)
6353 LPWSTR p, dir;
6354 LPCWSTR file;
6356 dir = strdupW(szPackagePath);
6357 p = strrchrW(dir, '\\');
6358 if (p)
6360 *(++p) = 0;
6361 file = szPackagePath + (p - dir);
6363 else
6365 msi_free(dir);
6366 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
6367 GetCurrentDirectoryW(MAX_PATH, dir);
6368 lstrcatW(dir, szBackSlash);
6369 file = szPackagePath;
6372 msi_free( package->PackagePath );
6373 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
6374 if (!package->PackagePath)
6376 msi_free(dir);
6377 return ERROR_OUTOFMEMORY;
6380 lstrcpyW(package->PackagePath, dir);
6381 lstrcatW(package->PackagePath, file);
6382 msi_free(dir);
6384 msi_set_sourcedir_props(package, FALSE);
6387 msi_parse_command_line( package, szCommandLine, FALSE );
6389 msi_apply_transforms( package );
6390 msi_apply_patches( package );
6392 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
6394 TRACE("setting reinstall property\n");
6395 MSI_SetPropertyW( package, szReinstall, szAll );
6398 /* properties may have been added by a transform */
6399 msi_clone_properties( package );
6400 msi_set_context( package );
6402 if (needs_ui_sequence( package))
6404 package->script->InWhatSequence |= SEQUENCE_UI;
6405 rc = ACTION_ProcessUISequence(package);
6406 ui_exists = ui_sequence_exists(package);
6407 if (rc == ERROR_SUCCESS || !ui_exists)
6409 package->script->InWhatSequence |= SEQUENCE_EXEC;
6410 rc = ACTION_ProcessExecSequence(package, ui_exists);
6413 else
6414 rc = ACTION_ProcessExecSequence(package, FALSE);
6416 package->script->CurrentlyScripting = FALSE;
6418 /* process the ending type action */
6419 if (rc == ERROR_SUCCESS)
6420 ACTION_PerformActionSequence(package, -1);
6421 else if (rc == ERROR_INSTALL_USEREXIT)
6422 ACTION_PerformActionSequence(package, -2);
6423 else if (rc == ERROR_INSTALL_SUSPEND)
6424 ACTION_PerformActionSequence(package, -4);
6425 else /* failed */
6426 ACTION_PerformActionSequence(package, -3);
6428 /* finish up running custom actions */
6429 ACTION_FinishCustomActions(package);
6431 if (rc == ERROR_SUCCESS && package->need_reboot)
6432 return ERROR_SUCCESS_REBOOT_REQUIRED;
6434 return rc;