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