Release 1.1.37.
[wine/gsoc-2012-control.git] / dlls / msi / action.c
blobfef8eae0ba05c8585172cf9029f7d9a6a447368b
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 return ERROR_SUCCESS;
722 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
724 UINT rc;
725 LPCWSTR cond, action;
726 MSIPACKAGE *package = param;
728 action = MSI_RecordGetString(row,1);
729 if (!action)
731 ERR("Error is retrieving action name\n");
732 return ERROR_FUNCTION_FAILED;
735 /* check conditions */
736 cond = MSI_RecordGetString(row,2);
738 /* this is a hack to skip errors in the condition code */
739 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
741 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
742 return ERROR_SUCCESS;
745 if (needs_ui_sequence(package))
746 rc = ACTION_PerformUIAction(package, action, -1);
747 else
748 rc = ACTION_PerformAction(package, action, -1, FALSE);
750 msi_dialog_check_messages( NULL );
752 if (package->CurrentInstallState != ERROR_SUCCESS)
753 rc = package->CurrentInstallState;
755 if (rc == ERROR_FUNCTION_NOT_CALLED)
756 rc = ERROR_SUCCESS;
758 if (rc != ERROR_SUCCESS)
759 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
761 return rc;
764 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
766 MSIQUERY * view;
767 UINT r;
768 static const WCHAR query[] =
769 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
770 '`','%','s','`',
771 ' ','W','H','E','R','E',' ',
772 '`','S','e','q','u','e','n','c','e','`',' ',
773 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
774 '`','S','e','q','u','e','n','c','e','`',0};
776 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
778 r = MSI_OpenQuery( package->db, &view, query, szTable );
779 if (r == ERROR_SUCCESS)
781 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
782 msiobj_release(&view->hdr);
785 return r;
788 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
790 MSIQUERY * view;
791 UINT rc;
792 static const WCHAR ExecSeqQuery[] =
793 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
794 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
795 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
796 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
797 'O','R','D','E','R',' ', 'B','Y',' ',
798 '`','S','e','q','u','e','n','c','e','`',0 };
799 static const WCHAR IVQuery[] =
800 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
801 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
802 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
803 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
804 ' ','\'', 'I','n','s','t','a','l','l',
805 'V','a','l','i','d','a','t','e','\'', 0};
806 INT seq = 0;
808 if (package->script->ExecuteSequenceRun)
810 TRACE("Execute Sequence already Run\n");
811 return ERROR_SUCCESS;
814 package->script->ExecuteSequenceRun = TRUE;
816 /* get the sequence number */
817 if (UIran)
819 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
820 if( !row )
821 return ERROR_FUNCTION_FAILED;
822 seq = MSI_RecordGetInteger(row,1);
823 msiobj_release(&row->hdr);
826 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
827 if (rc == ERROR_SUCCESS)
829 TRACE("Running the actions\n");
831 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
832 msiobj_release(&view->hdr);
835 return rc;
838 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
840 MSIQUERY * view;
841 UINT rc;
842 static const WCHAR ExecSeqQuery [] =
843 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
844 '`','I','n','s','t','a','l','l',
845 'U','I','S','e','q','u','e','n','c','e','`',
846 ' ','W','H','E','R','E',' ',
847 '`','S','e','q','u','e','n','c','e','`',' ',
848 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
849 '`','S','e','q','u','e','n','c','e','`',0};
851 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
852 if (rc == ERROR_SUCCESS)
854 TRACE("Running the actions\n");
856 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
857 msiobj_release(&view->hdr);
860 return rc;
863 /********************************************************
864 * ACTION helper functions and functions that perform the actions
865 *******************************************************/
866 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
867 UINT* rc, UINT script, BOOL force )
869 BOOL ret=FALSE;
870 UINT arc;
872 arc = ACTION_CustomAction(package, action, script, force);
874 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
876 *rc = arc;
877 ret = TRUE;
879 return ret;
883 * Actual Action Handlers
886 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
888 MSIPACKAGE *package = param;
889 LPCWSTR dir;
890 LPWSTR full_path;
891 MSIRECORD *uirow;
892 MSIFOLDER *folder;
894 dir = MSI_RecordGetString(row,1);
895 if (!dir)
897 ERR("Unable to get folder id\n");
898 return ERROR_SUCCESS;
901 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
902 if (!full_path)
904 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
905 return ERROR_SUCCESS;
908 TRACE("Folder is %s\n",debugstr_w(full_path));
910 /* UI stuff */
911 uirow = MSI_CreateRecord(1);
912 MSI_RecordSetStringW(uirow,1,full_path);
913 ui_actiondata(package,szCreateFolders,uirow);
914 msiobj_release( &uirow->hdr );
916 if (folder->State == 0)
917 create_full_pathW(full_path);
919 folder->State = 3;
921 msi_free(full_path);
922 return ERROR_SUCCESS;
925 /* FIXME: probably should merge this with the above function */
926 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
928 UINT rc = ERROR_SUCCESS;
929 MSIFOLDER *folder;
930 LPWSTR install_path;
932 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
933 if (!install_path)
934 return ERROR_FUNCTION_FAILED;
936 /* create the path */
937 if (folder->State == 0)
939 create_full_pathW(install_path);
940 folder->State = 2;
942 msi_free(install_path);
944 return rc;
947 UINT msi_create_component_directories( MSIPACKAGE *package )
949 MSICOMPONENT *comp;
951 /* create all the folders required by the components are going to install */
952 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
954 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
955 continue;
956 msi_create_directory( package, comp->Directory );
959 return ERROR_SUCCESS;
963 * Also we cannot enable/disable components either, so for now I am just going
964 * to do all the directories for all the components.
966 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
968 static const WCHAR ExecSeqQuery[] =
969 {'S','E','L','E','C','T',' ',
970 '`','D','i','r','e','c','t','o','r','y','_','`',
971 ' ','F','R','O','M',' ',
972 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
973 UINT rc;
974 MSIQUERY *view;
976 /* create all the empty folders specified in the CreateFolder table */
977 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
978 if (rc != ERROR_SUCCESS)
979 return ERROR_SUCCESS;
981 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
982 msiobj_release(&view->hdr);
984 msi_create_component_directories( package );
986 return rc;
989 static UINT load_component( MSIRECORD *row, LPVOID param )
991 MSIPACKAGE *package = param;
992 MSICOMPONENT *comp;
994 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
995 if (!comp)
996 return ERROR_FUNCTION_FAILED;
998 list_add_tail( &package->components, &comp->entry );
1000 /* fill in the data */
1001 comp->Component = msi_dup_record_field( row, 1 );
1003 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1005 comp->ComponentId = msi_dup_record_field( row, 2 );
1006 comp->Directory = msi_dup_record_field( row, 3 );
1007 comp->Attributes = MSI_RecordGetInteger(row,4);
1008 comp->Condition = msi_dup_record_field( row, 5 );
1009 comp->KeyPath = msi_dup_record_field( row, 6 );
1011 comp->Installed = INSTALLSTATE_UNKNOWN;
1012 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1014 return ERROR_SUCCESS;
1017 static UINT load_all_components( MSIPACKAGE *package )
1019 static const WCHAR query[] = {
1020 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1021 '`','C','o','m','p','o','n','e','n','t','`',0 };
1022 MSIQUERY *view;
1023 UINT r;
1025 if (!list_empty(&package->components))
1026 return ERROR_SUCCESS;
1028 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1029 if (r != ERROR_SUCCESS)
1030 return r;
1032 r = MSI_IterateRecords(view, NULL, load_component, package);
1033 msiobj_release(&view->hdr);
1034 return r;
1037 typedef struct {
1038 MSIPACKAGE *package;
1039 MSIFEATURE *feature;
1040 } _ilfs;
1042 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1044 ComponentList *cl;
1046 cl = msi_alloc( sizeof (*cl) );
1047 if ( !cl )
1048 return ERROR_NOT_ENOUGH_MEMORY;
1049 cl->component = comp;
1050 list_add_tail( &feature->Components, &cl->entry );
1052 return ERROR_SUCCESS;
1055 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1057 FeatureList *fl;
1059 fl = msi_alloc( sizeof(*fl) );
1060 if ( !fl )
1061 return ERROR_NOT_ENOUGH_MEMORY;
1062 fl->feature = child;
1063 list_add_tail( &parent->Children, &fl->entry );
1065 return ERROR_SUCCESS;
1068 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1070 _ilfs* ilfs = param;
1071 LPCWSTR component;
1072 MSICOMPONENT *comp;
1074 component = MSI_RecordGetString(row,1);
1076 /* check to see if the component is already loaded */
1077 comp = get_loaded_component( ilfs->package, component );
1078 if (!comp)
1080 ERR("unknown component %s\n", debugstr_w(component));
1081 return ERROR_FUNCTION_FAILED;
1084 add_feature_component( ilfs->feature, comp );
1085 comp->Enabled = TRUE;
1087 return ERROR_SUCCESS;
1090 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1092 MSIFEATURE *feature;
1094 if ( !name )
1095 return NULL;
1097 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1099 if ( !lstrcmpW( feature->Feature, name ) )
1100 return feature;
1103 return NULL;
1106 static UINT load_feature(MSIRECORD * row, LPVOID param)
1108 MSIPACKAGE* package = param;
1109 MSIFEATURE* feature;
1110 static const WCHAR Query1[] =
1111 {'S','E','L','E','C','T',' ',
1112 '`','C','o','m','p','o','n','e','n','t','_','`',
1113 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1114 'C','o','m','p','o','n','e','n','t','s','`',' ',
1115 'W','H','E','R','E',' ',
1116 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1117 MSIQUERY * view;
1118 UINT rc;
1119 _ilfs ilfs;
1121 /* fill in the data */
1123 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1124 if (!feature)
1125 return ERROR_NOT_ENOUGH_MEMORY;
1127 list_init( &feature->Children );
1128 list_init( &feature->Components );
1130 feature->Feature = msi_dup_record_field( row, 1 );
1132 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1134 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1135 feature->Title = msi_dup_record_field( row, 3 );
1136 feature->Description = msi_dup_record_field( row, 4 );
1138 if (!MSI_RecordIsNull(row,5))
1139 feature->Display = MSI_RecordGetInteger(row,5);
1141 feature->Level= MSI_RecordGetInteger(row,6);
1142 feature->Directory = msi_dup_record_field( row, 7 );
1143 feature->Attributes = MSI_RecordGetInteger(row,8);
1145 feature->Installed = INSTALLSTATE_UNKNOWN;
1146 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1148 list_add_tail( &package->features, &feature->entry );
1150 /* load feature components */
1152 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1153 if (rc != ERROR_SUCCESS)
1154 return ERROR_SUCCESS;
1156 ilfs.package = package;
1157 ilfs.feature = feature;
1159 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1160 msiobj_release(&view->hdr);
1162 return ERROR_SUCCESS;
1165 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1167 MSIPACKAGE* package = param;
1168 MSIFEATURE *parent, *child;
1170 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1171 if (!child)
1172 return ERROR_FUNCTION_FAILED;
1174 if (!child->Feature_Parent)
1175 return ERROR_SUCCESS;
1177 parent = find_feature_by_name( package, child->Feature_Parent );
1178 if (!parent)
1179 return ERROR_FUNCTION_FAILED;
1181 add_feature_child( parent, child );
1182 return ERROR_SUCCESS;
1185 static UINT load_all_features( MSIPACKAGE *package )
1187 static const WCHAR query[] = {
1188 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1189 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1190 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1191 MSIQUERY *view;
1192 UINT r;
1194 if (!list_empty(&package->features))
1195 return ERROR_SUCCESS;
1197 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1198 if (r != ERROR_SUCCESS)
1199 return r;
1201 r = MSI_IterateRecords( view, NULL, load_feature, package );
1202 if (r != ERROR_SUCCESS)
1203 return r;
1205 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1206 msiobj_release( &view->hdr );
1208 return r;
1211 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1213 if (!p)
1214 return p;
1215 p = strchrW(p, ch);
1216 if (!p)
1217 return p;
1218 *p = 0;
1219 return p+1;
1222 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1224 static const WCHAR query[] = {
1225 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1226 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1227 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1228 MSIQUERY *view = NULL;
1229 MSIRECORD *row = NULL;
1230 UINT r;
1232 TRACE("%s\n", debugstr_w(file->File));
1234 r = MSI_OpenQuery(package->db, &view, query, file->File);
1235 if (r != ERROR_SUCCESS)
1236 goto done;
1238 r = MSI_ViewExecute(view, NULL);
1239 if (r != ERROR_SUCCESS)
1240 goto done;
1242 r = MSI_ViewFetch(view, &row);
1243 if (r != ERROR_SUCCESS)
1244 goto done;
1246 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1247 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1248 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1249 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1250 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1252 done:
1253 if (view) msiobj_release(&view->hdr);
1254 if (row) msiobj_release(&row->hdr);
1255 return r;
1258 static UINT load_file(MSIRECORD *row, LPVOID param)
1260 MSIPACKAGE* package = param;
1261 LPCWSTR component;
1262 MSIFILE *file;
1264 /* fill in the data */
1266 file = msi_alloc_zero( sizeof (MSIFILE) );
1267 if (!file)
1268 return ERROR_NOT_ENOUGH_MEMORY;
1270 file->File = msi_dup_record_field( row, 1 );
1272 component = MSI_RecordGetString( row, 2 );
1273 file->Component = get_loaded_component( package, component );
1275 if (!file->Component)
1277 WARN("Component not found: %s\n", debugstr_w(component));
1278 msi_free(file->File);
1279 msi_free(file);
1280 return ERROR_SUCCESS;
1283 file->FileName = msi_dup_record_field( row, 3 );
1284 reduce_to_longfilename( file->FileName );
1286 file->ShortName = msi_dup_record_field( row, 3 );
1287 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1289 file->FileSize = MSI_RecordGetInteger( row, 4 );
1290 file->Version = msi_dup_record_field( row, 5 );
1291 file->Language = msi_dup_record_field( row, 6 );
1292 file->Attributes = MSI_RecordGetInteger( row, 7 );
1293 file->Sequence = MSI_RecordGetInteger( row, 8 );
1295 file->state = msifs_invalid;
1297 /* if the compressed bits are not set in the file attributes,
1298 * then read the information from the package word count property
1300 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1302 file->IsCompressed = FALSE;
1304 else if (file->Attributes &
1305 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1307 file->IsCompressed = TRUE;
1309 else if (file->Attributes & msidbFileAttributesNoncompressed)
1311 file->IsCompressed = FALSE;
1313 else
1315 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1318 load_file_hash(package, file);
1320 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1322 list_add_tail( &package->files, &file->entry );
1324 return ERROR_SUCCESS;
1327 static UINT load_all_files(MSIPACKAGE *package)
1329 MSIQUERY * view;
1330 UINT rc;
1331 static const WCHAR Query[] =
1332 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1333 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1334 '`','S','e','q','u','e','n','c','e','`', 0};
1336 if (!list_empty(&package->files))
1337 return ERROR_SUCCESS;
1339 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1340 if (rc != ERROR_SUCCESS)
1341 return ERROR_SUCCESS;
1343 rc = MSI_IterateRecords(view, NULL, load_file, package);
1344 msiobj_release(&view->hdr);
1346 return ERROR_SUCCESS;
1349 static UINT load_folder( MSIRECORD *row, LPVOID param )
1351 MSIPACKAGE *package = param;
1352 static WCHAR szEmpty[] = { 0 };
1353 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1354 MSIFOLDER *folder;
1356 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1357 if (!folder)
1358 return ERROR_NOT_ENOUGH_MEMORY;
1360 folder->Directory = msi_dup_record_field( row, 1 );
1362 TRACE("%s\n", debugstr_w(folder->Directory));
1364 p = msi_dup_record_field(row, 3);
1366 /* split src and target dir */
1367 tgt_short = p;
1368 src_short = folder_split_path( p, ':' );
1370 /* split the long and short paths */
1371 tgt_long = folder_split_path( tgt_short, '|' );
1372 src_long = folder_split_path( src_short, '|' );
1374 /* check for no-op dirs */
1375 if (!lstrcmpW(szDot, tgt_short))
1376 tgt_short = szEmpty;
1377 if (!lstrcmpW(szDot, src_short))
1378 src_short = szEmpty;
1380 if (!tgt_long)
1381 tgt_long = tgt_short;
1383 if (!src_short) {
1384 src_short = tgt_short;
1385 src_long = tgt_long;
1388 if (!src_long)
1389 src_long = src_short;
1391 /* FIXME: use the target short path too */
1392 folder->TargetDefault = strdupW(tgt_long);
1393 folder->SourceShortPath = strdupW(src_short);
1394 folder->SourceLongPath = strdupW(src_long);
1395 msi_free(p);
1397 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1398 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1399 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1401 folder->Parent = msi_dup_record_field( row, 2 );
1403 folder->Property = msi_dup_property( package, folder->Directory );
1405 list_add_tail( &package->folders, &folder->entry );
1407 TRACE("returning %p\n", folder);
1409 return ERROR_SUCCESS;
1412 static UINT load_all_folders( MSIPACKAGE *package )
1414 static const WCHAR query[] = {
1415 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1416 '`','D','i','r','e','c','t','o','r','y','`',0 };
1417 MSIQUERY *view;
1418 UINT r;
1420 if (!list_empty(&package->folders))
1421 return ERROR_SUCCESS;
1423 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1424 if (r != ERROR_SUCCESS)
1425 return r;
1427 r = MSI_IterateRecords(view, NULL, load_folder, package);
1428 msiobj_release(&view->hdr);
1429 return r;
1433 * I am not doing any of the costing functionality yet.
1434 * Mostly looking at doing the Component and Feature loading
1436 * The native MSI does A LOT of modification to tables here. Mostly adding
1437 * a lot of temporary columns to the Feature and Component tables.
1439 * note: Native msi also tracks the short filename. But I am only going to
1440 * track the long ones. Also looking at this directory table
1441 * it appears that the directory table does not get the parents
1442 * resolved base on property only based on their entries in the
1443 * directory table.
1445 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1447 static const WCHAR szCosting[] =
1448 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1450 MSI_SetPropertyW(package, szCosting, szZero);
1451 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1453 load_all_folders( package );
1454 load_all_components( package );
1455 load_all_features( package );
1456 load_all_files( package );
1458 return ERROR_SUCCESS;
1461 static UINT execute_script(MSIPACKAGE *package, UINT script )
1463 UINT i;
1464 UINT rc = ERROR_SUCCESS;
1466 TRACE("Executing Script %i\n",script);
1468 if (!package->script)
1470 ERR("no script!\n");
1471 return ERROR_FUNCTION_FAILED;
1474 for (i = 0; i < package->script->ActionCount[script]; i++)
1476 LPWSTR action;
1477 action = package->script->Actions[script][i];
1478 ui_actionstart(package, action);
1479 TRACE("Executing Action (%s)\n",debugstr_w(action));
1480 rc = ACTION_PerformAction(package, action, script, TRUE);
1481 if (rc != ERROR_SUCCESS)
1482 break;
1484 msi_free_action_script(package, script);
1485 return rc;
1488 static UINT ACTION_FileCost(MSIPACKAGE *package)
1490 return ERROR_SUCCESS;
1493 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1495 MSICOMPONENT *comp;
1496 INSTALLSTATE state;
1497 UINT r;
1499 state = MsiQueryProductStateW(package->ProductCode);
1501 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1503 if (!comp->ComponentId)
1504 continue;
1506 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1507 comp->Installed = INSTALLSTATE_ABSENT;
1508 else
1510 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1511 package->Context, comp->ComponentId,
1512 &comp->Installed);
1513 if (r != ERROR_SUCCESS)
1514 comp->Installed = INSTALLSTATE_ABSENT;
1519 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1521 MSIFEATURE *feature;
1522 INSTALLSTATE state;
1524 state = MsiQueryProductStateW(package->ProductCode);
1526 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1528 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1529 feature->Installed = INSTALLSTATE_ABSENT;
1530 else
1532 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1533 feature->Feature);
1538 static BOOL process_state_property(MSIPACKAGE* package, int level,
1539 LPCWSTR property, INSTALLSTATE state)
1541 LPWSTR override;
1542 MSIFEATURE *feature;
1544 override = msi_dup_property( package, property );
1545 if (!override)
1546 return FALSE;
1548 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1550 if (lstrcmpW(property, szRemove) &&
1551 (feature->Level <= 0 || feature->Level > level))
1552 continue;
1554 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1556 if (strcmpiW(override, szAll)==0)
1557 msi_feature_set_state(package, feature, state);
1558 else
1560 LPWSTR ptr = override;
1561 LPWSTR ptr2 = strchrW(override,',');
1563 while (ptr)
1565 int len = ptr2 - ptr;
1567 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1568 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1570 msi_feature_set_state(package, feature, state);
1571 break;
1573 if (ptr2)
1575 ptr=ptr2+1;
1576 ptr2 = strchrW(ptr,',');
1578 else
1579 break;
1583 msi_free(override);
1585 return TRUE;
1588 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1590 int level;
1591 static const WCHAR szlevel[] =
1592 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1593 static const WCHAR szAddLocal[] =
1594 {'A','D','D','L','O','C','A','L',0};
1595 static const WCHAR szAddSource[] =
1596 {'A','D','D','S','O','U','R','C','E',0};
1597 static const WCHAR szAdvertise[] =
1598 {'A','D','V','E','R','T','I','S','E',0};
1599 BOOL override = FALSE;
1600 MSICOMPONENT* component;
1601 MSIFEATURE *feature;
1604 /* I do not know if this is where it should happen.. but */
1606 TRACE("Checking Install Level\n");
1608 level = msi_get_property_int(package, szlevel, 1);
1610 /* ok here is the _real_ rub
1611 * all these activation/deactivation things happen in order and things
1612 * later on the list override things earlier on the list.
1613 * 0) INSTALLLEVEL processing
1614 * 1) ADDLOCAL
1615 * 2) REMOVE
1616 * 3) ADDSOURCE
1617 * 4) ADDDEFAULT
1618 * 5) REINSTALL
1619 * 6) ADVERTISE
1620 * 7) COMPADDLOCAL
1621 * 8) COMPADDSOURCE
1622 * 9) FILEADDLOCAL
1623 * 10) FILEADDSOURCE
1624 * 11) FILEADDDEFAULT
1626 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1627 * REMOVE are the big ones, since we don't handle administrative installs
1628 * yet anyway.
1630 override |= process_state_property(package, level, szAddLocal, INSTALLSTATE_LOCAL);
1631 override |= process_state_property(package, level, szRemove, INSTALLSTATE_ABSENT);
1632 override |= process_state_property(package, level, szAddSource, INSTALLSTATE_SOURCE);
1633 override |= process_state_property(package, level, szReinstall, INSTALLSTATE_UNKNOWN);
1634 override |= process_state_property(package, level, szAdvertise, INSTALLSTATE_ADVERTISED);
1636 if (!override)
1638 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1640 BOOL feature_state = ((feature->Level > 0) &&
1641 (feature->Level <= level));
1643 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1645 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1646 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1647 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1648 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1649 else
1650 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1654 /* disable child features of unselected parent features */
1655 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1657 FeatureList *fl;
1659 if (feature->Level > 0 && feature->Level <= level)
1660 continue;
1662 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1663 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1666 else
1667 MSI_SetPropertyW(package, szPreselected, szOne);
1670 * now we want to enable or disable components base on feature
1673 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1675 ComponentList *cl;
1677 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1678 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1680 if (!feature->Level)
1681 continue;
1683 /* features with components that have compressed files are made local */
1684 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1686 if (cl->component->Enabled &&
1687 cl->component->ForceLocalState &&
1688 feature->Action == INSTALLSTATE_SOURCE)
1690 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1691 break;
1695 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1697 component = cl->component;
1699 if (!component->Enabled)
1700 continue;
1702 switch (feature->Action)
1704 case INSTALLSTATE_ABSENT:
1705 component->anyAbsent = 1;
1706 break;
1707 case INSTALLSTATE_ADVERTISED:
1708 component->hasAdvertiseFeature = 1;
1709 break;
1710 case INSTALLSTATE_SOURCE:
1711 component->hasSourceFeature = 1;
1712 break;
1713 case INSTALLSTATE_LOCAL:
1714 component->hasLocalFeature = 1;
1715 break;
1716 case INSTALLSTATE_DEFAULT:
1717 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1718 component->hasAdvertiseFeature = 1;
1719 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1720 component->hasSourceFeature = 1;
1721 else
1722 component->hasLocalFeature = 1;
1723 break;
1724 default:
1725 break;
1730 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1732 /* if the component isn't enabled, leave it alone */
1733 if (!component->Enabled)
1734 continue;
1736 /* check if it's local or source */
1737 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1738 (component->hasLocalFeature || component->hasSourceFeature))
1740 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1741 !component->ForceLocalState)
1742 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1743 else
1744 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1745 continue;
1748 /* if any feature is local, the component must be local too */
1749 if (component->hasLocalFeature)
1751 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1752 continue;
1755 if (component->hasSourceFeature)
1757 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1758 continue;
1761 if (component->hasAdvertiseFeature)
1763 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1764 continue;
1767 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1768 if (component->anyAbsent)
1769 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1772 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1774 if (component->Action == INSTALLSTATE_DEFAULT)
1776 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1777 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1780 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1781 debugstr_w(component->Component), component->Installed, component->Action);
1785 return ERROR_SUCCESS;
1788 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1790 MSIPACKAGE *package = param;
1791 LPCWSTR name;
1792 LPWSTR path;
1793 MSIFOLDER *f;
1795 name = MSI_RecordGetString(row,1);
1797 f = get_loaded_folder(package, name);
1798 if (!f) return ERROR_SUCCESS;
1800 /* reset the ResolvedTarget */
1801 msi_free(f->ResolvedTarget);
1802 f->ResolvedTarget = NULL;
1804 /* This helper function now does ALL the work */
1805 TRACE("Dir %s ...\n",debugstr_w(name));
1806 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1807 TRACE("resolves to %s\n",debugstr_w(path));
1808 msi_free(path);
1810 return ERROR_SUCCESS;
1813 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1815 MSIPACKAGE *package = param;
1816 LPCWSTR name;
1817 MSIFEATURE *feature;
1819 name = MSI_RecordGetString( row, 1 );
1821 feature = get_loaded_feature( package, name );
1822 if (!feature)
1823 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1824 else
1826 LPCWSTR Condition;
1827 Condition = MSI_RecordGetString(row,3);
1829 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1831 int level = MSI_RecordGetInteger(row,2);
1832 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1833 feature->Level = level;
1836 return ERROR_SUCCESS;
1839 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1841 static const WCHAR name_fmt[] =
1842 {'%','u','.','%','u','.','%','u','.','%','u',0};
1843 static const WCHAR name[] = {'\\',0};
1844 VS_FIXEDFILEINFO *lpVer;
1845 WCHAR filever[0x100];
1846 LPVOID version;
1847 DWORD versize;
1848 DWORD handle;
1849 UINT sz;
1851 TRACE("%s\n", debugstr_w(filename));
1853 versize = GetFileVersionInfoSizeW( filename, &handle );
1854 if (!versize)
1855 return NULL;
1857 version = msi_alloc( versize );
1858 GetFileVersionInfoW( filename, 0, versize, version );
1860 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1862 msi_free( version );
1863 return NULL;
1866 sprintfW( filever, name_fmt,
1867 HIWORD(lpVer->dwFileVersionMS),
1868 LOWORD(lpVer->dwFileVersionMS),
1869 HIWORD(lpVer->dwFileVersionLS),
1870 LOWORD(lpVer->dwFileVersionLS));
1872 msi_free( version );
1874 return strdupW( filever );
1877 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1879 LPWSTR file_version;
1880 MSIFILE *file;
1882 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1884 MSICOMPONENT* comp = file->Component;
1885 LPWSTR p;
1887 if (!comp)
1888 continue;
1890 if (file->IsCompressed)
1891 comp->ForceLocalState = TRUE;
1893 /* calculate target */
1894 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1896 msi_free(file->TargetPath);
1898 TRACE("file %s is named %s\n",
1899 debugstr_w(file->File), debugstr_w(file->FileName));
1901 file->TargetPath = build_directory_name(2, p, file->FileName);
1903 msi_free(p);
1905 TRACE("file %s resolves to %s\n",
1906 debugstr_w(file->File), debugstr_w(file->TargetPath));
1908 /* don't check files of components that aren't installed */
1909 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1910 comp->Installed == INSTALLSTATE_ABSENT)
1912 file->state = msifs_missing; /* assume files are missing */
1913 continue;
1916 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1918 file->state = msifs_missing;
1919 comp->Cost += file->FileSize;
1920 continue;
1923 if (file->Version &&
1924 (file_version = msi_get_disk_file_version( file->TargetPath )))
1926 TRACE("new %s old %s\n", debugstr_w(file->Version),
1927 debugstr_w(file_version));
1928 /* FIXME: seems like a bad way to compare version numbers */
1929 if (lstrcmpiW(file_version, file->Version)<0)
1931 file->state = msifs_overwrite;
1932 comp->Cost += file->FileSize;
1934 else
1935 file->state = msifs_present;
1936 msi_free( file_version );
1938 else
1939 file->state = msifs_present;
1942 return ERROR_SUCCESS;
1946 * A lot is done in this function aside from just the costing.
1947 * The costing needs to be implemented at some point but for now I am going
1948 * to focus on the directory building
1951 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1953 static const WCHAR ExecSeqQuery[] =
1954 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1955 '`','D','i','r','e','c','t','o','r','y','`',0};
1956 static const WCHAR ConditionQuery[] =
1957 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1958 '`','C','o','n','d','i','t','i','o','n','`',0};
1959 static const WCHAR szCosting[] =
1960 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1961 static const WCHAR szlevel[] =
1962 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1963 static const WCHAR szOutOfDiskSpace[] =
1964 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
1965 MSICOMPONENT *comp;
1966 UINT rc;
1967 MSIQUERY * view;
1968 LPWSTR level;
1970 TRACE("Building Directory properties\n");
1972 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1973 if (rc == ERROR_SUCCESS)
1975 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1976 package);
1977 msiobj_release(&view->hdr);
1980 /* read components states from the registry */
1981 ACTION_GetComponentInstallStates(package);
1982 ACTION_GetFeatureInstallStates(package);
1984 TRACE("File calculations\n");
1985 msi_check_file_install_states( package );
1987 TRACE("Evaluating Condition Table\n");
1989 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1990 if (rc == ERROR_SUCCESS)
1992 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1993 package);
1994 msiobj_release(&view->hdr);
1997 TRACE("Enabling or Disabling Components\n");
1998 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2000 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2002 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2003 comp->Enabled = FALSE;
2005 else
2006 comp->Enabled = TRUE;
2009 MSI_SetPropertyW(package,szCosting,szOne);
2010 /* set default run level if not set */
2011 level = msi_dup_property( package, szlevel );
2012 if (!level)
2013 MSI_SetPropertyW(package,szlevel, szOne);
2014 msi_free(level);
2016 /* FIXME: check volume disk space */
2017 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2019 return MSI_SetFeatureStates(package);
2022 /* OK this value is "interpreted" and then formatted based on the
2023 first few characters */
2024 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2025 DWORD *size)
2027 LPSTR data = NULL;
2029 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2031 if (value[1]=='x')
2033 LPWSTR ptr;
2034 CHAR byte[5];
2035 LPWSTR deformated = NULL;
2036 int count;
2038 deformat_string(package, &value[2], &deformated);
2040 /* binary value type */
2041 ptr = deformated;
2042 *type = REG_BINARY;
2043 if (strlenW(ptr)%2)
2044 *size = (strlenW(ptr)/2)+1;
2045 else
2046 *size = strlenW(ptr)/2;
2048 data = msi_alloc(*size);
2050 byte[0] = '0';
2051 byte[1] = 'x';
2052 byte[4] = 0;
2053 count = 0;
2054 /* if uneven pad with a zero in front */
2055 if (strlenW(ptr)%2)
2057 byte[2]= '0';
2058 byte[3]= *ptr;
2059 ptr++;
2060 data[count] = (BYTE)strtol(byte,NULL,0);
2061 count ++;
2062 TRACE("Uneven byte count\n");
2064 while (*ptr)
2066 byte[2]= *ptr;
2067 ptr++;
2068 byte[3]= *ptr;
2069 ptr++;
2070 data[count] = (BYTE)strtol(byte,NULL,0);
2071 count ++;
2073 msi_free(deformated);
2075 TRACE("Data %i bytes(%i)\n",*size,count);
2077 else
2079 LPWSTR deformated;
2080 LPWSTR p;
2081 DWORD d = 0;
2082 deformat_string(package, &value[1], &deformated);
2084 *type=REG_DWORD;
2085 *size = sizeof(DWORD);
2086 data = msi_alloc(*size);
2087 p = deformated;
2088 if (*p == '-')
2089 p++;
2090 while (*p)
2092 if ( (*p < '0') || (*p > '9') )
2093 break;
2094 d *= 10;
2095 d += (*p - '0');
2096 p++;
2098 if (deformated[0] == '-')
2099 d = -d;
2100 *(LPDWORD)data = d;
2101 TRACE("DWORD %i\n",*(LPDWORD)data);
2103 msi_free(deformated);
2106 else
2108 static const WCHAR szMulti[] = {'[','~',']',0};
2109 LPCWSTR ptr;
2110 *type=REG_SZ;
2112 if (value[0]=='#')
2114 if (value[1]=='%')
2116 ptr = &value[2];
2117 *type=REG_EXPAND_SZ;
2119 else
2120 ptr = &value[1];
2122 else
2123 ptr=value;
2125 if (strstrW(value,szMulti))
2126 *type = REG_MULTI_SZ;
2128 /* remove initial delimiter */
2129 if (!strncmpW(value, szMulti, 3))
2130 ptr = value + 3;
2132 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2134 /* add double NULL terminator */
2135 if (*type == REG_MULTI_SZ)
2137 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2138 data = msi_realloc_zero(data, *size);
2141 return data;
2144 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2146 MSIPACKAGE *package = param;
2147 static const WCHAR szHCR[] =
2148 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2149 'R','O','O','T','\\',0};
2150 static const WCHAR szHCU[] =
2151 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2152 'U','S','E','R','\\',0};
2153 static const WCHAR szHLM[] =
2154 {'H','K','E','Y','_','L','O','C','A','L','_',
2155 'M','A','C','H','I','N','E','\\',0};
2156 static const WCHAR szHU[] =
2157 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2159 LPSTR value_data = NULL;
2160 HKEY root_key, hkey;
2161 DWORD type,size;
2162 LPWSTR deformated;
2163 LPCWSTR szRoot, component, name, key, value;
2164 MSICOMPONENT *comp;
2165 MSIRECORD * uirow;
2166 LPWSTR uikey;
2167 INT root;
2168 BOOL check_first = FALSE;
2169 UINT rc;
2171 ui_progress(package,2,0,0,0);
2173 value = NULL;
2174 key = NULL;
2175 uikey = NULL;
2176 name = NULL;
2178 component = MSI_RecordGetString(row, 6);
2179 comp = get_loaded_component(package,component);
2180 if (!comp)
2181 return ERROR_SUCCESS;
2183 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2185 TRACE("Skipping write due to disabled component %s\n",
2186 debugstr_w(component));
2188 comp->Action = comp->Installed;
2190 return ERROR_SUCCESS;
2193 comp->Action = INSTALLSTATE_LOCAL;
2195 name = MSI_RecordGetString(row, 4);
2196 if( MSI_RecordIsNull(row,5) && name )
2198 /* null values can have special meanings */
2199 if (name[0]=='-' && name[1] == 0)
2200 return ERROR_SUCCESS;
2201 else if ((name[0]=='+' && name[1] == 0) ||
2202 (name[0] == '*' && name[1] == 0))
2203 name = NULL;
2204 check_first = TRUE;
2207 root = MSI_RecordGetInteger(row,2);
2208 key = MSI_RecordGetString(row, 3);
2210 /* get the root key */
2211 switch (root)
2213 case -1:
2215 LPWSTR all_users = msi_dup_property( package, szAllUsers );
2216 if (all_users && all_users[0] == '1')
2218 root_key = HKEY_LOCAL_MACHINE;
2219 szRoot = szHLM;
2221 else
2223 root_key = HKEY_CURRENT_USER;
2224 szRoot = szHCU;
2226 msi_free(all_users);
2228 break;
2229 case 0: root_key = HKEY_CLASSES_ROOT;
2230 szRoot = szHCR;
2231 break;
2232 case 1: root_key = HKEY_CURRENT_USER;
2233 szRoot = szHCU;
2234 break;
2235 case 2: root_key = HKEY_LOCAL_MACHINE;
2236 szRoot = szHLM;
2237 break;
2238 case 3: root_key = HKEY_USERS;
2239 szRoot = szHU;
2240 break;
2241 default:
2242 ERR("Unknown root %i\n",root);
2243 root_key=NULL;
2244 szRoot = NULL;
2245 break;
2247 if (!root_key)
2248 return ERROR_SUCCESS;
2250 deformat_string(package, key , &deformated);
2251 size = strlenW(deformated) + strlenW(szRoot) + 1;
2252 uikey = msi_alloc(size*sizeof(WCHAR));
2253 strcpyW(uikey,szRoot);
2254 strcatW(uikey,deformated);
2256 if (RegCreateKeyW( root_key, deformated, &hkey))
2258 ERR("Could not create key %s\n",debugstr_w(deformated));
2259 msi_free(deformated);
2260 msi_free(uikey);
2261 return ERROR_SUCCESS;
2263 msi_free(deformated);
2265 value = MSI_RecordGetString(row,5);
2266 if (value)
2267 value_data = parse_value(package, value, &type, &size);
2268 else
2270 value_data = (LPSTR)strdupW(szEmpty);
2271 size = sizeof(szEmpty);
2272 type = REG_SZ;
2275 deformat_string(package, name, &deformated);
2277 if (!check_first)
2279 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2280 debugstr_w(uikey));
2281 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2283 else
2285 DWORD sz = 0;
2286 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2287 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2289 TRACE("value %s of %s checked already exists\n",
2290 debugstr_w(deformated), debugstr_w(uikey));
2292 else
2294 TRACE("Checked and setting value %s of %s\n",
2295 debugstr_w(deformated), debugstr_w(uikey));
2296 if (deformated || size)
2297 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2300 RegCloseKey(hkey);
2302 uirow = MSI_CreateRecord(3);
2303 MSI_RecordSetStringW(uirow,2,deformated);
2304 MSI_RecordSetStringW(uirow,1,uikey);
2306 if (type == REG_SZ)
2307 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2308 else
2309 MSI_RecordSetStringW(uirow,3,value);
2311 ui_actiondata(package,szWriteRegistryValues,uirow);
2312 msiobj_release( &uirow->hdr );
2314 msi_free(value_data);
2315 msi_free(deformated);
2316 msi_free(uikey);
2318 return ERROR_SUCCESS;
2321 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2323 UINT rc;
2324 MSIQUERY * view;
2325 static const WCHAR ExecSeqQuery[] =
2326 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2327 '`','R','e','g','i','s','t','r','y','`',0 };
2329 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2330 if (rc != ERROR_SUCCESS)
2331 return ERROR_SUCCESS;
2333 /* increment progress bar each time action data is sent */
2334 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2336 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2338 msiobj_release(&view->hdr);
2339 return rc;
2342 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2344 package->script->CurrentlyScripting = TRUE;
2346 return ERROR_SUCCESS;
2350 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2352 MSICOMPONENT *comp;
2353 DWORD progress = 0;
2354 DWORD total = 0;
2355 static const WCHAR q1[]=
2356 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2357 '`','R','e','g','i','s','t','r','y','`',0};
2358 UINT rc;
2359 MSIQUERY * view;
2360 MSIFEATURE *feature;
2361 MSIFILE *file;
2363 TRACE("InstallValidate\n");
2365 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2366 if (rc == ERROR_SUCCESS)
2368 MSI_IterateRecords( view, &progress, NULL, package );
2369 msiobj_release( &view->hdr );
2370 total += progress * REG_PROGRESS_VALUE;
2373 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2374 total += COMPONENT_PROGRESS_VALUE;
2376 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2377 total += file->FileSize;
2379 ui_progress(package,0,total,0,0);
2381 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2383 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2384 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2385 feature->ActionRequest);
2388 return ERROR_SUCCESS;
2391 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2393 MSIPACKAGE* package = param;
2394 LPCWSTR cond = NULL;
2395 LPCWSTR message = NULL;
2396 UINT r;
2398 static const WCHAR title[]=
2399 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2401 cond = MSI_RecordGetString(row,1);
2403 r = MSI_EvaluateConditionW(package,cond);
2404 if (r == MSICONDITION_FALSE)
2406 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2408 LPWSTR deformated;
2409 message = MSI_RecordGetString(row,2);
2410 deformat_string(package,message,&deformated);
2411 MessageBoxW(NULL,deformated,title,MB_OK);
2412 msi_free(deformated);
2415 return ERROR_INSTALL_FAILURE;
2418 return ERROR_SUCCESS;
2421 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2423 UINT rc;
2424 MSIQUERY * view = NULL;
2425 static const WCHAR ExecSeqQuery[] =
2426 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2427 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2429 TRACE("Checking launch conditions\n");
2431 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2432 if (rc != ERROR_SUCCESS)
2433 return ERROR_SUCCESS;
2435 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2436 msiobj_release(&view->hdr);
2438 return rc;
2441 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2444 if (!cmp->KeyPath)
2445 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2447 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2449 MSIRECORD * row = 0;
2450 UINT root,len;
2451 LPWSTR deformated,buffer,deformated_name;
2452 LPCWSTR key,name;
2453 static const WCHAR ExecSeqQuery[] =
2454 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2455 '`','R','e','g','i','s','t','r','y','`',' ',
2456 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2457 ' ','=',' ' ,'\'','%','s','\'',0 };
2458 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2459 static const WCHAR fmt2[]=
2460 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2462 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2463 if (!row)
2464 return NULL;
2466 root = MSI_RecordGetInteger(row,2);
2467 key = MSI_RecordGetString(row, 3);
2468 name = MSI_RecordGetString(row, 4);
2469 deformat_string(package, key , &deformated);
2470 deformat_string(package, name, &deformated_name);
2472 len = strlenW(deformated) + 6;
2473 if (deformated_name)
2474 len+=strlenW(deformated_name);
2476 buffer = msi_alloc( len *sizeof(WCHAR));
2478 if (deformated_name)
2479 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2480 else
2481 sprintfW(buffer,fmt,root,deformated);
2483 msi_free(deformated);
2484 msi_free(deformated_name);
2485 msiobj_release(&row->hdr);
2487 return buffer;
2489 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2491 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2492 return NULL;
2494 else
2496 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2498 if (file)
2499 return strdupW( file->TargetPath );
2501 return NULL;
2504 static HKEY openSharedDLLsKey(void)
2506 HKEY hkey=0;
2507 static const WCHAR path[] =
2508 {'S','o','f','t','w','a','r','e','\\',
2509 'M','i','c','r','o','s','o','f','t','\\',
2510 'W','i','n','d','o','w','s','\\',
2511 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2512 'S','h','a','r','e','d','D','L','L','s',0};
2514 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2515 return hkey;
2518 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2520 HKEY hkey;
2521 DWORD count=0;
2522 DWORD type;
2523 DWORD sz = sizeof(count);
2524 DWORD rc;
2526 hkey = openSharedDLLsKey();
2527 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2528 if (rc != ERROR_SUCCESS)
2529 count = 0;
2530 RegCloseKey(hkey);
2531 return count;
2534 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2536 HKEY hkey;
2538 hkey = openSharedDLLsKey();
2539 if (count > 0)
2540 msi_reg_set_val_dword( hkey, path, count );
2541 else
2542 RegDeleteValueW(hkey,path);
2543 RegCloseKey(hkey);
2544 return count;
2548 * Return TRUE if the count should be written out and FALSE if not
2550 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2552 MSIFEATURE *feature;
2553 INT count = 0;
2554 BOOL write = FALSE;
2556 /* only refcount DLLs */
2557 if (comp->KeyPath == NULL ||
2558 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2559 comp->Attributes & msidbComponentAttributesODBCDataSource)
2560 write = FALSE;
2561 else
2563 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2564 write = (count > 0);
2566 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2567 write = TRUE;
2570 /* increment counts */
2571 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2573 ComponentList *cl;
2575 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2576 continue;
2578 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2580 if ( cl->component == comp )
2581 count++;
2585 /* decrement counts */
2586 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2588 ComponentList *cl;
2590 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2591 continue;
2593 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2595 if ( cl->component == comp )
2596 count--;
2600 /* ref count all the files in the component */
2601 if (write)
2603 MSIFILE *file;
2605 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2607 if (file->Component == comp)
2608 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2612 /* add a count for permanent */
2613 if (comp->Attributes & msidbComponentAttributesPermanent)
2614 count ++;
2616 comp->RefCount = count;
2618 if (write)
2619 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2622 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2624 WCHAR squished_pc[GUID_SIZE];
2625 WCHAR squished_cc[GUID_SIZE];
2626 UINT rc;
2627 MSICOMPONENT *comp;
2628 HKEY hkey;
2630 TRACE("\n");
2632 squash_guid(package->ProductCode,squished_pc);
2633 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2635 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2637 MSIRECORD * uirow;
2639 ui_progress(package,2,0,0,0);
2640 if (!comp->ComponentId)
2641 continue;
2643 squash_guid(comp->ComponentId,squished_cc);
2645 msi_free(comp->FullKeypath);
2646 comp->FullKeypath = resolve_keypath( package, comp );
2648 ACTION_RefCountComponent( package, comp );
2650 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2651 debugstr_w(comp->Component),
2652 debugstr_w(squished_cc),
2653 debugstr_w(comp->FullKeypath),
2654 comp->RefCount);
2656 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL) ||
2657 ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE))
2659 if (!comp->FullKeypath)
2660 continue;
2662 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2663 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2664 &hkey, TRUE);
2665 else
2666 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2667 &hkey, TRUE);
2669 if (rc != ERROR_SUCCESS)
2670 continue;
2672 if (comp->Attributes & msidbComponentAttributesPermanent)
2674 static const WCHAR szPermKey[] =
2675 { '0','0','0','0','0','0','0','0','0','0','0','0',
2676 '0','0','0','0','0','0','0','0','0','0','0','0',
2677 '0','0','0','0','0','0','0','0',0 };
2679 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2682 if (comp->Action == INSTALLSTATE_LOCAL)
2683 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2684 else
2686 MSIFILE *file;
2687 MSIRECORD *row;
2688 LPWSTR ptr, ptr2;
2689 WCHAR source[MAX_PATH];
2690 WCHAR base[MAX_PATH];
2691 LPWSTR sourcepath;
2693 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2694 static const WCHAR query[] = {
2695 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2696 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2697 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2698 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2699 '`','D','i','s','k','I','d','`',0};
2701 file = get_loaded_file(package, comp->KeyPath);
2702 if (!file)
2703 continue;
2705 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2706 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2707 ptr2 = strrchrW(source, '\\') + 1;
2708 msiobj_release(&row->hdr);
2710 lstrcpyW(base, package->PackagePath);
2711 ptr = strrchrW(base, '\\');
2712 *(ptr + 1) = '\0';
2714 sourcepath = resolve_file_source(package, file);
2715 ptr = sourcepath + lstrlenW(base);
2716 lstrcpyW(ptr2, ptr);
2717 msi_free(sourcepath);
2719 msi_reg_set_val_str(hkey, squished_pc, source);
2721 RegCloseKey(hkey);
2723 else if (ACTION_VerifyComponentForAction(comp, INSTALLSTATE_ABSENT))
2725 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2726 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2727 else
2728 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2731 /* UI stuff */
2732 uirow = MSI_CreateRecord(3);
2733 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2734 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2735 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2736 ui_actiondata(package,szProcessComponents,uirow);
2737 msiobj_release( &uirow->hdr );
2740 return ERROR_SUCCESS;
2743 typedef struct {
2744 CLSID clsid;
2745 LPWSTR source;
2747 LPWSTR path;
2748 ITypeLib *ptLib;
2749 } typelib_struct;
2751 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2752 LPWSTR lpszName, LONG_PTR lParam)
2754 TLIBATTR *attr;
2755 typelib_struct *tl_struct = (typelib_struct*) lParam;
2756 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2757 int sz;
2758 HRESULT res;
2760 if (!IS_INTRESOURCE(lpszName))
2762 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2763 return TRUE;
2766 sz = strlenW(tl_struct->source)+4;
2767 sz *= sizeof(WCHAR);
2769 if ((INT_PTR)lpszName == 1)
2770 tl_struct->path = strdupW(tl_struct->source);
2771 else
2773 tl_struct->path = msi_alloc(sz);
2774 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2777 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2778 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2779 if (FAILED(res))
2781 msi_free(tl_struct->path);
2782 tl_struct->path = NULL;
2784 return TRUE;
2787 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2788 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2790 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2791 return FALSE;
2794 msi_free(tl_struct->path);
2795 tl_struct->path = NULL;
2797 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2798 ITypeLib_Release(tl_struct->ptLib);
2800 return TRUE;
2803 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2805 MSIPACKAGE* package = param;
2806 LPCWSTR component;
2807 MSICOMPONENT *comp;
2808 MSIFILE *file;
2809 typelib_struct tl_struct;
2810 ITypeLib *tlib;
2811 HMODULE module;
2812 HRESULT hr;
2814 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2816 component = MSI_RecordGetString(row,3);
2817 comp = get_loaded_component(package,component);
2818 if (!comp)
2819 return ERROR_SUCCESS;
2821 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2823 TRACE("Skipping typelib reg due to disabled component\n");
2825 comp->Action = comp->Installed;
2827 return ERROR_SUCCESS;
2830 comp->Action = INSTALLSTATE_LOCAL;
2832 file = get_loaded_file( package, comp->KeyPath );
2833 if (!file)
2834 return ERROR_SUCCESS;
2836 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2837 if (module)
2839 LPCWSTR guid;
2840 guid = MSI_RecordGetString(row,1);
2841 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2842 tl_struct.source = strdupW( file->TargetPath );
2843 tl_struct.path = NULL;
2845 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2846 (LONG_PTR)&tl_struct);
2848 if (tl_struct.path)
2850 LPWSTR help = NULL;
2851 LPCWSTR helpid;
2852 HRESULT res;
2854 helpid = MSI_RecordGetString(row,6);
2856 if (helpid)
2857 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
2858 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2859 msi_free(help);
2861 if (FAILED(res))
2862 ERR("Failed to register type library %s\n",
2863 debugstr_w(tl_struct.path));
2864 else
2866 ui_actiondata(package,szRegisterTypeLibraries,row);
2868 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2871 ITypeLib_Release(tl_struct.ptLib);
2872 msi_free(tl_struct.path);
2874 else
2875 ERR("Failed to load type library %s\n",
2876 debugstr_w(tl_struct.source));
2878 FreeLibrary(module);
2879 msi_free(tl_struct.source);
2881 else
2883 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
2884 if (FAILED(hr))
2886 ERR("Failed to load type library: %08x\n", hr);
2887 return ERROR_FUNCTION_FAILED;
2890 ITypeLib_Release(tlib);
2893 return ERROR_SUCCESS;
2896 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2899 * OK this is a bit confusing.. I am given a _Component key and I believe
2900 * that the file that is being registered as a type library is the "key file
2901 * of that component" which I interpret to mean "The file in the KeyPath of
2902 * that component".
2904 UINT rc;
2905 MSIQUERY * view;
2906 static const WCHAR Query[] =
2907 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2908 '`','T','y','p','e','L','i','b','`',0};
2910 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2911 if (rc != ERROR_SUCCESS)
2912 return ERROR_SUCCESS;
2914 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2915 msiobj_release(&view->hdr);
2916 return rc;
2919 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2921 MSIPACKAGE *package = param;
2922 LPWSTR target_file, target_folder, filename;
2923 LPCWSTR buffer, extension;
2924 MSICOMPONENT *comp;
2925 static const WCHAR szlnk[]={'.','l','n','k',0};
2926 IShellLinkW *sl = NULL;
2927 IPersistFile *pf = NULL;
2928 HRESULT res;
2930 buffer = MSI_RecordGetString(row,4);
2931 comp = get_loaded_component(package,buffer);
2932 if (!comp)
2933 return ERROR_SUCCESS;
2935 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2937 TRACE("Skipping shortcut creation due to disabled component\n");
2939 comp->Action = comp->Installed;
2941 return ERROR_SUCCESS;
2944 comp->Action = INSTALLSTATE_LOCAL;
2946 ui_actiondata(package,szCreateShortcuts,row);
2948 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2949 &IID_IShellLinkW, (LPVOID *) &sl );
2951 if (FAILED( res ))
2953 ERR("CLSID_ShellLink not available\n");
2954 goto err;
2957 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2958 if (FAILED( res ))
2960 ERR("QueryInterface(IID_IPersistFile) failed\n");
2961 goto err;
2964 buffer = MSI_RecordGetString(row,2);
2965 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
2967 /* may be needed because of a bug somewhere else */
2968 create_full_pathW(target_folder);
2970 filename = msi_dup_record_field( row, 3 );
2971 reduce_to_longfilename(filename);
2973 extension = strchrW(filename,'.');
2974 if (!extension || strcmpiW(extension,szlnk))
2976 int len = strlenW(filename);
2977 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2978 memcpy(filename + len, szlnk, sizeof(szlnk));
2980 target_file = build_directory_name(2, target_folder, filename);
2981 msi_free(target_folder);
2982 msi_free(filename);
2984 buffer = MSI_RecordGetString(row,5);
2985 if (strchrW(buffer,'['))
2987 LPWSTR deformated;
2988 deformat_string(package,buffer,&deformated);
2989 IShellLinkW_SetPath(sl,deformated);
2990 msi_free(deformated);
2992 else
2994 FIXME("poorly handled shortcut format, advertised shortcut\n");
2995 IShellLinkW_SetPath(sl,comp->FullKeypath);
2998 if (!MSI_RecordIsNull(row,6))
3000 LPWSTR deformated;
3001 buffer = MSI_RecordGetString(row,6);
3002 deformat_string(package,buffer,&deformated);
3003 IShellLinkW_SetArguments(sl,deformated);
3004 msi_free(deformated);
3007 if (!MSI_RecordIsNull(row,7))
3009 buffer = MSI_RecordGetString(row,7);
3010 IShellLinkW_SetDescription(sl,buffer);
3013 if (!MSI_RecordIsNull(row,8))
3014 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3016 if (!MSI_RecordIsNull(row,9))
3018 LPWSTR Path;
3019 INT index;
3021 buffer = MSI_RecordGetString(row,9);
3023 Path = build_icon_path(package,buffer);
3024 index = MSI_RecordGetInteger(row,10);
3026 /* no value means 0 */
3027 if (index == MSI_NULL_INTEGER)
3028 index = 0;
3030 IShellLinkW_SetIconLocation(sl,Path,index);
3031 msi_free(Path);
3034 if (!MSI_RecordIsNull(row,11))
3035 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3037 if (!MSI_RecordIsNull(row,12))
3039 LPWSTR Path;
3040 buffer = MSI_RecordGetString(row,12);
3041 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3042 if (Path)
3043 IShellLinkW_SetWorkingDirectory(sl,Path);
3044 msi_free(Path);
3047 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3048 IPersistFile_Save(pf,target_file,FALSE);
3050 msi_free(target_file);
3052 err:
3053 if (pf)
3054 IPersistFile_Release( pf );
3055 if (sl)
3056 IShellLinkW_Release( sl );
3058 return ERROR_SUCCESS;
3061 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3063 UINT rc;
3064 HRESULT res;
3065 MSIQUERY * view;
3066 static const WCHAR Query[] =
3067 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3068 '`','S','h','o','r','t','c','u','t','`',0};
3070 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3071 if (rc != ERROR_SUCCESS)
3072 return ERROR_SUCCESS;
3074 res = CoInitialize( NULL );
3076 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3077 msiobj_release(&view->hdr);
3079 if (SUCCEEDED(res))
3080 CoUninitialize();
3082 return rc;
3085 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3087 MSIPACKAGE* package = param;
3088 HANDLE the_file;
3089 LPWSTR FilePath;
3090 LPCWSTR FileName;
3091 CHAR buffer[1024];
3092 DWORD sz;
3093 UINT rc;
3094 MSIRECORD *uirow;
3096 FileName = MSI_RecordGetString(row,1);
3097 if (!FileName)
3099 ERR("Unable to get FileName\n");
3100 return ERROR_SUCCESS;
3103 FilePath = build_icon_path(package,FileName);
3105 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3107 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3108 FILE_ATTRIBUTE_NORMAL, NULL);
3110 if (the_file == INVALID_HANDLE_VALUE)
3112 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3113 msi_free(FilePath);
3114 return ERROR_SUCCESS;
3119 DWORD write;
3120 sz = 1024;
3121 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3122 if (rc != ERROR_SUCCESS)
3124 ERR("Failed to get stream\n");
3125 CloseHandle(the_file);
3126 DeleteFileW(FilePath);
3127 break;
3129 WriteFile(the_file,buffer,sz,&write,NULL);
3130 } while (sz == 1024);
3132 msi_free(FilePath);
3134 CloseHandle(the_file);
3136 uirow = MSI_CreateRecord(1);
3137 MSI_RecordSetStringW(uirow,1,FileName);
3138 ui_actiondata(package,szPublishProduct,uirow);
3139 msiobj_release( &uirow->hdr );
3141 return ERROR_SUCCESS;
3144 static UINT msi_publish_icons(MSIPACKAGE *package)
3146 UINT r;
3147 MSIQUERY *view;
3149 static const WCHAR query[]= {
3150 'S','E','L','E','C','T',' ','*',' ',
3151 'F','R','O','M',' ','`','I','c','o','n','`',0};
3153 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3154 if (r == ERROR_SUCCESS)
3156 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3157 msiobj_release(&view->hdr);
3160 return ERROR_SUCCESS;
3163 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3165 UINT r;
3166 HKEY source;
3167 LPWSTR buffer;
3168 MSIMEDIADISK *disk;
3169 MSISOURCELISTINFO *info;
3171 r = RegCreateKeyW(hkey, szSourceList, &source);
3172 if (r != ERROR_SUCCESS)
3173 return r;
3175 RegCloseKey(source);
3177 buffer = strrchrW(package->PackagePath, '\\') + 1;
3178 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3179 package->Context, MSICODE_PRODUCT,
3180 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3181 if (r != ERROR_SUCCESS)
3182 return r;
3184 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3185 package->Context, MSICODE_PRODUCT,
3186 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3187 if (r != ERROR_SUCCESS)
3188 return r;
3190 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3191 package->Context, MSICODE_PRODUCT,
3192 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3193 if (r != ERROR_SUCCESS)
3194 return r;
3196 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3198 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3199 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3200 info->options, info->value);
3201 else
3202 MsiSourceListSetInfoW(package->ProductCode, NULL,
3203 info->context, info->options,
3204 info->property, info->value);
3207 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3209 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3210 disk->context, disk->options,
3211 disk->disk_id, disk->volume_label, disk->disk_prompt);
3214 return ERROR_SUCCESS;
3217 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3219 MSIHANDLE hdb, suminfo;
3220 WCHAR guids[MAX_PATH];
3221 WCHAR packcode[SQUISH_GUID_SIZE];
3222 LPWSTR buffer;
3223 LPWSTR ptr;
3224 DWORD langid;
3225 DWORD size;
3226 UINT r;
3228 static const WCHAR szProductLanguage[] =
3229 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3230 static const WCHAR szARPProductIcon[] =
3231 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3232 static const WCHAR szProductVersion[] =
3233 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3234 static const WCHAR szAssignment[] =
3235 {'A','s','s','i','g','n','m','e','n','t',0};
3236 static const WCHAR szAdvertiseFlags[] =
3237 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3238 static const WCHAR szClients[] =
3239 {'C','l','i','e','n','t','s',0};
3240 static const WCHAR szColon[] = {':',0};
3242 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3243 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3244 msi_free(buffer);
3246 langid = msi_get_property_int(package, szProductLanguage, 0);
3247 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3249 /* FIXME */
3250 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3252 buffer = msi_dup_property(package, szARPProductIcon);
3253 if (buffer)
3255 LPWSTR path = build_icon_path(package,buffer);
3256 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3257 msi_free(path);
3258 msi_free(buffer);
3261 buffer = msi_dup_property(package, szProductVersion);
3262 if (buffer)
3264 DWORD verdword = msi_version_str_to_dword(buffer);
3265 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3266 msi_free(buffer);
3269 msi_reg_set_val_dword(hkey, szAssignment, 0);
3270 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3271 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3272 msi_reg_set_val_str(hkey, szClients, szColon);
3274 hdb = alloc_msihandle(&package->db->hdr);
3275 if (!hdb)
3276 return ERROR_NOT_ENOUGH_MEMORY;
3278 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3279 MsiCloseHandle(hdb);
3280 if (r != ERROR_SUCCESS)
3281 goto done;
3283 size = MAX_PATH;
3284 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3285 NULL, guids, &size);
3286 if (r != ERROR_SUCCESS)
3287 goto done;
3289 ptr = strchrW(guids, ';');
3290 if (ptr) *ptr = 0;
3291 squash_guid(guids, packcode);
3292 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3294 done:
3295 MsiCloseHandle(suminfo);
3296 return ERROR_SUCCESS;
3299 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3301 UINT r;
3302 HKEY hkey;
3303 LPWSTR upgrade;
3304 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3306 static const WCHAR szUpgradeCode[] =
3307 {'U','p','g','r','a','d','e','C','o','d','e',0};
3309 upgrade = msi_dup_property(package, szUpgradeCode);
3310 if (!upgrade)
3311 return ERROR_SUCCESS;
3313 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3315 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3316 if (r != ERROR_SUCCESS)
3317 goto done;
3319 else
3321 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3322 if (r != ERROR_SUCCESS)
3323 goto done;
3326 squash_guid(package->ProductCode, squashed_pc);
3327 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3329 RegCloseKey(hkey);
3331 done:
3332 msi_free(upgrade);
3333 return r;
3336 static BOOL msi_check_publish(MSIPACKAGE *package)
3338 MSIFEATURE *feature;
3340 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3342 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3343 return TRUE;
3346 return FALSE;
3349 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3351 MSIFEATURE *feature;
3353 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3355 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3356 return FALSE;
3359 return TRUE;
3362 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3364 WCHAR patch_squashed[GUID_SIZE];
3365 HKEY patches;
3366 LONG res;
3367 UINT r = ERROR_FUNCTION_FAILED;
3369 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3370 &patches, NULL);
3371 if (res != ERROR_SUCCESS)
3372 return ERROR_FUNCTION_FAILED;
3374 squash_guid(package->patch->patchcode, patch_squashed);
3376 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3377 (const BYTE *)patch_squashed,
3378 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3379 if (res != ERROR_SUCCESS)
3380 goto done;
3382 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3383 (const BYTE *)package->patch->transforms,
3384 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3385 if (res == ERROR_SUCCESS)
3386 r = ERROR_SUCCESS;
3388 done:
3389 RegCloseKey(patches);
3390 return r;
3394 * 99% of the work done here is only done for
3395 * advertised installs. However this is where the
3396 * Icon table is processed and written out
3397 * so that is what I am going to do here.
3399 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3401 UINT rc;
3402 HKEY hukey=0;
3403 HKEY hudkey=0;
3405 /* FIXME: also need to publish if the product is in advertise mode */
3406 if (!msi_check_publish(package))
3407 return ERROR_SUCCESS;
3409 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3410 &hukey, TRUE);
3411 if (rc != ERROR_SUCCESS)
3412 goto end;
3414 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3415 NULL, &hudkey, TRUE);
3416 if (rc != ERROR_SUCCESS)
3417 goto end;
3419 rc = msi_publish_upgrade_code(package);
3420 if (rc != ERROR_SUCCESS)
3421 goto end;
3423 if (package->patch)
3425 rc = msi_publish_patch(package, hukey, hudkey);
3426 if (rc != ERROR_SUCCESS)
3427 goto end;
3430 rc = msi_publish_product_properties(package, hukey);
3431 if (rc != ERROR_SUCCESS)
3432 goto end;
3434 rc = msi_publish_sourcelist(package, hukey);
3435 if (rc != ERROR_SUCCESS)
3436 goto end;
3438 rc = msi_publish_icons(package);
3440 end:
3441 RegCloseKey(hukey);
3442 RegCloseKey(hudkey);
3444 return rc;
3447 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3449 MSIPACKAGE *package = param;
3450 LPCWSTR component, section, key, value, identifier, dirproperty;
3451 LPWSTR deformated_section, deformated_key, deformated_value;
3452 LPWSTR folder, filename, fullname = NULL;
3453 LPCWSTR filenameptr;
3454 MSIRECORD * uirow;
3455 INT action;
3456 MSICOMPONENT *comp;
3457 static const WCHAR szWindowsFolder[] =
3458 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3460 component = MSI_RecordGetString(row, 8);
3461 comp = get_loaded_component(package,component);
3463 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3465 TRACE("Skipping ini file due to disabled component %s\n",
3466 debugstr_w(component));
3468 comp->Action = comp->Installed;
3470 return ERROR_SUCCESS;
3473 comp->Action = INSTALLSTATE_LOCAL;
3475 identifier = MSI_RecordGetString(row,1);
3476 dirproperty = MSI_RecordGetString(row,3);
3477 section = MSI_RecordGetString(row,4);
3478 key = MSI_RecordGetString(row,5);
3479 value = MSI_RecordGetString(row,6);
3480 action = MSI_RecordGetInteger(row,7);
3482 deformat_string(package,section,&deformated_section);
3483 deformat_string(package,key,&deformated_key);
3484 deformat_string(package,value,&deformated_value);
3486 filename = msi_dup_record_field(row, 2);
3487 if (filename && (filenameptr = strchrW(filename, '|')))
3488 filenameptr++;
3489 else
3490 filenameptr = filename;
3492 if (dirproperty)
3494 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3495 if (!folder)
3496 folder = msi_dup_property( package, dirproperty );
3498 else
3499 folder = msi_dup_property( package, szWindowsFolder );
3501 if (!folder)
3503 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3504 goto cleanup;
3507 fullname = build_directory_name(2, folder, filenameptr);
3509 if (action == 0)
3511 TRACE("Adding value %s to section %s in %s\n",
3512 debugstr_w(deformated_key), debugstr_w(deformated_section),
3513 debugstr_w(fullname));
3514 WritePrivateProfileStringW(deformated_section, deformated_key,
3515 deformated_value, fullname);
3517 else if (action == 1)
3519 WCHAR returned[10];
3520 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3521 returned, 10, fullname);
3522 if (returned[0] == 0)
3524 TRACE("Adding value %s to section %s in %s\n",
3525 debugstr_w(deformated_key), debugstr_w(deformated_section),
3526 debugstr_w(fullname));
3528 WritePrivateProfileStringW(deformated_section, deformated_key,
3529 deformated_value, fullname);
3532 else if (action == 3)
3533 FIXME("Append to existing section not yet implemented\n");
3535 uirow = MSI_CreateRecord(4);
3536 MSI_RecordSetStringW(uirow,1,identifier);
3537 MSI_RecordSetStringW(uirow,2,deformated_section);
3538 MSI_RecordSetStringW(uirow,3,deformated_key);
3539 MSI_RecordSetStringW(uirow,4,deformated_value);
3540 ui_actiondata(package,szWriteIniValues,uirow);
3541 msiobj_release( &uirow->hdr );
3543 cleanup:
3544 msi_free(filename);
3545 msi_free(fullname);
3546 msi_free(folder);
3547 msi_free(deformated_key);
3548 msi_free(deformated_value);
3549 msi_free(deformated_section);
3550 return ERROR_SUCCESS;
3553 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3555 UINT rc;
3556 MSIQUERY * view;
3557 static const WCHAR ExecSeqQuery[] =
3558 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3559 '`','I','n','i','F','i','l','e','`',0};
3561 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3562 if (rc != ERROR_SUCCESS)
3564 TRACE("no IniFile table\n");
3565 return ERROR_SUCCESS;
3568 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3569 msiobj_release(&view->hdr);
3570 return rc;
3573 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3575 MSIPACKAGE *package = param;
3576 LPCWSTR filename;
3577 LPWSTR FullName;
3578 MSIFILE *file;
3579 DWORD len;
3580 static const WCHAR ExeStr[] =
3581 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3582 static const WCHAR close[] = {'\"',0};
3583 STARTUPINFOW si;
3584 PROCESS_INFORMATION info;
3585 BOOL brc;
3586 MSIRECORD *uirow;
3587 LPWSTR uipath, p;
3589 memset(&si,0,sizeof(STARTUPINFOW));
3591 filename = MSI_RecordGetString(row,1);
3592 file = get_loaded_file( package, filename );
3594 if (!file)
3596 ERR("Unable to find file id %s\n",debugstr_w(filename));
3597 return ERROR_SUCCESS;
3600 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3602 FullName = msi_alloc(len*sizeof(WCHAR));
3603 strcpyW(FullName,ExeStr);
3604 strcatW( FullName, file->TargetPath );
3605 strcatW(FullName,close);
3607 TRACE("Registering %s\n",debugstr_w(FullName));
3608 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3609 &si, &info);
3611 if (brc)
3613 CloseHandle(info.hThread);
3614 msi_dialog_check_messages(info.hProcess);
3615 CloseHandle(info.hProcess);
3618 msi_free(FullName);
3620 /* the UI chunk */
3621 uirow = MSI_CreateRecord( 2 );
3622 uipath = strdupW( file->TargetPath );
3623 p = strrchrW(uipath,'\\');
3624 if (p)
3625 p[0]=0;
3626 MSI_RecordSetStringW( uirow, 1, &p[1] );
3627 MSI_RecordSetStringW( uirow, 2, uipath);
3628 ui_actiondata( package, szSelfRegModules, uirow);
3629 msiobj_release( &uirow->hdr );
3630 msi_free( uipath );
3631 /* FIXME: call ui_progress? */
3633 return ERROR_SUCCESS;
3636 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3638 UINT rc;
3639 MSIQUERY * view;
3640 static const WCHAR ExecSeqQuery[] =
3641 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3642 '`','S','e','l','f','R','e','g','`',0};
3644 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3645 if (rc != ERROR_SUCCESS)
3647 TRACE("no SelfReg table\n");
3648 return ERROR_SUCCESS;
3651 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3652 msiobj_release(&view->hdr);
3654 return ERROR_SUCCESS;
3657 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3659 MSIFEATURE *feature;
3660 UINT rc;
3661 HKEY hkey;
3662 HKEY userdata = NULL;
3664 if (!msi_check_publish(package))
3665 return ERROR_SUCCESS;
3667 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3668 &hkey, TRUE);
3669 if (rc != ERROR_SUCCESS)
3670 goto end;
3672 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3673 &userdata, TRUE);
3674 if (rc != ERROR_SUCCESS)
3675 goto end;
3677 /* here the guids are base 85 encoded */
3678 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3680 ComponentList *cl;
3681 LPWSTR data = NULL;
3682 GUID clsid;
3683 INT size;
3684 BOOL absent = FALSE;
3685 MSIRECORD *uirow;
3687 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3688 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3689 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3690 absent = TRUE;
3692 size = 1;
3693 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3695 size += 21;
3697 if (feature->Feature_Parent)
3698 size += strlenW( feature->Feature_Parent )+2;
3700 data = msi_alloc(size * sizeof(WCHAR));
3702 data[0] = 0;
3703 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3705 MSICOMPONENT* component = cl->component;
3706 WCHAR buf[21];
3708 buf[0] = 0;
3709 if (component->ComponentId)
3711 TRACE("From %s\n",debugstr_w(component->ComponentId));
3712 CLSIDFromString(component->ComponentId, &clsid);
3713 encode_base85_guid(&clsid,buf);
3714 TRACE("to %s\n",debugstr_w(buf));
3715 strcatW(data,buf);
3719 if (feature->Feature_Parent)
3721 static const WCHAR sep[] = {'\2',0};
3722 strcatW(data,sep);
3723 strcatW(data,feature->Feature_Parent);
3726 msi_reg_set_val_str( userdata, feature->Feature, data );
3727 msi_free(data);
3729 size = 0;
3730 if (feature->Feature_Parent)
3731 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3732 if (!absent)
3734 size += sizeof(WCHAR);
3735 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3736 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
3738 else
3740 size += 2*sizeof(WCHAR);
3741 data = msi_alloc(size);
3742 data[0] = 0x6;
3743 data[1] = 0;
3744 if (feature->Feature_Parent)
3745 strcpyW( &data[1], feature->Feature_Parent );
3746 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3747 (LPBYTE)data,size);
3748 msi_free(data);
3751 /* the UI chunk */
3752 uirow = MSI_CreateRecord( 1 );
3753 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3754 ui_actiondata( package, szPublishFeatures, uirow);
3755 msiobj_release( &uirow->hdr );
3756 /* FIXME: call ui_progress? */
3759 end:
3760 RegCloseKey(hkey);
3761 RegCloseKey(userdata);
3762 return rc;
3765 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
3767 UINT r;
3768 HKEY hkey;
3770 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
3772 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3773 &hkey, FALSE);
3774 if (r == ERROR_SUCCESS)
3776 RegDeleteValueW(hkey, feature->Feature);
3777 RegCloseKey(hkey);
3780 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3781 &hkey, FALSE);
3782 if (r == ERROR_SUCCESS)
3784 RegDeleteValueW(hkey, feature->Feature);
3785 RegCloseKey(hkey);
3788 return ERROR_SUCCESS;
3791 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
3793 MSIFEATURE *feature;
3795 if (!msi_check_unpublish(package))
3796 return ERROR_SUCCESS;
3798 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3800 msi_unpublish_feature(package, feature);
3803 return ERROR_SUCCESS;
3806 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
3808 LPWSTR prop, val, key;
3809 SYSTEMTIME systime;
3810 DWORD size, langid;
3811 WCHAR date[9];
3812 LPWSTR buffer;
3814 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
3815 static const WCHAR szWindowsInstaller[] =
3816 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3817 static const WCHAR modpath_fmt[] =
3818 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3819 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3820 static const WCHAR szModifyPath[] =
3821 {'M','o','d','i','f','y','P','a','t','h',0};
3822 static const WCHAR szUninstallString[] =
3823 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3824 static const WCHAR szEstimatedSize[] =
3825 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3826 static const WCHAR szProductLanguage[] =
3827 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3828 static const WCHAR szProductVersion[] =
3829 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3830 static const WCHAR szProductName[] =
3831 {'P','r','o','d','u','c','t','N','a','m','e',0};
3832 static const WCHAR szDisplayName[] =
3833 {'D','i','s','p','l','a','y','N','a','m','e',0};
3834 static const WCHAR szDisplayVersion[] =
3835 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
3836 static const WCHAR szManufacturer[] =
3837 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
3839 static const LPCSTR propval[] = {
3840 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3841 "ARPCONTACT", "Contact",
3842 "ARPCOMMENTS", "Comments",
3843 "ProductName", "DisplayName",
3844 "ProductVersion", "DisplayVersion",
3845 "ARPHELPLINK", "HelpLink",
3846 "ARPHELPTELEPHONE", "HelpTelephone",
3847 "ARPINSTALLLOCATION", "InstallLocation",
3848 "SourceDir", "InstallSource",
3849 "Manufacturer", "Publisher",
3850 "ARPREADME", "Readme",
3851 "ARPSIZE", "Size",
3852 "ARPURLINFOABOUT", "URLInfoAbout",
3853 "ARPURLUPDATEINFO", "URLUpdateInfo",
3854 NULL,
3856 const LPCSTR *p = propval;
3858 while (*p)
3860 prop = strdupAtoW(*p++);
3861 key = strdupAtoW(*p++);
3862 val = msi_dup_property(package, prop);
3863 msi_reg_set_val_str(hkey, key, val);
3864 msi_free(val);
3865 msi_free(key);
3866 msi_free(prop);
3869 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
3871 size = deformat_string(package, modpath_fmt, &buffer);
3872 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
3873 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
3874 msi_free(buffer);
3876 /* FIXME: Write real Estimated Size when we have it */
3877 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
3879 buffer = msi_dup_property(package, szProductName);
3880 msi_reg_set_val_str(hkey, szDisplayName, buffer);
3881 msi_free(buffer);
3883 buffer = msi_dup_property(package, cszSourceDir);
3884 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
3885 msi_free(buffer);
3887 buffer = msi_dup_property(package, szManufacturer);
3888 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
3889 msi_free(buffer);
3891 GetLocalTime(&systime);
3892 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
3893 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
3895 langid = msi_get_property_int(package, szProductLanguage, 0);
3896 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3898 buffer = msi_dup_property(package, szProductVersion);
3899 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
3900 if (buffer)
3902 DWORD verdword = msi_version_str_to_dword(buffer);
3904 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3905 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
3906 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
3907 msi_free(buffer);
3910 return ERROR_SUCCESS;
3913 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3915 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3916 LPWSTR upgrade_code;
3917 HKEY hkey, props;
3918 HKEY upgrade;
3919 UINT rc;
3921 static const WCHAR szUpgradeCode[] = {
3922 'U','p','g','r','a','d','e','C','o','d','e',0};
3924 /* FIXME: also need to publish if the product is in advertise mode */
3925 if (!msi_check_publish(package))
3926 return ERROR_SUCCESS;
3928 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
3929 if (rc != ERROR_SUCCESS)
3930 return rc;
3932 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
3933 NULL, &props, TRUE);
3934 if (rc != ERROR_SUCCESS)
3935 goto done;
3937 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
3938 msi_free( package->db->localfile );
3939 package->db->localfile = NULL;
3941 rc = msi_publish_install_properties(package, hkey);
3942 if (rc != ERROR_SUCCESS)
3943 goto done;
3945 rc = msi_publish_install_properties(package, props);
3946 if (rc != ERROR_SUCCESS)
3947 goto done;
3949 upgrade_code = msi_dup_property(package, szUpgradeCode);
3950 if (upgrade_code)
3952 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
3953 squash_guid(package->ProductCode, squashed_pc);
3954 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
3955 RegCloseKey(upgrade);
3956 msi_free(upgrade_code);
3959 done:
3960 RegCloseKey(hkey);
3962 return ERROR_SUCCESS;
3965 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3967 return execute_script(package,INSTALL_SCRIPT);
3970 static UINT msi_unpublish_product(MSIPACKAGE *package)
3972 LPWSTR upgrade;
3973 LPWSTR remove = NULL;
3974 LPWSTR *features = NULL;
3975 BOOL full_uninstall = TRUE;
3976 MSIFEATURE *feature;
3978 static const WCHAR szUpgradeCode[] =
3979 {'U','p','g','r','a','d','e','C','o','d','e',0};
3981 remove = msi_dup_property(package, szRemove);
3982 if (!remove)
3983 return ERROR_SUCCESS;
3985 features = msi_split_string(remove, ',');
3986 if (!features)
3988 msi_free(remove);
3989 ERR("REMOVE feature list is empty!\n");
3990 return ERROR_FUNCTION_FAILED;
3993 if (!lstrcmpW(features[0], szAll))
3994 full_uninstall = TRUE;
3995 else
3997 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3999 if (feature->Action != INSTALLSTATE_ABSENT)
4000 full_uninstall = FALSE;
4004 if (!full_uninstall)
4005 goto done;
4007 MSIREG_DeleteProductKey(package->ProductCode);
4008 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4009 MSIREG_DeleteUninstallKey(package->ProductCode);
4011 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4013 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4014 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4016 else
4018 MSIREG_DeleteUserProductKey(package->ProductCode);
4019 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4022 upgrade = msi_dup_property(package, szUpgradeCode);
4023 if (upgrade)
4025 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4026 msi_free(upgrade);
4029 done:
4030 msi_free(remove);
4031 msi_free(features);
4032 return ERROR_SUCCESS;
4035 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4037 UINT rc;
4039 rc = msi_unpublish_product(package);
4040 if (rc != ERROR_SUCCESS)
4041 return rc;
4043 /* turn off scheduling */
4044 package->script->CurrentlyScripting= FALSE;
4046 /* first do the same as an InstallExecute */
4047 rc = ACTION_InstallExecute(package);
4048 if (rc != ERROR_SUCCESS)
4049 return rc;
4051 /* then handle Commit Actions */
4052 rc = execute_script(package,COMMIT_SCRIPT);
4054 return rc;
4057 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4059 static const WCHAR RunOnce[] = {
4060 'S','o','f','t','w','a','r','e','\\',
4061 'M','i','c','r','o','s','o','f','t','\\',
4062 'W','i','n','d','o','w','s','\\',
4063 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4064 'R','u','n','O','n','c','e',0};
4065 static const WCHAR InstallRunOnce[] = {
4066 'S','o','f','t','w','a','r','e','\\',
4067 'M','i','c','r','o','s','o','f','t','\\',
4068 'W','i','n','d','o','w','s','\\',
4069 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4070 'I','n','s','t','a','l','l','e','r','\\',
4071 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4073 static const WCHAR msiexec_fmt[] = {
4074 '%','s',
4075 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4076 '\"','%','s','\"',0};
4077 static const WCHAR install_fmt[] = {
4078 '/','I',' ','\"','%','s','\"',' ',
4079 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4080 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4081 WCHAR buffer[256], sysdir[MAX_PATH];
4082 HKEY hkey;
4083 WCHAR squished_pc[100];
4085 squash_guid(package->ProductCode,squished_pc);
4087 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4088 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4089 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4090 squished_pc);
4092 msi_reg_set_val_str( hkey, squished_pc, buffer );
4093 RegCloseKey(hkey);
4095 TRACE("Reboot command %s\n",debugstr_w(buffer));
4097 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4098 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4100 msi_reg_set_val_str( hkey, squished_pc, buffer );
4101 RegCloseKey(hkey);
4103 return ERROR_INSTALL_SUSPEND;
4106 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4108 DWORD attrib;
4109 UINT rc;
4112 * We are currently doing what should be done here in the top level Install
4113 * however for Administrative and uninstalls this step will be needed
4115 if (!package->PackagePath)
4116 return ERROR_SUCCESS;
4118 msi_set_sourcedir_props(package, TRUE);
4120 attrib = GetFileAttributesW(package->db->path);
4121 if (attrib == INVALID_FILE_ATTRIBUTES)
4123 LPWSTR prompt;
4124 LPWSTR msg;
4125 DWORD size = 0;
4127 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4128 package->Context, MSICODE_PRODUCT,
4129 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4130 if (rc == ERROR_MORE_DATA)
4132 prompt = msi_alloc(size * sizeof(WCHAR));
4133 MsiSourceListGetInfoW(package->ProductCode, NULL,
4134 package->Context, MSICODE_PRODUCT,
4135 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4137 else
4138 prompt = strdupW(package->db->path);
4140 msg = generate_error_string(package,1302,1,prompt);
4141 while(attrib == INVALID_FILE_ATTRIBUTES)
4143 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4144 if (rc == IDCANCEL)
4146 rc = ERROR_INSTALL_USEREXIT;
4147 break;
4149 attrib = GetFileAttributesW(package->db->path);
4151 msi_free(prompt);
4152 rc = ERROR_SUCCESS;
4154 else
4155 return ERROR_SUCCESS;
4157 return rc;
4160 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4162 HKEY hkey=0;
4163 LPWSTR buffer;
4164 LPWSTR productid;
4165 UINT rc,i;
4167 static const WCHAR szPropKeys[][80] =
4169 {'P','r','o','d','u','c','t','I','D',0},
4170 {'U','S','E','R','N','A','M','E',0},
4171 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4172 {0},
4175 static const WCHAR szRegKeys[][80] =
4177 {'P','r','o','d','u','c','t','I','D',0},
4178 {'R','e','g','O','w','n','e','r',0},
4179 {'R','e','g','C','o','m','p','a','n','y',0},
4180 {0},
4183 if (msi_check_unpublish(package))
4185 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4186 return ERROR_SUCCESS;
4189 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4190 if (!productid)
4191 return ERROR_SUCCESS;
4193 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4194 NULL, &hkey, TRUE);
4195 if (rc != ERROR_SUCCESS)
4196 goto end;
4198 for( i = 0; szPropKeys[i][0]; i++ )
4200 buffer = msi_dup_property( package, szPropKeys[i] );
4201 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4202 msi_free( buffer );
4205 end:
4206 msi_free(productid);
4207 RegCloseKey(hkey);
4209 /* FIXME: call ui_actiondata */
4211 return rc;
4215 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4217 UINT rc;
4219 package->script->InWhatSequence |= SEQUENCE_EXEC;
4220 rc = ACTION_ProcessExecSequence(package,FALSE);
4221 return rc;
4225 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4227 MSIPACKAGE *package = param;
4228 LPCWSTR compgroupid=NULL;
4229 LPCWSTR feature=NULL;
4230 LPCWSTR text = NULL;
4231 LPCWSTR qualifier = NULL;
4232 LPCWSTR component = NULL;
4233 LPWSTR advertise = NULL;
4234 LPWSTR output = NULL;
4235 HKEY hkey;
4236 UINT rc = ERROR_SUCCESS;
4237 MSICOMPONENT *comp;
4238 DWORD sz = 0;
4239 MSIRECORD *uirow;
4241 component = MSI_RecordGetString(rec,3);
4242 comp = get_loaded_component(package,component);
4244 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4245 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4246 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4248 TRACE("Skipping: Component %s not scheduled for install\n",
4249 debugstr_w(component));
4251 return ERROR_SUCCESS;
4254 compgroupid = MSI_RecordGetString(rec,1);
4255 qualifier = MSI_RecordGetString(rec,2);
4257 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4258 if (rc != ERROR_SUCCESS)
4259 goto end;
4261 text = MSI_RecordGetString(rec,4);
4262 feature = MSI_RecordGetString(rec,5);
4264 advertise = create_component_advertise_string(package, comp, feature);
4266 sz = strlenW(advertise);
4268 if (text)
4269 sz += lstrlenW(text);
4271 sz+=3;
4272 sz *= sizeof(WCHAR);
4274 output = msi_alloc_zero(sz);
4275 strcpyW(output,advertise);
4276 msi_free(advertise);
4278 if (text)
4279 strcatW(output,text);
4281 msi_reg_set_val_multi_str( hkey, qualifier, output );
4283 end:
4284 RegCloseKey(hkey);
4285 msi_free(output);
4287 /* the UI chunk */
4288 uirow = MSI_CreateRecord( 2 );
4289 MSI_RecordSetStringW( uirow, 1, compgroupid );
4290 MSI_RecordSetStringW( uirow, 2, qualifier);
4291 ui_actiondata( package, szPublishComponents, uirow);
4292 msiobj_release( &uirow->hdr );
4293 /* FIXME: call ui_progress? */
4295 return rc;
4299 * At present I am ignorning the advertised components part of this and only
4300 * focusing on the qualified component sets
4302 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4304 UINT rc;
4305 MSIQUERY * view;
4306 static const WCHAR ExecSeqQuery[] =
4307 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4308 '`','P','u','b','l','i','s','h',
4309 'C','o','m','p','o','n','e','n','t','`',0};
4311 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4312 if (rc != ERROR_SUCCESS)
4313 return ERROR_SUCCESS;
4315 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4316 msiobj_release(&view->hdr);
4318 return rc;
4321 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4323 MSIPACKAGE *package = param;
4324 MSIRECORD *row;
4325 MSIFILE *file;
4326 SC_HANDLE hscm, service = NULL;
4327 LPCWSTR comp, depends, pass;
4328 LPWSTR name = NULL, disp = NULL;
4329 LPCWSTR load_order, serv_name, key;
4330 DWORD serv_type, start_type;
4331 DWORD err_control;
4333 static const WCHAR query[] =
4334 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4335 '`','C','o','m','p','o','n','e','n','t','`',' ',
4336 'W','H','E','R','E',' ',
4337 '`','C','o','m','p','o','n','e','n','t','`',' ',
4338 '=','\'','%','s','\'',0};
4340 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4341 if (!hscm)
4343 ERR("Failed to open the SC Manager!\n");
4344 goto done;
4347 start_type = MSI_RecordGetInteger(rec, 5);
4348 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4349 goto done;
4351 depends = MSI_RecordGetString(rec, 8);
4352 if (depends && *depends)
4353 FIXME("Dependency list unhandled!\n");
4355 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4356 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
4357 serv_type = MSI_RecordGetInteger(rec, 4);
4358 err_control = MSI_RecordGetInteger(rec, 6);
4359 load_order = MSI_RecordGetString(rec, 7);
4360 serv_name = MSI_RecordGetString(rec, 9);
4361 pass = MSI_RecordGetString(rec, 10);
4362 comp = MSI_RecordGetString(rec, 12);
4364 /* fetch the service path */
4365 row = MSI_QueryGetRecord(package->db, query, comp);
4366 if (!row)
4368 ERR("Control query failed!\n");
4369 goto done;
4372 key = MSI_RecordGetString(row, 6);
4374 file = get_loaded_file(package, key);
4375 msiobj_release(&row->hdr);
4376 if (!file)
4378 ERR("Failed to load the service file\n");
4379 goto done;
4382 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4383 start_type, err_control, file->TargetPath,
4384 load_order, NULL, NULL, serv_name, pass);
4385 if (!service)
4387 if (GetLastError() != ERROR_SERVICE_EXISTS)
4388 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4391 done:
4392 CloseServiceHandle(service);
4393 CloseServiceHandle(hscm);
4394 msi_free(name);
4395 msi_free(disp);
4397 return ERROR_SUCCESS;
4400 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4402 UINT rc;
4403 MSIQUERY * view;
4404 static const WCHAR ExecSeqQuery[] =
4405 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4406 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4408 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4409 if (rc != ERROR_SUCCESS)
4410 return ERROR_SUCCESS;
4412 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4413 msiobj_release(&view->hdr);
4415 return rc;
4418 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4419 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
4421 LPCWSTR *vector, *temp_vector;
4422 LPWSTR p, q;
4423 DWORD sep_len;
4425 static const WCHAR separator[] = {'[','~',']',0};
4427 *numargs = 0;
4428 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4430 if (!args)
4431 return NULL;
4433 vector = msi_alloc(sizeof(LPWSTR));
4434 if (!vector)
4435 return NULL;
4437 p = args;
4440 (*numargs)++;
4441 vector[*numargs - 1] = p;
4443 if ((q = strstrW(p, separator)))
4445 *q = '\0';
4447 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4448 if (!temp_vector)
4450 msi_free(vector);
4451 return NULL;
4453 vector = temp_vector;
4455 p = q + sep_len;
4457 } while (q);
4459 return vector;
4462 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4464 MSIPACKAGE *package = param;
4465 MSICOMPONENT *comp;
4466 SC_HANDLE scm, service = NULL;
4467 LPCWSTR name, *vector = NULL;
4468 LPWSTR args;
4469 DWORD event, numargs;
4470 UINT r = ERROR_FUNCTION_FAILED;
4472 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4473 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4474 return ERROR_SUCCESS;
4476 name = MSI_RecordGetString(rec, 2);
4477 event = MSI_RecordGetInteger(rec, 3);
4478 args = strdupW(MSI_RecordGetString(rec, 4));
4480 if (!(event & msidbServiceControlEventStart))
4481 return ERROR_SUCCESS;
4483 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4484 if (!scm)
4486 ERR("Failed to open the service control manager\n");
4487 goto done;
4490 service = OpenServiceW(scm, name, SERVICE_START);
4491 if (!service)
4493 ERR("Failed to open service %s\n", debugstr_w(name));
4494 goto done;
4497 vector = msi_service_args_to_vector(args, &numargs);
4499 if (!StartServiceW(service, numargs, vector))
4501 ERR("Failed to start service %s\n", debugstr_w(name));
4502 goto done;
4505 r = ERROR_SUCCESS;
4507 done:
4508 CloseServiceHandle(service);
4509 CloseServiceHandle(scm);
4511 msi_free(args);
4512 msi_free(vector);
4513 return r;
4516 static UINT ACTION_StartServices( MSIPACKAGE *package )
4518 UINT rc;
4519 MSIQUERY *view;
4521 static const WCHAR query[] = {
4522 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4523 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4525 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4526 if (rc != ERROR_SUCCESS)
4527 return ERROR_SUCCESS;
4529 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4530 msiobj_release(&view->hdr);
4532 return rc;
4535 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4537 DWORD i, needed, count;
4538 ENUM_SERVICE_STATUSW *dependencies;
4539 SERVICE_STATUS ss;
4540 SC_HANDLE depserv;
4542 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4543 0, &needed, &count))
4544 return TRUE;
4546 if (GetLastError() != ERROR_MORE_DATA)
4547 return FALSE;
4549 dependencies = msi_alloc(needed);
4550 if (!dependencies)
4551 return FALSE;
4553 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4554 needed, &needed, &count))
4555 goto error;
4557 for (i = 0; i < count; i++)
4559 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4560 SERVICE_STOP | SERVICE_QUERY_STATUS);
4561 if (!depserv)
4562 goto error;
4564 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4565 goto error;
4568 return TRUE;
4570 error:
4571 msi_free(dependencies);
4572 return FALSE;
4575 static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
4577 MSIPACKAGE *package = param;
4578 MSICOMPONENT *comp;
4579 SERVICE_STATUS status;
4580 SERVICE_STATUS_PROCESS ssp;
4581 SC_HANDLE scm = NULL, service = NULL;
4582 LPWSTR name, args;
4583 DWORD event, needed;
4585 event = MSI_RecordGetInteger(rec, 3);
4586 if (!(event & msidbServiceControlEventStop))
4587 return ERROR_SUCCESS;
4589 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4590 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4591 return ERROR_SUCCESS;
4593 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4594 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4595 args = strdupW(MSI_RecordGetString(rec, 4));
4597 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4598 if (!scm)
4600 WARN("Failed to open the SCM: %d\n", GetLastError());
4601 goto done;
4604 service = OpenServiceW(scm, name,
4605 SERVICE_STOP |
4606 SERVICE_QUERY_STATUS |
4607 SERVICE_ENUMERATE_DEPENDENTS);
4608 if (!service)
4610 WARN("Failed to open service (%s): %d\n",
4611 debugstr_w(name), GetLastError());
4612 goto done;
4615 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4616 sizeof(SERVICE_STATUS_PROCESS), &needed))
4618 WARN("Failed to query service status (%s): %d\n",
4619 debugstr_w(name), GetLastError());
4620 goto done;
4623 if (ssp.dwCurrentState == SERVICE_STOPPED)
4624 goto done;
4626 stop_service_dependents(scm, service);
4628 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
4629 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
4631 done:
4632 CloseServiceHandle(service);
4633 CloseServiceHandle(scm);
4634 msi_free(name);
4635 msi_free(args);
4637 return ERROR_SUCCESS;
4640 static UINT ACTION_StopServices( MSIPACKAGE *package )
4642 UINT rc;
4643 MSIQUERY *view;
4645 static const WCHAR query[] = {
4646 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4647 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4649 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4650 if (rc != ERROR_SUCCESS)
4651 return ERROR_SUCCESS;
4653 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
4654 msiobj_release(&view->hdr);
4656 return rc;
4659 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4661 MSIFILE *file;
4663 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4665 if (!lstrcmpW(file->File, filename))
4666 return file;
4669 return NULL;
4672 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4674 MSIPACKAGE *package = param;
4675 LPWSTR driver, driver_path, ptr;
4676 WCHAR outpath[MAX_PATH];
4677 MSIFILE *driver_file, *setup_file;
4678 LPCWSTR desc;
4679 DWORD len, usage;
4680 UINT r = ERROR_SUCCESS;
4682 static const WCHAR driver_fmt[] = {
4683 'D','r','i','v','e','r','=','%','s',0};
4684 static const WCHAR setup_fmt[] = {
4685 'S','e','t','u','p','=','%','s',0};
4686 static const WCHAR usage_fmt[] = {
4687 'F','i','l','e','U','s','a','g','e','=','1',0};
4689 desc = MSI_RecordGetString(rec, 3);
4691 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4692 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4694 if (!driver_file || !setup_file)
4696 ERR("ODBC Driver entry not found!\n");
4697 return ERROR_FUNCTION_FAILED;
4700 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4701 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4702 lstrlenW(usage_fmt) + 1;
4703 driver = msi_alloc(len * sizeof(WCHAR));
4704 if (!driver)
4705 return ERROR_OUTOFMEMORY;
4707 ptr = driver;
4708 lstrcpyW(ptr, desc);
4709 ptr += lstrlenW(ptr) + 1;
4711 sprintfW(ptr, driver_fmt, driver_file->FileName);
4712 ptr += lstrlenW(ptr) + 1;
4714 sprintfW(ptr, setup_fmt, setup_file->FileName);
4715 ptr += lstrlenW(ptr) + 1;
4717 lstrcpyW(ptr, usage_fmt);
4718 ptr += lstrlenW(ptr) + 1;
4719 *ptr = '\0';
4721 driver_path = strdupW(driver_file->TargetPath);
4722 ptr = strrchrW(driver_path, '\\');
4723 if (ptr) *ptr = '\0';
4725 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4726 NULL, ODBC_INSTALL_COMPLETE, &usage))
4728 ERR("Failed to install SQL driver!\n");
4729 r = ERROR_FUNCTION_FAILED;
4732 msi_free(driver);
4733 msi_free(driver_path);
4735 return r;
4738 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4740 MSIPACKAGE *package = param;
4741 LPWSTR translator, translator_path, ptr;
4742 WCHAR outpath[MAX_PATH];
4743 MSIFILE *translator_file, *setup_file;
4744 LPCWSTR desc;
4745 DWORD len, usage;
4746 UINT r = ERROR_SUCCESS;
4748 static const WCHAR translator_fmt[] = {
4749 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4750 static const WCHAR setup_fmt[] = {
4751 'S','e','t','u','p','=','%','s',0};
4753 desc = MSI_RecordGetString(rec, 3);
4755 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4756 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4758 if (!translator_file || !setup_file)
4760 ERR("ODBC Translator entry not found!\n");
4761 return ERROR_FUNCTION_FAILED;
4764 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
4765 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
4766 translator = msi_alloc(len * sizeof(WCHAR));
4767 if (!translator)
4768 return ERROR_OUTOFMEMORY;
4770 ptr = translator;
4771 lstrcpyW(ptr, desc);
4772 ptr += lstrlenW(ptr) + 1;
4774 sprintfW(ptr, translator_fmt, translator_file->FileName);
4775 ptr += lstrlenW(ptr) + 1;
4777 sprintfW(ptr, setup_fmt, setup_file->FileName);
4778 ptr += lstrlenW(ptr) + 1;
4779 *ptr = '\0';
4781 translator_path = strdupW(translator_file->TargetPath);
4782 ptr = strrchrW(translator_path, '\\');
4783 if (ptr) *ptr = '\0';
4785 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
4786 NULL, ODBC_INSTALL_COMPLETE, &usage))
4788 ERR("Failed to install SQL translator!\n");
4789 r = ERROR_FUNCTION_FAILED;
4792 msi_free(translator);
4793 msi_free(translator_path);
4795 return r;
4798 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
4800 LPWSTR attrs;
4801 LPCWSTR desc, driver;
4802 WORD request = ODBC_ADD_SYS_DSN;
4803 INT registration;
4804 DWORD len;
4805 UINT r = ERROR_SUCCESS;
4807 static const WCHAR attrs_fmt[] = {
4808 'D','S','N','=','%','s',0 };
4810 desc = MSI_RecordGetString(rec, 3);
4811 driver = MSI_RecordGetString(rec, 4);
4812 registration = MSI_RecordGetInteger(rec, 5);
4814 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
4815 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
4817 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
4818 attrs = msi_alloc(len * sizeof(WCHAR));
4819 if (!attrs)
4820 return ERROR_OUTOFMEMORY;
4822 sprintfW(attrs, attrs_fmt, desc);
4823 attrs[len - 1] = '\0';
4825 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
4827 ERR("Failed to install SQL data source!\n");
4828 r = ERROR_FUNCTION_FAILED;
4831 msi_free(attrs);
4833 return r;
4836 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
4838 UINT rc;
4839 MSIQUERY *view;
4841 static const WCHAR driver_query[] = {
4842 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4843 'O','D','B','C','D','r','i','v','e','r',0 };
4845 static const WCHAR translator_query[] = {
4846 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4847 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4849 static const WCHAR source_query[] = {
4850 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4851 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4853 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
4854 if (rc != ERROR_SUCCESS)
4855 return ERROR_SUCCESS;
4857 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
4858 msiobj_release(&view->hdr);
4860 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
4861 if (rc != ERROR_SUCCESS)
4862 return ERROR_SUCCESS;
4864 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
4865 msiobj_release(&view->hdr);
4867 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
4868 if (rc != ERROR_SUCCESS)
4869 return ERROR_SUCCESS;
4871 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
4872 msiobj_release(&view->hdr);
4874 return rc;
4877 #define ENV_ACT_SETALWAYS 0x1
4878 #define ENV_ACT_SETABSENT 0x2
4879 #define ENV_ACT_REMOVE 0x4
4880 #define ENV_ACT_REMOVEMATCH 0x8
4882 #define ENV_MOD_MACHINE 0x20000000
4883 #define ENV_MOD_APPEND 0x40000000
4884 #define ENV_MOD_PREFIX 0x80000000
4885 #define ENV_MOD_MASK 0xC0000000
4887 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
4889 static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
4891 LPCWSTR cptr = *name;
4893 static const WCHAR prefix[] = {'[','~',']',0};
4894 static const int prefix_len = 3;
4896 *flags = 0;
4897 while (*cptr)
4899 if (*cptr == '=')
4900 *flags |= ENV_ACT_SETALWAYS;
4901 else if (*cptr == '+')
4902 *flags |= ENV_ACT_SETABSENT;
4903 else if (*cptr == '-')
4904 *flags |= ENV_ACT_REMOVE;
4905 else if (*cptr == '!')
4906 *flags |= ENV_ACT_REMOVEMATCH;
4907 else if (*cptr == '*')
4908 *flags |= ENV_MOD_MACHINE;
4909 else
4910 break;
4912 cptr++;
4913 (*name)++;
4916 if (!*cptr)
4918 ERR("Missing environment variable\n");
4919 return ERROR_FUNCTION_FAILED;
4922 if (*value)
4924 LPCWSTR ptr = *value;
4925 if (!strncmpW(ptr, prefix, prefix_len))
4927 if (ptr[prefix_len] == szSemiColon[0])
4929 *flags |= ENV_MOD_APPEND;
4930 *value += lstrlenW(prefix);
4932 else
4934 *value = NULL;
4937 else if (lstrlenW(*value) >= prefix_len)
4939 ptr += lstrlenW(ptr) - prefix_len;
4940 if (!lstrcmpW(ptr, prefix))
4942 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
4944 *flags |= ENV_MOD_PREFIX;
4945 /* the "[~]" will be removed by deformat_string */;
4947 else
4949 *value = NULL;
4955 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
4956 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
4957 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
4958 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
4960 ERR("Invalid flags: %08x\n", *flags);
4961 return ERROR_FUNCTION_FAILED;
4964 if (!*flags)
4965 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
4967 return ERROR_SUCCESS;
4970 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
4972 MSIPACKAGE *package = param;
4973 LPCWSTR name, value;
4974 LPWSTR data = NULL, newval = NULL;
4975 LPWSTR deformatted = NULL, ptr;
4976 DWORD flags, type, size;
4977 LONG res;
4978 HKEY env = NULL, root;
4979 LPCWSTR environment;
4981 static const WCHAR user_env[] =
4982 {'E','n','v','i','r','o','n','m','e','n','t',0};
4983 static const WCHAR machine_env[] =
4984 {'S','y','s','t','e','m','\\',
4985 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
4986 'C','o','n','t','r','o','l','\\',
4987 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
4988 'E','n','v','i','r','o','n','m','e','n','t',0};
4990 name = MSI_RecordGetString(rec, 2);
4991 value = MSI_RecordGetString(rec, 3);
4993 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
4995 res = env_set_flags(&name, &value, &flags);
4996 if (res != ERROR_SUCCESS || !value)
4997 goto done;
4999 if (value && !deformat_string(package, value, &deformatted))
5001 res = ERROR_OUTOFMEMORY;
5002 goto done;
5005 value = deformatted;
5007 if (flags & ENV_MOD_MACHINE)
5009 environment = machine_env;
5010 root = HKEY_LOCAL_MACHINE;
5012 else
5014 environment = user_env;
5015 root = HKEY_CURRENT_USER;
5018 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5019 KEY_ALL_ACCESS, NULL, &env, NULL);
5020 if (res != ERROR_SUCCESS)
5021 goto done;
5023 if (flags & ENV_ACT_REMOVE)
5024 FIXME("Not removing environment variable on uninstall!\n");
5026 size = 0;
5027 type = REG_SZ;
5028 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5029 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
5030 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
5031 goto done;
5033 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
5035 /* Nothing to do. */
5036 if (!value)
5038 res = ERROR_SUCCESS;
5039 goto done;
5042 /* If we are appending but the string was empty, strip ; */
5043 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
5045 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
5046 newval = strdupW(value);
5047 if (!newval)
5049 res = ERROR_OUTOFMEMORY;
5050 goto done;
5053 else
5055 /* Contrary to MSDN, +-variable to [~];path works */
5056 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
5058 res = ERROR_SUCCESS;
5059 goto done;
5062 data = msi_alloc(size);
5063 if (!data)
5065 RegCloseKey(env);
5066 return ERROR_OUTOFMEMORY;
5069 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5070 if (res != ERROR_SUCCESS)
5071 goto done;
5073 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5075 res = RegDeleteKeyW(env, name);
5076 goto done;
5079 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
5080 if (flags & ENV_MOD_MASK)
5082 DWORD mod_size;
5083 int multiplier = 0;
5084 if (flags & ENV_MOD_APPEND) multiplier++;
5085 if (flags & ENV_MOD_PREFIX) multiplier++;
5086 mod_size = lstrlenW(value) * multiplier;
5087 size += mod_size * sizeof(WCHAR);
5090 newval = msi_alloc(size);
5091 ptr = newval;
5092 if (!newval)
5094 res = ERROR_OUTOFMEMORY;
5095 goto done;
5098 if (flags & ENV_MOD_PREFIX)
5100 lstrcpyW(newval, value);
5101 ptr = newval + lstrlenW(value);
5104 lstrcpyW(ptr, data);
5106 if (flags & ENV_MOD_APPEND)
5108 lstrcatW(newval, value);
5111 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5112 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
5114 done:
5115 if (env) RegCloseKey(env);
5116 msi_free(deformatted);
5117 msi_free(data);
5118 msi_free(newval);
5119 return res;
5122 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5124 UINT rc;
5125 MSIQUERY * view;
5126 static const WCHAR ExecSeqQuery[] =
5127 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5128 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5129 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5130 if (rc != ERROR_SUCCESS)
5131 return ERROR_SUCCESS;
5133 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5134 msiobj_release(&view->hdr);
5136 return rc;
5139 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5141 typedef struct
5143 struct list entry;
5144 LPWSTR sourcename;
5145 LPWSTR destname;
5146 LPWSTR source;
5147 LPWSTR dest;
5148 } FILE_LIST;
5150 static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5152 BOOL ret;
5154 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5155 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5157 WARN("Source or dest is directory, not moving\n");
5158 return FALSE;
5161 if (options == msidbMoveFileOptionsMove)
5163 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5164 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5165 if (!ret)
5167 WARN("MoveFile failed: %d\n", GetLastError());
5168 return FALSE;
5171 else
5173 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5174 ret = CopyFileW(source, dest, FALSE);
5175 if (!ret)
5177 WARN("CopyFile failed: %d\n", GetLastError());
5178 return FALSE;
5182 return TRUE;
5185 static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5187 LPWSTR path, ptr;
5188 DWORD dirlen, pathlen;
5190 ptr = strrchrW(wildcard, '\\');
5191 dirlen = ptr - wildcard + 1;
5193 pathlen = dirlen + lstrlenW(filename) + 1;
5194 path = msi_alloc(pathlen * sizeof(WCHAR));
5196 lstrcpynW(path, wildcard, dirlen + 1);
5197 lstrcatW(path, filename);
5199 return path;
5202 static void free_file_entry(FILE_LIST *file)
5204 msi_free(file->source);
5205 msi_free(file->dest);
5206 msi_free(file);
5209 static void free_list(FILE_LIST *list)
5211 while (!list_empty(&list->entry))
5213 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5215 list_remove(&file->entry);
5216 free_file_entry(file);
5220 static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5222 FILE_LIST *new, *file;
5223 LPWSTR ptr, filename;
5224 DWORD size;
5226 new = msi_alloc_zero(sizeof(FILE_LIST));
5227 if (!new)
5228 return FALSE;
5230 new->source = strdupW(source);
5231 ptr = strrchrW(dest, '\\') + 1;
5232 filename = strrchrW(new->source, '\\') + 1;
5234 new->sourcename = filename;
5236 if (*ptr)
5237 new->destname = ptr;
5238 else
5239 new->destname = new->sourcename;
5241 size = (ptr - dest) + lstrlenW(filename) + 1;
5242 new->dest = msi_alloc(size * sizeof(WCHAR));
5243 if (!new->dest)
5245 free_file_entry(new);
5246 return FALSE;
5249 lstrcpynW(new->dest, dest, ptr - dest + 1);
5250 lstrcatW(new->dest, filename);
5252 if (list_empty(&files->entry))
5254 list_add_head(&files->entry, &new->entry);
5255 return TRUE;
5258 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5260 if (lstrcmpW(source, file->source) < 0)
5262 list_add_before(&file->entry, &new->entry);
5263 return TRUE;
5267 list_add_after(&file->entry, &new->entry);
5268 return TRUE;
5271 static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
5273 WIN32_FIND_DATAW wfd;
5274 HANDLE hfile;
5275 LPWSTR path;
5276 BOOL res;
5277 FILE_LIST files, *file;
5278 DWORD size;
5280 hfile = FindFirstFileW(source, &wfd);
5281 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5283 list_init(&files.entry);
5285 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5287 if (is_dot_dir(wfd.cFileName)) continue;
5289 path = wildcard_to_file(source, wfd.cFileName);
5290 if (!path)
5292 res = FALSE;
5293 goto done;
5296 add_wildcard(&files, path, dest);
5297 msi_free(path);
5300 /* no files match the wildcard */
5301 if (list_empty(&files.entry))
5302 goto done;
5304 /* only the first wildcard match gets renamed to dest */
5305 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5306 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5307 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5308 if (!file->dest)
5310 res = FALSE;
5311 goto done;
5314 /* file->dest may be shorter after the reallocation, so add a NULL
5315 * terminator. This is needed for the call to strrchrW, as there will no
5316 * longer be a NULL terminator within the bounds of the allocation in this case.
5318 file->dest[size - 1] = '\0';
5319 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5321 while (!list_empty(&files.entry))
5323 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5325 msi_move_file(file->source, file->dest, options);
5327 list_remove(&file->entry);
5328 free_file_entry(file);
5331 res = TRUE;
5333 done:
5334 free_list(&files);
5335 FindClose(hfile);
5336 return res;
5339 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5341 MSIPACKAGE *package = param;
5342 MSICOMPONENT *comp;
5343 LPCWSTR sourcename;
5344 LPWSTR destname = NULL;
5345 LPWSTR sourcedir = NULL, destdir = NULL;
5346 LPWSTR source = NULL, dest = NULL;
5347 int options;
5348 DWORD size;
5349 BOOL ret, wildcards;
5351 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5352 if (!comp || !comp->Enabled ||
5353 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5355 TRACE("Component not set for install, not moving file\n");
5356 return ERROR_SUCCESS;
5359 sourcename = MSI_RecordGetString(rec, 3);
5360 options = MSI_RecordGetInteger(rec, 7);
5362 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5363 if (!sourcedir)
5364 goto done;
5366 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5367 if (!destdir)
5368 goto done;
5370 if (!sourcename)
5372 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5373 goto done;
5375 source = strdupW(sourcedir);
5376 if (!source)
5377 goto done;
5379 else
5381 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5382 source = msi_alloc(size * sizeof(WCHAR));
5383 if (!source)
5384 goto done;
5386 lstrcpyW(source, sourcedir);
5387 if (source[lstrlenW(source) - 1] != '\\')
5388 lstrcatW(source, szBackSlash);
5389 lstrcatW(source, sourcename);
5392 wildcards = strchrW(source, '*') || strchrW(source, '?');
5394 if (MSI_RecordIsNull(rec, 4))
5396 if (!wildcards)
5398 destname = strdupW(sourcename);
5399 if (!destname)
5400 goto done;
5403 else
5405 destname = strdupW(MSI_RecordGetString(rec, 4));
5406 if (destname)
5407 reduce_to_longfilename(destname);
5410 size = 0;
5411 if (destname)
5412 size = lstrlenW(destname);
5414 size += lstrlenW(destdir) + 2;
5415 dest = msi_alloc(size * sizeof(WCHAR));
5416 if (!dest)
5417 goto done;
5419 lstrcpyW(dest, destdir);
5420 if (dest[lstrlenW(dest) - 1] != '\\')
5421 lstrcatW(dest, szBackSlash);
5423 if (destname)
5424 lstrcatW(dest, destname);
5426 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5428 ret = CreateDirectoryW(destdir, NULL);
5429 if (!ret)
5431 WARN("CreateDirectory failed: %d\n", GetLastError());
5432 return ERROR_SUCCESS;
5436 if (!wildcards)
5437 msi_move_file(source, dest, options);
5438 else
5439 move_files_wildcard(source, dest, options);
5441 done:
5442 msi_free(sourcedir);
5443 msi_free(destdir);
5444 msi_free(destname);
5445 msi_free(source);
5446 msi_free(dest);
5448 return ERROR_SUCCESS;
5451 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5453 UINT rc;
5454 MSIQUERY *view;
5456 static const WCHAR ExecSeqQuery[] =
5457 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5458 '`','M','o','v','e','F','i','l','e','`',0};
5460 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5461 if (rc != ERROR_SUCCESS)
5462 return ERROR_SUCCESS;
5464 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5465 msiobj_release(&view->hdr);
5467 return rc;
5470 typedef struct tagMSIASSEMBLY
5472 struct list entry;
5473 MSICOMPONENT *component;
5474 MSIFEATURE *feature;
5475 MSIFILE *file;
5476 LPWSTR manifest;
5477 LPWSTR application;
5478 DWORD attributes;
5479 BOOL installed;
5480 } MSIASSEMBLY;
5482 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
5483 DWORD dwReserved);
5484 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
5485 LPVOID pvReserved, HMODULE *phModDll);
5487 static BOOL init_functionpointers(void)
5489 HRESULT hr;
5490 HMODULE hfusion;
5491 HMODULE hmscoree;
5493 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
5495 hmscoree = LoadLibraryA("mscoree.dll");
5496 if (!hmscoree)
5498 WARN("mscoree.dll not available\n");
5499 return FALSE;
5502 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
5503 if (!pLoadLibraryShim)
5505 WARN("LoadLibraryShim not available\n");
5506 FreeLibrary(hmscoree);
5507 return FALSE;
5510 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
5511 if (FAILED(hr))
5513 WARN("fusion.dll not available\n");
5514 FreeLibrary(hmscoree);
5515 return FALSE;
5518 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
5520 FreeLibrary(hmscoree);
5521 return TRUE;
5524 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
5525 LPWSTR path)
5527 IAssemblyCache *cache;
5528 HRESULT hr;
5529 UINT r = ERROR_FUNCTION_FAILED;
5531 TRACE("installing assembly: %s\n", debugstr_w(path));
5533 if (assembly->feature)
5534 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
5536 if (assembly->manifest)
5537 FIXME("Manifest unhandled\n");
5539 if (assembly->application)
5541 FIXME("Assembly should be privately installed\n");
5542 return ERROR_SUCCESS;
5545 if (assembly->attributes == msidbAssemblyAttributesWin32)
5547 FIXME("Win32 assemblies not handled\n");
5548 return ERROR_SUCCESS;
5551 hr = pCreateAssemblyCache(&cache, 0);
5552 if (FAILED(hr))
5553 goto done;
5555 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
5556 if (FAILED(hr))
5557 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
5559 r = ERROR_SUCCESS;
5561 done:
5562 IAssemblyCache_Release(cache);
5563 return r;
5566 typedef struct tagASSEMBLY_LIST
5568 MSIPACKAGE *package;
5569 IAssemblyCache *cache;
5570 struct list *assemblies;
5571 } ASSEMBLY_LIST;
5573 typedef struct tagASSEMBLY_NAME
5575 LPWSTR name;
5576 LPWSTR version;
5577 LPWSTR culture;
5578 LPWSTR pubkeytoken;
5579 } ASSEMBLY_NAME;
5581 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
5583 ASSEMBLY_NAME *asmname = param;
5584 LPCWSTR name = MSI_RecordGetString(rec, 2);
5585 LPWSTR val = msi_dup_record_field(rec, 3);
5587 static const WCHAR Name[] = {'N','a','m','e',0};
5588 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
5589 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
5590 static const WCHAR PublicKeyToken[] = {
5591 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
5593 if (!strcmpiW(name, Name))
5594 asmname->name = val;
5595 else if (!strcmpiW(name, Version))
5596 asmname->version = val;
5597 else if (!strcmpiW(name, Culture))
5598 asmname->culture = val;
5599 else if (!strcmpiW(name, PublicKeyToken))
5600 asmname->pubkeytoken = val;
5601 else
5602 msi_free(val);
5604 return ERROR_SUCCESS;
5607 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
5609 if (!*str)
5611 *size = lstrlenW(append) + 1;
5612 *str = msi_alloc((*size) * sizeof(WCHAR));
5613 lstrcpyW(*str, append);
5614 return;
5617 (*size) += lstrlenW(append);
5618 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
5619 lstrcatW(*str, append);
5622 static BOOL check_assembly_installed(MSIDATABASE *db, IAssemblyCache *cache,
5623 MSICOMPONENT *comp)
5625 ASSEMBLY_INFO asminfo;
5626 ASSEMBLY_NAME name;
5627 MSIQUERY *view;
5628 LPWSTR disp;
5629 DWORD size;
5630 BOOL found;
5631 UINT r;
5633 static const WCHAR separator[] = {',',' ',0};
5634 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
5635 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
5636 static const WCHAR PublicKeyToken[] = {
5637 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
5638 static const WCHAR query[] = {
5639 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5640 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
5641 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
5642 '=','\'','%','s','\'',0};
5644 disp = NULL;
5645 found = FALSE;
5646 ZeroMemory(&name, sizeof(ASSEMBLY_NAME));
5647 ZeroMemory(&asminfo, sizeof(ASSEMBLY_INFO));
5649 r = MSI_OpenQuery(db, &view, query, comp->Component);
5650 if (r != ERROR_SUCCESS)
5651 return ERROR_SUCCESS;
5653 MSI_IterateRecords(view, NULL, parse_assembly_name, &name);
5654 msiobj_release(&view->hdr);
5656 if (!name.name)
5658 ERR("No assembly name specified!\n");
5659 goto done;
5662 append_str(&disp, &size, name.name);
5664 if (name.version)
5666 append_str(&disp, &size, separator);
5667 append_str(&disp, &size, Version);
5668 append_str(&disp, &size, name.version);
5671 if (name.culture)
5673 append_str(&disp, &size, separator);
5674 append_str(&disp, &size, Culture);
5675 append_str(&disp, &size, name.culture);
5678 if (name.pubkeytoken)
5680 append_str(&disp, &size, separator);
5681 append_str(&disp, &size, PublicKeyToken);
5682 append_str(&disp, &size, name.pubkeytoken);
5685 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
5686 IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE,
5687 disp, &asminfo);
5688 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
5690 done:
5691 msi_free(disp);
5692 msi_free(name.name);
5693 msi_free(name.version);
5694 msi_free(name.culture);
5695 msi_free(name.pubkeytoken);
5697 return found;
5700 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
5702 ASSEMBLY_LIST *list = param;
5703 MSIASSEMBLY *assembly;
5705 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
5706 if (!assembly)
5707 return ERROR_OUTOFMEMORY;
5709 assembly->component = get_loaded_component(list->package, MSI_RecordGetString(rec, 1));
5711 if (!assembly->component || !assembly->component->Enabled ||
5712 !(assembly->component->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5714 TRACE("Component not set for install, not publishing assembly\n");
5715 msi_free(assembly);
5716 return ERROR_SUCCESS;
5719 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
5720 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
5722 if (!assembly->file)
5724 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
5725 return ERROR_FUNCTION_FAILED;
5728 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
5729 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
5730 assembly->attributes = MSI_RecordGetInteger(rec, 5);
5732 if (assembly->application)
5734 WCHAR version[24];
5735 DWORD size = sizeof(version)/sizeof(WCHAR);
5737 /* FIXME: we should probably check the manifest file here */
5739 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
5740 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
5742 assembly->installed = TRUE;
5745 else
5746 assembly->installed = check_assembly_installed(list->package->db,
5747 list->cache,
5748 assembly->component);
5750 list_add_head(list->assemblies, &assembly->entry);
5751 return ERROR_SUCCESS;
5754 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
5756 IAssemblyCache *cache = NULL;
5757 ASSEMBLY_LIST list;
5758 MSIQUERY *view;
5759 HRESULT hr;
5760 UINT r;
5762 static const WCHAR query[] =
5763 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5764 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
5766 r = MSI_DatabaseOpenViewW(package->db, query, &view);
5767 if (r != ERROR_SUCCESS)
5768 return ERROR_SUCCESS;
5770 hr = pCreateAssemblyCache(&cache, 0);
5771 if (FAILED(hr))
5772 return ERROR_FUNCTION_FAILED;
5774 list.package = package;
5775 list.cache = cache;
5776 list.assemblies = assemblies;
5778 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
5779 msiobj_release(&view->hdr);
5781 IAssemblyCache_Release(cache);
5783 return r;
5786 static void free_assemblies(struct list *assemblies)
5788 struct list *item, *cursor;
5790 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
5792 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
5794 list_remove(&assembly->entry);
5795 msi_free(assembly->application);
5796 msi_free(assembly->manifest);
5797 msi_free(assembly);
5801 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
5803 MSIASSEMBLY *assembly;
5805 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
5807 if (!lstrcmpW(assembly->file->File, file))
5809 *out = assembly;
5810 return TRUE;
5814 return FALSE;
5817 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
5818 LPWSTR *path, DWORD *attrs, PVOID user)
5820 MSIASSEMBLY *assembly;
5821 WCHAR temppath[MAX_PATH];
5822 struct list *assemblies = user;
5823 UINT r;
5825 if (!find_assembly(assemblies, file, &assembly))
5826 return FALSE;
5828 GetTempPathW(MAX_PATH, temppath);
5829 PathAddBackslashW(temppath);
5830 lstrcatW(temppath, assembly->file->FileName);
5832 if (action == MSICABEXTRACT_BEGINEXTRACT)
5834 if (assembly->installed)
5835 return FALSE;
5837 *path = strdupW(temppath);
5838 *attrs = assembly->file->Attributes;
5840 else if (action == MSICABEXTRACT_FILEEXTRACTED)
5842 assembly->installed = TRUE;
5844 r = install_assembly(package, assembly, temppath);
5845 if (r != ERROR_SUCCESS)
5846 ERR("Failed to install assembly\n");
5849 return TRUE;
5852 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
5854 UINT r;
5855 struct list assemblies = LIST_INIT(assemblies);
5856 MSIASSEMBLY *assembly;
5857 MSIMEDIAINFO *mi;
5859 if (!init_functionpointers() || !pCreateAssemblyCache)
5860 return ERROR_FUNCTION_FAILED;
5862 r = load_assemblies(package, &assemblies);
5863 if (r != ERROR_SUCCESS)
5864 goto done;
5866 if (list_empty(&assemblies))
5867 goto done;
5869 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
5870 if (!mi)
5872 r = ERROR_OUTOFMEMORY;
5873 goto done;
5876 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
5878 if (assembly->installed && !mi->is_continuous)
5879 continue;
5881 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
5882 (assembly->file->IsCompressed && !mi->is_extracted))
5884 MSICABDATA data;
5886 r = ready_media(package, assembly->file, mi);
5887 if (r != ERROR_SUCCESS)
5889 ERR("Failed to ready media\n");
5890 break;
5893 data.mi = mi;
5894 data.package = package;
5895 data.cb = installassembly_cb;
5896 data.user = &assemblies;
5898 if (assembly->file->IsCompressed &&
5899 !msi_cabextract(package, mi, &data))
5901 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
5902 r = ERROR_FUNCTION_FAILED;
5903 break;
5907 if (!assembly->file->IsCompressed)
5909 LPWSTR source = resolve_file_source(package, assembly->file);
5911 r = install_assembly(package, assembly, source);
5912 if (r != ERROR_SUCCESS)
5913 ERR("Failed to install assembly\n");
5915 msi_free(source);
5918 /* FIXME: write Installer assembly reg values */
5921 done:
5922 free_assemblies(&assemblies);
5923 return r;
5926 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
5927 LPCSTR action, LPCWSTR table )
5929 static const WCHAR query[] = {
5930 'S','E','L','E','C','T',' ','*',' ',
5931 'F','R','O','M',' ','`','%','s','`',0 };
5932 MSIQUERY *view = NULL;
5933 DWORD count = 0;
5934 UINT r;
5936 r = MSI_OpenQuery( package->db, &view, query, table );
5937 if (r == ERROR_SUCCESS)
5939 r = MSI_IterateRecords(view, &count, NULL, package);
5940 msiobj_release(&view->hdr);
5943 if (count)
5944 FIXME("%s -> %u ignored %s table values\n",
5945 action, count, debugstr_w(table));
5947 return ERROR_SUCCESS;
5950 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
5952 TRACE("%p\n", package);
5953 return ERROR_SUCCESS;
5956 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
5958 static const WCHAR table[] =
5959 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
5960 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
5963 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
5965 static const WCHAR table[] = { 'P','a','t','c','h',0 };
5966 return msi_unimplemented_action_stub( package, "PatchFiles", table );
5969 static UINT ACTION_BindImage( MSIPACKAGE *package )
5971 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
5972 return msi_unimplemented_action_stub( package, "BindImage", table );
5975 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
5977 static const WCHAR table[] = {
5978 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
5979 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
5982 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
5984 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5985 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
5988 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
5990 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
5991 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
5994 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5996 static const WCHAR table[] = {
5997 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5998 return msi_unimplemented_action_stub( package, "DeleteServices", table );
6000 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6002 static const WCHAR table[] = {
6003 'P','r','o','d','u','c','t','I','D',0 };
6004 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
6007 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6009 static const WCHAR table[] = {
6010 'E','n','v','i','r','o','n','m','e','n','t',0 };
6011 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
6014 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6016 static const WCHAR table[] = {
6017 'M','s','i','A','s','s','e','m','b','l','y',0 };
6018 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6021 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
6023 static const WCHAR table[] = { 'F','o','n','t',0 };
6024 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
6027 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6029 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6030 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6033 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6035 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6036 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6039 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6041 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6042 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6045 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6047 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6048 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6051 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
6053 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6054 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
6057 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6059 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6060 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6063 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
6065 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6066 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
6069 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6071 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6072 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
6075 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
6077 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6078 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
6081 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
6083 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
6084 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
6087 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
6089 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6090 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
6093 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6095 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6096 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6099 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6101 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6102 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6105 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6107 static const WCHAR table[] = { 'M','I','M','E',0 };
6108 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6111 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6113 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6114 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6117 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
6119 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
6120 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
6123 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6125 static const struct
6127 const WCHAR *action;
6128 UINT (*handler)(MSIPACKAGE *);
6130 StandardActions[] =
6132 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6133 { szAppSearch, ACTION_AppSearch },
6134 { szBindImage, ACTION_BindImage },
6135 { szCCPSearch, ACTION_CCPSearch },
6136 { szCostFinalize, ACTION_CostFinalize },
6137 { szCostInitialize, ACTION_CostInitialize },
6138 { szCreateFolders, ACTION_CreateFolders },
6139 { szCreateShortcuts, ACTION_CreateShortcuts },
6140 { szDeleteServices, ACTION_DeleteServices },
6141 { szDisableRollback, NULL },
6142 { szDuplicateFiles, ACTION_DuplicateFiles },
6143 { szExecuteAction, ACTION_ExecuteAction },
6144 { szFileCost, ACTION_FileCost },
6145 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6146 { szForceReboot, ACTION_ForceReboot },
6147 { szInstallAdminPackage, NULL },
6148 { szInstallExecute, ACTION_InstallExecute },
6149 { szInstallExecuteAgain, ACTION_InstallExecute },
6150 { szInstallFiles, ACTION_InstallFiles},
6151 { szInstallFinalize, ACTION_InstallFinalize },
6152 { szInstallInitialize, ACTION_InstallInitialize },
6153 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6154 { szInstallValidate, ACTION_InstallValidate },
6155 { szIsolateComponents, ACTION_IsolateComponents },
6156 { szLaunchConditions, ACTION_LaunchConditions },
6157 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6158 { szMoveFiles, ACTION_MoveFiles },
6159 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6160 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6161 { szInstallODBC, ACTION_InstallODBC },
6162 { szInstallServices, ACTION_InstallServices },
6163 { szPatchFiles, ACTION_PatchFiles },
6164 { szProcessComponents, ACTION_ProcessComponents },
6165 { szPublishComponents, ACTION_PublishComponents },
6166 { szPublishFeatures, ACTION_PublishFeatures },
6167 { szPublishProduct, ACTION_PublishProduct },
6168 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6169 { szRegisterComPlus, ACTION_RegisterComPlus},
6170 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6171 { szRegisterFonts, ACTION_RegisterFonts },
6172 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6173 { szRegisterProduct, ACTION_RegisterProduct },
6174 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6175 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6176 { szRegisterUser, ACTION_RegisterUser },
6177 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6178 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6179 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6180 { szRemoveFiles, ACTION_RemoveFiles },
6181 { szRemoveFolders, ACTION_RemoveFolders },
6182 { szRemoveIniValues, ACTION_RemoveIniValues },
6183 { szRemoveODBC, ACTION_RemoveODBC },
6184 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6185 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6186 { szResolveSource, ACTION_ResolveSource },
6187 { szRMCCPSearch, ACTION_RMCCPSearch },
6188 { szScheduleReboot, NULL },
6189 { szSelfRegModules, ACTION_SelfRegModules },
6190 { szSelfUnregModules, ACTION_SelfUnregModules },
6191 { szSetODBCFolders, NULL },
6192 { szStartServices, ACTION_StartServices },
6193 { szStopServices, ACTION_StopServices },
6194 { szUnpublishComponents, ACTION_UnpublishComponents },
6195 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6196 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6197 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6198 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6199 { szUnregisterFonts, ACTION_UnregisterFonts },
6200 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6201 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6202 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6203 { szValidateProductID, ACTION_ValidateProductID },
6204 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6205 { szWriteIniValues, ACTION_WriteIniValues },
6206 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6207 { NULL, NULL },
6210 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
6211 UINT* rc, BOOL force )
6213 BOOL ret = FALSE;
6214 BOOL run = force;
6215 int i;
6217 if (!run && !package->script->CurrentlyScripting)
6218 run = TRUE;
6220 if (!run)
6222 if (strcmpW(action,szInstallFinalize) == 0 ||
6223 strcmpW(action,szInstallExecute) == 0 ||
6224 strcmpW(action,szInstallExecuteAgain) == 0)
6225 run = TRUE;
6228 i = 0;
6229 while (StandardActions[i].action != NULL)
6231 if (strcmpW(StandardActions[i].action, action)==0)
6233 if (!run)
6235 ui_actioninfo(package, action, TRUE, 0);
6236 *rc = schedule_action(package,INSTALL_SCRIPT,action);
6237 ui_actioninfo(package, action, FALSE, *rc);
6239 else
6241 ui_actionstart(package, action);
6242 if (StandardActions[i].handler)
6244 *rc = StandardActions[i].handler(package);
6246 else
6248 FIXME("unhandled standard action %s\n",debugstr_w(action));
6249 *rc = ERROR_SUCCESS;
6252 ret = TRUE;
6253 break;
6255 i++;
6257 return ret;
6260 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
6262 UINT rc = ERROR_SUCCESS;
6263 BOOL handled;
6265 TRACE("Performing action (%s)\n", debugstr_w(action));
6267 handled = ACTION_HandleStandardAction(package, action, &rc, force);
6269 if (!handled)
6270 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
6272 if (!handled)
6274 WARN("unhandled msi action %s\n", debugstr_w(action));
6275 rc = ERROR_FUNCTION_NOT_CALLED;
6278 return rc;
6281 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
6283 UINT rc = ERROR_SUCCESS;
6284 BOOL handled = FALSE;
6286 TRACE("Performing action (%s)\n", debugstr_w(action));
6288 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
6290 if (!handled)
6291 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
6293 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
6294 handled = TRUE;
6296 if (!handled)
6298 WARN("unhandled msi action %s\n", debugstr_w(action));
6299 rc = ERROR_FUNCTION_NOT_CALLED;
6302 return rc;
6305 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
6307 UINT rc = ERROR_SUCCESS;
6308 MSIRECORD *row;
6310 static const WCHAR ExecSeqQuery[] =
6311 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6312 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
6313 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
6314 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
6315 static const WCHAR UISeqQuery[] =
6316 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6317 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
6318 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
6319 ' ', '=',' ','%','i',0};
6321 if (needs_ui_sequence(package))
6322 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
6323 else
6324 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
6326 if (row)
6328 LPCWSTR action, cond;
6330 TRACE("Running the actions\n");
6332 /* check conditions */
6333 cond = MSI_RecordGetString(row, 2);
6335 /* this is a hack to skip errors in the condition code */
6336 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
6338 msiobj_release(&row->hdr);
6339 return ERROR_SUCCESS;
6342 action = MSI_RecordGetString(row, 1);
6343 if (!action)
6345 ERR("failed to fetch action\n");
6346 msiobj_release(&row->hdr);
6347 return ERROR_FUNCTION_FAILED;
6350 if (needs_ui_sequence(package))
6351 rc = ACTION_PerformUIAction(package, action, -1);
6352 else
6353 rc = ACTION_PerformAction(package, action, -1, FALSE);
6355 msiobj_release(&row->hdr);
6358 return rc;
6361 /****************************************************
6362 * TOP level entry points
6363 *****************************************************/
6365 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
6366 LPCWSTR szCommandLine )
6368 UINT rc;
6369 BOOL ui_exists;
6371 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
6372 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
6374 MSI_SetPropertyW(package, szAction, szInstall);
6376 package->script->InWhatSequence = SEQUENCE_INSTALL;
6378 if (szPackagePath)
6380 LPWSTR p, dir;
6381 LPCWSTR file;
6383 dir = strdupW(szPackagePath);
6384 p = strrchrW(dir, '\\');
6385 if (p)
6387 *(++p) = 0;
6388 file = szPackagePath + (p - dir);
6390 else
6392 msi_free(dir);
6393 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
6394 GetCurrentDirectoryW(MAX_PATH, dir);
6395 lstrcatW(dir, szBackSlash);
6396 file = szPackagePath;
6399 msi_free( package->PackagePath );
6400 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
6401 if (!package->PackagePath)
6403 msi_free(dir);
6404 return ERROR_OUTOFMEMORY;
6407 lstrcpyW(package->PackagePath, dir);
6408 lstrcatW(package->PackagePath, file);
6409 msi_free(dir);
6411 msi_set_sourcedir_props(package, FALSE);
6414 msi_parse_command_line( package, szCommandLine, FALSE );
6416 msi_apply_transforms( package );
6417 msi_apply_patches( package );
6419 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
6421 TRACE("setting reinstall property\n");
6422 MSI_SetPropertyW( package, szReinstall, szAll );
6425 /* properties may have been added by a transform */
6426 msi_clone_properties( package );
6427 msi_set_context( package );
6429 if (needs_ui_sequence( package))
6431 package->script->InWhatSequence |= SEQUENCE_UI;
6432 rc = ACTION_ProcessUISequence(package);
6433 ui_exists = ui_sequence_exists(package);
6434 if (rc == ERROR_SUCCESS || !ui_exists)
6436 package->script->InWhatSequence |= SEQUENCE_EXEC;
6437 rc = ACTION_ProcessExecSequence(package, ui_exists);
6440 else
6441 rc = ACTION_ProcessExecSequence(package, FALSE);
6443 package->script->CurrentlyScripting = FALSE;
6445 /* process the ending type action */
6446 if (rc == ERROR_SUCCESS)
6447 ACTION_PerformActionSequence(package, -1);
6448 else if (rc == ERROR_INSTALL_USEREXIT)
6449 ACTION_PerformActionSequence(package, -2);
6450 else if (rc == ERROR_INSTALL_SUSPEND)
6451 ACTION_PerformActionSequence(package, -4);
6452 else /* failed */
6453 ACTION_PerformActionSequence(package, -3);
6455 /* finish up running custom actions */
6456 ACTION_FinishCustomActions(package);
6458 if (rc == ERROR_SUCCESS && package->need_reboot)
6459 return ERROR_SUCCESS_REBOOT_REQUIRED;
6461 return rc;