push 5b1efc32b5a8acb1d5b5e60584746392dd0c436e
[wine/hacks.git] / dlls / msi / action.c
blobef30dda2e0d56ea7268a7badbd88a515f89574ff
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 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1566 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1568 msi_feature_set_state(package, feature, state);
1569 break;
1571 if (ptr2)
1573 ptr=ptr2+1;
1574 ptr2 = strchrW(ptr,',');
1576 else
1577 break;
1581 msi_free(override);
1583 return TRUE;
1586 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1588 int level;
1589 static const WCHAR szlevel[] =
1590 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1591 static const WCHAR szAddLocal[] =
1592 {'A','D','D','L','O','C','A','L',0};
1593 static const WCHAR szAddSource[] =
1594 {'A','D','D','S','O','U','R','C','E',0};
1595 static const WCHAR szAdvertise[] =
1596 {'A','D','V','E','R','T','I','S','E',0};
1597 BOOL override = FALSE;
1598 MSICOMPONENT* component;
1599 MSIFEATURE *feature;
1602 /* I do not know if this is where it should happen.. but */
1604 TRACE("Checking Install Level\n");
1606 level = msi_get_property_int(package, szlevel, 1);
1608 /* ok here is the _real_ rub
1609 * all these activation/deactivation things happen in order and things
1610 * later on the list override things earlier on the list.
1611 * 0) INSTALLLEVEL processing
1612 * 1) ADDLOCAL
1613 * 2) REMOVE
1614 * 3) ADDSOURCE
1615 * 4) ADDDEFAULT
1616 * 5) REINSTALL
1617 * 6) ADVERTISE
1618 * 7) COMPADDLOCAL
1619 * 8) COMPADDSOURCE
1620 * 9) FILEADDLOCAL
1621 * 10) FILEADDSOURCE
1622 * 11) FILEADDDEFAULT
1624 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1625 * REMOVE are the big ones, since we don't handle administrative installs
1626 * yet anyway.
1628 override |= process_state_property(package, level, szAddLocal, INSTALLSTATE_LOCAL);
1629 override |= process_state_property(package, level, szRemove, INSTALLSTATE_ABSENT);
1630 override |= process_state_property(package, level, szAddSource, INSTALLSTATE_SOURCE);
1631 override |= process_state_property(package, level, szReinstall, INSTALLSTATE_UNKNOWN);
1632 override |= process_state_property(package, level, szAdvertise, INSTALLSTATE_ADVERTISED);
1634 if (!override)
1636 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1638 BOOL feature_state = ((feature->Level > 0) &&
1639 (feature->Level <= level));
1641 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1643 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1644 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1645 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1646 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1647 else
1648 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1652 /* disable child features of unselected parent features */
1653 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1655 FeatureList *fl;
1657 if (feature->Level > 0 && feature->Level <= level)
1658 continue;
1660 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1661 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1664 else
1665 MSI_SetPropertyW(package, szPreselected, szOne);
1668 * now we want to enable or disable components base on feature
1671 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1673 ComponentList *cl;
1675 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1676 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1678 if (!feature->Level)
1679 continue;
1681 /* features with components that have compressed files are made local */
1682 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1684 if (cl->component->Enabled &&
1685 cl->component->ForceLocalState &&
1686 feature->Action == INSTALLSTATE_SOURCE)
1688 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1689 break;
1693 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1695 component = cl->component;
1697 if (!component->Enabled)
1698 continue;
1700 switch (feature->Action)
1702 case INSTALLSTATE_ABSENT:
1703 component->anyAbsent = 1;
1704 break;
1705 case INSTALLSTATE_ADVERTISED:
1706 component->hasAdvertiseFeature = 1;
1707 break;
1708 case INSTALLSTATE_SOURCE:
1709 component->hasSourceFeature = 1;
1710 break;
1711 case INSTALLSTATE_LOCAL:
1712 component->hasLocalFeature = 1;
1713 break;
1714 case INSTALLSTATE_DEFAULT:
1715 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1716 component->hasAdvertiseFeature = 1;
1717 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1718 component->hasSourceFeature = 1;
1719 else
1720 component->hasLocalFeature = 1;
1721 break;
1722 default:
1723 break;
1728 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1730 /* if the component isn't enabled, leave it alone */
1731 if (!component->Enabled)
1732 continue;
1734 /* check if it's local or source */
1735 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1736 (component->hasLocalFeature || component->hasSourceFeature))
1738 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1739 !component->ForceLocalState)
1740 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1741 else
1742 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1743 continue;
1746 /* if any feature is local, the component must be local too */
1747 if (component->hasLocalFeature)
1749 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1750 continue;
1753 if (component->hasSourceFeature)
1755 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1756 continue;
1759 if (component->hasAdvertiseFeature)
1761 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1762 continue;
1765 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1766 if (component->anyAbsent)
1767 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1770 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1772 if (component->Action == INSTALLSTATE_DEFAULT)
1774 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1775 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1778 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1779 debugstr_w(component->Component), component->Installed, component->Action);
1783 return ERROR_SUCCESS;
1786 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1788 MSIPACKAGE *package = param;
1789 LPCWSTR name;
1790 LPWSTR path;
1791 MSIFOLDER *f;
1793 name = MSI_RecordGetString(row,1);
1795 f = get_loaded_folder(package, name);
1796 if (!f) return ERROR_SUCCESS;
1798 /* reset the ResolvedTarget */
1799 msi_free(f->ResolvedTarget);
1800 f->ResolvedTarget = NULL;
1802 /* This helper function now does ALL the work */
1803 TRACE("Dir %s ...\n",debugstr_w(name));
1804 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1805 TRACE("resolves to %s\n",debugstr_w(path));
1806 msi_free(path);
1808 return ERROR_SUCCESS;
1811 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1813 MSIPACKAGE *package = param;
1814 LPCWSTR name;
1815 MSIFEATURE *feature;
1817 name = MSI_RecordGetString( row, 1 );
1819 feature = get_loaded_feature( package, name );
1820 if (!feature)
1821 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1822 else
1824 LPCWSTR Condition;
1825 Condition = MSI_RecordGetString(row,3);
1827 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1829 int level = MSI_RecordGetInteger(row,2);
1830 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1831 feature->Level = level;
1834 return ERROR_SUCCESS;
1837 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1839 static const WCHAR name_fmt[] =
1840 {'%','u','.','%','u','.','%','u','.','%','u',0};
1841 static const WCHAR name[] = {'\\',0};
1842 VS_FIXEDFILEINFO *lpVer;
1843 WCHAR filever[0x100];
1844 LPVOID version;
1845 DWORD versize;
1846 DWORD handle;
1847 UINT sz;
1849 TRACE("%s\n", debugstr_w(filename));
1851 versize = GetFileVersionInfoSizeW( filename, &handle );
1852 if (!versize)
1853 return NULL;
1855 version = msi_alloc( versize );
1856 GetFileVersionInfoW( filename, 0, versize, version );
1858 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1860 msi_free( version );
1861 return NULL;
1864 sprintfW( filever, name_fmt,
1865 HIWORD(lpVer->dwFileVersionMS),
1866 LOWORD(lpVer->dwFileVersionMS),
1867 HIWORD(lpVer->dwFileVersionLS),
1868 LOWORD(lpVer->dwFileVersionLS));
1870 msi_free( version );
1872 return strdupW( filever );
1875 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1877 LPWSTR file_version;
1878 MSIFILE *file;
1880 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1882 MSICOMPONENT* comp = file->Component;
1883 LPWSTR p;
1885 if (!comp)
1886 continue;
1888 if (file->IsCompressed)
1889 comp->ForceLocalState = TRUE;
1891 /* calculate target */
1892 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1894 msi_free(file->TargetPath);
1896 TRACE("file %s is named %s\n",
1897 debugstr_w(file->File), debugstr_w(file->FileName));
1899 file->TargetPath = build_directory_name(2, p, file->FileName);
1901 msi_free(p);
1903 TRACE("file %s resolves to %s\n",
1904 debugstr_w(file->File), debugstr_w(file->TargetPath));
1906 /* don't check files of components that aren't installed */
1907 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1908 comp->Installed == INSTALLSTATE_ABSENT)
1910 file->state = msifs_missing; /* assume files are missing */
1911 continue;
1914 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1916 file->state = msifs_missing;
1917 comp->Cost += file->FileSize;
1918 continue;
1921 if (file->Version &&
1922 (file_version = msi_get_disk_file_version( file->TargetPath )))
1924 TRACE("new %s old %s\n", debugstr_w(file->Version),
1925 debugstr_w(file_version));
1926 /* FIXME: seems like a bad way to compare version numbers */
1927 if (lstrcmpiW(file_version, file->Version)<0)
1929 file->state = msifs_overwrite;
1930 comp->Cost += file->FileSize;
1932 else
1933 file->state = msifs_present;
1934 msi_free( file_version );
1936 else
1937 file->state = msifs_present;
1940 return ERROR_SUCCESS;
1944 * A lot is done in this function aside from just the costing.
1945 * The costing needs to be implemented at some point but for now I am going
1946 * to focus on the directory building
1949 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1951 static const WCHAR ExecSeqQuery[] =
1952 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1953 '`','D','i','r','e','c','t','o','r','y','`',0};
1954 static const WCHAR ConditionQuery[] =
1955 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1956 '`','C','o','n','d','i','t','i','o','n','`',0};
1957 static const WCHAR szCosting[] =
1958 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1959 static const WCHAR szlevel[] =
1960 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1961 static const WCHAR szOutOfDiskSpace[] =
1962 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
1963 MSICOMPONENT *comp;
1964 UINT rc;
1965 MSIQUERY * view;
1966 LPWSTR level;
1968 TRACE("Building Directory properties\n");
1970 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1971 if (rc == ERROR_SUCCESS)
1973 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1974 package);
1975 msiobj_release(&view->hdr);
1978 /* read components states from the registry */
1979 ACTION_GetComponentInstallStates(package);
1980 ACTION_GetFeatureInstallStates(package);
1982 TRACE("File calculations\n");
1983 msi_check_file_install_states( package );
1985 TRACE("Evaluating Condition Table\n");
1987 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1988 if (rc == ERROR_SUCCESS)
1990 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1991 package);
1992 msiobj_release(&view->hdr);
1995 TRACE("Enabling or Disabling Components\n");
1996 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1998 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2000 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2001 comp->Enabled = FALSE;
2003 else
2004 comp->Enabled = TRUE;
2007 MSI_SetPropertyW(package,szCosting,szOne);
2008 /* set default run level if not set */
2009 level = msi_dup_property( package, szlevel );
2010 if (!level)
2011 MSI_SetPropertyW(package,szlevel, szOne);
2012 msi_free(level);
2014 /* FIXME: check volume disk space */
2015 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2017 return MSI_SetFeatureStates(package);
2020 /* OK this value is "interpreted" and then formatted based on the
2021 first few characters */
2022 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2023 DWORD *size)
2025 LPSTR data = NULL;
2027 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2029 if (value[1]=='x')
2031 LPWSTR ptr;
2032 CHAR byte[5];
2033 LPWSTR deformated = NULL;
2034 int count;
2036 deformat_string(package, &value[2], &deformated);
2038 /* binary value type */
2039 ptr = deformated;
2040 *type = REG_BINARY;
2041 if (strlenW(ptr)%2)
2042 *size = (strlenW(ptr)/2)+1;
2043 else
2044 *size = strlenW(ptr)/2;
2046 data = msi_alloc(*size);
2048 byte[0] = '0';
2049 byte[1] = 'x';
2050 byte[4] = 0;
2051 count = 0;
2052 /* if uneven pad with a zero in front */
2053 if (strlenW(ptr)%2)
2055 byte[2]= '0';
2056 byte[3]= *ptr;
2057 ptr++;
2058 data[count] = (BYTE)strtol(byte,NULL,0);
2059 count ++;
2060 TRACE("Uneven byte count\n");
2062 while (*ptr)
2064 byte[2]= *ptr;
2065 ptr++;
2066 byte[3]= *ptr;
2067 ptr++;
2068 data[count] = (BYTE)strtol(byte,NULL,0);
2069 count ++;
2071 msi_free(deformated);
2073 TRACE("Data %i bytes(%i)\n",*size,count);
2075 else
2077 LPWSTR deformated;
2078 LPWSTR p;
2079 DWORD d = 0;
2080 deformat_string(package, &value[1], &deformated);
2082 *type=REG_DWORD;
2083 *size = sizeof(DWORD);
2084 data = msi_alloc(*size);
2085 p = deformated;
2086 if (*p == '-')
2087 p++;
2088 while (*p)
2090 if ( (*p < '0') || (*p > '9') )
2091 break;
2092 d *= 10;
2093 d += (*p - '0');
2094 p++;
2096 if (deformated[0] == '-')
2097 d = -d;
2098 *(LPDWORD)data = d;
2099 TRACE("DWORD %i\n",*(LPDWORD)data);
2101 msi_free(deformated);
2104 else
2106 static const WCHAR szMulti[] = {'[','~',']',0};
2107 LPCWSTR ptr;
2108 *type=REG_SZ;
2110 if (value[0]=='#')
2112 if (value[1]=='%')
2114 ptr = &value[2];
2115 *type=REG_EXPAND_SZ;
2117 else
2118 ptr = &value[1];
2120 else
2121 ptr=value;
2123 if (strstrW(value,szMulti))
2124 *type = REG_MULTI_SZ;
2126 /* remove initial delimiter */
2127 if (!strncmpW(value, szMulti, 3))
2128 ptr = value + 3;
2130 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2132 /* add double NULL terminator */
2133 if (*type == REG_MULTI_SZ)
2135 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2136 data = msi_realloc_zero(data, *size);
2139 return data;
2142 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2144 MSIPACKAGE *package = param;
2145 static const WCHAR szHCR[] =
2146 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2147 'R','O','O','T','\\',0};
2148 static const WCHAR szHCU[] =
2149 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2150 'U','S','E','R','\\',0};
2151 static const WCHAR szHLM[] =
2152 {'H','K','E','Y','_','L','O','C','A','L','_',
2153 'M','A','C','H','I','N','E','\\',0};
2154 static const WCHAR szHU[] =
2155 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2157 LPSTR value_data = NULL;
2158 HKEY root_key, hkey;
2159 DWORD type,size;
2160 LPWSTR deformated;
2161 LPCWSTR szRoot, component, name, key, value;
2162 MSICOMPONENT *comp;
2163 MSIRECORD * uirow;
2164 LPWSTR uikey;
2165 INT root;
2166 BOOL check_first = FALSE;
2167 UINT rc;
2169 ui_progress(package,2,0,0,0);
2171 value = NULL;
2172 key = NULL;
2173 uikey = NULL;
2174 name = NULL;
2176 component = MSI_RecordGetString(row, 6);
2177 comp = get_loaded_component(package,component);
2178 if (!comp)
2179 return ERROR_SUCCESS;
2181 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2183 TRACE("Skipping write due to disabled component %s\n",
2184 debugstr_w(component));
2186 comp->Action = comp->Installed;
2188 return ERROR_SUCCESS;
2191 comp->Action = INSTALLSTATE_LOCAL;
2193 name = MSI_RecordGetString(row, 4);
2194 if( MSI_RecordIsNull(row,5) && name )
2196 /* null values can have special meanings */
2197 if (name[0]=='-' && name[1] == 0)
2198 return ERROR_SUCCESS;
2199 else if ((name[0]=='+' && name[1] == 0) ||
2200 (name[0] == '*' && name[1] == 0))
2201 name = NULL;
2202 check_first = TRUE;
2205 root = MSI_RecordGetInteger(row,2);
2206 key = MSI_RecordGetString(row, 3);
2208 /* get the root key */
2209 switch (root)
2211 case -1:
2213 LPWSTR all_users = msi_dup_property( package, szAllUsers );
2214 if (all_users && all_users[0] == '1')
2216 root_key = HKEY_LOCAL_MACHINE;
2217 szRoot = szHLM;
2219 else
2221 root_key = HKEY_CURRENT_USER;
2222 szRoot = szHCU;
2224 msi_free(all_users);
2226 break;
2227 case 0: root_key = HKEY_CLASSES_ROOT;
2228 szRoot = szHCR;
2229 break;
2230 case 1: root_key = HKEY_CURRENT_USER;
2231 szRoot = szHCU;
2232 break;
2233 case 2: root_key = HKEY_LOCAL_MACHINE;
2234 szRoot = szHLM;
2235 break;
2236 case 3: root_key = HKEY_USERS;
2237 szRoot = szHU;
2238 break;
2239 default:
2240 ERR("Unknown root %i\n",root);
2241 root_key=NULL;
2242 szRoot = NULL;
2243 break;
2245 if (!root_key)
2246 return ERROR_SUCCESS;
2248 deformat_string(package, key , &deformated);
2249 size = strlenW(deformated) + strlenW(szRoot) + 1;
2250 uikey = msi_alloc(size*sizeof(WCHAR));
2251 strcpyW(uikey,szRoot);
2252 strcatW(uikey,deformated);
2254 if (RegCreateKeyW( root_key, deformated, &hkey))
2256 ERR("Could not create key %s\n",debugstr_w(deformated));
2257 msi_free(deformated);
2258 msi_free(uikey);
2259 return ERROR_SUCCESS;
2261 msi_free(deformated);
2263 value = MSI_RecordGetString(row,5);
2264 if (value)
2265 value_data = parse_value(package, value, &type, &size);
2266 else
2268 value_data = (LPSTR)strdupW(szEmpty);
2269 size = sizeof(szEmpty);
2270 type = REG_SZ;
2273 deformat_string(package, name, &deformated);
2275 if (!check_first)
2277 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2278 debugstr_w(uikey));
2279 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2281 else
2283 DWORD sz = 0;
2284 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2285 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2287 TRACE("value %s of %s checked already exists\n",
2288 debugstr_w(deformated), debugstr_w(uikey));
2290 else
2292 TRACE("Checked and setting value %s of %s\n",
2293 debugstr_w(deformated), debugstr_w(uikey));
2294 if (deformated || size)
2295 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2298 RegCloseKey(hkey);
2300 uirow = MSI_CreateRecord(3);
2301 MSI_RecordSetStringW(uirow,2,deformated);
2302 MSI_RecordSetStringW(uirow,1,uikey);
2304 if (type == REG_SZ)
2305 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2306 else
2307 MSI_RecordSetStringW(uirow,3,value);
2309 ui_actiondata(package,szWriteRegistryValues,uirow);
2310 msiobj_release( &uirow->hdr );
2312 msi_free(value_data);
2313 msi_free(deformated);
2314 msi_free(uikey);
2316 return ERROR_SUCCESS;
2319 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2321 UINT rc;
2322 MSIQUERY * view;
2323 static const WCHAR ExecSeqQuery[] =
2324 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2325 '`','R','e','g','i','s','t','r','y','`',0 };
2327 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2328 if (rc != ERROR_SUCCESS)
2329 return ERROR_SUCCESS;
2331 /* increment progress bar each time action data is sent */
2332 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2334 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2336 msiobj_release(&view->hdr);
2337 return rc;
2340 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2342 package->script->CurrentlyScripting = TRUE;
2344 return ERROR_SUCCESS;
2348 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2350 MSICOMPONENT *comp;
2351 DWORD progress = 0;
2352 DWORD total = 0;
2353 static const WCHAR q1[]=
2354 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2355 '`','R','e','g','i','s','t','r','y','`',0};
2356 UINT rc;
2357 MSIQUERY * view;
2358 MSIFEATURE *feature;
2359 MSIFILE *file;
2361 TRACE("InstallValidate\n");
2363 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2364 if (rc == ERROR_SUCCESS)
2366 MSI_IterateRecords( view, &progress, NULL, package );
2367 msiobj_release( &view->hdr );
2368 total += progress * REG_PROGRESS_VALUE;
2371 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2372 total += COMPONENT_PROGRESS_VALUE;
2374 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2375 total += file->FileSize;
2377 ui_progress(package,0,total,0,0);
2379 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2381 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2382 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2383 feature->ActionRequest);
2386 return ERROR_SUCCESS;
2389 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2391 MSIPACKAGE* package = param;
2392 LPCWSTR cond = NULL;
2393 LPCWSTR message = NULL;
2394 UINT r;
2396 static const WCHAR title[]=
2397 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2399 cond = MSI_RecordGetString(row,1);
2401 r = MSI_EvaluateConditionW(package,cond);
2402 if (r == MSICONDITION_FALSE)
2404 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2406 LPWSTR deformated;
2407 message = MSI_RecordGetString(row,2);
2408 deformat_string(package,message,&deformated);
2409 MessageBoxW(NULL,deformated,title,MB_OK);
2410 msi_free(deformated);
2413 return ERROR_INSTALL_FAILURE;
2416 return ERROR_SUCCESS;
2419 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2421 UINT rc;
2422 MSIQUERY * view = NULL;
2423 static const WCHAR ExecSeqQuery[] =
2424 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2425 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2427 TRACE("Checking launch conditions\n");
2429 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2430 if (rc != ERROR_SUCCESS)
2431 return ERROR_SUCCESS;
2433 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2434 msiobj_release(&view->hdr);
2436 return rc;
2439 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2442 if (!cmp->KeyPath)
2443 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2445 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2447 MSIRECORD * row = 0;
2448 UINT root,len;
2449 LPWSTR deformated,buffer,deformated_name;
2450 LPCWSTR key,name;
2451 static const WCHAR ExecSeqQuery[] =
2452 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2453 '`','R','e','g','i','s','t','r','y','`',' ',
2454 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2455 ' ','=',' ' ,'\'','%','s','\'',0 };
2456 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2457 static const WCHAR fmt2[]=
2458 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2460 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2461 if (!row)
2462 return NULL;
2464 root = MSI_RecordGetInteger(row,2);
2465 key = MSI_RecordGetString(row, 3);
2466 name = MSI_RecordGetString(row, 4);
2467 deformat_string(package, key , &deformated);
2468 deformat_string(package, name, &deformated_name);
2470 len = strlenW(deformated) + 6;
2471 if (deformated_name)
2472 len+=strlenW(deformated_name);
2474 buffer = msi_alloc( len *sizeof(WCHAR));
2476 if (deformated_name)
2477 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2478 else
2479 sprintfW(buffer,fmt,root,deformated);
2481 msi_free(deformated);
2482 msi_free(deformated_name);
2483 msiobj_release(&row->hdr);
2485 return buffer;
2487 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2489 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2490 return NULL;
2492 else
2494 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2496 if (file)
2497 return strdupW( file->TargetPath );
2499 return NULL;
2502 static HKEY openSharedDLLsKey(void)
2504 HKEY hkey=0;
2505 static const WCHAR path[] =
2506 {'S','o','f','t','w','a','r','e','\\',
2507 'M','i','c','r','o','s','o','f','t','\\',
2508 'W','i','n','d','o','w','s','\\',
2509 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2510 'S','h','a','r','e','d','D','L','L','s',0};
2512 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2513 return hkey;
2516 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2518 HKEY hkey;
2519 DWORD count=0;
2520 DWORD type;
2521 DWORD sz = sizeof(count);
2522 DWORD rc;
2524 hkey = openSharedDLLsKey();
2525 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2526 if (rc != ERROR_SUCCESS)
2527 count = 0;
2528 RegCloseKey(hkey);
2529 return count;
2532 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2534 HKEY hkey;
2536 hkey = openSharedDLLsKey();
2537 if (count > 0)
2538 msi_reg_set_val_dword( hkey, path, count );
2539 else
2540 RegDeleteValueW(hkey,path);
2541 RegCloseKey(hkey);
2542 return count;
2546 * Return TRUE if the count should be written out and FALSE if not
2548 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2550 MSIFEATURE *feature;
2551 INT count = 0;
2552 BOOL write = FALSE;
2554 /* only refcount DLLs */
2555 if (comp->KeyPath == NULL ||
2556 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2557 comp->Attributes & msidbComponentAttributesODBCDataSource)
2558 write = FALSE;
2559 else
2561 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2562 write = (count > 0);
2564 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2565 write = TRUE;
2568 /* increment counts */
2569 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2571 ComponentList *cl;
2573 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2574 continue;
2576 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2578 if ( cl->component == comp )
2579 count++;
2583 /* decrement counts */
2584 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2586 ComponentList *cl;
2588 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2589 continue;
2591 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2593 if ( cl->component == comp )
2594 count--;
2598 /* ref count all the files in the component */
2599 if (write)
2601 MSIFILE *file;
2603 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2605 if (file->Component == comp)
2606 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2610 /* add a count for permanent */
2611 if (comp->Attributes & msidbComponentAttributesPermanent)
2612 count ++;
2614 comp->RefCount = count;
2616 if (write)
2617 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2620 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2622 WCHAR squished_pc[GUID_SIZE];
2623 WCHAR squished_cc[GUID_SIZE];
2624 UINT rc;
2625 MSICOMPONENT *comp;
2626 HKEY hkey;
2628 TRACE("\n");
2630 squash_guid(package->ProductCode,squished_pc);
2631 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2633 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2635 MSIRECORD * uirow;
2637 ui_progress(package,2,0,0,0);
2638 if (!comp->ComponentId)
2639 continue;
2641 squash_guid(comp->ComponentId,squished_cc);
2643 msi_free(comp->FullKeypath);
2644 comp->FullKeypath = resolve_keypath( package, comp );
2646 ACTION_RefCountComponent( package, comp );
2648 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2649 debugstr_w(comp->Component),
2650 debugstr_w(squished_cc),
2651 debugstr_w(comp->FullKeypath),
2652 comp->RefCount);
2654 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL) ||
2655 ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE))
2657 if (!comp->FullKeypath)
2658 continue;
2660 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2661 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2662 &hkey, TRUE);
2663 else
2664 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2665 &hkey, TRUE);
2667 if (rc != ERROR_SUCCESS)
2668 continue;
2670 if (comp->Attributes & msidbComponentAttributesPermanent)
2672 static const WCHAR szPermKey[] =
2673 { '0','0','0','0','0','0','0','0','0','0','0','0',
2674 '0','0','0','0','0','0','0','0','0','0','0','0',
2675 '0','0','0','0','0','0','0','0',0 };
2677 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2680 if (comp->Action == INSTALLSTATE_LOCAL)
2681 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2682 else
2684 MSIFILE *file;
2685 MSIRECORD *row;
2686 LPWSTR ptr, ptr2;
2687 WCHAR source[MAX_PATH];
2688 WCHAR base[MAX_PATH];
2689 LPWSTR sourcepath;
2691 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2692 static const WCHAR query[] = {
2693 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2694 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2695 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2696 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2697 '`','D','i','s','k','I','d','`',0};
2699 file = get_loaded_file(package, comp->KeyPath);
2700 if (!file)
2701 continue;
2703 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2704 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2705 ptr2 = strrchrW(source, '\\') + 1;
2706 msiobj_release(&row->hdr);
2708 lstrcpyW(base, package->PackagePath);
2709 ptr = strrchrW(base, '\\');
2710 *(ptr + 1) = '\0';
2712 sourcepath = resolve_file_source(package, file);
2713 ptr = sourcepath + lstrlenW(base);
2714 lstrcpyW(ptr2, ptr);
2715 msi_free(sourcepath);
2717 msi_reg_set_val_str(hkey, squished_pc, source);
2719 RegCloseKey(hkey);
2721 else if (ACTION_VerifyComponentForAction(comp, INSTALLSTATE_ABSENT))
2723 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2724 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2725 else
2726 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2729 /* UI stuff */
2730 uirow = MSI_CreateRecord(3);
2731 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2732 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2733 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2734 ui_actiondata(package,szProcessComponents,uirow);
2735 msiobj_release( &uirow->hdr );
2738 return ERROR_SUCCESS;
2741 typedef struct {
2742 CLSID clsid;
2743 LPWSTR source;
2745 LPWSTR path;
2746 ITypeLib *ptLib;
2747 } typelib_struct;
2749 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2750 LPWSTR lpszName, LONG_PTR lParam)
2752 TLIBATTR *attr;
2753 typelib_struct *tl_struct = (typelib_struct*) lParam;
2754 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2755 int sz;
2756 HRESULT res;
2758 if (!IS_INTRESOURCE(lpszName))
2760 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2761 return TRUE;
2764 sz = strlenW(tl_struct->source)+4;
2765 sz *= sizeof(WCHAR);
2767 if ((INT_PTR)lpszName == 1)
2768 tl_struct->path = strdupW(tl_struct->source);
2769 else
2771 tl_struct->path = msi_alloc(sz);
2772 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2775 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2776 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2777 if (FAILED(res))
2779 msi_free(tl_struct->path);
2780 tl_struct->path = NULL;
2782 return TRUE;
2785 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2786 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2788 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2789 return FALSE;
2792 msi_free(tl_struct->path);
2793 tl_struct->path = NULL;
2795 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2796 ITypeLib_Release(tl_struct->ptLib);
2798 return TRUE;
2801 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2803 MSIPACKAGE* package = param;
2804 LPCWSTR component;
2805 MSICOMPONENT *comp;
2806 MSIFILE *file;
2807 typelib_struct tl_struct;
2808 ITypeLib *tlib;
2809 HMODULE module;
2810 HRESULT hr;
2812 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2814 component = MSI_RecordGetString(row,3);
2815 comp = get_loaded_component(package,component);
2816 if (!comp)
2817 return ERROR_SUCCESS;
2819 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2821 TRACE("Skipping typelib reg due to disabled component\n");
2823 comp->Action = comp->Installed;
2825 return ERROR_SUCCESS;
2828 comp->Action = INSTALLSTATE_LOCAL;
2830 file = get_loaded_file( package, comp->KeyPath );
2831 if (!file)
2832 return ERROR_SUCCESS;
2834 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2835 if (module)
2837 LPCWSTR guid;
2838 guid = MSI_RecordGetString(row,1);
2839 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2840 tl_struct.source = strdupW( file->TargetPath );
2841 tl_struct.path = NULL;
2843 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2844 (LONG_PTR)&tl_struct);
2846 if (tl_struct.path)
2848 LPWSTR help = NULL;
2849 LPCWSTR helpid;
2850 HRESULT res;
2852 helpid = MSI_RecordGetString(row,6);
2854 if (helpid)
2855 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
2856 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2857 msi_free(help);
2859 if (FAILED(res))
2860 ERR("Failed to register type library %s\n",
2861 debugstr_w(tl_struct.path));
2862 else
2864 ui_actiondata(package,szRegisterTypeLibraries,row);
2866 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2869 ITypeLib_Release(tl_struct.ptLib);
2870 msi_free(tl_struct.path);
2872 else
2873 ERR("Failed to load type library %s\n",
2874 debugstr_w(tl_struct.source));
2876 FreeLibrary(module);
2877 msi_free(tl_struct.source);
2879 else
2881 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
2882 if (FAILED(hr))
2884 ERR("Failed to load type library: %08x\n", hr);
2885 return ERROR_FUNCTION_FAILED;
2888 ITypeLib_Release(tlib);
2891 return ERROR_SUCCESS;
2894 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2897 * OK this is a bit confusing.. I am given a _Component key and I believe
2898 * that the file that is being registered as a type library is the "key file
2899 * of that component" which I interpret to mean "The file in the KeyPath of
2900 * that component".
2902 UINT rc;
2903 MSIQUERY * view;
2904 static const WCHAR Query[] =
2905 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2906 '`','T','y','p','e','L','i','b','`',0};
2908 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2909 if (rc != ERROR_SUCCESS)
2910 return ERROR_SUCCESS;
2912 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2913 msiobj_release(&view->hdr);
2914 return rc;
2917 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2919 MSIPACKAGE *package = param;
2920 LPWSTR target_file, target_folder, filename;
2921 LPCWSTR buffer, extension;
2922 MSICOMPONENT *comp;
2923 static const WCHAR szlnk[]={'.','l','n','k',0};
2924 IShellLinkW *sl = NULL;
2925 IPersistFile *pf = NULL;
2926 HRESULT res;
2928 buffer = MSI_RecordGetString(row,4);
2929 comp = get_loaded_component(package,buffer);
2930 if (!comp)
2931 return ERROR_SUCCESS;
2933 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2935 TRACE("Skipping shortcut creation due to disabled component\n");
2937 comp->Action = comp->Installed;
2939 return ERROR_SUCCESS;
2942 comp->Action = INSTALLSTATE_LOCAL;
2944 ui_actiondata(package,szCreateShortcuts,row);
2946 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2947 &IID_IShellLinkW, (LPVOID *) &sl );
2949 if (FAILED( res ))
2951 ERR("CLSID_ShellLink not available\n");
2952 goto err;
2955 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2956 if (FAILED( res ))
2958 ERR("QueryInterface(IID_IPersistFile) failed\n");
2959 goto err;
2962 buffer = MSI_RecordGetString(row,2);
2963 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
2965 /* may be needed because of a bug somewhere else */
2966 create_full_pathW(target_folder);
2968 filename = msi_dup_record_field( row, 3 );
2969 reduce_to_longfilename(filename);
2971 extension = strchrW(filename,'.');
2972 if (!extension || strcmpiW(extension,szlnk))
2974 int len = strlenW(filename);
2975 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2976 memcpy(filename + len, szlnk, sizeof(szlnk));
2978 target_file = build_directory_name(2, target_folder, filename);
2979 msi_free(target_folder);
2980 msi_free(filename);
2982 buffer = MSI_RecordGetString(row,5);
2983 if (strchrW(buffer,'['))
2985 LPWSTR deformated;
2986 deformat_string(package,buffer,&deformated);
2987 IShellLinkW_SetPath(sl,deformated);
2988 msi_free(deformated);
2990 else
2992 FIXME("poorly handled shortcut format, advertised shortcut\n");
2993 IShellLinkW_SetPath(sl,comp->FullKeypath);
2996 if (!MSI_RecordIsNull(row,6))
2998 LPWSTR deformated;
2999 buffer = MSI_RecordGetString(row,6);
3000 deformat_string(package,buffer,&deformated);
3001 IShellLinkW_SetArguments(sl,deformated);
3002 msi_free(deformated);
3005 if (!MSI_RecordIsNull(row,7))
3007 buffer = MSI_RecordGetString(row,7);
3008 IShellLinkW_SetDescription(sl,buffer);
3011 if (!MSI_RecordIsNull(row,8))
3012 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3014 if (!MSI_RecordIsNull(row,9))
3016 LPWSTR Path;
3017 INT index;
3019 buffer = MSI_RecordGetString(row,9);
3021 Path = build_icon_path(package,buffer);
3022 index = MSI_RecordGetInteger(row,10);
3024 /* no value means 0 */
3025 if (index == MSI_NULL_INTEGER)
3026 index = 0;
3028 IShellLinkW_SetIconLocation(sl,Path,index);
3029 msi_free(Path);
3032 if (!MSI_RecordIsNull(row,11))
3033 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3035 if (!MSI_RecordIsNull(row,12))
3037 LPWSTR Path;
3038 buffer = MSI_RecordGetString(row,12);
3039 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3040 if (Path)
3041 IShellLinkW_SetWorkingDirectory(sl,Path);
3042 msi_free(Path);
3045 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3046 IPersistFile_Save(pf,target_file,FALSE);
3048 msi_free(target_file);
3050 err:
3051 if (pf)
3052 IPersistFile_Release( pf );
3053 if (sl)
3054 IShellLinkW_Release( sl );
3056 return ERROR_SUCCESS;
3059 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3061 UINT rc;
3062 HRESULT res;
3063 MSIQUERY * view;
3064 static const WCHAR Query[] =
3065 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3066 '`','S','h','o','r','t','c','u','t','`',0};
3068 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3069 if (rc != ERROR_SUCCESS)
3070 return ERROR_SUCCESS;
3072 res = CoInitialize( NULL );
3074 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3075 msiobj_release(&view->hdr);
3077 if (SUCCEEDED(res))
3078 CoUninitialize();
3080 return rc;
3083 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3085 MSIPACKAGE* package = param;
3086 HANDLE the_file;
3087 LPWSTR FilePath;
3088 LPCWSTR FileName;
3089 CHAR buffer[1024];
3090 DWORD sz;
3091 UINT rc;
3092 MSIRECORD *uirow;
3094 FileName = MSI_RecordGetString(row,1);
3095 if (!FileName)
3097 ERR("Unable to get FileName\n");
3098 return ERROR_SUCCESS;
3101 FilePath = build_icon_path(package,FileName);
3103 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3105 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3106 FILE_ATTRIBUTE_NORMAL, NULL);
3108 if (the_file == INVALID_HANDLE_VALUE)
3110 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3111 msi_free(FilePath);
3112 return ERROR_SUCCESS;
3117 DWORD write;
3118 sz = 1024;
3119 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3120 if (rc != ERROR_SUCCESS)
3122 ERR("Failed to get stream\n");
3123 CloseHandle(the_file);
3124 DeleteFileW(FilePath);
3125 break;
3127 WriteFile(the_file,buffer,sz,&write,NULL);
3128 } while (sz == 1024);
3130 msi_free(FilePath);
3132 CloseHandle(the_file);
3134 uirow = MSI_CreateRecord(1);
3135 MSI_RecordSetStringW(uirow,1,FileName);
3136 ui_actiondata(package,szPublishProduct,uirow);
3137 msiobj_release( &uirow->hdr );
3139 return ERROR_SUCCESS;
3142 static UINT msi_publish_icons(MSIPACKAGE *package)
3144 UINT r;
3145 MSIQUERY *view;
3147 static const WCHAR query[]= {
3148 'S','E','L','E','C','T',' ','*',' ',
3149 'F','R','O','M',' ','`','I','c','o','n','`',0};
3151 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3152 if (r == ERROR_SUCCESS)
3154 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3155 msiobj_release(&view->hdr);
3158 return ERROR_SUCCESS;
3161 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3163 UINT r;
3164 HKEY source;
3165 LPWSTR buffer;
3166 MSIMEDIADISK *disk;
3167 MSISOURCELISTINFO *info;
3169 r = RegCreateKeyW(hkey, szSourceList, &source);
3170 if (r != ERROR_SUCCESS)
3171 return r;
3173 RegCloseKey(source);
3175 buffer = strrchrW(package->PackagePath, '\\') + 1;
3176 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3177 package->Context, MSICODE_PRODUCT,
3178 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3179 if (r != ERROR_SUCCESS)
3180 return r;
3182 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3183 package->Context, MSICODE_PRODUCT,
3184 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3185 if (r != ERROR_SUCCESS)
3186 return r;
3188 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3189 package->Context, MSICODE_PRODUCT,
3190 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3191 if (r != ERROR_SUCCESS)
3192 return r;
3194 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3196 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3197 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3198 info->options, info->value);
3199 else
3200 MsiSourceListSetInfoW(package->ProductCode, NULL,
3201 info->context, info->options,
3202 info->property, info->value);
3205 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3207 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3208 disk->context, disk->options,
3209 disk->disk_id, disk->volume_label, disk->disk_prompt);
3212 return ERROR_SUCCESS;
3215 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3217 MSIHANDLE hdb, suminfo;
3218 WCHAR guids[MAX_PATH];
3219 WCHAR packcode[SQUISH_GUID_SIZE];
3220 LPWSTR buffer;
3221 LPWSTR ptr;
3222 DWORD langid;
3223 DWORD size;
3224 UINT r;
3226 static const WCHAR szProductLanguage[] =
3227 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3228 static const WCHAR szARPProductIcon[] =
3229 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3230 static const WCHAR szProductVersion[] =
3231 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3232 static const WCHAR szAssignment[] =
3233 {'A','s','s','i','g','n','m','e','n','t',0};
3234 static const WCHAR szAdvertiseFlags[] =
3235 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3236 static const WCHAR szClients[] =
3237 {'C','l','i','e','n','t','s',0};
3238 static const WCHAR szColon[] = {':',0};
3240 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3241 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3242 msi_free(buffer);
3244 langid = msi_get_property_int(package, szProductLanguage, 0);
3245 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3247 /* FIXME */
3248 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3250 buffer = msi_dup_property(package, szARPProductIcon);
3251 if (buffer)
3253 LPWSTR path = build_icon_path(package,buffer);
3254 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3255 msi_free(path);
3256 msi_free(buffer);
3259 buffer = msi_dup_property(package, szProductVersion);
3260 if (buffer)
3262 DWORD verdword = msi_version_str_to_dword(buffer);
3263 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3264 msi_free(buffer);
3267 msi_reg_set_val_dword(hkey, szAssignment, 0);
3268 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3269 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3270 msi_reg_set_val_str(hkey, szClients, szColon);
3272 hdb = alloc_msihandle(&package->db->hdr);
3273 if (!hdb)
3274 return ERROR_NOT_ENOUGH_MEMORY;
3276 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3277 MsiCloseHandle(hdb);
3278 if (r != ERROR_SUCCESS)
3279 goto done;
3281 size = MAX_PATH;
3282 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3283 NULL, guids, &size);
3284 if (r != ERROR_SUCCESS)
3285 goto done;
3287 ptr = strchrW(guids, ';');
3288 if (ptr) *ptr = 0;
3289 squash_guid(guids, packcode);
3290 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3292 done:
3293 MsiCloseHandle(suminfo);
3294 return ERROR_SUCCESS;
3297 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3299 UINT r;
3300 HKEY hkey;
3301 LPWSTR upgrade;
3302 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3304 static const WCHAR szUpgradeCode[] =
3305 {'U','p','g','r','a','d','e','C','o','d','e',0};
3307 upgrade = msi_dup_property(package, szUpgradeCode);
3308 if (!upgrade)
3309 return ERROR_SUCCESS;
3311 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3313 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3314 if (r != ERROR_SUCCESS)
3315 goto done;
3317 else
3319 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3320 if (r != ERROR_SUCCESS)
3321 goto done;
3324 squash_guid(package->ProductCode, squashed_pc);
3325 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3327 RegCloseKey(hkey);
3329 done:
3330 msi_free(upgrade);
3331 return r;
3334 static BOOL msi_check_publish(MSIPACKAGE *package)
3336 MSIFEATURE *feature;
3338 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3340 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3341 return TRUE;
3344 return FALSE;
3347 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3349 MSIFEATURE *feature;
3351 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3353 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3354 return FALSE;
3357 return TRUE;
3360 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3362 WCHAR patch_squashed[GUID_SIZE];
3363 HKEY patches;
3364 LONG res;
3365 UINT r = ERROR_FUNCTION_FAILED;
3367 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3368 &patches, NULL);
3369 if (res != ERROR_SUCCESS)
3370 return ERROR_FUNCTION_FAILED;
3372 squash_guid(package->patch->patchcode, patch_squashed);
3374 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3375 (const BYTE *)patch_squashed,
3376 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3377 if (res != ERROR_SUCCESS)
3378 goto done;
3380 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3381 (const BYTE *)package->patch->transforms,
3382 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3383 if (res == ERROR_SUCCESS)
3384 r = ERROR_SUCCESS;
3386 done:
3387 RegCloseKey(patches);
3388 return r;
3392 * 99% of the work done here is only done for
3393 * advertised installs. However this is where the
3394 * Icon table is processed and written out
3395 * so that is what I am going to do here.
3397 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3399 UINT rc;
3400 HKEY hukey=0;
3401 HKEY hudkey=0;
3403 /* FIXME: also need to publish if the product is in advertise mode */
3404 if (!msi_check_publish(package))
3405 return ERROR_SUCCESS;
3407 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3408 &hukey, TRUE);
3409 if (rc != ERROR_SUCCESS)
3410 goto end;
3412 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3413 NULL, &hudkey, TRUE);
3414 if (rc != ERROR_SUCCESS)
3415 goto end;
3417 rc = msi_publish_upgrade_code(package);
3418 if (rc != ERROR_SUCCESS)
3419 goto end;
3421 if (package->patch)
3423 rc = msi_publish_patch(package, hukey, hudkey);
3424 if (rc != ERROR_SUCCESS)
3425 goto end;
3428 rc = msi_publish_product_properties(package, hukey);
3429 if (rc != ERROR_SUCCESS)
3430 goto end;
3432 rc = msi_publish_sourcelist(package, hukey);
3433 if (rc != ERROR_SUCCESS)
3434 goto end;
3436 rc = msi_publish_icons(package);
3438 end:
3439 RegCloseKey(hukey);
3440 RegCloseKey(hudkey);
3442 return rc;
3445 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3447 MSIPACKAGE *package = param;
3448 LPCWSTR component, section, key, value, identifier, dirproperty;
3449 LPWSTR deformated_section, deformated_key, deformated_value;
3450 LPWSTR folder, filename, fullname = NULL;
3451 LPCWSTR filenameptr;
3452 MSIRECORD * uirow;
3453 INT action;
3454 MSICOMPONENT *comp;
3455 static const WCHAR szWindowsFolder[] =
3456 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3458 component = MSI_RecordGetString(row, 8);
3459 comp = get_loaded_component(package,component);
3461 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3463 TRACE("Skipping ini file due to disabled component %s\n",
3464 debugstr_w(component));
3466 comp->Action = comp->Installed;
3468 return ERROR_SUCCESS;
3471 comp->Action = INSTALLSTATE_LOCAL;
3473 identifier = MSI_RecordGetString(row,1);
3474 dirproperty = MSI_RecordGetString(row,3);
3475 section = MSI_RecordGetString(row,4);
3476 key = MSI_RecordGetString(row,5);
3477 value = MSI_RecordGetString(row,6);
3478 action = MSI_RecordGetInteger(row,7);
3480 deformat_string(package,section,&deformated_section);
3481 deformat_string(package,key,&deformated_key);
3482 deformat_string(package,value,&deformated_value);
3484 filename = msi_dup_record_field(row, 2);
3485 if (filename && (filenameptr = strchrW(filename, '|')))
3486 filenameptr++;
3487 else
3488 filenameptr = filename;
3490 if (dirproperty)
3492 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3493 if (!folder)
3494 folder = msi_dup_property( package, dirproperty );
3496 else
3497 folder = msi_dup_property( package, szWindowsFolder );
3499 if (!folder)
3501 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3502 goto cleanup;
3505 fullname = build_directory_name(2, folder, filenameptr);
3507 if (action == 0)
3509 TRACE("Adding value %s to section %s in %s\n",
3510 debugstr_w(deformated_key), debugstr_w(deformated_section),
3511 debugstr_w(fullname));
3512 WritePrivateProfileStringW(deformated_section, deformated_key,
3513 deformated_value, fullname);
3515 else if (action == 1)
3517 WCHAR returned[10];
3518 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3519 returned, 10, fullname);
3520 if (returned[0] == 0)
3522 TRACE("Adding value %s to section %s in %s\n",
3523 debugstr_w(deformated_key), debugstr_w(deformated_section),
3524 debugstr_w(fullname));
3526 WritePrivateProfileStringW(deformated_section, deformated_key,
3527 deformated_value, fullname);
3530 else if (action == 3)
3531 FIXME("Append to existing section not yet implemented\n");
3533 uirow = MSI_CreateRecord(4);
3534 MSI_RecordSetStringW(uirow,1,identifier);
3535 MSI_RecordSetStringW(uirow,2,deformated_section);
3536 MSI_RecordSetStringW(uirow,3,deformated_key);
3537 MSI_RecordSetStringW(uirow,4,deformated_value);
3538 ui_actiondata(package,szWriteIniValues,uirow);
3539 msiobj_release( &uirow->hdr );
3541 cleanup:
3542 msi_free(filename);
3543 msi_free(fullname);
3544 msi_free(folder);
3545 msi_free(deformated_key);
3546 msi_free(deformated_value);
3547 msi_free(deformated_section);
3548 return ERROR_SUCCESS;
3551 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3553 UINT rc;
3554 MSIQUERY * view;
3555 static const WCHAR ExecSeqQuery[] =
3556 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3557 '`','I','n','i','F','i','l','e','`',0};
3559 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3560 if (rc != ERROR_SUCCESS)
3562 TRACE("no IniFile table\n");
3563 return ERROR_SUCCESS;
3566 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3567 msiobj_release(&view->hdr);
3568 return rc;
3571 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3573 MSIPACKAGE *package = param;
3574 LPCWSTR filename;
3575 LPWSTR FullName;
3576 MSIFILE *file;
3577 DWORD len;
3578 static const WCHAR ExeStr[] =
3579 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3580 static const WCHAR close[] = {'\"',0};
3581 STARTUPINFOW si;
3582 PROCESS_INFORMATION info;
3583 BOOL brc;
3584 MSIRECORD *uirow;
3585 LPWSTR uipath, p;
3587 memset(&si,0,sizeof(STARTUPINFOW));
3589 filename = MSI_RecordGetString(row,1);
3590 file = get_loaded_file( package, filename );
3592 if (!file)
3594 ERR("Unable to find file id %s\n",debugstr_w(filename));
3595 return ERROR_SUCCESS;
3598 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3600 FullName = msi_alloc(len*sizeof(WCHAR));
3601 strcpyW(FullName,ExeStr);
3602 strcatW( FullName, file->TargetPath );
3603 strcatW(FullName,close);
3605 TRACE("Registering %s\n",debugstr_w(FullName));
3606 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3607 &si, &info);
3609 if (brc)
3611 CloseHandle(info.hThread);
3612 msi_dialog_check_messages(info.hProcess);
3613 CloseHandle(info.hProcess);
3616 msi_free(FullName);
3618 /* the UI chunk */
3619 uirow = MSI_CreateRecord( 2 );
3620 uipath = strdupW( file->TargetPath );
3621 p = strrchrW(uipath,'\\');
3622 if (p)
3623 p[0]=0;
3624 MSI_RecordSetStringW( uirow, 1, &p[1] );
3625 MSI_RecordSetStringW( uirow, 2, uipath);
3626 ui_actiondata( package, szSelfRegModules, uirow);
3627 msiobj_release( &uirow->hdr );
3628 msi_free( uipath );
3629 /* FIXME: call ui_progress? */
3631 return ERROR_SUCCESS;
3634 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3636 UINT rc;
3637 MSIQUERY * view;
3638 static const WCHAR ExecSeqQuery[] =
3639 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3640 '`','S','e','l','f','R','e','g','`',0};
3642 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3643 if (rc != ERROR_SUCCESS)
3645 TRACE("no SelfReg table\n");
3646 return ERROR_SUCCESS;
3649 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3650 msiobj_release(&view->hdr);
3652 return ERROR_SUCCESS;
3655 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3657 MSIFEATURE *feature;
3658 UINT rc;
3659 HKEY hkey;
3660 HKEY userdata = NULL;
3662 if (!msi_check_publish(package))
3663 return ERROR_SUCCESS;
3665 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3666 &hkey, TRUE);
3667 if (rc != ERROR_SUCCESS)
3668 goto end;
3670 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3671 &userdata, TRUE);
3672 if (rc != ERROR_SUCCESS)
3673 goto end;
3675 /* here the guids are base 85 encoded */
3676 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3678 ComponentList *cl;
3679 LPWSTR data = NULL;
3680 GUID clsid;
3681 INT size;
3682 BOOL absent = FALSE;
3683 MSIRECORD *uirow;
3685 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3686 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3687 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3688 absent = TRUE;
3690 size = 1;
3691 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3693 size += 21;
3695 if (feature->Feature_Parent)
3696 size += strlenW( feature->Feature_Parent )+2;
3698 data = msi_alloc(size * sizeof(WCHAR));
3700 data[0] = 0;
3701 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3703 MSICOMPONENT* component = cl->component;
3704 WCHAR buf[21];
3706 buf[0] = 0;
3707 if (component->ComponentId)
3709 TRACE("From %s\n",debugstr_w(component->ComponentId));
3710 CLSIDFromString(component->ComponentId, &clsid);
3711 encode_base85_guid(&clsid,buf);
3712 TRACE("to %s\n",debugstr_w(buf));
3713 strcatW(data,buf);
3717 if (feature->Feature_Parent)
3719 static const WCHAR sep[] = {'\2',0};
3720 strcatW(data,sep);
3721 strcatW(data,feature->Feature_Parent);
3724 msi_reg_set_val_str( userdata, feature->Feature, data );
3725 msi_free(data);
3727 size = 0;
3728 if (feature->Feature_Parent)
3729 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3730 if (!absent)
3732 size += sizeof(WCHAR);
3733 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3734 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
3736 else
3738 size += 2*sizeof(WCHAR);
3739 data = msi_alloc(size);
3740 data[0] = 0x6;
3741 data[1] = 0;
3742 if (feature->Feature_Parent)
3743 strcpyW( &data[1], feature->Feature_Parent );
3744 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3745 (LPBYTE)data,size);
3746 msi_free(data);
3749 /* the UI chunk */
3750 uirow = MSI_CreateRecord( 1 );
3751 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3752 ui_actiondata( package, szPublishFeatures, uirow);
3753 msiobj_release( &uirow->hdr );
3754 /* FIXME: call ui_progress? */
3757 end:
3758 RegCloseKey(hkey);
3759 RegCloseKey(userdata);
3760 return rc;
3763 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
3765 UINT r;
3766 HKEY hkey;
3768 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
3770 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3771 &hkey, FALSE);
3772 if (r == ERROR_SUCCESS)
3774 RegDeleteValueW(hkey, feature->Feature);
3775 RegCloseKey(hkey);
3778 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3779 &hkey, FALSE);
3780 if (r == ERROR_SUCCESS)
3782 RegDeleteValueW(hkey, feature->Feature);
3783 RegCloseKey(hkey);
3786 return ERROR_SUCCESS;
3789 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
3791 MSIFEATURE *feature;
3793 if (!msi_check_unpublish(package))
3794 return ERROR_SUCCESS;
3796 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3798 msi_unpublish_feature(package, feature);
3801 return ERROR_SUCCESS;
3804 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
3806 LPWSTR prop, val, key;
3807 SYSTEMTIME systime;
3808 DWORD size, langid;
3809 WCHAR date[9];
3810 LPWSTR buffer;
3812 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
3813 static const WCHAR szWindowsInstaller[] =
3814 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3815 static const WCHAR modpath_fmt[] =
3816 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3817 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3818 static const WCHAR szModifyPath[] =
3819 {'M','o','d','i','f','y','P','a','t','h',0};
3820 static const WCHAR szUninstallString[] =
3821 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3822 static const WCHAR szEstimatedSize[] =
3823 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3824 static const WCHAR szProductLanguage[] =
3825 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3826 static const WCHAR szProductVersion[] =
3827 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3828 static const WCHAR szProductName[] =
3829 {'P','r','o','d','u','c','t','N','a','m','e',0};
3830 static const WCHAR szDisplayName[] =
3831 {'D','i','s','p','l','a','y','N','a','m','e',0};
3832 static const WCHAR szDisplayVersion[] =
3833 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
3834 static const WCHAR szManufacturer[] =
3835 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
3837 static const LPCSTR propval[] = {
3838 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3839 "ARPCONTACT", "Contact",
3840 "ARPCOMMENTS", "Comments",
3841 "ProductName", "DisplayName",
3842 "ProductVersion", "DisplayVersion",
3843 "ARPHELPLINK", "HelpLink",
3844 "ARPHELPTELEPHONE", "HelpTelephone",
3845 "ARPINSTALLLOCATION", "InstallLocation",
3846 "SourceDir", "InstallSource",
3847 "Manufacturer", "Publisher",
3848 "ARPREADME", "Readme",
3849 "ARPSIZE", "Size",
3850 "ARPURLINFOABOUT", "URLInfoAbout",
3851 "ARPURLUPDATEINFO", "URLUpdateInfo",
3852 NULL,
3854 const LPCSTR *p = propval;
3856 while (*p)
3858 prop = strdupAtoW(*p++);
3859 key = strdupAtoW(*p++);
3860 val = msi_dup_property(package, prop);
3861 msi_reg_set_val_str(hkey, key, val);
3862 msi_free(val);
3863 msi_free(key);
3864 msi_free(prop);
3867 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
3869 size = deformat_string(package, modpath_fmt, &buffer);
3870 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
3871 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
3872 msi_free(buffer);
3874 /* FIXME: Write real Estimated Size when we have it */
3875 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
3877 buffer = msi_dup_property(package, szProductName);
3878 msi_reg_set_val_str(hkey, szDisplayName, buffer);
3879 msi_free(buffer);
3881 buffer = msi_dup_property(package, cszSourceDir);
3882 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
3883 msi_free(buffer);
3885 buffer = msi_dup_property(package, szManufacturer);
3886 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
3887 msi_free(buffer);
3889 GetLocalTime(&systime);
3890 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
3891 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
3893 langid = msi_get_property_int(package, szProductLanguage, 0);
3894 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3896 buffer = msi_dup_property(package, szProductVersion);
3897 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
3898 if (buffer)
3900 DWORD verdword = msi_version_str_to_dword(buffer);
3902 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3903 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
3904 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
3905 msi_free(buffer);
3908 return ERROR_SUCCESS;
3911 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3913 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3914 LPWSTR upgrade_code;
3915 HKEY hkey, props;
3916 HKEY upgrade;
3917 UINT rc;
3919 static const WCHAR szUpgradeCode[] = {
3920 'U','p','g','r','a','d','e','C','o','d','e',0};
3922 /* FIXME: also need to publish if the product is in advertise mode */
3923 if (!msi_check_publish(package))
3924 return ERROR_SUCCESS;
3926 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
3927 if (rc != ERROR_SUCCESS)
3928 return rc;
3930 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
3931 NULL, &props, TRUE);
3932 if (rc != ERROR_SUCCESS)
3933 goto done;
3935 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
3936 msi_free( package->db->localfile );
3937 package->db->localfile = NULL;
3939 rc = msi_publish_install_properties(package, hkey);
3940 if (rc != ERROR_SUCCESS)
3941 goto done;
3943 rc = msi_publish_install_properties(package, props);
3944 if (rc != ERROR_SUCCESS)
3945 goto done;
3947 upgrade_code = msi_dup_property(package, szUpgradeCode);
3948 if (upgrade_code)
3950 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
3951 squash_guid(package->ProductCode, squashed_pc);
3952 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
3953 RegCloseKey(upgrade);
3954 msi_free(upgrade_code);
3957 done:
3958 RegCloseKey(hkey);
3960 return ERROR_SUCCESS;
3963 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3965 return execute_script(package,INSTALL_SCRIPT);
3968 static UINT msi_unpublish_product(MSIPACKAGE *package)
3970 LPWSTR upgrade;
3971 LPWSTR remove = NULL;
3972 LPWSTR *features = NULL;
3973 BOOL full_uninstall = TRUE;
3974 MSIFEATURE *feature;
3976 static const WCHAR szUpgradeCode[] =
3977 {'U','p','g','r','a','d','e','C','o','d','e',0};
3979 remove = msi_dup_property(package, szRemove);
3980 if (!remove)
3981 return ERROR_SUCCESS;
3983 features = msi_split_string(remove, ',');
3984 if (!features)
3986 msi_free(remove);
3987 ERR("REMOVE feature list is empty!\n");
3988 return ERROR_FUNCTION_FAILED;
3991 if (!lstrcmpW(features[0], szAll))
3992 full_uninstall = TRUE;
3993 else
3995 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3997 if (feature->Action != INSTALLSTATE_ABSENT)
3998 full_uninstall = FALSE;
4002 if (!full_uninstall)
4003 goto done;
4005 MSIREG_DeleteProductKey(package->ProductCode);
4006 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4007 MSIREG_DeleteUninstallKey(package->ProductCode);
4009 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4011 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4012 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4014 else
4016 MSIREG_DeleteUserProductKey(package->ProductCode);
4017 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4020 upgrade = msi_dup_property(package, szUpgradeCode);
4021 if (upgrade)
4023 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4024 msi_free(upgrade);
4027 done:
4028 msi_free(remove);
4029 msi_free(features);
4030 return ERROR_SUCCESS;
4033 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4035 UINT rc;
4037 rc = msi_unpublish_product(package);
4038 if (rc != ERROR_SUCCESS)
4039 return rc;
4041 /* turn off scheduling */
4042 package->script->CurrentlyScripting= FALSE;
4044 /* first do the same as an InstallExecute */
4045 rc = ACTION_InstallExecute(package);
4046 if (rc != ERROR_SUCCESS)
4047 return rc;
4049 /* then handle Commit Actions */
4050 rc = execute_script(package,COMMIT_SCRIPT);
4052 return rc;
4055 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4057 static const WCHAR RunOnce[] = {
4058 'S','o','f','t','w','a','r','e','\\',
4059 'M','i','c','r','o','s','o','f','t','\\',
4060 'W','i','n','d','o','w','s','\\',
4061 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4062 'R','u','n','O','n','c','e',0};
4063 static const WCHAR InstallRunOnce[] = {
4064 'S','o','f','t','w','a','r','e','\\',
4065 'M','i','c','r','o','s','o','f','t','\\',
4066 'W','i','n','d','o','w','s','\\',
4067 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4068 'I','n','s','t','a','l','l','e','r','\\',
4069 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4071 static const WCHAR msiexec_fmt[] = {
4072 '%','s',
4073 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4074 '\"','%','s','\"',0};
4075 static const WCHAR install_fmt[] = {
4076 '/','I',' ','\"','%','s','\"',' ',
4077 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4078 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4079 WCHAR buffer[256], sysdir[MAX_PATH];
4080 HKEY hkey;
4081 WCHAR squished_pc[100];
4083 squash_guid(package->ProductCode,squished_pc);
4085 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4086 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4087 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4088 squished_pc);
4090 msi_reg_set_val_str( hkey, squished_pc, buffer );
4091 RegCloseKey(hkey);
4093 TRACE("Reboot command %s\n",debugstr_w(buffer));
4095 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4096 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4098 msi_reg_set_val_str( hkey, squished_pc, buffer );
4099 RegCloseKey(hkey);
4101 return ERROR_INSTALL_SUSPEND;
4104 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4106 DWORD attrib;
4107 UINT rc;
4110 * We are currently doing what should be done here in the top level Install
4111 * however for Administrative and uninstalls this step will be needed
4113 if (!package->PackagePath)
4114 return ERROR_SUCCESS;
4116 msi_set_sourcedir_props(package, TRUE);
4118 attrib = GetFileAttributesW(package->db->path);
4119 if (attrib == INVALID_FILE_ATTRIBUTES)
4121 LPWSTR prompt;
4122 LPWSTR msg;
4123 DWORD size = 0;
4125 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4126 package->Context, MSICODE_PRODUCT,
4127 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4128 if (rc == ERROR_MORE_DATA)
4130 prompt = msi_alloc(size * sizeof(WCHAR));
4131 MsiSourceListGetInfoW(package->ProductCode, NULL,
4132 package->Context, MSICODE_PRODUCT,
4133 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4135 else
4136 prompt = strdupW(package->db->path);
4138 msg = generate_error_string(package,1302,1,prompt);
4139 while(attrib == INVALID_FILE_ATTRIBUTES)
4141 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4142 if (rc == IDCANCEL)
4144 rc = ERROR_INSTALL_USEREXIT;
4145 break;
4147 attrib = GetFileAttributesW(package->db->path);
4149 msi_free(prompt);
4150 rc = ERROR_SUCCESS;
4152 else
4153 return ERROR_SUCCESS;
4155 return rc;
4158 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4160 HKEY hkey=0;
4161 LPWSTR buffer;
4162 LPWSTR productid;
4163 UINT rc,i;
4165 static const WCHAR szPropKeys[][80] =
4167 {'P','r','o','d','u','c','t','I','D',0},
4168 {'U','S','E','R','N','A','M','E',0},
4169 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4170 {0},
4173 static const WCHAR szRegKeys[][80] =
4175 {'P','r','o','d','u','c','t','I','D',0},
4176 {'R','e','g','O','w','n','e','r',0},
4177 {'R','e','g','C','o','m','p','a','n','y',0},
4178 {0},
4181 if (msi_check_unpublish(package))
4183 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4184 return ERROR_SUCCESS;
4187 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4188 if (!productid)
4189 return ERROR_SUCCESS;
4191 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4192 NULL, &hkey, TRUE);
4193 if (rc != ERROR_SUCCESS)
4194 goto end;
4196 for( i = 0; szPropKeys[i][0]; i++ )
4198 buffer = msi_dup_property( package, szPropKeys[i] );
4199 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4200 msi_free( buffer );
4203 end:
4204 msi_free(productid);
4205 RegCloseKey(hkey);
4207 /* FIXME: call ui_actiondata */
4209 return rc;
4213 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4215 UINT rc;
4217 package->script->InWhatSequence |= SEQUENCE_EXEC;
4218 rc = ACTION_ProcessExecSequence(package,FALSE);
4219 return rc;
4223 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4225 MSIPACKAGE *package = param;
4226 LPCWSTR compgroupid=NULL;
4227 LPCWSTR feature=NULL;
4228 LPCWSTR text = NULL;
4229 LPCWSTR qualifier = NULL;
4230 LPCWSTR component = NULL;
4231 LPWSTR advertise = NULL;
4232 LPWSTR output = NULL;
4233 HKEY hkey;
4234 UINT rc = ERROR_SUCCESS;
4235 MSICOMPONENT *comp;
4236 DWORD sz = 0;
4237 MSIRECORD *uirow;
4239 component = MSI_RecordGetString(rec,3);
4240 comp = get_loaded_component(package,component);
4242 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4243 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4244 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4246 TRACE("Skipping: Component %s not scheduled for install\n",
4247 debugstr_w(component));
4249 return ERROR_SUCCESS;
4252 compgroupid = MSI_RecordGetString(rec,1);
4253 qualifier = MSI_RecordGetString(rec,2);
4255 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4256 if (rc != ERROR_SUCCESS)
4257 goto end;
4259 text = MSI_RecordGetString(rec,4);
4260 feature = MSI_RecordGetString(rec,5);
4262 advertise = create_component_advertise_string(package, comp, feature);
4264 sz = strlenW(advertise);
4266 if (text)
4267 sz += lstrlenW(text);
4269 sz+=3;
4270 sz *= sizeof(WCHAR);
4272 output = msi_alloc_zero(sz);
4273 strcpyW(output,advertise);
4274 msi_free(advertise);
4276 if (text)
4277 strcatW(output,text);
4279 msi_reg_set_val_multi_str( hkey, qualifier, output );
4281 end:
4282 RegCloseKey(hkey);
4283 msi_free(output);
4285 /* the UI chunk */
4286 uirow = MSI_CreateRecord( 2 );
4287 MSI_RecordSetStringW( uirow, 1, compgroupid );
4288 MSI_RecordSetStringW( uirow, 2, qualifier);
4289 ui_actiondata( package, szPublishComponents, uirow);
4290 msiobj_release( &uirow->hdr );
4291 /* FIXME: call ui_progress? */
4293 return rc;
4297 * At present I am ignorning the advertised components part of this and only
4298 * focusing on the qualified component sets
4300 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4302 UINT rc;
4303 MSIQUERY * view;
4304 static const WCHAR ExecSeqQuery[] =
4305 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4306 '`','P','u','b','l','i','s','h',
4307 'C','o','m','p','o','n','e','n','t','`',0};
4309 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4310 if (rc != ERROR_SUCCESS)
4311 return ERROR_SUCCESS;
4313 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4314 msiobj_release(&view->hdr);
4316 return rc;
4319 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4321 MSIPACKAGE *package = param;
4322 MSIRECORD *row;
4323 MSIFILE *file;
4324 SC_HANDLE hscm, service = NULL;
4325 LPCWSTR comp, depends, pass;
4326 LPWSTR name = NULL, disp = NULL;
4327 LPCWSTR load_order, serv_name, key;
4328 DWORD serv_type, start_type;
4329 DWORD err_control;
4331 static const WCHAR query[] =
4332 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4333 '`','C','o','m','p','o','n','e','n','t','`',' ',
4334 'W','H','E','R','E',' ',
4335 '`','C','o','m','p','o','n','e','n','t','`',' ',
4336 '=','\'','%','s','\'',0};
4338 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4339 if (!hscm)
4341 ERR("Failed to open the SC Manager!\n");
4342 goto done;
4345 start_type = MSI_RecordGetInteger(rec, 5);
4346 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4347 goto done;
4349 depends = MSI_RecordGetString(rec, 8);
4350 if (depends && *depends)
4351 FIXME("Dependency list unhandled!\n");
4353 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4354 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
4355 serv_type = MSI_RecordGetInteger(rec, 4);
4356 err_control = MSI_RecordGetInteger(rec, 6);
4357 load_order = MSI_RecordGetString(rec, 7);
4358 serv_name = MSI_RecordGetString(rec, 9);
4359 pass = MSI_RecordGetString(rec, 10);
4360 comp = MSI_RecordGetString(rec, 12);
4362 /* fetch the service path */
4363 row = MSI_QueryGetRecord(package->db, query, comp);
4364 if (!row)
4366 ERR("Control query failed!\n");
4367 goto done;
4370 key = MSI_RecordGetString(row, 6);
4372 file = get_loaded_file(package, key);
4373 msiobj_release(&row->hdr);
4374 if (!file)
4376 ERR("Failed to load the service file\n");
4377 goto done;
4380 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4381 start_type, err_control, file->TargetPath,
4382 load_order, NULL, NULL, serv_name, pass);
4383 if (!service)
4385 if (GetLastError() != ERROR_SERVICE_EXISTS)
4386 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4389 done:
4390 CloseServiceHandle(service);
4391 CloseServiceHandle(hscm);
4392 msi_free(name);
4393 msi_free(disp);
4395 return ERROR_SUCCESS;
4398 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4400 UINT rc;
4401 MSIQUERY * view;
4402 static const WCHAR ExecSeqQuery[] =
4403 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4404 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4406 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4407 if (rc != ERROR_SUCCESS)
4408 return ERROR_SUCCESS;
4410 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4411 msiobj_release(&view->hdr);
4413 return rc;
4416 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4417 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
4419 LPCWSTR *vector, *temp_vector;
4420 LPWSTR p, q;
4421 DWORD sep_len;
4423 static const WCHAR separator[] = {'[','~',']',0};
4425 *numargs = 0;
4426 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4428 if (!args)
4429 return NULL;
4431 vector = msi_alloc(sizeof(LPWSTR));
4432 if (!vector)
4433 return NULL;
4435 p = args;
4438 (*numargs)++;
4439 vector[*numargs - 1] = p;
4441 if ((q = strstrW(p, separator)))
4443 *q = '\0';
4445 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4446 if (!temp_vector)
4448 msi_free(vector);
4449 return NULL;
4451 vector = temp_vector;
4453 p = q + sep_len;
4455 } while (q);
4457 return vector;
4460 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4462 MSIPACKAGE *package = param;
4463 MSICOMPONENT *comp;
4464 SC_HANDLE scm, service = NULL;
4465 LPCWSTR name, *vector = NULL;
4466 LPWSTR args;
4467 DWORD event, numargs;
4468 UINT r = ERROR_FUNCTION_FAILED;
4470 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4471 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4472 return ERROR_SUCCESS;
4474 name = MSI_RecordGetString(rec, 2);
4475 event = MSI_RecordGetInteger(rec, 3);
4476 args = strdupW(MSI_RecordGetString(rec, 4));
4478 if (!(event & msidbServiceControlEventStart))
4479 return ERROR_SUCCESS;
4481 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4482 if (!scm)
4484 ERR("Failed to open the service control manager\n");
4485 goto done;
4488 service = OpenServiceW(scm, name, SERVICE_START);
4489 if (!service)
4491 ERR("Failed to open service %s\n", debugstr_w(name));
4492 goto done;
4495 vector = msi_service_args_to_vector(args, &numargs);
4497 if (!StartServiceW(service, numargs, vector))
4499 ERR("Failed to start service %s\n", debugstr_w(name));
4500 goto done;
4503 r = ERROR_SUCCESS;
4505 done:
4506 CloseServiceHandle(service);
4507 CloseServiceHandle(scm);
4509 msi_free(args);
4510 msi_free(vector);
4511 return r;
4514 static UINT ACTION_StartServices( MSIPACKAGE *package )
4516 UINT rc;
4517 MSIQUERY *view;
4519 static const WCHAR query[] = {
4520 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4521 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4523 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4524 if (rc != ERROR_SUCCESS)
4525 return ERROR_SUCCESS;
4527 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4528 msiobj_release(&view->hdr);
4530 return rc;
4533 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4535 DWORD i, needed, count;
4536 ENUM_SERVICE_STATUSW *dependencies;
4537 SERVICE_STATUS ss;
4538 SC_HANDLE depserv;
4540 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4541 0, &needed, &count))
4542 return TRUE;
4544 if (GetLastError() != ERROR_MORE_DATA)
4545 return FALSE;
4547 dependencies = msi_alloc(needed);
4548 if (!dependencies)
4549 return FALSE;
4551 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4552 needed, &needed, &count))
4553 goto error;
4555 for (i = 0; i < count; i++)
4557 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4558 SERVICE_STOP | SERVICE_QUERY_STATUS);
4559 if (!depserv)
4560 goto error;
4562 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4563 goto error;
4566 return TRUE;
4568 error:
4569 msi_free(dependencies);
4570 return FALSE;
4573 static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
4575 MSIPACKAGE *package = param;
4576 MSICOMPONENT *comp;
4577 SERVICE_STATUS status;
4578 SERVICE_STATUS_PROCESS ssp;
4579 SC_HANDLE scm = NULL, service = NULL;
4580 LPWSTR name, args;
4581 DWORD event, needed;
4583 event = MSI_RecordGetInteger(rec, 3);
4584 if (!(event & msidbServiceControlEventStop))
4585 return ERROR_SUCCESS;
4587 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4588 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4589 return ERROR_SUCCESS;
4591 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4592 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4593 args = strdupW(MSI_RecordGetString(rec, 4));
4595 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4596 if (!scm)
4598 WARN("Failed to open the SCM: %d\n", GetLastError());
4599 goto done;
4602 service = OpenServiceW(scm, name,
4603 SERVICE_STOP |
4604 SERVICE_QUERY_STATUS |
4605 SERVICE_ENUMERATE_DEPENDENTS);
4606 if (!service)
4608 WARN("Failed to open service (%s): %d\n",
4609 debugstr_w(name), GetLastError());
4610 goto done;
4613 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4614 sizeof(SERVICE_STATUS_PROCESS), &needed))
4616 WARN("Failed to query service status (%s): %d\n",
4617 debugstr_w(name), GetLastError());
4618 goto done;
4621 if (ssp.dwCurrentState == SERVICE_STOPPED)
4622 goto done;
4624 stop_service_dependents(scm, service);
4626 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
4627 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
4629 done:
4630 CloseServiceHandle(service);
4631 CloseServiceHandle(scm);
4632 msi_free(name);
4633 msi_free(args);
4635 return ERROR_SUCCESS;
4638 static UINT ACTION_StopServices( MSIPACKAGE *package )
4640 UINT rc;
4641 MSIQUERY *view;
4643 static const WCHAR query[] = {
4644 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4645 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4647 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4648 if (rc != ERROR_SUCCESS)
4649 return ERROR_SUCCESS;
4651 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
4652 msiobj_release(&view->hdr);
4654 return rc;
4657 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4659 MSIFILE *file;
4661 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4663 if (!lstrcmpW(file->File, filename))
4664 return file;
4667 return NULL;
4670 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4672 MSIPACKAGE *package = param;
4673 LPWSTR driver, driver_path, ptr;
4674 WCHAR outpath[MAX_PATH];
4675 MSIFILE *driver_file, *setup_file;
4676 LPCWSTR desc;
4677 DWORD len, usage;
4678 UINT r = ERROR_SUCCESS;
4680 static const WCHAR driver_fmt[] = {
4681 'D','r','i','v','e','r','=','%','s',0};
4682 static const WCHAR setup_fmt[] = {
4683 'S','e','t','u','p','=','%','s',0};
4684 static const WCHAR usage_fmt[] = {
4685 'F','i','l','e','U','s','a','g','e','=','1',0};
4687 desc = MSI_RecordGetString(rec, 3);
4689 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4690 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4692 if (!driver_file || !setup_file)
4694 ERR("ODBC Driver entry not found!\n");
4695 return ERROR_FUNCTION_FAILED;
4698 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4699 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4700 lstrlenW(usage_fmt) + 1;
4701 driver = msi_alloc(len * sizeof(WCHAR));
4702 if (!driver)
4703 return ERROR_OUTOFMEMORY;
4705 ptr = driver;
4706 lstrcpyW(ptr, desc);
4707 ptr += lstrlenW(ptr) + 1;
4709 sprintfW(ptr, driver_fmt, driver_file->FileName);
4710 ptr += lstrlenW(ptr) + 1;
4712 sprintfW(ptr, setup_fmt, setup_file->FileName);
4713 ptr += lstrlenW(ptr) + 1;
4715 lstrcpyW(ptr, usage_fmt);
4716 ptr += lstrlenW(ptr) + 1;
4717 *ptr = '\0';
4719 driver_path = strdupW(driver_file->TargetPath);
4720 ptr = strrchrW(driver_path, '\\');
4721 if (ptr) *ptr = '\0';
4723 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4724 NULL, ODBC_INSTALL_COMPLETE, &usage))
4726 ERR("Failed to install SQL driver!\n");
4727 r = ERROR_FUNCTION_FAILED;
4730 msi_free(driver);
4731 msi_free(driver_path);
4733 return r;
4736 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4738 MSIPACKAGE *package = param;
4739 LPWSTR translator, translator_path, ptr;
4740 WCHAR outpath[MAX_PATH];
4741 MSIFILE *translator_file, *setup_file;
4742 LPCWSTR desc;
4743 DWORD len, usage;
4744 UINT r = ERROR_SUCCESS;
4746 static const WCHAR translator_fmt[] = {
4747 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4748 static const WCHAR setup_fmt[] = {
4749 'S','e','t','u','p','=','%','s',0};
4751 desc = MSI_RecordGetString(rec, 3);
4753 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4754 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4756 if (!translator_file || !setup_file)
4758 ERR("ODBC Translator entry not found!\n");
4759 return ERROR_FUNCTION_FAILED;
4762 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
4763 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
4764 translator = msi_alloc(len * sizeof(WCHAR));
4765 if (!translator)
4766 return ERROR_OUTOFMEMORY;
4768 ptr = translator;
4769 lstrcpyW(ptr, desc);
4770 ptr += lstrlenW(ptr) + 1;
4772 sprintfW(ptr, translator_fmt, translator_file->FileName);
4773 ptr += lstrlenW(ptr) + 1;
4775 sprintfW(ptr, setup_fmt, setup_file->FileName);
4776 ptr += lstrlenW(ptr) + 1;
4777 *ptr = '\0';
4779 translator_path = strdupW(translator_file->TargetPath);
4780 ptr = strrchrW(translator_path, '\\');
4781 if (ptr) *ptr = '\0';
4783 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
4784 NULL, ODBC_INSTALL_COMPLETE, &usage))
4786 ERR("Failed to install SQL translator!\n");
4787 r = ERROR_FUNCTION_FAILED;
4790 msi_free(translator);
4791 msi_free(translator_path);
4793 return r;
4796 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
4798 LPWSTR attrs;
4799 LPCWSTR desc, driver;
4800 WORD request = ODBC_ADD_SYS_DSN;
4801 INT registration;
4802 DWORD len;
4803 UINT r = ERROR_SUCCESS;
4805 static const WCHAR attrs_fmt[] = {
4806 'D','S','N','=','%','s',0 };
4808 desc = MSI_RecordGetString(rec, 3);
4809 driver = MSI_RecordGetString(rec, 4);
4810 registration = MSI_RecordGetInteger(rec, 5);
4812 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
4813 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
4815 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
4816 attrs = msi_alloc(len * sizeof(WCHAR));
4817 if (!attrs)
4818 return ERROR_OUTOFMEMORY;
4820 sprintfW(attrs, attrs_fmt, desc);
4821 attrs[len - 1] = '\0';
4823 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
4825 ERR("Failed to install SQL data source!\n");
4826 r = ERROR_FUNCTION_FAILED;
4829 msi_free(attrs);
4831 return r;
4834 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
4836 UINT rc;
4837 MSIQUERY *view;
4839 static const WCHAR driver_query[] = {
4840 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4841 'O','D','B','C','D','r','i','v','e','r',0 };
4843 static const WCHAR translator_query[] = {
4844 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4845 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4847 static const WCHAR source_query[] = {
4848 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4849 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4851 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
4852 if (rc != ERROR_SUCCESS)
4853 return ERROR_SUCCESS;
4855 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
4856 msiobj_release(&view->hdr);
4858 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
4859 if (rc != ERROR_SUCCESS)
4860 return ERROR_SUCCESS;
4862 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
4863 msiobj_release(&view->hdr);
4865 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
4866 if (rc != ERROR_SUCCESS)
4867 return ERROR_SUCCESS;
4869 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
4870 msiobj_release(&view->hdr);
4872 return rc;
4875 #define ENV_ACT_SETALWAYS 0x1
4876 #define ENV_ACT_SETABSENT 0x2
4877 #define ENV_ACT_REMOVE 0x4
4878 #define ENV_ACT_REMOVEMATCH 0x8
4880 #define ENV_MOD_MACHINE 0x20000000
4881 #define ENV_MOD_APPEND 0x40000000
4882 #define ENV_MOD_PREFIX 0x80000000
4883 #define ENV_MOD_MASK 0xC0000000
4885 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
4887 static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
4889 LPCWSTR cptr = *name;
4891 static const WCHAR prefix[] = {'[','~',']',0};
4892 static const int prefix_len = 3;
4894 *flags = 0;
4895 while (*cptr)
4897 if (*cptr == '=')
4898 *flags |= ENV_ACT_SETALWAYS;
4899 else if (*cptr == '+')
4900 *flags |= ENV_ACT_SETABSENT;
4901 else if (*cptr == '-')
4902 *flags |= ENV_ACT_REMOVE;
4903 else if (*cptr == '!')
4904 *flags |= ENV_ACT_REMOVEMATCH;
4905 else if (*cptr == '*')
4906 *flags |= ENV_MOD_MACHINE;
4907 else
4908 break;
4910 cptr++;
4911 (*name)++;
4914 if (!*cptr)
4916 ERR("Missing environment variable\n");
4917 return ERROR_FUNCTION_FAILED;
4920 if (*value)
4922 LPCWSTR ptr = *value;
4923 if (!strncmpW(ptr, prefix, prefix_len))
4925 *flags |= ENV_MOD_APPEND;
4926 *value += lstrlenW(prefix);
4928 else if (lstrlenW(*value) >= prefix_len)
4930 ptr += lstrlenW(ptr) - prefix_len;
4931 if (!lstrcmpW(ptr, prefix))
4933 *flags |= ENV_MOD_PREFIX;
4934 /* the "[~]" will be removed by deformat_string */;
4939 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
4940 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
4941 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
4942 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
4944 ERR("Invalid flags: %08x\n", *flags);
4945 return ERROR_FUNCTION_FAILED;
4948 if (!*flags)
4949 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
4951 return ERROR_SUCCESS;
4954 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
4956 MSIPACKAGE *package = param;
4957 LPCWSTR name, value;
4958 LPWSTR data = NULL, newval = NULL;
4959 LPWSTR deformatted = NULL, ptr;
4960 DWORD flags, type, size;
4961 LONG res;
4962 HKEY env = NULL, root;
4963 LPCWSTR environment;
4965 static const WCHAR user_env[] =
4966 {'E','n','v','i','r','o','n','m','e','n','t',0};
4967 static const WCHAR machine_env[] =
4968 {'S','y','s','t','e','m','\\',
4969 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
4970 'C','o','n','t','r','o','l','\\',
4971 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
4972 'E','n','v','i','r','o','n','m','e','n','t',0};
4974 name = MSI_RecordGetString(rec, 2);
4975 value = MSI_RecordGetString(rec, 3);
4977 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
4979 res = env_set_flags(&name, &value, &flags);
4980 if (res != ERROR_SUCCESS)
4981 goto done;
4983 if (value && !deformat_string(package, value, &deformatted))
4985 res = ERROR_OUTOFMEMORY;
4986 goto done;
4989 value = deformatted;
4991 if (flags & ENV_MOD_MACHINE)
4993 environment = machine_env;
4994 root = HKEY_LOCAL_MACHINE;
4996 else
4998 environment = user_env;
4999 root = HKEY_CURRENT_USER;
5002 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5003 KEY_ALL_ACCESS, NULL, &env, NULL);
5004 if (res != ERROR_SUCCESS)
5005 goto done;
5007 if (flags & ENV_ACT_REMOVE)
5008 FIXME("Not removing environment variable on uninstall!\n");
5010 size = 0;
5011 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5012 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
5013 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
5014 goto done;
5016 if (res != ERROR_FILE_NOT_FOUND)
5018 if (flags & ENV_ACT_SETABSENT)
5020 res = ERROR_SUCCESS;
5021 goto done;
5024 data = msi_alloc(size);
5025 if (!data)
5027 RegCloseKey(env);
5028 return ERROR_OUTOFMEMORY;
5031 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5032 if (res != ERROR_SUCCESS)
5033 goto done;
5035 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5037 res = RegDeleteKeyW(env, name);
5038 goto done;
5041 size += (lstrlenW(value) + 1) * sizeof(WCHAR);
5042 newval = msi_alloc(size);
5043 ptr = newval;
5044 if (!newval)
5046 res = ERROR_OUTOFMEMORY;
5047 goto done;
5050 if (!(flags & ENV_MOD_MASK))
5051 lstrcpyW(newval, value);
5052 else
5054 if (flags & ENV_MOD_PREFIX)
5056 lstrcpyW(newval, value);
5057 lstrcatW(newval, szSemiColon);
5058 ptr = newval + lstrlenW(value) + 1;
5061 lstrcpyW(ptr, data);
5063 if (flags & ENV_MOD_APPEND)
5065 lstrcatW(newval, szSemiColon);
5066 lstrcatW(newval, value);
5070 else if (value)
5072 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
5073 newval = msi_alloc(size);
5074 if (!newval)
5076 res = ERROR_OUTOFMEMORY;
5077 goto done;
5080 lstrcpyW(newval, value);
5083 if (newval)
5085 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5086 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
5088 else
5089 res = ERROR_SUCCESS;
5091 done:
5092 if (env) RegCloseKey(env);
5093 msi_free(deformatted);
5094 msi_free(data);
5095 msi_free(newval);
5096 return res;
5099 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5101 UINT rc;
5102 MSIQUERY * view;
5103 static const WCHAR ExecSeqQuery[] =
5104 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5105 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5106 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5107 if (rc != ERROR_SUCCESS)
5108 return ERROR_SUCCESS;
5110 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5111 msiobj_release(&view->hdr);
5113 return rc;
5116 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5118 typedef struct
5120 struct list entry;
5121 LPWSTR sourcename;
5122 LPWSTR destname;
5123 LPWSTR source;
5124 LPWSTR dest;
5125 } FILE_LIST;
5127 static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5129 BOOL ret;
5131 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5132 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5134 WARN("Source or dest is directory, not moving\n");
5135 return FALSE;
5138 if (options == msidbMoveFileOptionsMove)
5140 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5141 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5142 if (!ret)
5144 WARN("MoveFile failed: %d\n", GetLastError());
5145 return FALSE;
5148 else
5150 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5151 ret = CopyFileW(source, dest, FALSE);
5152 if (!ret)
5154 WARN("CopyFile failed: %d\n", GetLastError());
5155 return FALSE;
5159 return TRUE;
5162 static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5164 LPWSTR path, ptr;
5165 DWORD dirlen, pathlen;
5167 ptr = strrchrW(wildcard, '\\');
5168 dirlen = ptr - wildcard + 1;
5170 pathlen = dirlen + lstrlenW(filename) + 1;
5171 path = msi_alloc(pathlen * sizeof(WCHAR));
5173 lstrcpynW(path, wildcard, dirlen + 1);
5174 lstrcatW(path, filename);
5176 return path;
5179 static void free_file_entry(FILE_LIST *file)
5181 msi_free(file->source);
5182 msi_free(file->dest);
5183 msi_free(file);
5186 static void free_list(FILE_LIST *list)
5188 while (!list_empty(&list->entry))
5190 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5192 list_remove(&file->entry);
5193 free_file_entry(file);
5197 static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5199 FILE_LIST *new, *file;
5200 LPWSTR ptr, filename;
5201 DWORD size;
5203 new = msi_alloc_zero(sizeof(FILE_LIST));
5204 if (!new)
5205 return FALSE;
5207 new->source = strdupW(source);
5208 ptr = strrchrW(dest, '\\') + 1;
5209 filename = strrchrW(new->source, '\\') + 1;
5211 new->sourcename = filename;
5213 if (*ptr)
5214 new->destname = ptr;
5215 else
5216 new->destname = new->sourcename;
5218 size = (ptr - dest) + lstrlenW(filename) + 1;
5219 new->dest = msi_alloc(size * sizeof(WCHAR));
5220 if (!new->dest)
5222 free_file_entry(new);
5223 return FALSE;
5226 lstrcpynW(new->dest, dest, ptr - dest + 1);
5227 lstrcatW(new->dest, filename);
5229 if (list_empty(&files->entry))
5231 list_add_head(&files->entry, &new->entry);
5232 return TRUE;
5235 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5237 if (lstrcmpW(source, file->source) < 0)
5239 list_add_before(&file->entry, &new->entry);
5240 return TRUE;
5244 list_add_after(&file->entry, &new->entry);
5245 return TRUE;
5248 static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
5250 WIN32_FIND_DATAW wfd;
5251 HANDLE hfile;
5252 LPWSTR path;
5253 BOOL res;
5254 FILE_LIST files, *file;
5255 DWORD size;
5257 hfile = FindFirstFileW(source, &wfd);
5258 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5260 list_init(&files.entry);
5262 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5264 if (is_dot_dir(wfd.cFileName)) continue;
5266 path = wildcard_to_file(source, wfd.cFileName);
5267 if (!path)
5269 res = FALSE;
5270 goto done;
5273 add_wildcard(&files, path, dest);
5274 msi_free(path);
5277 /* no files match the wildcard */
5278 if (list_empty(&files.entry))
5279 goto done;
5281 /* only the first wildcard match gets renamed to dest */
5282 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5283 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5284 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5285 if (!file->dest)
5287 res = FALSE;
5288 goto done;
5291 /* file->dest may be shorter after the reallocation, so add a NULL
5292 * terminator. This is needed for the call to strrchrW, as there will no
5293 * longer be a NULL terminator within the bounds of the allocation in this case.
5295 file->dest[size - 1] = '\0';
5296 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5298 while (!list_empty(&files.entry))
5300 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5302 msi_move_file(file->source, file->dest, options);
5304 list_remove(&file->entry);
5305 free_file_entry(file);
5308 res = TRUE;
5310 done:
5311 free_list(&files);
5312 FindClose(hfile);
5313 return res;
5316 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5318 MSIPACKAGE *package = param;
5319 MSICOMPONENT *comp;
5320 LPCWSTR sourcename;
5321 LPWSTR destname = NULL;
5322 LPWSTR sourcedir = NULL, destdir = NULL;
5323 LPWSTR source = NULL, dest = NULL;
5324 int options;
5325 DWORD size;
5326 BOOL ret, wildcards;
5328 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5329 if (!comp || !comp->Enabled ||
5330 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5332 TRACE("Component not set for install, not moving file\n");
5333 return ERROR_SUCCESS;
5336 sourcename = MSI_RecordGetString(rec, 3);
5337 options = MSI_RecordGetInteger(rec, 7);
5339 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5340 if (!sourcedir)
5341 goto done;
5343 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5344 if (!destdir)
5345 goto done;
5347 if (!sourcename)
5349 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5350 goto done;
5352 source = strdupW(sourcedir);
5353 if (!source)
5354 goto done;
5356 else
5358 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5359 source = msi_alloc(size * sizeof(WCHAR));
5360 if (!source)
5361 goto done;
5363 lstrcpyW(source, sourcedir);
5364 if (source[lstrlenW(source) - 1] != '\\')
5365 lstrcatW(source, szBackSlash);
5366 lstrcatW(source, sourcename);
5369 wildcards = strchrW(source, '*') || strchrW(source, '?');
5371 if (MSI_RecordIsNull(rec, 4))
5373 if (!wildcards)
5375 destname = strdupW(sourcename);
5376 if (!destname)
5377 goto done;
5380 else
5382 destname = strdupW(MSI_RecordGetString(rec, 4));
5383 if (destname)
5384 reduce_to_longfilename(destname);
5387 size = 0;
5388 if (destname)
5389 size = lstrlenW(destname);
5391 size += lstrlenW(destdir) + 2;
5392 dest = msi_alloc(size * sizeof(WCHAR));
5393 if (!dest)
5394 goto done;
5396 lstrcpyW(dest, destdir);
5397 if (dest[lstrlenW(dest) - 1] != '\\')
5398 lstrcatW(dest, szBackSlash);
5400 if (destname)
5401 lstrcatW(dest, destname);
5403 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5405 ret = CreateDirectoryW(destdir, NULL);
5406 if (!ret)
5408 WARN("CreateDirectory failed: %d\n", GetLastError());
5409 return ERROR_SUCCESS;
5413 if (!wildcards)
5414 msi_move_file(source, dest, options);
5415 else
5416 move_files_wildcard(source, dest, options);
5418 done:
5419 msi_free(sourcedir);
5420 msi_free(destdir);
5421 msi_free(destname);
5422 msi_free(source);
5423 msi_free(dest);
5425 return ERROR_SUCCESS;
5428 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5430 UINT rc;
5431 MSIQUERY *view;
5433 static const WCHAR ExecSeqQuery[] =
5434 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5435 '`','M','o','v','e','F','i','l','e','`',0};
5437 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5438 if (rc != ERROR_SUCCESS)
5439 return ERROR_SUCCESS;
5441 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5442 msiobj_release(&view->hdr);
5444 return rc;
5447 typedef struct tagMSIASSEMBLY
5449 struct list entry;
5450 MSICOMPONENT *component;
5451 MSIFEATURE *feature;
5452 MSIFILE *file;
5453 LPWSTR manifest;
5454 LPWSTR application;
5455 DWORD attributes;
5456 BOOL installed;
5457 } MSIASSEMBLY;
5459 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
5460 DWORD dwReserved);
5461 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
5462 LPVOID pvReserved, HMODULE *phModDll);
5464 static BOOL init_functionpointers(void)
5466 HRESULT hr;
5467 HMODULE hfusion;
5468 HMODULE hmscoree;
5470 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
5472 hmscoree = LoadLibraryA("mscoree.dll");
5473 if (!hmscoree)
5475 WARN("mscoree.dll not available\n");
5476 return FALSE;
5479 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
5480 if (!pLoadLibraryShim)
5482 WARN("LoadLibraryShim not available\n");
5483 FreeLibrary(hmscoree);
5484 return FALSE;
5487 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
5488 if (FAILED(hr))
5490 WARN("fusion.dll not available\n");
5491 FreeLibrary(hmscoree);
5492 return FALSE;
5495 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
5497 FreeLibrary(hmscoree);
5498 return TRUE;
5501 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
5502 LPWSTR path)
5504 IAssemblyCache *cache;
5505 HRESULT hr;
5506 UINT r = ERROR_FUNCTION_FAILED;
5508 TRACE("installing assembly: %s\n", debugstr_w(path));
5510 if (assembly->feature)
5511 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
5513 if (assembly->manifest)
5514 FIXME("Manifest unhandled\n");
5516 if (assembly->application)
5518 FIXME("Assembly should be privately installed\n");
5519 return ERROR_SUCCESS;
5522 if (assembly->attributes == msidbAssemblyAttributesWin32)
5524 FIXME("Win32 assemblies not handled\n");
5525 return ERROR_SUCCESS;
5528 hr = pCreateAssemblyCache(&cache, 0);
5529 if (FAILED(hr))
5530 goto done;
5532 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
5533 if (FAILED(hr))
5534 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
5536 r = ERROR_SUCCESS;
5538 done:
5539 IAssemblyCache_Release(cache);
5540 return r;
5543 typedef struct tagASSEMBLY_LIST
5545 MSIPACKAGE *package;
5546 IAssemblyCache *cache;
5547 struct list *assemblies;
5548 } ASSEMBLY_LIST;
5550 typedef struct tagASSEMBLY_NAME
5552 LPWSTR name;
5553 LPWSTR version;
5554 LPWSTR culture;
5555 LPWSTR pubkeytoken;
5556 } ASSEMBLY_NAME;
5558 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
5560 ASSEMBLY_NAME *asmname = param;
5561 LPCWSTR name = MSI_RecordGetString(rec, 2);
5562 LPWSTR val = msi_dup_record_field(rec, 3);
5564 static const WCHAR Name[] = {'N','a','m','e',0};
5565 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
5566 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
5567 static const WCHAR PublicKeyToken[] = {
5568 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
5570 if (!strcmpiW(name, Name))
5571 asmname->name = val;
5572 else if (!strcmpiW(name, Version))
5573 asmname->version = val;
5574 else if (!strcmpiW(name, Culture))
5575 asmname->culture = val;
5576 else if (!strcmpiW(name, PublicKeyToken))
5577 asmname->pubkeytoken = val;
5578 else
5579 msi_free(val);
5581 return ERROR_SUCCESS;
5584 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
5586 if (!*str)
5588 *size = lstrlenW(append) + 1;
5589 *str = msi_alloc((*size) * sizeof(WCHAR));
5590 lstrcpyW(*str, append);
5591 return;
5594 (*size) += lstrlenW(append);
5595 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
5596 lstrcatW(*str, append);
5599 static BOOL check_assembly_installed(MSIDATABASE *db, IAssemblyCache *cache,
5600 MSICOMPONENT *comp)
5602 ASSEMBLY_INFO asminfo;
5603 ASSEMBLY_NAME name;
5604 MSIQUERY *view;
5605 LPWSTR disp;
5606 DWORD size;
5607 BOOL found;
5608 UINT r;
5610 static const WCHAR separator[] = {',',' ',0};
5611 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
5612 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
5613 static const WCHAR PublicKeyToken[] = {
5614 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
5615 static const WCHAR query[] = {
5616 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5617 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
5618 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
5619 '=','\'','%','s','\'',0};
5621 disp = NULL;
5622 found = FALSE;
5623 ZeroMemory(&name, sizeof(ASSEMBLY_NAME));
5624 ZeroMemory(&asminfo, sizeof(ASSEMBLY_INFO));
5626 r = MSI_OpenQuery(db, &view, query, comp->Component);
5627 if (r != ERROR_SUCCESS)
5628 return ERROR_SUCCESS;
5630 MSI_IterateRecords(view, NULL, parse_assembly_name, &name);
5631 msiobj_release(&view->hdr);
5633 if (!name.name)
5635 ERR("No assembly name specified!\n");
5636 goto done;
5639 append_str(&disp, &size, name.name);
5641 if (name.version)
5643 append_str(&disp, &size, separator);
5644 append_str(&disp, &size, Version);
5645 append_str(&disp, &size, name.version);
5648 if (name.culture)
5650 append_str(&disp, &size, separator);
5651 append_str(&disp, &size, Culture);
5652 append_str(&disp, &size, name.culture);
5655 if (name.pubkeytoken)
5657 append_str(&disp, &size, separator);
5658 append_str(&disp, &size, PublicKeyToken);
5659 append_str(&disp, &size, name.pubkeytoken);
5662 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
5663 IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE,
5664 disp, &asminfo);
5665 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
5667 done:
5668 msi_free(disp);
5669 msi_free(name.name);
5670 msi_free(name.version);
5671 msi_free(name.culture);
5672 msi_free(name.pubkeytoken);
5674 return found;
5677 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
5679 ASSEMBLY_LIST *list = param;
5680 MSIASSEMBLY *assembly;
5682 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
5683 if (!assembly)
5684 return ERROR_OUTOFMEMORY;
5686 assembly->component = get_loaded_component(list->package, MSI_RecordGetString(rec, 1));
5688 if (!assembly->component || !assembly->component->Enabled ||
5689 !(assembly->component->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5691 TRACE("Component not set for install, not publishing assembly\n");
5692 msi_free(assembly);
5693 return ERROR_SUCCESS;
5696 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
5697 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
5699 if (!assembly->file)
5701 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
5702 return ERROR_FUNCTION_FAILED;
5705 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
5706 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
5707 assembly->attributes = MSI_RecordGetInteger(rec, 5);
5709 if (assembly->application)
5711 WCHAR version[24];
5712 DWORD size = sizeof(version)/sizeof(WCHAR);
5714 /* FIXME: we should probably check the manifest file here */
5716 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
5717 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
5719 assembly->installed = TRUE;
5722 else
5723 assembly->installed = check_assembly_installed(list->package->db,
5724 list->cache,
5725 assembly->component);
5727 list_add_head(list->assemblies, &assembly->entry);
5728 return ERROR_SUCCESS;
5731 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
5733 IAssemblyCache *cache = NULL;
5734 ASSEMBLY_LIST list;
5735 MSIQUERY *view;
5736 HRESULT hr;
5737 UINT r;
5739 static const WCHAR query[] =
5740 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5741 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
5743 r = MSI_DatabaseOpenViewW(package->db, query, &view);
5744 if (r != ERROR_SUCCESS)
5745 return ERROR_SUCCESS;
5747 hr = pCreateAssemblyCache(&cache, 0);
5748 if (FAILED(hr))
5749 return ERROR_FUNCTION_FAILED;
5751 list.package = package;
5752 list.cache = cache;
5753 list.assemblies = assemblies;
5755 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
5756 msiobj_release(&view->hdr);
5758 IAssemblyCache_Release(cache);
5760 return r;
5763 static void free_assemblies(struct list *assemblies)
5765 struct list *item, *cursor;
5767 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
5769 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
5771 list_remove(&assembly->entry);
5772 msi_free(assembly->application);
5773 msi_free(assembly->manifest);
5774 msi_free(assembly);
5778 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
5780 MSIASSEMBLY *assembly;
5782 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
5784 if (!lstrcmpW(assembly->file->File, file))
5786 *out = assembly;
5787 return TRUE;
5791 return FALSE;
5794 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
5795 LPWSTR *path, DWORD *attrs, PVOID user)
5797 MSIASSEMBLY *assembly;
5798 WCHAR temppath[MAX_PATH];
5799 struct list *assemblies = user;
5800 UINT r;
5802 if (!find_assembly(assemblies, file, &assembly))
5803 return FALSE;
5805 GetTempPathW(MAX_PATH, temppath);
5806 PathAddBackslashW(temppath);
5807 lstrcatW(temppath, assembly->file->FileName);
5809 if (action == MSICABEXTRACT_BEGINEXTRACT)
5811 if (assembly->installed)
5812 return FALSE;
5814 *path = strdupW(temppath);
5815 *attrs = assembly->file->Attributes;
5817 else if (action == MSICABEXTRACT_FILEEXTRACTED)
5819 assembly->installed = TRUE;
5821 r = install_assembly(package, assembly, temppath);
5822 if (r != ERROR_SUCCESS)
5823 ERR("Failed to install assembly\n");
5826 return TRUE;
5829 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
5831 UINT r;
5832 struct list assemblies = LIST_INIT(assemblies);
5833 MSIASSEMBLY *assembly;
5834 MSIMEDIAINFO *mi;
5836 if (!init_functionpointers() || !pCreateAssemblyCache)
5837 return ERROR_FUNCTION_FAILED;
5839 r = load_assemblies(package, &assemblies);
5840 if (r != ERROR_SUCCESS)
5841 goto done;
5843 if (list_empty(&assemblies))
5844 goto done;
5846 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
5847 if (!mi)
5849 r = ERROR_OUTOFMEMORY;
5850 goto done;
5853 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
5855 if (assembly->installed && !mi->is_continuous)
5856 continue;
5858 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
5859 (assembly->file->IsCompressed && !mi->is_extracted))
5861 MSICABDATA data;
5863 r = ready_media(package, assembly->file, mi);
5864 if (r != ERROR_SUCCESS)
5866 ERR("Failed to ready media\n");
5867 break;
5870 data.mi = mi;
5871 data.package = package;
5872 data.cb = installassembly_cb;
5873 data.user = &assemblies;
5875 if (assembly->file->IsCompressed &&
5876 !msi_cabextract(package, mi, &data))
5878 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
5879 r = ERROR_FUNCTION_FAILED;
5880 break;
5884 if (!assembly->file->IsCompressed)
5886 LPWSTR source = resolve_file_source(package, assembly->file);
5888 r = install_assembly(package, assembly, source);
5889 if (r != ERROR_SUCCESS)
5890 ERR("Failed to install assembly\n");
5892 msi_free(source);
5895 /* FIXME: write Installer assembly reg values */
5898 done:
5899 free_assemblies(&assemblies);
5900 return r;
5903 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
5904 LPCSTR action, LPCWSTR table )
5906 static const WCHAR query[] = {
5907 'S','E','L','E','C','T',' ','*',' ',
5908 'F','R','O','M',' ','`','%','s','`',0 };
5909 MSIQUERY *view = NULL;
5910 DWORD count = 0;
5911 UINT r;
5913 r = MSI_OpenQuery( package->db, &view, query, table );
5914 if (r == ERROR_SUCCESS)
5916 r = MSI_IterateRecords(view, &count, NULL, package);
5917 msiobj_release(&view->hdr);
5920 if (count)
5921 FIXME("%s -> %u ignored %s table values\n",
5922 action, count, debugstr_w(table));
5924 return ERROR_SUCCESS;
5927 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
5929 TRACE("%p\n", package);
5930 return ERROR_SUCCESS;
5933 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
5935 static const WCHAR table[] =
5936 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
5937 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
5940 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
5942 static const WCHAR table[] = { 'P','a','t','c','h',0 };
5943 return msi_unimplemented_action_stub( package, "PatchFiles", table );
5946 static UINT ACTION_BindImage( MSIPACKAGE *package )
5948 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
5949 return msi_unimplemented_action_stub( package, "BindImage", table );
5952 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
5954 static const WCHAR table[] = {
5955 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
5956 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
5959 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
5961 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5962 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
5965 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
5967 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
5968 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
5971 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5973 static const WCHAR table[] = {
5974 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5975 return msi_unimplemented_action_stub( package, "DeleteServices", table );
5977 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
5979 static const WCHAR table[] = {
5980 'P','r','o','d','u','c','t','I','D',0 };
5981 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
5984 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
5986 static const WCHAR table[] = {
5987 'E','n','v','i','r','o','n','m','e','n','t',0 };
5988 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
5991 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
5993 static const WCHAR table[] = {
5994 'M','s','i','A','s','s','e','m','b','l','y',0 };
5995 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
5998 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
6000 static const WCHAR table[] = { 'F','o','n','t',0 };
6001 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
6004 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6006 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6007 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6010 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6012 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6013 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6016 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6018 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6019 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6022 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6024 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6025 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6028 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
6030 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6031 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
6034 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6036 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6037 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6040 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
6042 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6043 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
6046 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6048 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6049 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
6052 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
6054 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6055 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
6058 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
6060 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
6061 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
6064 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
6066 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6067 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
6070 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6072 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6073 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6076 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6078 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6079 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6082 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6084 static const WCHAR table[] = { 'M','I','M','E',0 };
6085 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6088 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6090 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6091 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6094 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
6096 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
6097 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
6100 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6102 static const struct
6104 const WCHAR *action;
6105 UINT (*handler)(MSIPACKAGE *);
6107 StandardActions[] =
6109 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6110 { szAppSearch, ACTION_AppSearch },
6111 { szBindImage, ACTION_BindImage },
6112 { szCCPSearch, ACTION_CCPSearch },
6113 { szCostFinalize, ACTION_CostFinalize },
6114 { szCostInitialize, ACTION_CostInitialize },
6115 { szCreateFolders, ACTION_CreateFolders },
6116 { szCreateShortcuts, ACTION_CreateShortcuts },
6117 { szDeleteServices, ACTION_DeleteServices },
6118 { szDisableRollback, NULL },
6119 { szDuplicateFiles, ACTION_DuplicateFiles },
6120 { szExecuteAction, ACTION_ExecuteAction },
6121 { szFileCost, ACTION_FileCost },
6122 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6123 { szForceReboot, ACTION_ForceReboot },
6124 { szInstallAdminPackage, NULL },
6125 { szInstallExecute, ACTION_InstallExecute },
6126 { szInstallExecuteAgain, ACTION_InstallExecute },
6127 { szInstallFiles, ACTION_InstallFiles},
6128 { szInstallFinalize, ACTION_InstallFinalize },
6129 { szInstallInitialize, ACTION_InstallInitialize },
6130 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6131 { szInstallValidate, ACTION_InstallValidate },
6132 { szIsolateComponents, ACTION_IsolateComponents },
6133 { szLaunchConditions, ACTION_LaunchConditions },
6134 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6135 { szMoveFiles, ACTION_MoveFiles },
6136 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6137 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6138 { szInstallODBC, ACTION_InstallODBC },
6139 { szInstallServices, ACTION_InstallServices },
6140 { szPatchFiles, ACTION_PatchFiles },
6141 { szProcessComponents, ACTION_ProcessComponents },
6142 { szPublishComponents, ACTION_PublishComponents },
6143 { szPublishFeatures, ACTION_PublishFeatures },
6144 { szPublishProduct, ACTION_PublishProduct },
6145 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6146 { szRegisterComPlus, ACTION_RegisterComPlus},
6147 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6148 { szRegisterFonts, ACTION_RegisterFonts },
6149 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6150 { szRegisterProduct, ACTION_RegisterProduct },
6151 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6152 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6153 { szRegisterUser, ACTION_RegisterUser },
6154 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6155 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6156 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6157 { szRemoveFiles, ACTION_RemoveFiles },
6158 { szRemoveFolders, ACTION_RemoveFolders },
6159 { szRemoveIniValues, ACTION_RemoveIniValues },
6160 { szRemoveODBC, ACTION_RemoveODBC },
6161 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6162 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6163 { szResolveSource, ACTION_ResolveSource },
6164 { szRMCCPSearch, ACTION_RMCCPSearch },
6165 { szScheduleReboot, NULL },
6166 { szSelfRegModules, ACTION_SelfRegModules },
6167 { szSelfUnregModules, ACTION_SelfUnregModules },
6168 { szSetODBCFolders, NULL },
6169 { szStartServices, ACTION_StartServices },
6170 { szStopServices, ACTION_StopServices },
6171 { szUnpublishComponents, ACTION_UnpublishComponents },
6172 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6173 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6174 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6175 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6176 { szUnregisterFonts, ACTION_UnregisterFonts },
6177 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6178 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6179 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6180 { szValidateProductID, ACTION_ValidateProductID },
6181 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6182 { szWriteIniValues, ACTION_WriteIniValues },
6183 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6184 { NULL, NULL },
6187 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
6188 UINT* rc, BOOL force )
6190 BOOL ret = FALSE;
6191 BOOL run = force;
6192 int i;
6194 if (!run && !package->script->CurrentlyScripting)
6195 run = TRUE;
6197 if (!run)
6199 if (strcmpW(action,szInstallFinalize) == 0 ||
6200 strcmpW(action,szInstallExecute) == 0 ||
6201 strcmpW(action,szInstallExecuteAgain) == 0)
6202 run = TRUE;
6205 i = 0;
6206 while (StandardActions[i].action != NULL)
6208 if (strcmpW(StandardActions[i].action, action)==0)
6210 if (!run)
6212 ui_actioninfo(package, action, TRUE, 0);
6213 *rc = schedule_action(package,INSTALL_SCRIPT,action);
6214 ui_actioninfo(package, action, FALSE, *rc);
6216 else
6218 ui_actionstart(package, action);
6219 if (StandardActions[i].handler)
6221 *rc = StandardActions[i].handler(package);
6223 else
6225 FIXME("unhandled standard action %s\n",debugstr_w(action));
6226 *rc = ERROR_SUCCESS;
6229 ret = TRUE;
6230 break;
6232 i++;
6234 return ret;
6237 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
6239 UINT rc = ERROR_SUCCESS;
6240 BOOL handled;
6242 TRACE("Performing action (%s)\n", debugstr_w(action));
6244 handled = ACTION_HandleStandardAction(package, action, &rc, force);
6246 if (!handled)
6247 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
6249 if (!handled)
6251 WARN("unhandled msi action %s\n", debugstr_w(action));
6252 rc = ERROR_FUNCTION_NOT_CALLED;
6255 return rc;
6258 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
6260 UINT rc = ERROR_SUCCESS;
6261 BOOL handled = FALSE;
6263 TRACE("Performing action (%s)\n", debugstr_w(action));
6265 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
6267 if (!handled)
6268 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
6270 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
6271 handled = TRUE;
6273 if (!handled)
6275 WARN("unhandled msi action %s\n", debugstr_w(action));
6276 rc = ERROR_FUNCTION_NOT_CALLED;
6279 return rc;
6282 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
6284 UINT rc = ERROR_SUCCESS;
6285 MSIRECORD *row;
6287 static const WCHAR ExecSeqQuery[] =
6288 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6289 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
6290 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
6291 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
6292 static const WCHAR UISeqQuery[] =
6293 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6294 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
6295 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
6296 ' ', '=',' ','%','i',0};
6298 if (needs_ui_sequence(package))
6299 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
6300 else
6301 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
6303 if (row)
6305 LPCWSTR action, cond;
6307 TRACE("Running the actions\n");
6309 /* check conditions */
6310 cond = MSI_RecordGetString(row, 2);
6312 /* this is a hack to skip errors in the condition code */
6313 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
6315 msiobj_release(&row->hdr);
6316 return ERROR_SUCCESS;
6319 action = MSI_RecordGetString(row, 1);
6320 if (!action)
6322 ERR("failed to fetch action\n");
6323 msiobj_release(&row->hdr);
6324 return ERROR_FUNCTION_FAILED;
6327 if (needs_ui_sequence(package))
6328 rc = ACTION_PerformUIAction(package, action, -1);
6329 else
6330 rc = ACTION_PerformAction(package, action, -1, FALSE);
6332 msiobj_release(&row->hdr);
6335 return rc;
6338 /****************************************************
6339 * TOP level entry points
6340 *****************************************************/
6342 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
6343 LPCWSTR szCommandLine )
6345 UINT rc;
6346 BOOL ui_exists;
6348 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
6349 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
6351 MSI_SetPropertyW(package, szAction, szInstall);
6353 package->script->InWhatSequence = SEQUENCE_INSTALL;
6355 if (szPackagePath)
6357 LPWSTR p, dir;
6358 LPCWSTR file;
6360 dir = strdupW(szPackagePath);
6361 p = strrchrW(dir, '\\');
6362 if (p)
6364 *(++p) = 0;
6365 file = szPackagePath + (p - dir);
6367 else
6369 msi_free(dir);
6370 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
6371 GetCurrentDirectoryW(MAX_PATH, dir);
6372 lstrcatW(dir, szBackSlash);
6373 file = szPackagePath;
6376 msi_free( package->PackagePath );
6377 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
6378 if (!package->PackagePath)
6380 msi_free(dir);
6381 return ERROR_OUTOFMEMORY;
6384 lstrcpyW(package->PackagePath, dir);
6385 lstrcatW(package->PackagePath, file);
6386 msi_free(dir);
6388 msi_set_sourcedir_props(package, FALSE);
6391 msi_parse_command_line( package, szCommandLine, FALSE );
6393 msi_apply_transforms( package );
6394 msi_apply_patches( package );
6396 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
6398 TRACE("setting reinstall property\n");
6399 MSI_SetPropertyW( package, szReinstall, szAll );
6402 /* properties may have been added by a transform */
6403 msi_clone_properties( package );
6404 msi_set_context( package );
6406 if (needs_ui_sequence( package))
6408 package->script->InWhatSequence |= SEQUENCE_UI;
6409 rc = ACTION_ProcessUISequence(package);
6410 ui_exists = ui_sequence_exists(package);
6411 if (rc == ERROR_SUCCESS || !ui_exists)
6413 package->script->InWhatSequence |= SEQUENCE_EXEC;
6414 rc = ACTION_ProcessExecSequence(package, ui_exists);
6417 else
6418 rc = ACTION_ProcessExecSequence(package, FALSE);
6420 package->script->CurrentlyScripting = FALSE;
6422 /* process the ending type action */
6423 if (rc == ERROR_SUCCESS)
6424 ACTION_PerformActionSequence(package, -1);
6425 else if (rc == ERROR_INSTALL_USEREXIT)
6426 ACTION_PerformActionSequence(package, -2);
6427 else if (rc == ERROR_INSTALL_SUSPEND)
6428 ACTION_PerformActionSequence(package, -4);
6429 else /* failed */
6430 ACTION_PerformActionSequence(package, -3);
6432 /* finish up running custom actions */
6433 ACTION_FinishCustomActions(package);
6435 if (rc == ERROR_SUCCESS && package->need_reboot)
6436 return ERROR_SUCCESS_REBOOT_REQUIRED;
6438 return rc;