msi: Implement the DeleteServices standard action.
[wine.git] / dlls / msi / action.c
blob46d0f7eef5219032c56267cbd380ffa2c3d20d95
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "winreg.h"
29 #include "winsvc.h"
30 #include "odbcinst.h"
31 #include "wine/debug.h"
32 #include "msidefs.h"
33 #include "msipriv.h"
34 #include "winuser.h"
35 #include "shlobj.h"
36 #include "objbase.h"
37 #include "mscoree.h"
38 #include "fusion.h"
39 #include "shlwapi.h"
40 #include "wine/unicode.h"
41 #include "winver.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
49 * consts and values used
51 static const WCHAR c_colon[] = {'C',':','\\',0};
53 static const WCHAR szCreateFolders[] =
54 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
55 static const WCHAR szCostFinalize[] =
56 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
57 static const WCHAR szWriteRegistryValues[] =
58 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
59 static const WCHAR szCostInitialize[] =
60 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
61 static const WCHAR szFileCost[] =
62 {'F','i','l','e','C','o','s','t',0};
63 static const WCHAR szInstallInitialize[] =
64 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
65 static const WCHAR szInstallValidate[] =
66 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
67 static const WCHAR szLaunchConditions[] =
68 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
69 static const WCHAR szProcessComponents[] =
70 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
71 static const WCHAR szRegisterTypeLibraries[] =
72 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
73 static const WCHAR szCreateShortcuts[] =
74 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
75 static const WCHAR szPublishProduct[] =
76 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
77 static const WCHAR szWriteIniValues[] =
78 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
79 static const WCHAR szSelfRegModules[] =
80 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
81 static const WCHAR szPublishFeatures[] =
82 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
83 static const WCHAR szRegisterProduct[] =
84 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
85 static const WCHAR szInstallExecute[] =
86 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
87 static const WCHAR szInstallExecuteAgain[] =
88 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
89 static const WCHAR szInstallFinalize[] =
90 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
91 static const WCHAR szForceReboot[] =
92 {'F','o','r','c','e','R','e','b','o','o','t',0};
93 static const WCHAR szResolveSource[] =
94 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
95 static const WCHAR szAppSearch[] =
96 {'A','p','p','S','e','a','r','c','h',0};
97 static const WCHAR szAllocateRegistrySpace[] =
98 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
99 static const WCHAR szBindImage[] =
100 {'B','i','n','d','I','m','a','g','e',0};
101 static const WCHAR szCCPSearch[] =
102 {'C','C','P','S','e','a','r','c','h',0};
103 static const WCHAR szDeleteServices[] =
104 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
105 static const WCHAR szDisableRollback[] =
106 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
107 static const WCHAR szExecuteAction[] =
108 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
109 static const WCHAR szInstallAdminPackage[] =
110 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
111 static const WCHAR szInstallSFPCatalogFile[] =
112 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
113 static const WCHAR szIsolateComponents[] =
114 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
115 static const WCHAR szMigrateFeatureStates[] =
116 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
117 static const WCHAR szMoveFiles[] =
118 {'M','o','v','e','F','i','l','e','s',0};
119 static const WCHAR szMsiPublishAssemblies[] =
120 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
121 static const WCHAR szMsiUnpublishAssemblies[] =
122 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
123 static const WCHAR szInstallODBC[] =
124 {'I','n','s','t','a','l','l','O','D','B','C',0};
125 static const WCHAR szInstallServices[] =
126 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szPatchFiles[] =
128 {'P','a','t','c','h','F','i','l','e','s',0};
129 static const WCHAR szPublishComponents[] =
130 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
131 static const WCHAR szRegisterComPlus[] =
132 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
133 static const WCHAR szRegisterFonts[] =
134 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
135 static const WCHAR szRegisterUser[] =
136 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
137 static const WCHAR szRemoveDuplicateFiles[] =
138 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
139 static const WCHAR szRemoveEnvironmentStrings[] =
140 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
141 static const WCHAR szRemoveExistingProducts[] =
142 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
143 static const WCHAR szRemoveFolders[] =
144 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
145 static const WCHAR szRemoveIniValues[] =
146 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
147 static const WCHAR szRemoveODBC[] =
148 {'R','e','m','o','v','e','O','D','B','C',0};
149 static const WCHAR szRemoveRegistryValues[] =
150 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
151 static const WCHAR szRemoveShortcuts[] =
152 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
153 static const WCHAR szRMCCPSearch[] =
154 {'R','M','C','C','P','S','e','a','r','c','h',0};
155 static const WCHAR szScheduleReboot[] =
156 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
157 static const WCHAR szSelfUnregModules[] =
158 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
159 static const WCHAR szSetODBCFolders[] =
160 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
161 static const WCHAR szStartServices[] =
162 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
163 static const WCHAR szStopServices[] =
164 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
165 static const WCHAR szUnpublishComponents[] =
166 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
167 static const WCHAR szUnpublishFeatures[] =
168 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
169 static const WCHAR szUnregisterClassInfo[] =
170 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
171 static const WCHAR szUnregisterComPlus[] =
172 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
173 static const WCHAR szUnregisterExtensionInfo[] =
174 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
175 static const WCHAR szUnregisterFonts[] =
176 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
177 static const WCHAR szUnregisterMIMEInfo[] =
178 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
179 static const WCHAR szUnregisterProgIdInfo[] =
180 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
181 static const WCHAR szUnregisterTypeLibraries[] =
182 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
183 static const WCHAR szValidateProductID[] =
184 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
185 static const WCHAR szWriteEnvironmentStrings[] =
186 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
188 /********************************************************
189 * helper functions
190 ********************************************************/
192 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
194 static const WCHAR Query_t[] =
195 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
196 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
197 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
198 ' ','\'','%','s','\'',0};
199 MSIRECORD * row;
201 row = MSI_QueryGetRecord( package->db, Query_t, action );
202 if (!row)
203 return;
204 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
205 msiobj_release(&row->hdr);
208 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
209 UINT rc)
211 MSIRECORD * row;
212 static const WCHAR template_s[]=
213 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
214 '%','s', '.',0};
215 static const WCHAR template_e[]=
216 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
217 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
218 '%','i','.',0};
219 static const WCHAR format[] =
220 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
221 WCHAR message[1024];
222 WCHAR timet[0x100];
224 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
225 if (start)
226 sprintfW(message,template_s,timet,action);
227 else
228 sprintfW(message,template_e,timet,action,rc);
230 row = MSI_CreateRecord(1);
231 MSI_RecordSetStringW(row,1,message);
233 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
234 msiobj_release(&row->hdr);
237 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
238 BOOL preserve_case )
240 LPCWSTR ptr,ptr2;
241 BOOL quote;
242 DWORD len;
243 LPWSTR prop = NULL, val = NULL;
245 if (!szCommandLine)
246 return ERROR_SUCCESS;
248 ptr = szCommandLine;
250 while (*ptr)
252 if (*ptr==' ')
254 ptr++;
255 continue;
258 TRACE("Looking at %s\n",debugstr_w(ptr));
260 ptr2 = strchrW(ptr,'=');
261 if (!ptr2)
263 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
264 break;
267 quote = FALSE;
269 len = ptr2-ptr;
270 prop = msi_alloc((len+1)*sizeof(WCHAR));
271 memcpy(prop,ptr,len*sizeof(WCHAR));
272 prop[len]=0;
274 if (!preserve_case)
275 struprW(prop);
277 ptr2++;
279 len = 0;
280 ptr = ptr2;
281 while (*ptr && (quote || (!quote && *ptr!=' ')))
283 if (*ptr == '"')
284 quote = !quote;
285 ptr++;
286 len++;
289 if (*ptr2=='"')
291 ptr2++;
292 len -= 2;
294 val = msi_alloc((len+1)*sizeof(WCHAR));
295 memcpy(val,ptr2,len*sizeof(WCHAR));
296 val[len] = 0;
298 if (lstrlenW(prop) > 0)
300 TRACE("Found commandline property (%s) = (%s)\n",
301 debugstr_w(prop), debugstr_w(val));
302 MSI_SetPropertyW(package,prop,val);
304 msi_free(val);
305 msi_free(prop);
308 return ERROR_SUCCESS;
312 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
314 LPCWSTR pc;
315 LPWSTR p, *ret = NULL;
316 UINT count = 0;
318 if (!str)
319 return ret;
321 /* count the number of substrings */
322 for ( pc = str, count = 0; pc; count++ )
324 pc = strchrW( pc, sep );
325 if (pc)
326 pc++;
329 /* allocate space for an array of substring pointers and the substrings */
330 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
331 (lstrlenW(str)+1) * sizeof(WCHAR) );
332 if (!ret)
333 return ret;
335 /* copy the string and set the pointers */
336 p = (LPWSTR) &ret[count+1];
337 lstrcpyW( p, str );
338 for( count = 0; (ret[count] = p); count++ )
340 p = strchrW( p, sep );
341 if (p)
342 *p++ = 0;
345 return ret;
348 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
350 static const WCHAR szSystemLanguageID[] =
351 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
353 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
354 UINT ret = ERROR_FUNCTION_FAILED;
356 prod_code = msi_dup_property( package, szProductCode );
357 patch_product = msi_get_suminfo_product( patch );
359 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
361 if ( strstrW( patch_product, prod_code ) )
363 MSISUMMARYINFO *si;
364 const WCHAR *p;
366 si = MSI_GetSummaryInformationW( patch, 0 );
367 if (!si)
369 ERR("no summary information!\n");
370 goto end;
373 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
374 if (!template)
376 ERR("no template property!\n");
377 msiobj_release( &si->hdr );
378 goto end;
381 if (!template[0])
383 ret = ERROR_SUCCESS;
384 msiobj_release( &si->hdr );
385 goto end;
388 langid = msi_dup_property( package, szSystemLanguageID );
389 if (!langid)
391 msiobj_release( &si->hdr );
392 goto end;
395 p = strchrW( template, ';' );
396 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
398 TRACE("applicable transform\n");
399 ret = ERROR_SUCCESS;
402 /* FIXME: check platform */
404 msiobj_release( &si->hdr );
407 end:
408 msi_free( patch_product );
409 msi_free( prod_code );
410 msi_free( template );
411 msi_free( langid );
413 return ret;
416 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
417 MSIDATABASE *patch_db, LPCWSTR name )
419 UINT ret = ERROR_FUNCTION_FAILED;
420 IStorage *stg = NULL;
421 HRESULT r;
423 TRACE("%p %s\n", package, debugstr_w(name) );
425 if (*name++ != ':')
427 ERR("expected a colon in %s\n", debugstr_w(name));
428 return ERROR_FUNCTION_FAILED;
431 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
432 if (SUCCEEDED(r))
434 ret = msi_check_transform_applicable( package, stg );
435 if (ret == ERROR_SUCCESS)
436 msi_table_apply_transform( package->db, stg );
437 else
438 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
439 IStorage_Release( stg );
441 else
442 ERR("failed to open substorage %s\n", debugstr_w(name));
444 return ERROR_SUCCESS;
447 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
449 LPWSTR guid_list, *guids, product_code;
450 UINT i, ret = ERROR_FUNCTION_FAILED;
452 product_code = msi_dup_property( package, szProductCode );
453 if (!product_code)
455 /* FIXME: the property ProductCode should be written into the DB somewhere */
456 ERR("no product code to check\n");
457 return ERROR_SUCCESS;
460 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
461 guids = msi_split_string( guid_list, ';' );
462 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
464 if (!lstrcmpW( guids[i], product_code ))
465 ret = ERROR_SUCCESS;
467 msi_free( guids );
468 msi_free( guid_list );
469 msi_free( product_code );
471 return ret;
474 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
476 MSIQUERY *view;
477 MSIRECORD *rec = NULL;
478 LPWSTR patch;
479 LPCWSTR prop;
480 UINT r;
482 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
483 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
484 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
485 '`','S','o','u','r','c','e','`',' ','I','S',' ',
486 'N','O','T',' ','N','U','L','L',0};
488 r = MSI_DatabaseOpenViewW(package->db, query, &view);
489 if (r != ERROR_SUCCESS)
490 return r;
492 r = MSI_ViewExecute(view, 0);
493 if (r != ERROR_SUCCESS)
494 goto done;
496 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
498 prop = MSI_RecordGetString(rec, 1);
499 patch = msi_dup_property(package, szPatch);
500 MSI_SetPropertyW(package, prop, patch);
501 msi_free(patch);
504 done:
505 if (rec) msiobj_release(&rec->hdr);
506 msiobj_release(&view->hdr);
508 return r;
511 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
513 MSISUMMARYINFO *si;
514 LPWSTR str, *substorage;
515 UINT i, r = ERROR_SUCCESS;
517 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
518 if (!si)
519 return ERROR_FUNCTION_FAILED;
521 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
523 TRACE("Patch not applicable\n");
524 return ERROR_SUCCESS;
527 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
528 if (!package->patch)
529 return ERROR_OUTOFMEMORY;
531 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
532 if (!package->patch->patchcode)
533 return ERROR_OUTOFMEMORY;
535 /* enumerate the substorage */
536 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
537 package->patch->transforms = str;
539 substorage = msi_split_string( str, ';' );
540 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
541 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
543 msi_free( substorage );
544 msiobj_release( &si->hdr );
546 msi_set_media_source_prop(package);
548 return r;
551 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
553 MSIDATABASE *patch_db = NULL;
554 UINT r;
556 TRACE("%p %s\n", package, debugstr_w( file ) );
558 /* FIXME:
559 * We probably want to make sure we only open a patch collection here.
560 * Patch collections (.msp) and databases (.msi) have different GUIDs
561 * but currently MSI_OpenDatabaseW will accept both.
563 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
564 if ( r != ERROR_SUCCESS )
566 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
567 return r;
570 msi_parse_patch_summary( package, patch_db );
573 * There might be a CAB file in the patch package,
574 * so append it to the list of storage to search for streams.
576 append_storage_to_db( package->db, patch_db->storage );
578 msiobj_release( &patch_db->hdr );
580 return ERROR_SUCCESS;
583 /* get the PATCH property, and apply all the patches it specifies */
584 static UINT msi_apply_patches( MSIPACKAGE *package )
586 LPWSTR patch_list, *patches;
587 UINT i, r = ERROR_SUCCESS;
589 patch_list = msi_dup_property( package, szPatch );
591 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
593 patches = msi_split_string( patch_list, ';' );
594 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
595 r = msi_apply_patch_package( package, patches[i] );
597 msi_free( patches );
598 msi_free( patch_list );
600 return r;
603 static UINT msi_apply_transforms( MSIPACKAGE *package )
605 static const WCHAR szTransforms[] = {
606 'T','R','A','N','S','F','O','R','M','S',0 };
607 LPWSTR xform_list, *xforms;
608 UINT i, r = ERROR_SUCCESS;
610 xform_list = msi_dup_property( package, szTransforms );
611 xforms = msi_split_string( xform_list, ';' );
613 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
615 if (xforms[i][0] == ':')
616 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
617 else
618 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
621 msi_free( xforms );
622 msi_free( xform_list );
624 return r;
627 static BOOL ui_sequence_exists( MSIPACKAGE *package )
629 MSIQUERY *view;
630 UINT rc;
632 static const WCHAR ExecSeqQuery [] =
633 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
634 '`','I','n','s','t','a','l','l',
635 'U','I','S','e','q','u','e','n','c','e','`',
636 ' ','W','H','E','R','E',' ',
637 '`','S','e','q','u','e','n','c','e','`',' ',
638 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
639 '`','S','e','q','u','e','n','c','e','`',0};
641 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
642 if (rc == ERROR_SUCCESS)
644 msiobj_release(&view->hdr);
645 return TRUE;
648 return FALSE;
651 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
653 LPWSTR p, db;
654 LPWSTR source, check;
655 DWORD len;
657 static const WCHAR szOriginalDatabase[] =
658 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
660 db = msi_dup_property( package, szOriginalDatabase );
661 if (!db)
662 return ERROR_OUTOFMEMORY;
664 p = strrchrW( db, '\\' );
665 if (!p)
667 p = strrchrW( db, '/' );
668 if (!p)
670 msi_free(db);
671 return ERROR_SUCCESS;
675 len = p - db + 2;
676 source = msi_alloc( len * sizeof(WCHAR) );
677 lstrcpynW( source, db, len );
679 check = msi_dup_property( package, cszSourceDir );
680 if (!check || replace)
681 MSI_SetPropertyW( package, cszSourceDir, source );
683 msi_free( check );
685 check = msi_dup_property( package, cszSOURCEDIR );
686 if (!check || replace)
687 MSI_SetPropertyW( package, cszSOURCEDIR, source );
689 msi_free( check );
690 msi_free( source );
691 msi_free( db );
693 return ERROR_SUCCESS;
696 static BOOL needs_ui_sequence(MSIPACKAGE *package)
698 INT level = msi_get_property_int(package, szUILevel, 0);
699 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
702 static UINT msi_set_context(MSIPACKAGE *package)
704 WCHAR val[10];
705 DWORD sz = 10;
706 DWORD num;
707 UINT r;
709 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
711 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
712 if (r == ERROR_SUCCESS)
714 num = atolW(val);
715 if (num == 1 || num == 2)
716 package->Context = MSIINSTALLCONTEXT_MACHINE;
719 return ERROR_SUCCESS;
722 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
724 UINT rc;
725 LPCWSTR cond, action;
726 MSIPACKAGE *package = param;
728 action = MSI_RecordGetString(row,1);
729 if (!action)
731 ERR("Error is retrieving action name\n");
732 return ERROR_FUNCTION_FAILED;
735 /* check conditions */
736 cond = MSI_RecordGetString(row,2);
738 /* this is a hack to skip errors in the condition code */
739 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
741 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
742 return ERROR_SUCCESS;
745 if (needs_ui_sequence(package))
746 rc = ACTION_PerformUIAction(package, action, -1);
747 else
748 rc = ACTION_PerformAction(package, action, -1, FALSE);
750 msi_dialog_check_messages( NULL );
752 if (package->CurrentInstallState != ERROR_SUCCESS)
753 rc = package->CurrentInstallState;
755 if (rc == ERROR_FUNCTION_NOT_CALLED)
756 rc = ERROR_SUCCESS;
758 if (rc != ERROR_SUCCESS)
759 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
761 return rc;
764 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
766 MSIQUERY * view;
767 UINT r;
768 static const WCHAR query[] =
769 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
770 '`','%','s','`',
771 ' ','W','H','E','R','E',' ',
772 '`','S','e','q','u','e','n','c','e','`',' ',
773 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
774 '`','S','e','q','u','e','n','c','e','`',0};
776 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
778 r = MSI_OpenQuery( package->db, &view, query, szTable );
779 if (r == ERROR_SUCCESS)
781 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
782 msiobj_release(&view->hdr);
785 return r;
788 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
790 MSIQUERY * view;
791 UINT rc;
792 static const WCHAR ExecSeqQuery[] =
793 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
794 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
795 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
796 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
797 'O','R','D','E','R',' ', 'B','Y',' ',
798 '`','S','e','q','u','e','n','c','e','`',0 };
799 static const WCHAR IVQuery[] =
800 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
801 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
802 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
803 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
804 ' ','\'', 'I','n','s','t','a','l','l',
805 'V','a','l','i','d','a','t','e','\'', 0};
806 INT seq = 0;
808 if (package->script->ExecuteSequenceRun)
810 TRACE("Execute Sequence already Run\n");
811 return ERROR_SUCCESS;
814 package->script->ExecuteSequenceRun = TRUE;
816 /* get the sequence number */
817 if (UIran)
819 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
820 if( !row )
821 return ERROR_FUNCTION_FAILED;
822 seq = MSI_RecordGetInteger(row,1);
823 msiobj_release(&row->hdr);
826 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
827 if (rc == ERROR_SUCCESS)
829 TRACE("Running the actions\n");
831 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
832 msiobj_release(&view->hdr);
835 return rc;
838 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
840 MSIQUERY * view;
841 UINT rc;
842 static const WCHAR ExecSeqQuery [] =
843 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
844 '`','I','n','s','t','a','l','l',
845 'U','I','S','e','q','u','e','n','c','e','`',
846 ' ','W','H','E','R','E',' ',
847 '`','S','e','q','u','e','n','c','e','`',' ',
848 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
849 '`','S','e','q','u','e','n','c','e','`',0};
851 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
852 if (rc == ERROR_SUCCESS)
854 TRACE("Running the actions\n");
856 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
857 msiobj_release(&view->hdr);
860 return rc;
863 /********************************************************
864 * ACTION helper functions and functions that perform the actions
865 *******************************************************/
866 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
867 UINT* rc, UINT script, BOOL force )
869 BOOL ret=FALSE;
870 UINT arc;
872 arc = ACTION_CustomAction(package, action, script, force);
874 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
876 *rc = arc;
877 ret = TRUE;
879 return ret;
883 * Actual Action Handlers
886 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
888 MSIPACKAGE *package = param;
889 LPCWSTR dir;
890 LPWSTR full_path;
891 MSIRECORD *uirow;
892 MSIFOLDER *folder;
894 dir = MSI_RecordGetString(row,1);
895 if (!dir)
897 ERR("Unable to get folder id\n");
898 return ERROR_SUCCESS;
901 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
902 if (!full_path)
904 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
905 return ERROR_SUCCESS;
908 TRACE("Folder is %s\n",debugstr_w(full_path));
910 /* UI stuff */
911 uirow = MSI_CreateRecord(1);
912 MSI_RecordSetStringW(uirow,1,full_path);
913 ui_actiondata(package,szCreateFolders,uirow);
914 msiobj_release( &uirow->hdr );
916 if (folder->State == 0)
917 create_full_pathW(full_path);
919 folder->State = 3;
921 msi_free(full_path);
922 return ERROR_SUCCESS;
925 /* FIXME: probably should merge this with the above function */
926 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
928 UINT rc = ERROR_SUCCESS;
929 MSIFOLDER *folder;
930 LPWSTR install_path;
932 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
933 if (!install_path)
934 return ERROR_FUNCTION_FAILED;
936 /* create the path */
937 if (folder->State == 0)
939 create_full_pathW(install_path);
940 folder->State = 2;
942 msi_free(install_path);
944 return rc;
947 UINT msi_create_component_directories( MSIPACKAGE *package )
949 MSICOMPONENT *comp;
951 /* create all the folders required by the components are going to install */
952 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
954 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
955 continue;
956 msi_create_directory( package, comp->Directory );
959 return ERROR_SUCCESS;
962 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
964 static const WCHAR ExecSeqQuery[] =
965 {'S','E','L','E','C','T',' ',
966 '`','D','i','r','e','c','t','o','r','y','_','`',
967 ' ','F','R','O','M',' ',
968 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
969 UINT rc;
970 MSIQUERY *view;
972 /* create all the empty folders specified in the CreateFolder table */
973 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
974 if (rc != ERROR_SUCCESS)
975 return ERROR_SUCCESS;
977 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
978 msiobj_release(&view->hdr);
980 return rc;
983 static UINT load_component( MSIRECORD *row, LPVOID param )
985 MSIPACKAGE *package = param;
986 MSICOMPONENT *comp;
988 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
989 if (!comp)
990 return ERROR_FUNCTION_FAILED;
992 list_add_tail( &package->components, &comp->entry );
994 /* fill in the data */
995 comp->Component = msi_dup_record_field( row, 1 );
997 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
999 comp->ComponentId = msi_dup_record_field( row, 2 );
1000 comp->Directory = msi_dup_record_field( row, 3 );
1001 comp->Attributes = MSI_RecordGetInteger(row,4);
1002 comp->Condition = msi_dup_record_field( row, 5 );
1003 comp->KeyPath = msi_dup_record_field( row, 6 );
1005 comp->Installed = INSTALLSTATE_UNKNOWN;
1006 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1008 return ERROR_SUCCESS;
1011 static UINT load_all_components( MSIPACKAGE *package )
1013 static const WCHAR query[] = {
1014 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1015 '`','C','o','m','p','o','n','e','n','t','`',0 };
1016 MSIQUERY *view;
1017 UINT r;
1019 if (!list_empty(&package->components))
1020 return ERROR_SUCCESS;
1022 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1023 if (r != ERROR_SUCCESS)
1024 return r;
1026 r = MSI_IterateRecords(view, NULL, load_component, package);
1027 msiobj_release(&view->hdr);
1028 return r;
1031 typedef struct {
1032 MSIPACKAGE *package;
1033 MSIFEATURE *feature;
1034 } _ilfs;
1036 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1038 ComponentList *cl;
1040 cl = msi_alloc( sizeof (*cl) );
1041 if ( !cl )
1042 return ERROR_NOT_ENOUGH_MEMORY;
1043 cl->component = comp;
1044 list_add_tail( &feature->Components, &cl->entry );
1046 return ERROR_SUCCESS;
1049 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1051 FeatureList *fl;
1053 fl = msi_alloc( sizeof(*fl) );
1054 if ( !fl )
1055 return ERROR_NOT_ENOUGH_MEMORY;
1056 fl->feature = child;
1057 list_add_tail( &parent->Children, &fl->entry );
1059 return ERROR_SUCCESS;
1062 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1064 _ilfs* ilfs = param;
1065 LPCWSTR component;
1066 MSICOMPONENT *comp;
1068 component = MSI_RecordGetString(row,1);
1070 /* check to see if the component is already loaded */
1071 comp = get_loaded_component( ilfs->package, component );
1072 if (!comp)
1074 ERR("unknown component %s\n", debugstr_w(component));
1075 return ERROR_FUNCTION_FAILED;
1078 add_feature_component( ilfs->feature, comp );
1079 comp->Enabled = TRUE;
1081 return ERROR_SUCCESS;
1084 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1086 MSIFEATURE *feature;
1088 if ( !name )
1089 return NULL;
1091 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1093 if ( !lstrcmpW( feature->Feature, name ) )
1094 return feature;
1097 return NULL;
1100 static UINT load_feature(MSIRECORD * row, LPVOID param)
1102 MSIPACKAGE* package = param;
1103 MSIFEATURE* feature;
1104 static const WCHAR Query1[] =
1105 {'S','E','L','E','C','T',' ',
1106 '`','C','o','m','p','o','n','e','n','t','_','`',
1107 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1108 'C','o','m','p','o','n','e','n','t','s','`',' ',
1109 'W','H','E','R','E',' ',
1110 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1111 MSIQUERY * view;
1112 UINT rc;
1113 _ilfs ilfs;
1115 /* fill in the data */
1117 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1118 if (!feature)
1119 return ERROR_NOT_ENOUGH_MEMORY;
1121 list_init( &feature->Children );
1122 list_init( &feature->Components );
1124 feature->Feature = msi_dup_record_field( row, 1 );
1126 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1128 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1129 feature->Title = msi_dup_record_field( row, 3 );
1130 feature->Description = msi_dup_record_field( row, 4 );
1132 if (!MSI_RecordIsNull(row,5))
1133 feature->Display = MSI_RecordGetInteger(row,5);
1135 feature->Level= MSI_RecordGetInteger(row,6);
1136 feature->Directory = msi_dup_record_field( row, 7 );
1137 feature->Attributes = MSI_RecordGetInteger(row,8);
1139 feature->Installed = INSTALLSTATE_UNKNOWN;
1140 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1142 list_add_tail( &package->features, &feature->entry );
1144 /* load feature components */
1146 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1147 if (rc != ERROR_SUCCESS)
1148 return ERROR_SUCCESS;
1150 ilfs.package = package;
1151 ilfs.feature = feature;
1153 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1154 msiobj_release(&view->hdr);
1156 return ERROR_SUCCESS;
1159 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1161 MSIPACKAGE* package = param;
1162 MSIFEATURE *parent, *child;
1164 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1165 if (!child)
1166 return ERROR_FUNCTION_FAILED;
1168 if (!child->Feature_Parent)
1169 return ERROR_SUCCESS;
1171 parent = find_feature_by_name( package, child->Feature_Parent );
1172 if (!parent)
1173 return ERROR_FUNCTION_FAILED;
1175 add_feature_child( parent, child );
1176 return ERROR_SUCCESS;
1179 static UINT load_all_features( MSIPACKAGE *package )
1181 static const WCHAR query[] = {
1182 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1183 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1184 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1185 MSIQUERY *view;
1186 UINT r;
1188 if (!list_empty(&package->features))
1189 return ERROR_SUCCESS;
1191 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1192 if (r != ERROR_SUCCESS)
1193 return r;
1195 r = MSI_IterateRecords( view, NULL, load_feature, package );
1196 if (r != ERROR_SUCCESS)
1197 return r;
1199 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1200 msiobj_release( &view->hdr );
1202 return r;
1205 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1207 if (!p)
1208 return p;
1209 p = strchrW(p, ch);
1210 if (!p)
1211 return p;
1212 *p = 0;
1213 return p+1;
1216 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1218 static const WCHAR query[] = {
1219 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1220 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1221 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1222 MSIQUERY *view = NULL;
1223 MSIRECORD *row = NULL;
1224 UINT r;
1226 TRACE("%s\n", debugstr_w(file->File));
1228 r = MSI_OpenQuery(package->db, &view, query, file->File);
1229 if (r != ERROR_SUCCESS)
1230 goto done;
1232 r = MSI_ViewExecute(view, NULL);
1233 if (r != ERROR_SUCCESS)
1234 goto done;
1236 r = MSI_ViewFetch(view, &row);
1237 if (r != ERROR_SUCCESS)
1238 goto done;
1240 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1241 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1242 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1243 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1244 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1246 done:
1247 if (view) msiobj_release(&view->hdr);
1248 if (row) msiobj_release(&row->hdr);
1249 return r;
1252 static UINT load_file(MSIRECORD *row, LPVOID param)
1254 MSIPACKAGE* package = param;
1255 LPCWSTR component;
1256 MSIFILE *file;
1258 /* fill in the data */
1260 file = msi_alloc_zero( sizeof (MSIFILE) );
1261 if (!file)
1262 return ERROR_NOT_ENOUGH_MEMORY;
1264 file->File = msi_dup_record_field( row, 1 );
1266 component = MSI_RecordGetString( row, 2 );
1267 file->Component = get_loaded_component( package, component );
1269 if (!file->Component)
1271 WARN("Component not found: %s\n", debugstr_w(component));
1272 msi_free(file->File);
1273 msi_free(file);
1274 return ERROR_SUCCESS;
1277 file->FileName = msi_dup_record_field( row, 3 );
1278 reduce_to_longfilename( file->FileName );
1280 file->ShortName = msi_dup_record_field( row, 3 );
1281 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1283 file->FileSize = MSI_RecordGetInteger( row, 4 );
1284 file->Version = msi_dup_record_field( row, 5 );
1285 file->Language = msi_dup_record_field( row, 6 );
1286 file->Attributes = MSI_RecordGetInteger( row, 7 );
1287 file->Sequence = MSI_RecordGetInteger( row, 8 );
1289 file->state = msifs_invalid;
1291 /* if the compressed bits are not set in the file attributes,
1292 * then read the information from the package word count property
1294 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1296 file->IsCompressed = FALSE;
1298 else if (file->Attributes &
1299 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1301 file->IsCompressed = TRUE;
1303 else if (file->Attributes & msidbFileAttributesNoncompressed)
1305 file->IsCompressed = FALSE;
1307 else
1309 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1312 load_file_hash(package, file);
1314 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1316 list_add_tail( &package->files, &file->entry );
1318 return ERROR_SUCCESS;
1321 static UINT load_all_files(MSIPACKAGE *package)
1323 MSIQUERY * view;
1324 UINT rc;
1325 static const WCHAR Query[] =
1326 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1327 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1328 '`','S','e','q','u','e','n','c','e','`', 0};
1330 if (!list_empty(&package->files))
1331 return ERROR_SUCCESS;
1333 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1334 if (rc != ERROR_SUCCESS)
1335 return ERROR_SUCCESS;
1337 rc = MSI_IterateRecords(view, NULL, load_file, package);
1338 msiobj_release(&view->hdr);
1340 return ERROR_SUCCESS;
1343 static UINT load_folder( MSIRECORD *row, LPVOID param )
1345 MSIPACKAGE *package = param;
1346 static WCHAR szEmpty[] = { 0 };
1347 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1348 MSIFOLDER *folder;
1350 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1351 if (!folder)
1352 return ERROR_NOT_ENOUGH_MEMORY;
1354 folder->Directory = msi_dup_record_field( row, 1 );
1356 TRACE("%s\n", debugstr_w(folder->Directory));
1358 p = msi_dup_record_field(row, 3);
1360 /* split src and target dir */
1361 tgt_short = p;
1362 src_short = folder_split_path( p, ':' );
1364 /* split the long and short paths */
1365 tgt_long = folder_split_path( tgt_short, '|' );
1366 src_long = folder_split_path( src_short, '|' );
1368 /* check for no-op dirs */
1369 if (!lstrcmpW(szDot, tgt_short))
1370 tgt_short = szEmpty;
1371 if (!lstrcmpW(szDot, src_short))
1372 src_short = szEmpty;
1374 if (!tgt_long)
1375 tgt_long = tgt_short;
1377 if (!src_short) {
1378 src_short = tgt_short;
1379 src_long = tgt_long;
1382 if (!src_long)
1383 src_long = src_short;
1385 /* FIXME: use the target short path too */
1386 folder->TargetDefault = strdupW(tgt_long);
1387 folder->SourceShortPath = strdupW(src_short);
1388 folder->SourceLongPath = strdupW(src_long);
1389 msi_free(p);
1391 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1392 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1393 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1395 folder->Parent = msi_dup_record_field( row, 2 );
1397 folder->Property = msi_dup_property( package, folder->Directory );
1399 list_add_tail( &package->folders, &folder->entry );
1401 TRACE("returning %p\n", folder);
1403 return ERROR_SUCCESS;
1406 static UINT load_all_folders( MSIPACKAGE *package )
1408 static const WCHAR query[] = {
1409 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1410 '`','D','i','r','e','c','t','o','r','y','`',0 };
1411 MSIQUERY *view;
1412 UINT r;
1414 if (!list_empty(&package->folders))
1415 return ERROR_SUCCESS;
1417 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1418 if (r != ERROR_SUCCESS)
1419 return r;
1421 r = MSI_IterateRecords(view, NULL, load_folder, package);
1422 msiobj_release(&view->hdr);
1423 return r;
1427 * I am not doing any of the costing functionality yet.
1428 * Mostly looking at doing the Component and Feature loading
1430 * The native MSI does A LOT of modification to tables here. Mostly adding
1431 * a lot of temporary columns to the Feature and Component tables.
1433 * note: Native msi also tracks the short filename. But I am only going to
1434 * track the long ones. Also looking at this directory table
1435 * it appears that the directory table does not get the parents
1436 * resolved base on property only based on their entries in the
1437 * directory table.
1439 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1441 static const WCHAR szCosting[] =
1442 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1444 MSI_SetPropertyW(package, szCosting, szZero);
1445 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1447 load_all_folders( package );
1448 load_all_components( package );
1449 load_all_features( package );
1450 load_all_files( package );
1452 return ERROR_SUCCESS;
1455 static UINT execute_script(MSIPACKAGE *package, UINT script )
1457 UINT i;
1458 UINT rc = ERROR_SUCCESS;
1460 TRACE("Executing Script %i\n",script);
1462 if (!package->script)
1464 ERR("no script!\n");
1465 return ERROR_FUNCTION_FAILED;
1468 for (i = 0; i < package->script->ActionCount[script]; i++)
1470 LPWSTR action;
1471 action = package->script->Actions[script][i];
1472 ui_actionstart(package, action);
1473 TRACE("Executing Action (%s)\n",debugstr_w(action));
1474 rc = ACTION_PerformAction(package, action, script, TRUE);
1475 if (rc != ERROR_SUCCESS)
1476 break;
1478 msi_free_action_script(package, script);
1479 return rc;
1482 static UINT ACTION_FileCost(MSIPACKAGE *package)
1484 return ERROR_SUCCESS;
1487 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1489 MSICOMPONENT *comp;
1490 INSTALLSTATE state;
1491 UINT r;
1493 state = MsiQueryProductStateW(package->ProductCode);
1495 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1497 if (!comp->ComponentId)
1498 continue;
1500 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1501 comp->Installed = INSTALLSTATE_ABSENT;
1502 else
1504 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1505 package->Context, comp->ComponentId,
1506 &comp->Installed);
1507 if (r != ERROR_SUCCESS)
1508 comp->Installed = INSTALLSTATE_ABSENT;
1513 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1515 MSIFEATURE *feature;
1516 INSTALLSTATE state;
1518 state = MsiQueryProductStateW(package->ProductCode);
1520 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1522 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1523 feature->Installed = INSTALLSTATE_ABSENT;
1524 else
1526 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1527 feature->Feature);
1532 static BOOL process_state_property(MSIPACKAGE* package, int level,
1533 LPCWSTR property, INSTALLSTATE state)
1535 LPWSTR override;
1536 MSIFEATURE *feature;
1538 override = msi_dup_property( package, property );
1539 if (!override)
1540 return FALSE;
1542 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1544 if (lstrcmpW(property, szRemove) &&
1545 (feature->Level <= 0 || feature->Level > level))
1546 continue;
1548 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1550 if (strcmpiW(override, szAll)==0)
1551 msi_feature_set_state(package, feature, state);
1552 else
1554 LPWSTR ptr = override;
1555 LPWSTR ptr2 = strchrW(override,',');
1557 while (ptr)
1559 int len = ptr2 - ptr;
1561 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1562 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1564 msi_feature_set_state(package, feature, state);
1565 break;
1567 if (ptr2)
1569 ptr=ptr2+1;
1570 ptr2 = strchrW(ptr,',');
1572 else
1573 break;
1577 msi_free(override);
1579 return TRUE;
1582 static BOOL process_overrides( MSIPACKAGE *package, int level )
1584 static const WCHAR szAddLocal[] =
1585 {'A','D','D','L','O','C','A','L',0};
1586 static const WCHAR szAddSource[] =
1587 {'A','D','D','S','O','U','R','C','E',0};
1588 static const WCHAR szAdvertise[] =
1589 {'A','D','V','E','R','T','I','S','E',0};
1590 BOOL ret = FALSE;
1592 /* all these activation/deactivation things happen in order and things
1593 * later on the list override things earlier on the list.
1595 * 0 INSTALLLEVEL processing
1596 * 1 ADDLOCAL
1597 * 2 REMOVE
1598 * 3 ADDSOURCE
1599 * 4 ADDDEFAULT
1600 * 5 REINSTALL
1601 * 6 ADVERTISE
1602 * 7 COMPADDLOCAL
1603 * 8 COMPADDSOURCE
1604 * 9 FILEADDLOCAL
1605 * 10 FILEADDSOURCE
1606 * 11 FILEADDDEFAULT
1608 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1609 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1610 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1611 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1612 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1614 if (ret)
1615 MSI_SetPropertyW( package, szPreselected, szOne );
1617 return ret;
1620 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1622 int level;
1623 static const WCHAR szlevel[] =
1624 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1625 MSICOMPONENT* component;
1626 MSIFEATURE *feature;
1628 TRACE("Checking Install Level\n");
1630 level = msi_get_property_int(package, szlevel, 1);
1632 if (!msi_get_property_int( package, szPreselected, 0 ))
1634 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1636 BOOL feature_state = ((feature->Level > 0) &&
1637 (feature->Level <= level));
1639 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1641 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1642 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1643 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1644 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1645 else
1646 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1650 /* disable child features of unselected parent features */
1651 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1653 FeatureList *fl;
1655 if (feature->Level > 0 && feature->Level <= level)
1656 continue;
1658 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1659 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1664 * now we want to enable or disable components base on feature
1667 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1669 ComponentList *cl;
1671 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1672 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1674 if (!feature->Level)
1675 continue;
1677 /* features with components that have compressed files are made local */
1678 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1680 if (cl->component->Enabled &&
1681 cl->component->ForceLocalState &&
1682 feature->Action == INSTALLSTATE_SOURCE)
1684 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1685 break;
1689 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1691 component = cl->component;
1693 if (!component->Enabled)
1694 continue;
1696 switch (feature->Action)
1698 case INSTALLSTATE_ABSENT:
1699 component->anyAbsent = 1;
1700 break;
1701 case INSTALLSTATE_ADVERTISED:
1702 component->hasAdvertiseFeature = 1;
1703 break;
1704 case INSTALLSTATE_SOURCE:
1705 component->hasSourceFeature = 1;
1706 break;
1707 case INSTALLSTATE_LOCAL:
1708 component->hasLocalFeature = 1;
1709 break;
1710 case INSTALLSTATE_DEFAULT:
1711 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1712 component->hasAdvertiseFeature = 1;
1713 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1714 component->hasSourceFeature = 1;
1715 else
1716 component->hasLocalFeature = 1;
1717 break;
1718 default:
1719 break;
1724 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1726 /* if the component isn't enabled, leave it alone */
1727 if (!component->Enabled)
1728 continue;
1730 /* check if it's local or source */
1731 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1732 (component->hasLocalFeature || component->hasSourceFeature))
1734 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1735 !component->ForceLocalState)
1736 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1737 else
1738 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1739 continue;
1742 /* if any feature is local, the component must be local too */
1743 if (component->hasLocalFeature)
1745 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1746 continue;
1749 if (component->hasSourceFeature)
1751 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1752 continue;
1755 if (component->hasAdvertiseFeature)
1757 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1758 continue;
1761 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1762 if (component->anyAbsent)
1763 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1766 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1768 if (component->Action == INSTALLSTATE_DEFAULT)
1770 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1771 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1774 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1775 debugstr_w(component->Component), component->Installed, component->Action);
1779 return ERROR_SUCCESS;
1782 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1784 MSIPACKAGE *package = param;
1785 LPCWSTR name;
1786 LPWSTR path;
1787 MSIFOLDER *f;
1789 name = MSI_RecordGetString(row,1);
1791 f = get_loaded_folder(package, name);
1792 if (!f) return ERROR_SUCCESS;
1794 /* reset the ResolvedTarget */
1795 msi_free(f->ResolvedTarget);
1796 f->ResolvedTarget = NULL;
1798 /* This helper function now does ALL the work */
1799 TRACE("Dir %s ...\n",debugstr_w(name));
1800 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1801 TRACE("resolves to %s\n",debugstr_w(path));
1802 msi_free(path);
1804 return ERROR_SUCCESS;
1807 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1809 MSIPACKAGE *package = param;
1810 LPCWSTR name;
1811 MSIFEATURE *feature;
1813 name = MSI_RecordGetString( row, 1 );
1815 feature = get_loaded_feature( package, name );
1816 if (!feature)
1817 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1818 else
1820 LPCWSTR Condition;
1821 Condition = MSI_RecordGetString(row,3);
1823 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1825 int level = MSI_RecordGetInteger(row,2);
1826 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1827 feature->Level = level;
1830 return ERROR_SUCCESS;
1833 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1835 static const WCHAR name_fmt[] =
1836 {'%','u','.','%','u','.','%','u','.','%','u',0};
1837 static const WCHAR name[] = {'\\',0};
1838 VS_FIXEDFILEINFO *lpVer;
1839 WCHAR filever[0x100];
1840 LPVOID version;
1841 DWORD versize;
1842 DWORD handle;
1843 UINT sz;
1845 TRACE("%s\n", debugstr_w(filename));
1847 versize = GetFileVersionInfoSizeW( filename, &handle );
1848 if (!versize)
1849 return NULL;
1851 version = msi_alloc( versize );
1852 GetFileVersionInfoW( filename, 0, versize, version );
1854 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1856 msi_free( version );
1857 return NULL;
1860 sprintfW( filever, name_fmt,
1861 HIWORD(lpVer->dwFileVersionMS),
1862 LOWORD(lpVer->dwFileVersionMS),
1863 HIWORD(lpVer->dwFileVersionLS),
1864 LOWORD(lpVer->dwFileVersionLS));
1866 msi_free( version );
1868 return strdupW( filever );
1871 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1873 LPWSTR file_version;
1874 MSIFILE *file;
1876 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1878 MSICOMPONENT* comp = file->Component;
1879 LPWSTR p;
1881 if (!comp)
1882 continue;
1884 if (file->IsCompressed)
1885 comp->ForceLocalState = TRUE;
1887 /* calculate target */
1888 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1890 msi_free(file->TargetPath);
1892 TRACE("file %s is named %s\n",
1893 debugstr_w(file->File), debugstr_w(file->FileName));
1895 file->TargetPath = build_directory_name(2, p, file->FileName);
1897 msi_free(p);
1899 TRACE("file %s resolves to %s\n",
1900 debugstr_w(file->File), debugstr_w(file->TargetPath));
1902 /* don't check files of components that aren't installed */
1903 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1904 comp->Installed == INSTALLSTATE_ABSENT)
1906 file->state = msifs_missing; /* assume files are missing */
1907 continue;
1910 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1912 file->state = msifs_missing;
1913 comp->Cost += file->FileSize;
1914 continue;
1917 if (file->Version &&
1918 (file_version = msi_get_disk_file_version( file->TargetPath )))
1920 TRACE("new %s old %s\n", debugstr_w(file->Version),
1921 debugstr_w(file_version));
1922 /* FIXME: seems like a bad way to compare version numbers */
1923 if (lstrcmpiW(file_version, file->Version)<0)
1925 file->state = msifs_overwrite;
1926 comp->Cost += file->FileSize;
1928 else
1929 file->state = msifs_present;
1930 msi_free( file_version );
1932 else
1933 file->state = msifs_present;
1936 return ERROR_SUCCESS;
1940 * A lot is done in this function aside from just the costing.
1941 * The costing needs to be implemented at some point but for now I am going
1942 * to focus on the directory building
1945 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1947 static const WCHAR ExecSeqQuery[] =
1948 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1949 '`','D','i','r','e','c','t','o','r','y','`',0};
1950 static const WCHAR ConditionQuery[] =
1951 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1952 '`','C','o','n','d','i','t','i','o','n','`',0};
1953 static const WCHAR szCosting[] =
1954 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1955 static const WCHAR szlevel[] =
1956 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1957 static const WCHAR szOutOfDiskSpace[] =
1958 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
1959 MSICOMPONENT *comp;
1960 UINT rc = ERROR_SUCCESS;
1961 MSIQUERY * view;
1962 LPWSTR level;
1964 TRACE("Building Directory properties\n");
1966 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1967 if (rc == ERROR_SUCCESS)
1969 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1970 package);
1971 msiobj_release(&view->hdr);
1974 /* read components states from the registry */
1975 ACTION_GetComponentInstallStates(package);
1976 ACTION_GetFeatureInstallStates(package);
1978 TRACE("File calculations\n");
1979 msi_check_file_install_states( package );
1981 if (!process_overrides( package, msi_get_property_int( package, szlevel, 1 ) ))
1983 TRACE("Evaluating Condition Table\n");
1985 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
1986 if (rc == ERROR_SUCCESS)
1988 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
1989 msiobj_release( &view->hdr );
1992 TRACE("Enabling or Disabling Components\n");
1993 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1995 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
1997 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1998 comp->Enabled = FALSE;
2000 else
2001 comp->Enabled = TRUE;
2005 MSI_SetPropertyW(package,szCosting,szOne);
2006 /* set default run level if not set */
2007 level = msi_dup_property( package, szlevel );
2008 if (!level)
2009 MSI_SetPropertyW(package,szlevel, szOne);
2010 msi_free(level);
2012 /* FIXME: check volume disk space */
2013 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2015 return MSI_SetFeatureStates(package);
2018 /* OK this value is "interpreted" and then formatted based on the
2019 first few characters */
2020 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2021 DWORD *size)
2023 LPSTR data = NULL;
2025 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2027 if (value[1]=='x')
2029 LPWSTR ptr;
2030 CHAR byte[5];
2031 LPWSTR deformated = NULL;
2032 int count;
2034 deformat_string(package, &value[2], &deformated);
2036 /* binary value type */
2037 ptr = deformated;
2038 *type = REG_BINARY;
2039 if (strlenW(ptr)%2)
2040 *size = (strlenW(ptr)/2)+1;
2041 else
2042 *size = strlenW(ptr)/2;
2044 data = msi_alloc(*size);
2046 byte[0] = '0';
2047 byte[1] = 'x';
2048 byte[4] = 0;
2049 count = 0;
2050 /* if uneven pad with a zero in front */
2051 if (strlenW(ptr)%2)
2053 byte[2]= '0';
2054 byte[3]= *ptr;
2055 ptr++;
2056 data[count] = (BYTE)strtol(byte,NULL,0);
2057 count ++;
2058 TRACE("Uneven byte count\n");
2060 while (*ptr)
2062 byte[2]= *ptr;
2063 ptr++;
2064 byte[3]= *ptr;
2065 ptr++;
2066 data[count] = (BYTE)strtol(byte,NULL,0);
2067 count ++;
2069 msi_free(deformated);
2071 TRACE("Data %i bytes(%i)\n",*size,count);
2073 else
2075 LPWSTR deformated;
2076 LPWSTR p;
2077 DWORD d = 0;
2078 deformat_string(package, &value[1], &deformated);
2080 *type=REG_DWORD;
2081 *size = sizeof(DWORD);
2082 data = msi_alloc(*size);
2083 p = deformated;
2084 if (*p == '-')
2085 p++;
2086 while (*p)
2088 if ( (*p < '0') || (*p > '9') )
2089 break;
2090 d *= 10;
2091 d += (*p - '0');
2092 p++;
2094 if (deformated[0] == '-')
2095 d = -d;
2096 *(LPDWORD)data = d;
2097 TRACE("DWORD %i\n",*(LPDWORD)data);
2099 msi_free(deformated);
2102 else
2104 static const WCHAR szMulti[] = {'[','~',']',0};
2105 LPCWSTR ptr;
2106 *type=REG_SZ;
2108 if (value[0]=='#')
2110 if (value[1]=='%')
2112 ptr = &value[2];
2113 *type=REG_EXPAND_SZ;
2115 else
2116 ptr = &value[1];
2118 else
2119 ptr=value;
2121 if (strstrW(value,szMulti))
2122 *type = REG_MULTI_SZ;
2124 /* remove initial delimiter */
2125 if (!strncmpW(value, szMulti, 3))
2126 ptr = value + 3;
2128 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2130 /* add double NULL terminator */
2131 if (*type == REG_MULTI_SZ)
2133 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2134 data = msi_realloc_zero(data, *size);
2137 return data;
2140 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2142 MSIPACKAGE *package = param;
2143 static const WCHAR szHCR[] =
2144 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2145 'R','O','O','T','\\',0};
2146 static const WCHAR szHCU[] =
2147 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2148 'U','S','E','R','\\',0};
2149 static const WCHAR szHLM[] =
2150 {'H','K','E','Y','_','L','O','C','A','L','_',
2151 'M','A','C','H','I','N','E','\\',0};
2152 static const WCHAR szHU[] =
2153 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2155 LPSTR value_data = NULL;
2156 HKEY root_key, hkey;
2157 DWORD type,size;
2158 LPWSTR deformated;
2159 LPCWSTR szRoot, component, name, key, value;
2160 MSICOMPONENT *comp;
2161 MSIRECORD * uirow;
2162 LPWSTR uikey;
2163 INT root;
2164 BOOL check_first = FALSE;
2165 UINT rc;
2167 ui_progress(package,2,0,0,0);
2169 value = NULL;
2170 key = NULL;
2171 uikey = NULL;
2172 name = NULL;
2174 component = MSI_RecordGetString(row, 6);
2175 comp = get_loaded_component(package,component);
2176 if (!comp)
2177 return ERROR_SUCCESS;
2179 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2181 TRACE("Skipping write due to disabled component %s\n",
2182 debugstr_w(component));
2184 comp->Action = comp->Installed;
2186 return ERROR_SUCCESS;
2189 comp->Action = INSTALLSTATE_LOCAL;
2191 name = MSI_RecordGetString(row, 4);
2192 if( MSI_RecordIsNull(row,5) && name )
2194 /* null values can have special meanings */
2195 if (name[0]=='-' && name[1] == 0)
2196 return ERROR_SUCCESS;
2197 else if ((name[0]=='+' && name[1] == 0) ||
2198 (name[0] == '*' && name[1] == 0))
2199 name = NULL;
2200 check_first = TRUE;
2203 root = MSI_RecordGetInteger(row,2);
2204 key = MSI_RecordGetString(row, 3);
2206 /* get the root key */
2207 switch (root)
2209 case -1:
2211 LPWSTR all_users = msi_dup_property( package, szAllUsers );
2212 if (all_users && all_users[0] == '1')
2214 root_key = HKEY_LOCAL_MACHINE;
2215 szRoot = szHLM;
2217 else
2219 root_key = HKEY_CURRENT_USER;
2220 szRoot = szHCU;
2222 msi_free(all_users);
2224 break;
2225 case 0: root_key = HKEY_CLASSES_ROOT;
2226 szRoot = szHCR;
2227 break;
2228 case 1: root_key = HKEY_CURRENT_USER;
2229 szRoot = szHCU;
2230 break;
2231 case 2: root_key = HKEY_LOCAL_MACHINE;
2232 szRoot = szHLM;
2233 break;
2234 case 3: root_key = HKEY_USERS;
2235 szRoot = szHU;
2236 break;
2237 default:
2238 ERR("Unknown root %i\n",root);
2239 root_key=NULL;
2240 szRoot = NULL;
2241 break;
2243 if (!root_key)
2244 return ERROR_SUCCESS;
2246 deformat_string(package, key , &deformated);
2247 size = strlenW(deformated) + strlenW(szRoot) + 1;
2248 uikey = msi_alloc(size*sizeof(WCHAR));
2249 strcpyW(uikey,szRoot);
2250 strcatW(uikey,deformated);
2252 if (RegCreateKeyW( root_key, deformated, &hkey))
2254 ERR("Could not create key %s\n",debugstr_w(deformated));
2255 msi_free(deformated);
2256 msi_free(uikey);
2257 return ERROR_SUCCESS;
2259 msi_free(deformated);
2261 value = MSI_RecordGetString(row,5);
2262 if (value)
2263 value_data = parse_value(package, value, &type, &size);
2264 else
2266 value_data = (LPSTR)strdupW(szEmpty);
2267 size = sizeof(szEmpty);
2268 type = REG_SZ;
2271 deformat_string(package, name, &deformated);
2273 if (!check_first)
2275 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2276 debugstr_w(uikey));
2277 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2279 else
2281 DWORD sz = 0;
2282 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2283 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2285 TRACE("value %s of %s checked already exists\n",
2286 debugstr_w(deformated), debugstr_w(uikey));
2288 else
2290 TRACE("Checked and setting value %s of %s\n",
2291 debugstr_w(deformated), debugstr_w(uikey));
2292 if (deformated || size)
2293 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2296 RegCloseKey(hkey);
2298 uirow = MSI_CreateRecord(3);
2299 MSI_RecordSetStringW(uirow,2,deformated);
2300 MSI_RecordSetStringW(uirow,1,uikey);
2302 if (type == REG_SZ)
2303 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2304 else
2305 MSI_RecordSetStringW(uirow,3,value);
2307 ui_actiondata(package,szWriteRegistryValues,uirow);
2308 msiobj_release( &uirow->hdr );
2310 msi_free(value_data);
2311 msi_free(deformated);
2312 msi_free(uikey);
2314 return ERROR_SUCCESS;
2317 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2319 UINT rc;
2320 MSIQUERY * view;
2321 static const WCHAR ExecSeqQuery[] =
2322 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2323 '`','R','e','g','i','s','t','r','y','`',0 };
2325 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2326 if (rc != ERROR_SUCCESS)
2327 return ERROR_SUCCESS;
2329 /* increment progress bar each time action data is sent */
2330 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2332 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2334 msiobj_release(&view->hdr);
2335 return rc;
2338 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2340 package->script->CurrentlyScripting = TRUE;
2342 return ERROR_SUCCESS;
2346 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2348 MSICOMPONENT *comp;
2349 DWORD progress = 0;
2350 DWORD total = 0;
2351 static const WCHAR q1[]=
2352 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2353 '`','R','e','g','i','s','t','r','y','`',0};
2354 UINT rc;
2355 MSIQUERY * view;
2356 MSIFEATURE *feature;
2357 MSIFILE *file;
2359 TRACE("InstallValidate\n");
2361 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2362 if (rc == ERROR_SUCCESS)
2364 MSI_IterateRecords( view, &progress, NULL, package );
2365 msiobj_release( &view->hdr );
2366 total += progress * REG_PROGRESS_VALUE;
2369 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2370 total += COMPONENT_PROGRESS_VALUE;
2372 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2373 total += file->FileSize;
2375 ui_progress(package,0,total,0,0);
2377 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2379 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2380 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2381 feature->ActionRequest);
2384 return ERROR_SUCCESS;
2387 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2389 MSIPACKAGE* package = param;
2390 LPCWSTR cond = NULL;
2391 LPCWSTR message = NULL;
2392 UINT r;
2394 static const WCHAR title[]=
2395 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2397 cond = MSI_RecordGetString(row,1);
2399 r = MSI_EvaluateConditionW(package,cond);
2400 if (r == MSICONDITION_FALSE)
2402 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2404 LPWSTR deformated;
2405 message = MSI_RecordGetString(row,2);
2406 deformat_string(package,message,&deformated);
2407 MessageBoxW(NULL,deformated,title,MB_OK);
2408 msi_free(deformated);
2411 return ERROR_INSTALL_FAILURE;
2414 return ERROR_SUCCESS;
2417 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2419 UINT rc;
2420 MSIQUERY * view = NULL;
2421 static const WCHAR ExecSeqQuery[] =
2422 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2423 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2425 TRACE("Checking launch conditions\n");
2427 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2428 if (rc != ERROR_SUCCESS)
2429 return ERROR_SUCCESS;
2431 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2432 msiobj_release(&view->hdr);
2434 return rc;
2437 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2440 if (!cmp->KeyPath)
2441 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2443 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2445 MSIRECORD * row = 0;
2446 UINT root,len;
2447 LPWSTR deformated,buffer,deformated_name;
2448 LPCWSTR key,name;
2449 static const WCHAR ExecSeqQuery[] =
2450 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2451 '`','R','e','g','i','s','t','r','y','`',' ',
2452 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2453 ' ','=',' ' ,'\'','%','s','\'',0 };
2454 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2455 static const WCHAR fmt2[]=
2456 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2458 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2459 if (!row)
2460 return NULL;
2462 root = MSI_RecordGetInteger(row,2);
2463 key = MSI_RecordGetString(row, 3);
2464 name = MSI_RecordGetString(row, 4);
2465 deformat_string(package, key , &deformated);
2466 deformat_string(package, name, &deformated_name);
2468 len = strlenW(deformated) + 6;
2469 if (deformated_name)
2470 len+=strlenW(deformated_name);
2472 buffer = msi_alloc( len *sizeof(WCHAR));
2474 if (deformated_name)
2475 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2476 else
2477 sprintfW(buffer,fmt,root,deformated);
2479 msi_free(deformated);
2480 msi_free(deformated_name);
2481 msiobj_release(&row->hdr);
2483 return buffer;
2485 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2487 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2488 return NULL;
2490 else
2492 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2494 if (file)
2495 return strdupW( file->TargetPath );
2497 return NULL;
2500 static HKEY openSharedDLLsKey(void)
2502 HKEY hkey=0;
2503 static const WCHAR path[] =
2504 {'S','o','f','t','w','a','r','e','\\',
2505 'M','i','c','r','o','s','o','f','t','\\',
2506 'W','i','n','d','o','w','s','\\',
2507 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2508 'S','h','a','r','e','d','D','L','L','s',0};
2510 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2511 return hkey;
2514 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2516 HKEY hkey;
2517 DWORD count=0;
2518 DWORD type;
2519 DWORD sz = sizeof(count);
2520 DWORD rc;
2522 hkey = openSharedDLLsKey();
2523 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2524 if (rc != ERROR_SUCCESS)
2525 count = 0;
2526 RegCloseKey(hkey);
2527 return count;
2530 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2532 HKEY hkey;
2534 hkey = openSharedDLLsKey();
2535 if (count > 0)
2536 msi_reg_set_val_dword( hkey, path, count );
2537 else
2538 RegDeleteValueW(hkey,path);
2539 RegCloseKey(hkey);
2540 return count;
2544 * Return TRUE if the count should be written out and FALSE if not
2546 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2548 MSIFEATURE *feature;
2549 INT count = 0;
2550 BOOL write = FALSE;
2552 /* only refcount DLLs */
2553 if (comp->KeyPath == NULL ||
2554 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2555 comp->Attributes & msidbComponentAttributesODBCDataSource)
2556 write = FALSE;
2557 else
2559 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2560 write = (count > 0);
2562 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2563 write = TRUE;
2566 /* increment counts */
2567 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2569 ComponentList *cl;
2571 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2572 continue;
2574 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2576 if ( cl->component == comp )
2577 count++;
2581 /* decrement counts */
2582 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2584 ComponentList *cl;
2586 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2587 continue;
2589 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2591 if ( cl->component == comp )
2592 count--;
2596 /* ref count all the files in the component */
2597 if (write)
2599 MSIFILE *file;
2601 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2603 if (file->Component == comp)
2604 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2608 /* add a count for permanent */
2609 if (comp->Attributes & msidbComponentAttributesPermanent)
2610 count ++;
2612 comp->RefCount = count;
2614 if (write)
2615 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2618 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2620 WCHAR squished_pc[GUID_SIZE];
2621 WCHAR squished_cc[GUID_SIZE];
2622 UINT rc;
2623 MSICOMPONENT *comp;
2624 HKEY hkey;
2626 TRACE("\n");
2628 squash_guid(package->ProductCode,squished_pc);
2629 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2631 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2633 MSIRECORD * uirow;
2635 ui_progress(package,2,0,0,0);
2636 if (!comp->ComponentId)
2637 continue;
2639 squash_guid(comp->ComponentId,squished_cc);
2641 msi_free(comp->FullKeypath);
2642 comp->FullKeypath = resolve_keypath( package, comp );
2644 ACTION_RefCountComponent( package, comp );
2646 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2647 debugstr_w(comp->Component),
2648 debugstr_w(squished_cc),
2649 debugstr_w(comp->FullKeypath),
2650 comp->RefCount);
2652 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL) ||
2653 ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE))
2655 if (!comp->FullKeypath)
2656 continue;
2658 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2659 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2660 &hkey, TRUE);
2661 else
2662 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2663 &hkey, TRUE);
2665 if (rc != ERROR_SUCCESS)
2666 continue;
2668 if (comp->Attributes & msidbComponentAttributesPermanent)
2670 static const WCHAR szPermKey[] =
2671 { '0','0','0','0','0','0','0','0','0','0','0','0',
2672 '0','0','0','0','0','0','0','0','0','0','0','0',
2673 '0','0','0','0','0','0','0','0',0 };
2675 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2678 if (comp->Action == INSTALLSTATE_LOCAL)
2679 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2680 else
2682 MSIFILE *file;
2683 MSIRECORD *row;
2684 LPWSTR ptr, ptr2;
2685 WCHAR source[MAX_PATH];
2686 WCHAR base[MAX_PATH];
2687 LPWSTR sourcepath;
2689 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2690 static const WCHAR query[] = {
2691 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2692 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2693 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2694 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2695 '`','D','i','s','k','I','d','`',0};
2697 file = get_loaded_file(package, comp->KeyPath);
2698 if (!file)
2699 continue;
2701 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2702 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2703 ptr2 = strrchrW(source, '\\') + 1;
2704 msiobj_release(&row->hdr);
2706 lstrcpyW(base, package->PackagePath);
2707 ptr = strrchrW(base, '\\');
2708 *(ptr + 1) = '\0';
2710 sourcepath = resolve_file_source(package, file);
2711 ptr = sourcepath + lstrlenW(base);
2712 lstrcpyW(ptr2, ptr);
2713 msi_free(sourcepath);
2715 msi_reg_set_val_str(hkey, squished_pc, source);
2717 RegCloseKey(hkey);
2719 else if (ACTION_VerifyComponentForAction(comp, INSTALLSTATE_ABSENT))
2721 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2722 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2723 else
2724 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2727 /* UI stuff */
2728 uirow = MSI_CreateRecord(3);
2729 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2730 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2731 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2732 ui_actiondata(package,szProcessComponents,uirow);
2733 msiobj_release( &uirow->hdr );
2736 return ERROR_SUCCESS;
2739 typedef struct {
2740 CLSID clsid;
2741 LPWSTR source;
2743 LPWSTR path;
2744 ITypeLib *ptLib;
2745 } typelib_struct;
2747 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2748 LPWSTR lpszName, LONG_PTR lParam)
2750 TLIBATTR *attr;
2751 typelib_struct *tl_struct = (typelib_struct*) lParam;
2752 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2753 int sz;
2754 HRESULT res;
2756 if (!IS_INTRESOURCE(lpszName))
2758 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2759 return TRUE;
2762 sz = strlenW(tl_struct->source)+4;
2763 sz *= sizeof(WCHAR);
2765 if ((INT_PTR)lpszName == 1)
2766 tl_struct->path = strdupW(tl_struct->source);
2767 else
2769 tl_struct->path = msi_alloc(sz);
2770 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2773 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2774 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2775 if (FAILED(res))
2777 msi_free(tl_struct->path);
2778 tl_struct->path = NULL;
2780 return TRUE;
2783 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2784 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2786 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2787 return FALSE;
2790 msi_free(tl_struct->path);
2791 tl_struct->path = NULL;
2793 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2794 ITypeLib_Release(tl_struct->ptLib);
2796 return TRUE;
2799 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2801 MSIPACKAGE* package = param;
2802 LPCWSTR component;
2803 MSICOMPONENT *comp;
2804 MSIFILE *file;
2805 typelib_struct tl_struct;
2806 ITypeLib *tlib;
2807 HMODULE module;
2808 HRESULT hr;
2810 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2812 component = MSI_RecordGetString(row,3);
2813 comp = get_loaded_component(package,component);
2814 if (!comp)
2815 return ERROR_SUCCESS;
2817 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2819 TRACE("Skipping typelib reg due to disabled component\n");
2821 comp->Action = comp->Installed;
2823 return ERROR_SUCCESS;
2826 comp->Action = INSTALLSTATE_LOCAL;
2828 file = get_loaded_file( package, comp->KeyPath );
2829 if (!file)
2830 return ERROR_SUCCESS;
2832 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2833 if (module)
2835 LPCWSTR guid;
2836 guid = MSI_RecordGetString(row,1);
2837 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2838 tl_struct.source = strdupW( file->TargetPath );
2839 tl_struct.path = NULL;
2841 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2842 (LONG_PTR)&tl_struct);
2844 if (tl_struct.path)
2846 LPWSTR help = NULL;
2847 LPCWSTR helpid;
2848 HRESULT res;
2850 helpid = MSI_RecordGetString(row,6);
2852 if (helpid)
2853 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
2854 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2855 msi_free(help);
2857 if (FAILED(res))
2858 ERR("Failed to register type library %s\n",
2859 debugstr_w(tl_struct.path));
2860 else
2862 ui_actiondata(package,szRegisterTypeLibraries,row);
2864 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2867 ITypeLib_Release(tl_struct.ptLib);
2868 msi_free(tl_struct.path);
2870 else
2871 ERR("Failed to load type library %s\n",
2872 debugstr_w(tl_struct.source));
2874 FreeLibrary(module);
2875 msi_free(tl_struct.source);
2877 else
2879 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
2880 if (FAILED(hr))
2882 ERR("Failed to load type library: %08x\n", hr);
2883 return ERROR_FUNCTION_FAILED;
2886 ITypeLib_Release(tlib);
2889 return ERROR_SUCCESS;
2892 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2895 * OK this is a bit confusing.. I am given a _Component key and I believe
2896 * that the file that is being registered as a type library is the "key file
2897 * of that component" which I interpret to mean "The file in the KeyPath of
2898 * that component".
2900 UINT rc;
2901 MSIQUERY * view;
2902 static const WCHAR Query[] =
2903 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2904 '`','T','y','p','e','L','i','b','`',0};
2906 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2907 if (rc != ERROR_SUCCESS)
2908 return ERROR_SUCCESS;
2910 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2911 msiobj_release(&view->hdr);
2912 return rc;
2915 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2917 MSIPACKAGE *package = param;
2918 LPWSTR target_file, target_folder, filename;
2919 LPCWSTR buffer, extension;
2920 MSICOMPONENT *comp;
2921 static const WCHAR szlnk[]={'.','l','n','k',0};
2922 IShellLinkW *sl = NULL;
2923 IPersistFile *pf = NULL;
2924 HRESULT res;
2926 buffer = MSI_RecordGetString(row,4);
2927 comp = get_loaded_component(package,buffer);
2928 if (!comp)
2929 return ERROR_SUCCESS;
2931 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2933 TRACE("Skipping shortcut creation due to disabled component\n");
2935 comp->Action = comp->Installed;
2937 return ERROR_SUCCESS;
2940 comp->Action = INSTALLSTATE_LOCAL;
2942 ui_actiondata(package,szCreateShortcuts,row);
2944 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2945 &IID_IShellLinkW, (LPVOID *) &sl );
2947 if (FAILED( res ))
2949 ERR("CLSID_ShellLink not available\n");
2950 goto err;
2953 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2954 if (FAILED( res ))
2956 ERR("QueryInterface(IID_IPersistFile) failed\n");
2957 goto err;
2960 buffer = MSI_RecordGetString(row,2);
2961 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
2963 /* may be needed because of a bug somewhere else */
2964 create_full_pathW(target_folder);
2966 filename = msi_dup_record_field( row, 3 );
2967 reduce_to_longfilename(filename);
2969 extension = strchrW(filename,'.');
2970 if (!extension || strcmpiW(extension,szlnk))
2972 int len = strlenW(filename);
2973 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2974 memcpy(filename + len, szlnk, sizeof(szlnk));
2976 target_file = build_directory_name(2, target_folder, filename);
2977 msi_free(target_folder);
2978 msi_free(filename);
2980 buffer = MSI_RecordGetString(row,5);
2981 if (strchrW(buffer,'['))
2983 LPWSTR deformated;
2984 deformat_string(package,buffer,&deformated);
2985 IShellLinkW_SetPath(sl,deformated);
2986 msi_free(deformated);
2988 else
2990 FIXME("poorly handled shortcut format, advertised shortcut\n");
2991 IShellLinkW_SetPath(sl,comp->FullKeypath);
2994 if (!MSI_RecordIsNull(row,6))
2996 LPWSTR deformated;
2997 buffer = MSI_RecordGetString(row,6);
2998 deformat_string(package,buffer,&deformated);
2999 IShellLinkW_SetArguments(sl,deformated);
3000 msi_free(deformated);
3003 if (!MSI_RecordIsNull(row,7))
3005 buffer = MSI_RecordGetString(row,7);
3006 IShellLinkW_SetDescription(sl,buffer);
3009 if (!MSI_RecordIsNull(row,8))
3010 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3012 if (!MSI_RecordIsNull(row,9))
3014 LPWSTR Path;
3015 INT index;
3017 buffer = MSI_RecordGetString(row,9);
3019 Path = build_icon_path(package,buffer);
3020 index = MSI_RecordGetInteger(row,10);
3022 /* no value means 0 */
3023 if (index == MSI_NULL_INTEGER)
3024 index = 0;
3026 IShellLinkW_SetIconLocation(sl,Path,index);
3027 msi_free(Path);
3030 if (!MSI_RecordIsNull(row,11))
3031 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3033 if (!MSI_RecordIsNull(row,12))
3035 LPWSTR Path;
3036 buffer = MSI_RecordGetString(row,12);
3037 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3038 if (Path)
3039 IShellLinkW_SetWorkingDirectory(sl,Path);
3040 msi_free(Path);
3043 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3044 IPersistFile_Save(pf,target_file,FALSE);
3046 msi_free(target_file);
3048 err:
3049 if (pf)
3050 IPersistFile_Release( pf );
3051 if (sl)
3052 IShellLinkW_Release( sl );
3054 return ERROR_SUCCESS;
3057 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3059 UINT rc;
3060 HRESULT res;
3061 MSIQUERY * view;
3062 static const WCHAR Query[] =
3063 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3064 '`','S','h','o','r','t','c','u','t','`',0};
3066 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3067 if (rc != ERROR_SUCCESS)
3068 return ERROR_SUCCESS;
3070 res = CoInitialize( NULL );
3072 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3073 msiobj_release(&view->hdr);
3075 if (SUCCEEDED(res))
3076 CoUninitialize();
3078 return rc;
3081 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3083 MSIPACKAGE* package = param;
3084 HANDLE the_file;
3085 LPWSTR FilePath;
3086 LPCWSTR FileName;
3087 CHAR buffer[1024];
3088 DWORD sz;
3089 UINT rc;
3090 MSIRECORD *uirow;
3092 FileName = MSI_RecordGetString(row,1);
3093 if (!FileName)
3095 ERR("Unable to get FileName\n");
3096 return ERROR_SUCCESS;
3099 FilePath = build_icon_path(package,FileName);
3101 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3103 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3104 FILE_ATTRIBUTE_NORMAL, NULL);
3106 if (the_file == INVALID_HANDLE_VALUE)
3108 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3109 msi_free(FilePath);
3110 return ERROR_SUCCESS;
3115 DWORD write;
3116 sz = 1024;
3117 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3118 if (rc != ERROR_SUCCESS)
3120 ERR("Failed to get stream\n");
3121 CloseHandle(the_file);
3122 DeleteFileW(FilePath);
3123 break;
3125 WriteFile(the_file,buffer,sz,&write,NULL);
3126 } while (sz == 1024);
3128 msi_free(FilePath);
3130 CloseHandle(the_file);
3132 uirow = MSI_CreateRecord(1);
3133 MSI_RecordSetStringW(uirow,1,FileName);
3134 ui_actiondata(package,szPublishProduct,uirow);
3135 msiobj_release( &uirow->hdr );
3137 return ERROR_SUCCESS;
3140 static UINT msi_publish_icons(MSIPACKAGE *package)
3142 UINT r;
3143 MSIQUERY *view;
3145 static const WCHAR query[]= {
3146 'S','E','L','E','C','T',' ','*',' ',
3147 'F','R','O','M',' ','`','I','c','o','n','`',0};
3149 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3150 if (r == ERROR_SUCCESS)
3152 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3153 msiobj_release(&view->hdr);
3156 return ERROR_SUCCESS;
3159 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3161 UINT r;
3162 HKEY source;
3163 LPWSTR buffer;
3164 MSIMEDIADISK *disk;
3165 MSISOURCELISTINFO *info;
3167 r = RegCreateKeyW(hkey, szSourceList, &source);
3168 if (r != ERROR_SUCCESS)
3169 return r;
3171 RegCloseKey(source);
3173 buffer = strrchrW(package->PackagePath, '\\') + 1;
3174 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3175 package->Context, MSICODE_PRODUCT,
3176 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3177 if (r != ERROR_SUCCESS)
3178 return r;
3180 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3181 package->Context, MSICODE_PRODUCT,
3182 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3183 if (r != ERROR_SUCCESS)
3184 return r;
3186 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3187 package->Context, MSICODE_PRODUCT,
3188 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3189 if (r != ERROR_SUCCESS)
3190 return r;
3192 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3194 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3195 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3196 info->options, info->value);
3197 else
3198 MsiSourceListSetInfoW(package->ProductCode, NULL,
3199 info->context, info->options,
3200 info->property, info->value);
3203 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3205 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3206 disk->context, disk->options,
3207 disk->disk_id, disk->volume_label, disk->disk_prompt);
3210 return ERROR_SUCCESS;
3213 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3215 MSIHANDLE hdb, suminfo;
3216 WCHAR guids[MAX_PATH];
3217 WCHAR packcode[SQUISH_GUID_SIZE];
3218 LPWSTR buffer;
3219 LPWSTR ptr;
3220 DWORD langid;
3221 DWORD size;
3222 UINT r;
3224 static const WCHAR szProductLanguage[] =
3225 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3226 static const WCHAR szARPProductIcon[] =
3227 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3228 static const WCHAR szProductVersion[] =
3229 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3230 static const WCHAR szAssignment[] =
3231 {'A','s','s','i','g','n','m','e','n','t',0};
3232 static const WCHAR szAdvertiseFlags[] =
3233 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3234 static const WCHAR szClients[] =
3235 {'C','l','i','e','n','t','s',0};
3236 static const WCHAR szColon[] = {':',0};
3238 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3239 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3240 msi_free(buffer);
3242 langid = msi_get_property_int(package, szProductLanguage, 0);
3243 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3245 /* FIXME */
3246 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3248 buffer = msi_dup_property(package, szARPProductIcon);
3249 if (buffer)
3251 LPWSTR path = build_icon_path(package,buffer);
3252 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3253 msi_free(path);
3254 msi_free(buffer);
3257 buffer = msi_dup_property(package, szProductVersion);
3258 if (buffer)
3260 DWORD verdword = msi_version_str_to_dword(buffer);
3261 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3262 msi_free(buffer);
3265 msi_reg_set_val_dword(hkey, szAssignment, 0);
3266 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3267 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3268 msi_reg_set_val_str(hkey, szClients, szColon);
3270 hdb = alloc_msihandle(&package->db->hdr);
3271 if (!hdb)
3272 return ERROR_NOT_ENOUGH_MEMORY;
3274 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3275 MsiCloseHandle(hdb);
3276 if (r != ERROR_SUCCESS)
3277 goto done;
3279 size = MAX_PATH;
3280 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3281 NULL, guids, &size);
3282 if (r != ERROR_SUCCESS)
3283 goto done;
3285 ptr = strchrW(guids, ';');
3286 if (ptr) *ptr = 0;
3287 squash_guid(guids, packcode);
3288 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3290 done:
3291 MsiCloseHandle(suminfo);
3292 return ERROR_SUCCESS;
3295 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3297 UINT r;
3298 HKEY hkey;
3299 LPWSTR upgrade;
3300 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3302 static const WCHAR szUpgradeCode[] =
3303 {'U','p','g','r','a','d','e','C','o','d','e',0};
3305 upgrade = msi_dup_property(package, szUpgradeCode);
3306 if (!upgrade)
3307 return ERROR_SUCCESS;
3309 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3311 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3312 if (r != ERROR_SUCCESS)
3313 goto done;
3315 else
3317 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3318 if (r != ERROR_SUCCESS)
3319 goto done;
3322 squash_guid(package->ProductCode, squashed_pc);
3323 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3325 RegCloseKey(hkey);
3327 done:
3328 msi_free(upgrade);
3329 return r;
3332 static BOOL msi_check_publish(MSIPACKAGE *package)
3334 MSIFEATURE *feature;
3336 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3338 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3339 return TRUE;
3342 return FALSE;
3345 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3347 MSIFEATURE *feature;
3349 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3351 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3352 return FALSE;
3355 return TRUE;
3358 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3360 WCHAR patch_squashed[GUID_SIZE];
3361 HKEY patches;
3362 LONG res;
3363 UINT r = ERROR_FUNCTION_FAILED;
3365 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3366 &patches, NULL);
3367 if (res != ERROR_SUCCESS)
3368 return ERROR_FUNCTION_FAILED;
3370 squash_guid(package->patch->patchcode, patch_squashed);
3372 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3373 (const BYTE *)patch_squashed,
3374 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3375 if (res != ERROR_SUCCESS)
3376 goto done;
3378 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3379 (const BYTE *)package->patch->transforms,
3380 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3381 if (res == ERROR_SUCCESS)
3382 r = ERROR_SUCCESS;
3384 done:
3385 RegCloseKey(patches);
3386 return r;
3390 * 99% of the work done here is only done for
3391 * advertised installs. However this is where the
3392 * Icon table is processed and written out
3393 * so that is what I am going to do here.
3395 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3397 UINT rc;
3398 HKEY hukey=0;
3399 HKEY hudkey=0;
3401 /* FIXME: also need to publish if the product is in advertise mode */
3402 if (!msi_check_publish(package))
3403 return ERROR_SUCCESS;
3405 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3406 &hukey, TRUE);
3407 if (rc != ERROR_SUCCESS)
3408 goto end;
3410 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3411 NULL, &hudkey, TRUE);
3412 if (rc != ERROR_SUCCESS)
3413 goto end;
3415 rc = msi_publish_upgrade_code(package);
3416 if (rc != ERROR_SUCCESS)
3417 goto end;
3419 if (package->patch)
3421 rc = msi_publish_patch(package, hukey, hudkey);
3422 if (rc != ERROR_SUCCESS)
3423 goto end;
3426 rc = msi_publish_product_properties(package, hukey);
3427 if (rc != ERROR_SUCCESS)
3428 goto end;
3430 rc = msi_publish_sourcelist(package, hukey);
3431 if (rc != ERROR_SUCCESS)
3432 goto end;
3434 rc = msi_publish_icons(package);
3436 end:
3437 RegCloseKey(hukey);
3438 RegCloseKey(hudkey);
3440 return rc;
3443 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3445 MSIPACKAGE *package = param;
3446 LPCWSTR component, section, key, value, identifier, dirproperty;
3447 LPWSTR deformated_section, deformated_key, deformated_value;
3448 LPWSTR folder, filename, fullname = NULL;
3449 LPCWSTR filenameptr;
3450 MSIRECORD * uirow;
3451 INT action;
3452 MSICOMPONENT *comp;
3453 static const WCHAR szWindowsFolder[] =
3454 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3456 component = MSI_RecordGetString(row, 8);
3457 comp = get_loaded_component(package,component);
3459 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3461 TRACE("Skipping ini file due to disabled component %s\n",
3462 debugstr_w(component));
3464 comp->Action = comp->Installed;
3466 return ERROR_SUCCESS;
3469 comp->Action = INSTALLSTATE_LOCAL;
3471 identifier = MSI_RecordGetString(row,1);
3472 dirproperty = MSI_RecordGetString(row,3);
3473 section = MSI_RecordGetString(row,4);
3474 key = MSI_RecordGetString(row,5);
3475 value = MSI_RecordGetString(row,6);
3476 action = MSI_RecordGetInteger(row,7);
3478 deformat_string(package,section,&deformated_section);
3479 deformat_string(package,key,&deformated_key);
3480 deformat_string(package,value,&deformated_value);
3482 filename = msi_dup_record_field(row, 2);
3483 if (filename && (filenameptr = strchrW(filename, '|')))
3484 filenameptr++;
3485 else
3486 filenameptr = filename;
3488 if (dirproperty)
3490 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3491 if (!folder)
3492 folder = msi_dup_property( package, dirproperty );
3494 else
3495 folder = msi_dup_property( package, szWindowsFolder );
3497 if (!folder)
3499 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3500 goto cleanup;
3503 fullname = build_directory_name(2, folder, filenameptr);
3505 if (action == 0)
3507 TRACE("Adding value %s to section %s in %s\n",
3508 debugstr_w(deformated_key), debugstr_w(deformated_section),
3509 debugstr_w(fullname));
3510 WritePrivateProfileStringW(deformated_section, deformated_key,
3511 deformated_value, fullname);
3513 else if (action == 1)
3515 WCHAR returned[10];
3516 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3517 returned, 10, fullname);
3518 if (returned[0] == 0)
3520 TRACE("Adding value %s to section %s in %s\n",
3521 debugstr_w(deformated_key), debugstr_w(deformated_section),
3522 debugstr_w(fullname));
3524 WritePrivateProfileStringW(deformated_section, deformated_key,
3525 deformated_value, fullname);
3528 else if (action == 3)
3529 FIXME("Append to existing section not yet implemented\n");
3531 uirow = MSI_CreateRecord(4);
3532 MSI_RecordSetStringW(uirow,1,identifier);
3533 MSI_RecordSetStringW(uirow,2,deformated_section);
3534 MSI_RecordSetStringW(uirow,3,deformated_key);
3535 MSI_RecordSetStringW(uirow,4,deformated_value);
3536 ui_actiondata(package,szWriteIniValues,uirow);
3537 msiobj_release( &uirow->hdr );
3539 cleanup:
3540 msi_free(filename);
3541 msi_free(fullname);
3542 msi_free(folder);
3543 msi_free(deformated_key);
3544 msi_free(deformated_value);
3545 msi_free(deformated_section);
3546 return ERROR_SUCCESS;
3549 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3551 UINT rc;
3552 MSIQUERY * view;
3553 static const WCHAR ExecSeqQuery[] =
3554 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3555 '`','I','n','i','F','i','l','e','`',0};
3557 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3558 if (rc != ERROR_SUCCESS)
3560 TRACE("no IniFile table\n");
3561 return ERROR_SUCCESS;
3564 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3565 msiobj_release(&view->hdr);
3566 return rc;
3569 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3571 MSIPACKAGE *package = param;
3572 LPCWSTR filename;
3573 LPWSTR FullName;
3574 MSIFILE *file;
3575 DWORD len;
3576 static const WCHAR ExeStr[] =
3577 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3578 static const WCHAR close[] = {'\"',0};
3579 STARTUPINFOW si;
3580 PROCESS_INFORMATION info;
3581 BOOL brc;
3582 MSIRECORD *uirow;
3583 LPWSTR uipath, p;
3585 memset(&si,0,sizeof(STARTUPINFOW));
3587 filename = MSI_RecordGetString(row,1);
3588 file = get_loaded_file( package, filename );
3590 if (!file)
3592 ERR("Unable to find file id %s\n",debugstr_w(filename));
3593 return ERROR_SUCCESS;
3596 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3598 FullName = msi_alloc(len*sizeof(WCHAR));
3599 strcpyW(FullName,ExeStr);
3600 strcatW( FullName, file->TargetPath );
3601 strcatW(FullName,close);
3603 TRACE("Registering %s\n",debugstr_w(FullName));
3604 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3605 &si, &info);
3607 if (brc)
3609 CloseHandle(info.hThread);
3610 msi_dialog_check_messages(info.hProcess);
3611 CloseHandle(info.hProcess);
3614 msi_free(FullName);
3616 /* the UI chunk */
3617 uirow = MSI_CreateRecord( 2 );
3618 uipath = strdupW( file->TargetPath );
3619 p = strrchrW(uipath,'\\');
3620 if (p)
3621 p[0]=0;
3622 MSI_RecordSetStringW( uirow, 1, &p[1] );
3623 MSI_RecordSetStringW( uirow, 2, uipath);
3624 ui_actiondata( package, szSelfRegModules, uirow);
3625 msiobj_release( &uirow->hdr );
3626 msi_free( uipath );
3627 /* FIXME: call ui_progress? */
3629 return ERROR_SUCCESS;
3632 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3634 UINT rc;
3635 MSIQUERY * view;
3636 static const WCHAR ExecSeqQuery[] =
3637 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3638 '`','S','e','l','f','R','e','g','`',0};
3640 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3641 if (rc != ERROR_SUCCESS)
3643 TRACE("no SelfReg table\n");
3644 return ERROR_SUCCESS;
3647 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3648 msiobj_release(&view->hdr);
3650 return ERROR_SUCCESS;
3653 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3655 MSIFEATURE *feature;
3656 UINT rc;
3657 HKEY hkey;
3658 HKEY userdata = NULL;
3660 if (!msi_check_publish(package))
3661 return ERROR_SUCCESS;
3663 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3664 &hkey, TRUE);
3665 if (rc != ERROR_SUCCESS)
3666 goto end;
3668 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3669 &userdata, TRUE);
3670 if (rc != ERROR_SUCCESS)
3671 goto end;
3673 /* here the guids are base 85 encoded */
3674 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3676 ComponentList *cl;
3677 LPWSTR data = NULL;
3678 GUID clsid;
3679 INT size;
3680 BOOL absent = FALSE;
3681 MSIRECORD *uirow;
3683 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3684 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3685 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3686 absent = TRUE;
3688 size = 1;
3689 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3691 size += 21;
3693 if (feature->Feature_Parent)
3694 size += strlenW( feature->Feature_Parent )+2;
3696 data = msi_alloc(size * sizeof(WCHAR));
3698 data[0] = 0;
3699 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3701 MSICOMPONENT* component = cl->component;
3702 WCHAR buf[21];
3704 buf[0] = 0;
3705 if (component->ComponentId)
3707 TRACE("From %s\n",debugstr_w(component->ComponentId));
3708 CLSIDFromString(component->ComponentId, &clsid);
3709 encode_base85_guid(&clsid,buf);
3710 TRACE("to %s\n",debugstr_w(buf));
3711 strcatW(data,buf);
3715 if (feature->Feature_Parent)
3717 static const WCHAR sep[] = {'\2',0};
3718 strcatW(data,sep);
3719 strcatW(data,feature->Feature_Parent);
3722 msi_reg_set_val_str( userdata, feature->Feature, data );
3723 msi_free(data);
3725 size = 0;
3726 if (feature->Feature_Parent)
3727 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3728 if (!absent)
3730 size += sizeof(WCHAR);
3731 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3732 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
3734 else
3736 size += 2*sizeof(WCHAR);
3737 data = msi_alloc(size);
3738 data[0] = 0x6;
3739 data[1] = 0;
3740 if (feature->Feature_Parent)
3741 strcpyW( &data[1], feature->Feature_Parent );
3742 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3743 (LPBYTE)data,size);
3744 msi_free(data);
3747 /* the UI chunk */
3748 uirow = MSI_CreateRecord( 1 );
3749 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3750 ui_actiondata( package, szPublishFeatures, uirow);
3751 msiobj_release( &uirow->hdr );
3752 /* FIXME: call ui_progress? */
3755 end:
3756 RegCloseKey(hkey);
3757 RegCloseKey(userdata);
3758 return rc;
3761 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
3763 UINT r;
3764 HKEY hkey;
3766 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
3768 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3769 &hkey, FALSE);
3770 if (r == ERROR_SUCCESS)
3772 RegDeleteValueW(hkey, feature->Feature);
3773 RegCloseKey(hkey);
3776 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3777 &hkey, FALSE);
3778 if (r == ERROR_SUCCESS)
3780 RegDeleteValueW(hkey, feature->Feature);
3781 RegCloseKey(hkey);
3784 return ERROR_SUCCESS;
3787 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
3789 MSIFEATURE *feature;
3791 if (!msi_check_unpublish(package))
3792 return ERROR_SUCCESS;
3794 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3796 msi_unpublish_feature(package, feature);
3799 return ERROR_SUCCESS;
3802 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
3804 LPWSTR prop, val, key;
3805 SYSTEMTIME systime;
3806 DWORD size, langid;
3807 WCHAR date[9];
3808 LPWSTR buffer;
3810 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
3811 static const WCHAR szWindowsInstaller[] =
3812 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3813 static const WCHAR modpath_fmt[] =
3814 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3815 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3816 static const WCHAR szModifyPath[] =
3817 {'M','o','d','i','f','y','P','a','t','h',0};
3818 static const WCHAR szUninstallString[] =
3819 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3820 static const WCHAR szEstimatedSize[] =
3821 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3822 static const WCHAR szProductLanguage[] =
3823 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3824 static const WCHAR szProductVersion[] =
3825 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3826 static const WCHAR szProductName[] =
3827 {'P','r','o','d','u','c','t','N','a','m','e',0};
3828 static const WCHAR szDisplayName[] =
3829 {'D','i','s','p','l','a','y','N','a','m','e',0};
3830 static const WCHAR szDisplayVersion[] =
3831 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
3832 static const WCHAR szManufacturer[] =
3833 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
3835 static const LPCSTR propval[] = {
3836 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3837 "ARPCONTACT", "Contact",
3838 "ARPCOMMENTS", "Comments",
3839 "ProductName", "DisplayName",
3840 "ProductVersion", "DisplayVersion",
3841 "ARPHELPLINK", "HelpLink",
3842 "ARPHELPTELEPHONE", "HelpTelephone",
3843 "ARPINSTALLLOCATION", "InstallLocation",
3844 "SourceDir", "InstallSource",
3845 "Manufacturer", "Publisher",
3846 "ARPREADME", "Readme",
3847 "ARPSIZE", "Size",
3848 "ARPURLINFOABOUT", "URLInfoAbout",
3849 "ARPURLUPDATEINFO", "URLUpdateInfo",
3850 NULL,
3852 const LPCSTR *p = propval;
3854 while (*p)
3856 prop = strdupAtoW(*p++);
3857 key = strdupAtoW(*p++);
3858 val = msi_dup_property(package, prop);
3859 msi_reg_set_val_str(hkey, key, val);
3860 msi_free(val);
3861 msi_free(key);
3862 msi_free(prop);
3865 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
3867 size = deformat_string(package, modpath_fmt, &buffer);
3868 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
3869 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
3870 msi_free(buffer);
3872 /* FIXME: Write real Estimated Size when we have it */
3873 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
3875 buffer = msi_dup_property(package, szProductName);
3876 msi_reg_set_val_str(hkey, szDisplayName, buffer);
3877 msi_free(buffer);
3879 buffer = msi_dup_property(package, cszSourceDir);
3880 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
3881 msi_free(buffer);
3883 buffer = msi_dup_property(package, szManufacturer);
3884 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
3885 msi_free(buffer);
3887 GetLocalTime(&systime);
3888 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
3889 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
3891 langid = msi_get_property_int(package, szProductLanguage, 0);
3892 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3894 buffer = msi_dup_property(package, szProductVersion);
3895 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
3896 if (buffer)
3898 DWORD verdword = msi_version_str_to_dword(buffer);
3900 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3901 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
3902 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
3903 msi_free(buffer);
3906 return ERROR_SUCCESS;
3909 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3911 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3912 LPWSTR upgrade_code;
3913 HKEY hkey, props;
3914 HKEY upgrade;
3915 UINT rc;
3917 static const WCHAR szUpgradeCode[] = {
3918 'U','p','g','r','a','d','e','C','o','d','e',0};
3920 /* FIXME: also need to publish if the product is in advertise mode */
3921 if (!msi_check_publish(package))
3922 return ERROR_SUCCESS;
3924 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
3925 if (rc != ERROR_SUCCESS)
3926 return rc;
3928 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
3929 NULL, &props, TRUE);
3930 if (rc != ERROR_SUCCESS)
3931 goto done;
3933 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
3934 msi_free( package->db->localfile );
3935 package->db->localfile = NULL;
3937 rc = msi_publish_install_properties(package, hkey);
3938 if (rc != ERROR_SUCCESS)
3939 goto done;
3941 rc = msi_publish_install_properties(package, props);
3942 if (rc != ERROR_SUCCESS)
3943 goto done;
3945 upgrade_code = msi_dup_property(package, szUpgradeCode);
3946 if (upgrade_code)
3948 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
3949 squash_guid(package->ProductCode, squashed_pc);
3950 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
3951 RegCloseKey(upgrade);
3952 msi_free(upgrade_code);
3955 done:
3956 RegCloseKey(hkey);
3958 return ERROR_SUCCESS;
3961 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3963 return execute_script(package,INSTALL_SCRIPT);
3966 static UINT msi_unpublish_product(MSIPACKAGE *package)
3968 LPWSTR upgrade;
3969 LPWSTR remove = NULL;
3970 LPWSTR *features = NULL;
3971 BOOL full_uninstall = TRUE;
3972 MSIFEATURE *feature;
3974 static const WCHAR szUpgradeCode[] =
3975 {'U','p','g','r','a','d','e','C','o','d','e',0};
3977 remove = msi_dup_property(package, szRemove);
3978 if (!remove)
3979 return ERROR_SUCCESS;
3981 features = msi_split_string(remove, ',');
3982 if (!features)
3984 msi_free(remove);
3985 ERR("REMOVE feature list is empty!\n");
3986 return ERROR_FUNCTION_FAILED;
3989 if (!lstrcmpW(features[0], szAll))
3990 full_uninstall = TRUE;
3991 else
3993 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3995 if (feature->Action != INSTALLSTATE_ABSENT)
3996 full_uninstall = FALSE;
4000 if (!full_uninstall)
4001 goto done;
4003 MSIREG_DeleteProductKey(package->ProductCode);
4004 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4005 MSIREG_DeleteUninstallKey(package->ProductCode);
4007 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4009 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4010 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4012 else
4014 MSIREG_DeleteUserProductKey(package->ProductCode);
4015 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4018 upgrade = msi_dup_property(package, szUpgradeCode);
4019 if (upgrade)
4021 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4022 msi_free(upgrade);
4025 done:
4026 msi_free(remove);
4027 msi_free(features);
4028 return ERROR_SUCCESS;
4031 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4033 UINT rc;
4035 rc = msi_unpublish_product(package);
4036 if (rc != ERROR_SUCCESS)
4037 return rc;
4039 /* turn off scheduling */
4040 package->script->CurrentlyScripting= FALSE;
4042 /* first do the same as an InstallExecute */
4043 rc = ACTION_InstallExecute(package);
4044 if (rc != ERROR_SUCCESS)
4045 return rc;
4047 /* then handle Commit Actions */
4048 rc = execute_script(package,COMMIT_SCRIPT);
4050 return rc;
4053 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4055 static const WCHAR RunOnce[] = {
4056 'S','o','f','t','w','a','r','e','\\',
4057 'M','i','c','r','o','s','o','f','t','\\',
4058 'W','i','n','d','o','w','s','\\',
4059 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4060 'R','u','n','O','n','c','e',0};
4061 static const WCHAR InstallRunOnce[] = {
4062 'S','o','f','t','w','a','r','e','\\',
4063 'M','i','c','r','o','s','o','f','t','\\',
4064 'W','i','n','d','o','w','s','\\',
4065 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4066 'I','n','s','t','a','l','l','e','r','\\',
4067 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4069 static const WCHAR msiexec_fmt[] = {
4070 '%','s',
4071 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4072 '\"','%','s','\"',0};
4073 static const WCHAR install_fmt[] = {
4074 '/','I',' ','\"','%','s','\"',' ',
4075 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4076 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4077 WCHAR buffer[256], sysdir[MAX_PATH];
4078 HKEY hkey;
4079 WCHAR squished_pc[100];
4081 squash_guid(package->ProductCode,squished_pc);
4083 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4084 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4085 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4086 squished_pc);
4088 msi_reg_set_val_str( hkey, squished_pc, buffer );
4089 RegCloseKey(hkey);
4091 TRACE("Reboot command %s\n",debugstr_w(buffer));
4093 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4094 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4096 msi_reg_set_val_str( hkey, squished_pc, buffer );
4097 RegCloseKey(hkey);
4099 return ERROR_INSTALL_SUSPEND;
4102 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4104 DWORD attrib;
4105 UINT rc;
4108 * We are currently doing what should be done here in the top level Install
4109 * however for Administrative and uninstalls this step will be needed
4111 if (!package->PackagePath)
4112 return ERROR_SUCCESS;
4114 msi_set_sourcedir_props(package, TRUE);
4116 attrib = GetFileAttributesW(package->db->path);
4117 if (attrib == INVALID_FILE_ATTRIBUTES)
4119 LPWSTR prompt;
4120 LPWSTR msg;
4121 DWORD size = 0;
4123 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4124 package->Context, MSICODE_PRODUCT,
4125 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4126 if (rc == ERROR_MORE_DATA)
4128 prompt = msi_alloc(size * sizeof(WCHAR));
4129 MsiSourceListGetInfoW(package->ProductCode, NULL,
4130 package->Context, MSICODE_PRODUCT,
4131 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4133 else
4134 prompt = strdupW(package->db->path);
4136 msg = generate_error_string(package,1302,1,prompt);
4137 while(attrib == INVALID_FILE_ATTRIBUTES)
4139 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4140 if (rc == IDCANCEL)
4142 rc = ERROR_INSTALL_USEREXIT;
4143 break;
4145 attrib = GetFileAttributesW(package->db->path);
4147 msi_free(prompt);
4148 rc = ERROR_SUCCESS;
4150 else
4151 return ERROR_SUCCESS;
4153 return rc;
4156 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4158 HKEY hkey=0;
4159 LPWSTR buffer;
4160 LPWSTR productid;
4161 UINT rc,i;
4163 static const WCHAR szPropKeys[][80] =
4165 {'P','r','o','d','u','c','t','I','D',0},
4166 {'U','S','E','R','N','A','M','E',0},
4167 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4168 {0},
4171 static const WCHAR szRegKeys[][80] =
4173 {'P','r','o','d','u','c','t','I','D',0},
4174 {'R','e','g','O','w','n','e','r',0},
4175 {'R','e','g','C','o','m','p','a','n','y',0},
4176 {0},
4179 if (msi_check_unpublish(package))
4181 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4182 return ERROR_SUCCESS;
4185 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4186 if (!productid)
4187 return ERROR_SUCCESS;
4189 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4190 NULL, &hkey, TRUE);
4191 if (rc != ERROR_SUCCESS)
4192 goto end;
4194 for( i = 0; szPropKeys[i][0]; i++ )
4196 buffer = msi_dup_property( package, szPropKeys[i] );
4197 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4198 msi_free( buffer );
4201 end:
4202 msi_free(productid);
4203 RegCloseKey(hkey);
4205 /* FIXME: call ui_actiondata */
4207 return rc;
4211 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4213 UINT rc;
4215 package->script->InWhatSequence |= SEQUENCE_EXEC;
4216 rc = ACTION_ProcessExecSequence(package,FALSE);
4217 return rc;
4221 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4223 MSIPACKAGE *package = param;
4224 LPCWSTR compgroupid=NULL;
4225 LPCWSTR feature=NULL;
4226 LPCWSTR text = NULL;
4227 LPCWSTR qualifier = NULL;
4228 LPCWSTR component = NULL;
4229 LPWSTR advertise = NULL;
4230 LPWSTR output = NULL;
4231 HKEY hkey;
4232 UINT rc = ERROR_SUCCESS;
4233 MSICOMPONENT *comp;
4234 DWORD sz = 0;
4235 MSIRECORD *uirow;
4237 component = MSI_RecordGetString(rec,3);
4238 comp = get_loaded_component(package,component);
4240 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4241 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4242 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4244 TRACE("Skipping: Component %s not scheduled for install\n",
4245 debugstr_w(component));
4247 return ERROR_SUCCESS;
4250 compgroupid = MSI_RecordGetString(rec,1);
4251 qualifier = MSI_RecordGetString(rec,2);
4253 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4254 if (rc != ERROR_SUCCESS)
4255 goto end;
4257 text = MSI_RecordGetString(rec,4);
4258 feature = MSI_RecordGetString(rec,5);
4260 advertise = create_component_advertise_string(package, comp, feature);
4262 sz = strlenW(advertise);
4264 if (text)
4265 sz += lstrlenW(text);
4267 sz+=3;
4268 sz *= sizeof(WCHAR);
4270 output = msi_alloc_zero(sz);
4271 strcpyW(output,advertise);
4272 msi_free(advertise);
4274 if (text)
4275 strcatW(output,text);
4277 msi_reg_set_val_multi_str( hkey, qualifier, output );
4279 end:
4280 RegCloseKey(hkey);
4281 msi_free(output);
4283 /* the UI chunk */
4284 uirow = MSI_CreateRecord( 2 );
4285 MSI_RecordSetStringW( uirow, 1, compgroupid );
4286 MSI_RecordSetStringW( uirow, 2, qualifier);
4287 ui_actiondata( package, szPublishComponents, uirow);
4288 msiobj_release( &uirow->hdr );
4289 /* FIXME: call ui_progress? */
4291 return rc;
4295 * At present I am ignorning the advertised components part of this and only
4296 * focusing on the qualified component sets
4298 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4300 UINT rc;
4301 MSIQUERY * view;
4302 static const WCHAR ExecSeqQuery[] =
4303 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4304 '`','P','u','b','l','i','s','h',
4305 'C','o','m','p','o','n','e','n','t','`',0};
4307 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4308 if (rc != ERROR_SUCCESS)
4309 return ERROR_SUCCESS;
4311 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4312 msiobj_release(&view->hdr);
4314 return rc;
4317 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4319 MSIPACKAGE *package = param;
4320 MSIRECORD *row;
4321 MSIFILE *file;
4322 SC_HANDLE hscm, service = NULL;
4323 LPCWSTR comp, depends, pass;
4324 LPWSTR name = NULL, disp = NULL;
4325 LPCWSTR load_order, serv_name, key;
4326 DWORD serv_type, start_type;
4327 DWORD err_control;
4329 static const WCHAR query[] =
4330 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4331 '`','C','o','m','p','o','n','e','n','t','`',' ',
4332 'W','H','E','R','E',' ',
4333 '`','C','o','m','p','o','n','e','n','t','`',' ',
4334 '=','\'','%','s','\'',0};
4336 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4337 if (!hscm)
4339 ERR("Failed to open the SC Manager!\n");
4340 goto done;
4343 start_type = MSI_RecordGetInteger(rec, 5);
4344 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4345 goto done;
4347 depends = MSI_RecordGetString(rec, 8);
4348 if (depends && *depends)
4349 FIXME("Dependency list unhandled!\n");
4351 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4352 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
4353 serv_type = MSI_RecordGetInteger(rec, 4);
4354 err_control = MSI_RecordGetInteger(rec, 6);
4355 load_order = MSI_RecordGetString(rec, 7);
4356 serv_name = MSI_RecordGetString(rec, 9);
4357 pass = MSI_RecordGetString(rec, 10);
4358 comp = MSI_RecordGetString(rec, 12);
4360 /* fetch the service path */
4361 row = MSI_QueryGetRecord(package->db, query, comp);
4362 if (!row)
4364 ERR("Control query failed!\n");
4365 goto done;
4368 key = MSI_RecordGetString(row, 6);
4370 file = get_loaded_file(package, key);
4371 msiobj_release(&row->hdr);
4372 if (!file)
4374 ERR("Failed to load the service file\n");
4375 goto done;
4378 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4379 start_type, err_control, file->TargetPath,
4380 load_order, NULL, NULL, serv_name, pass);
4381 if (!service)
4383 if (GetLastError() != ERROR_SERVICE_EXISTS)
4384 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4387 done:
4388 CloseServiceHandle(service);
4389 CloseServiceHandle(hscm);
4390 msi_free(name);
4391 msi_free(disp);
4393 return ERROR_SUCCESS;
4396 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4398 UINT rc;
4399 MSIQUERY * view;
4400 static const WCHAR ExecSeqQuery[] =
4401 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4402 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4404 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4405 if (rc != ERROR_SUCCESS)
4406 return ERROR_SUCCESS;
4408 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4409 msiobj_release(&view->hdr);
4411 return rc;
4414 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4415 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
4417 LPCWSTR *vector, *temp_vector;
4418 LPWSTR p, q;
4419 DWORD sep_len;
4421 static const WCHAR separator[] = {'[','~',']',0};
4423 *numargs = 0;
4424 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4426 if (!args)
4427 return NULL;
4429 vector = msi_alloc(sizeof(LPWSTR));
4430 if (!vector)
4431 return NULL;
4433 p = args;
4436 (*numargs)++;
4437 vector[*numargs - 1] = p;
4439 if ((q = strstrW(p, separator)))
4441 *q = '\0';
4443 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4444 if (!temp_vector)
4446 msi_free(vector);
4447 return NULL;
4449 vector = temp_vector;
4451 p = q + sep_len;
4453 } while (q);
4455 return vector;
4458 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4460 MSIPACKAGE *package = param;
4461 MSICOMPONENT *comp;
4462 SC_HANDLE scm, service = NULL;
4463 LPCWSTR *vector = NULL;
4464 LPWSTR name, args;
4465 DWORD event, numargs;
4466 UINT r = ERROR_FUNCTION_FAILED;
4468 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4469 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4470 return ERROR_SUCCESS;
4472 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4473 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4474 event = MSI_RecordGetInteger(rec, 3);
4476 if (!(event & msidbServiceControlEventStart))
4477 return ERROR_SUCCESS;
4479 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4480 if (!scm)
4482 ERR("Failed to open the service control manager\n");
4483 goto done;
4486 service = OpenServiceW(scm, name, SERVICE_START);
4487 if (!service)
4489 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
4490 goto done;
4493 vector = msi_service_args_to_vector(args, &numargs);
4495 if (!StartServiceW(service, numargs, vector) &&
4496 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
4498 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
4499 goto done;
4502 r = ERROR_SUCCESS;
4504 done:
4505 CloseServiceHandle(service);
4506 CloseServiceHandle(scm);
4508 msi_free(name);
4509 msi_free(args);
4510 msi_free(vector);
4511 return r;
4514 static UINT ACTION_StartServices( MSIPACKAGE *package )
4516 UINT rc;
4517 MSIQUERY *view;
4519 static const WCHAR query[] = {
4520 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4521 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4523 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4524 if (rc != ERROR_SUCCESS)
4525 return ERROR_SUCCESS;
4527 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4528 msiobj_release(&view->hdr);
4530 return rc;
4533 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4535 DWORD i, needed, count;
4536 ENUM_SERVICE_STATUSW *dependencies;
4537 SERVICE_STATUS ss;
4538 SC_HANDLE depserv;
4540 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4541 0, &needed, &count))
4542 return TRUE;
4544 if (GetLastError() != ERROR_MORE_DATA)
4545 return FALSE;
4547 dependencies = msi_alloc(needed);
4548 if (!dependencies)
4549 return FALSE;
4551 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4552 needed, &needed, &count))
4553 goto error;
4555 for (i = 0; i < count; i++)
4557 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4558 SERVICE_STOP | SERVICE_QUERY_STATUS);
4559 if (!depserv)
4560 goto error;
4562 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4563 goto error;
4566 return TRUE;
4568 error:
4569 msi_free(dependencies);
4570 return FALSE;
4573 static UINT stop_service( LPCWSTR name )
4575 SC_HANDLE scm = NULL, service = NULL;
4576 SERVICE_STATUS status;
4577 SERVICE_STATUS_PROCESS ssp;
4578 DWORD needed;
4580 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4581 if (!scm)
4583 WARN("Failed to open the SCM: %d\n", GetLastError());
4584 goto done;
4587 service = OpenServiceW(scm, name,
4588 SERVICE_STOP |
4589 SERVICE_QUERY_STATUS |
4590 SERVICE_ENUMERATE_DEPENDENTS);
4591 if (!service)
4593 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
4594 goto done;
4597 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4598 sizeof(SERVICE_STATUS_PROCESS), &needed))
4600 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
4601 goto done;
4604 if (ssp.dwCurrentState == SERVICE_STOPPED)
4605 goto done;
4607 stop_service_dependents(scm, service);
4609 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
4610 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
4612 done:
4613 CloseServiceHandle(service);
4614 CloseServiceHandle(scm);
4616 return ERROR_SUCCESS;
4619 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
4621 MSIPACKAGE *package = param;
4622 MSICOMPONENT *comp;
4623 LPWSTR name;
4624 DWORD event;
4626 event = MSI_RecordGetInteger( rec, 3 );
4627 if (!(event & msidbServiceControlEventStop))
4628 return ERROR_SUCCESS;
4630 comp = get_loaded_component( package, MSI_RecordGetString( rec, 6 ) );
4631 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4632 return ERROR_SUCCESS;
4634 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
4635 stop_service( name );
4636 msi_free( name );
4638 return ERROR_SUCCESS;
4641 static UINT ACTION_StopServices( MSIPACKAGE *package )
4643 UINT rc;
4644 MSIQUERY *view;
4646 static const WCHAR query[] = {
4647 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4648 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4650 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4651 if (rc != ERROR_SUCCESS)
4652 return ERROR_SUCCESS;
4654 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
4655 msiobj_release(&view->hdr);
4657 return rc;
4660 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
4662 MSIPACKAGE *package = param;
4663 MSICOMPONENT *comp;
4664 LPWSTR name = NULL;
4665 DWORD event;
4666 SC_HANDLE scm = NULL, service = NULL;
4668 event = MSI_RecordGetInteger( rec, 3 );
4669 if (!(event & msidbServiceControlEventDelete))
4670 return ERROR_SUCCESS;
4672 comp = get_loaded_component( package, MSI_RecordGetString(rec, 6) );
4673 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4674 return ERROR_SUCCESS;
4676 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
4677 stop_service( name );
4679 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
4680 if (!scm)
4682 WARN("Failed to open the SCM: %d\n", GetLastError());
4683 goto done;
4686 service = OpenServiceW( scm, name, DELETE );
4687 if (!service)
4689 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
4690 goto done;
4693 if (!DeleteService( service ))
4694 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
4696 done:
4697 CloseServiceHandle( service );
4698 CloseServiceHandle( scm );
4699 msi_free( name );
4701 return ERROR_SUCCESS;
4704 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4706 UINT rc;
4707 MSIQUERY *view;
4709 static const WCHAR query[] = {
4710 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4711 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4713 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4714 if (rc != ERROR_SUCCESS)
4715 return ERROR_SUCCESS;
4717 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
4718 msiobj_release( &view->hdr );
4720 return rc;
4723 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4725 MSIFILE *file;
4727 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4729 if (!lstrcmpW(file->File, filename))
4730 return file;
4733 return NULL;
4736 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4738 MSIPACKAGE *package = param;
4739 LPWSTR driver, driver_path, ptr;
4740 WCHAR outpath[MAX_PATH];
4741 MSIFILE *driver_file, *setup_file;
4742 LPCWSTR desc;
4743 DWORD len, usage;
4744 UINT r = ERROR_SUCCESS;
4746 static const WCHAR driver_fmt[] = {
4747 'D','r','i','v','e','r','=','%','s',0};
4748 static const WCHAR setup_fmt[] = {
4749 'S','e','t','u','p','=','%','s',0};
4750 static const WCHAR usage_fmt[] = {
4751 'F','i','l','e','U','s','a','g','e','=','1',0};
4753 desc = MSI_RecordGetString(rec, 3);
4755 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4756 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4758 if (!driver_file || !setup_file)
4760 ERR("ODBC Driver entry not found!\n");
4761 return ERROR_FUNCTION_FAILED;
4764 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4765 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4766 lstrlenW(usage_fmt) + 1;
4767 driver = msi_alloc(len * sizeof(WCHAR));
4768 if (!driver)
4769 return ERROR_OUTOFMEMORY;
4771 ptr = driver;
4772 lstrcpyW(ptr, desc);
4773 ptr += lstrlenW(ptr) + 1;
4775 sprintfW(ptr, driver_fmt, driver_file->FileName);
4776 ptr += lstrlenW(ptr) + 1;
4778 sprintfW(ptr, setup_fmt, setup_file->FileName);
4779 ptr += lstrlenW(ptr) + 1;
4781 lstrcpyW(ptr, usage_fmt);
4782 ptr += lstrlenW(ptr) + 1;
4783 *ptr = '\0';
4785 driver_path = strdupW(driver_file->TargetPath);
4786 ptr = strrchrW(driver_path, '\\');
4787 if (ptr) *ptr = '\0';
4789 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4790 NULL, ODBC_INSTALL_COMPLETE, &usage))
4792 ERR("Failed to install SQL driver!\n");
4793 r = ERROR_FUNCTION_FAILED;
4796 msi_free(driver);
4797 msi_free(driver_path);
4799 return r;
4802 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4804 MSIPACKAGE *package = param;
4805 LPWSTR translator, translator_path, ptr;
4806 WCHAR outpath[MAX_PATH];
4807 MSIFILE *translator_file, *setup_file;
4808 LPCWSTR desc;
4809 DWORD len, usage;
4810 UINT r = ERROR_SUCCESS;
4812 static const WCHAR translator_fmt[] = {
4813 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4814 static const WCHAR setup_fmt[] = {
4815 'S','e','t','u','p','=','%','s',0};
4817 desc = MSI_RecordGetString(rec, 3);
4819 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4820 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4822 if (!translator_file || !setup_file)
4824 ERR("ODBC Translator entry not found!\n");
4825 return ERROR_FUNCTION_FAILED;
4828 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
4829 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
4830 translator = msi_alloc(len * sizeof(WCHAR));
4831 if (!translator)
4832 return ERROR_OUTOFMEMORY;
4834 ptr = translator;
4835 lstrcpyW(ptr, desc);
4836 ptr += lstrlenW(ptr) + 1;
4838 sprintfW(ptr, translator_fmt, translator_file->FileName);
4839 ptr += lstrlenW(ptr) + 1;
4841 sprintfW(ptr, setup_fmt, setup_file->FileName);
4842 ptr += lstrlenW(ptr) + 1;
4843 *ptr = '\0';
4845 translator_path = strdupW(translator_file->TargetPath);
4846 ptr = strrchrW(translator_path, '\\');
4847 if (ptr) *ptr = '\0';
4849 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
4850 NULL, ODBC_INSTALL_COMPLETE, &usage))
4852 ERR("Failed to install SQL translator!\n");
4853 r = ERROR_FUNCTION_FAILED;
4856 msi_free(translator);
4857 msi_free(translator_path);
4859 return r;
4862 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
4864 LPWSTR attrs;
4865 LPCWSTR desc, driver;
4866 WORD request = ODBC_ADD_SYS_DSN;
4867 INT registration;
4868 DWORD len;
4869 UINT r = ERROR_SUCCESS;
4871 static const WCHAR attrs_fmt[] = {
4872 'D','S','N','=','%','s',0 };
4874 desc = MSI_RecordGetString(rec, 3);
4875 driver = MSI_RecordGetString(rec, 4);
4876 registration = MSI_RecordGetInteger(rec, 5);
4878 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
4879 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
4881 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
4882 attrs = msi_alloc(len * sizeof(WCHAR));
4883 if (!attrs)
4884 return ERROR_OUTOFMEMORY;
4886 sprintfW(attrs, attrs_fmt, desc);
4887 attrs[len - 1] = '\0';
4889 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
4891 ERR("Failed to install SQL data source!\n");
4892 r = ERROR_FUNCTION_FAILED;
4895 msi_free(attrs);
4897 return r;
4900 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
4902 UINT rc;
4903 MSIQUERY *view;
4905 static const WCHAR driver_query[] = {
4906 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4907 'O','D','B','C','D','r','i','v','e','r',0 };
4909 static const WCHAR translator_query[] = {
4910 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4911 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4913 static const WCHAR source_query[] = {
4914 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4915 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4917 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
4918 if (rc != ERROR_SUCCESS)
4919 return ERROR_SUCCESS;
4921 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
4922 msiobj_release(&view->hdr);
4924 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
4925 if (rc != ERROR_SUCCESS)
4926 return ERROR_SUCCESS;
4928 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
4929 msiobj_release(&view->hdr);
4931 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
4932 if (rc != ERROR_SUCCESS)
4933 return ERROR_SUCCESS;
4935 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
4936 msiobj_release(&view->hdr);
4938 return rc;
4941 #define ENV_ACT_SETALWAYS 0x1
4942 #define ENV_ACT_SETABSENT 0x2
4943 #define ENV_ACT_REMOVE 0x4
4944 #define ENV_ACT_REMOVEMATCH 0x8
4946 #define ENV_MOD_MACHINE 0x20000000
4947 #define ENV_MOD_APPEND 0x40000000
4948 #define ENV_MOD_PREFIX 0x80000000
4949 #define ENV_MOD_MASK 0xC0000000
4951 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
4953 static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
4955 LPCWSTR cptr = *name;
4957 static const WCHAR prefix[] = {'[','~',']',0};
4958 static const int prefix_len = 3;
4960 *flags = 0;
4961 while (*cptr)
4963 if (*cptr == '=')
4964 *flags |= ENV_ACT_SETALWAYS;
4965 else if (*cptr == '+')
4966 *flags |= ENV_ACT_SETABSENT;
4967 else if (*cptr == '-')
4968 *flags |= ENV_ACT_REMOVE;
4969 else if (*cptr == '!')
4970 *flags |= ENV_ACT_REMOVEMATCH;
4971 else if (*cptr == '*')
4972 *flags |= ENV_MOD_MACHINE;
4973 else
4974 break;
4976 cptr++;
4977 (*name)++;
4980 if (!*cptr)
4982 ERR("Missing environment variable\n");
4983 return ERROR_FUNCTION_FAILED;
4986 if (*value)
4988 LPCWSTR ptr = *value;
4989 if (!strncmpW(ptr, prefix, prefix_len))
4991 if (ptr[prefix_len] == szSemiColon[0])
4993 *flags |= ENV_MOD_APPEND;
4994 *value += lstrlenW(prefix);
4996 else
4998 *value = NULL;
5001 else if (lstrlenW(*value) >= prefix_len)
5003 ptr += lstrlenW(ptr) - prefix_len;
5004 if (!lstrcmpW(ptr, prefix))
5006 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5008 *flags |= ENV_MOD_PREFIX;
5009 /* the "[~]" will be removed by deformat_string */;
5011 else
5013 *value = NULL;
5019 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5020 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5021 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5022 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5024 ERR("Invalid flags: %08x\n", *flags);
5025 return ERROR_FUNCTION_FAILED;
5028 if (!*flags)
5029 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5031 return ERROR_SUCCESS;
5034 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5036 MSIPACKAGE *package = param;
5037 LPCWSTR name, value;
5038 LPWSTR data = NULL, newval = NULL;
5039 LPWSTR deformatted = NULL, ptr;
5040 DWORD flags, type, size;
5041 LONG res;
5042 HKEY env = NULL, root;
5043 LPCWSTR environment;
5045 static const WCHAR user_env[] =
5046 {'E','n','v','i','r','o','n','m','e','n','t',0};
5047 static const WCHAR machine_env[] =
5048 {'S','y','s','t','e','m','\\',
5049 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5050 'C','o','n','t','r','o','l','\\',
5051 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5052 'E','n','v','i','r','o','n','m','e','n','t',0};
5054 name = MSI_RecordGetString(rec, 2);
5055 value = MSI_RecordGetString(rec, 3);
5057 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
5059 res = env_set_flags(&name, &value, &flags);
5060 if (res != ERROR_SUCCESS || !value)
5061 goto done;
5063 if (value && !deformat_string(package, value, &deformatted))
5065 res = ERROR_OUTOFMEMORY;
5066 goto done;
5069 value = deformatted;
5071 if (flags & ENV_MOD_MACHINE)
5073 environment = machine_env;
5074 root = HKEY_LOCAL_MACHINE;
5076 else
5078 environment = user_env;
5079 root = HKEY_CURRENT_USER;
5082 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5083 KEY_ALL_ACCESS, NULL, &env, NULL);
5084 if (res != ERROR_SUCCESS)
5085 goto done;
5087 if (flags & ENV_ACT_REMOVE)
5088 FIXME("Not removing environment variable on uninstall!\n");
5090 size = 0;
5091 type = REG_SZ;
5092 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5093 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
5094 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
5095 goto done;
5097 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
5099 /* Nothing to do. */
5100 if (!value)
5102 res = ERROR_SUCCESS;
5103 goto done;
5106 /* If we are appending but the string was empty, strip ; */
5107 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
5109 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
5110 newval = strdupW(value);
5111 if (!newval)
5113 res = ERROR_OUTOFMEMORY;
5114 goto done;
5117 else
5119 /* Contrary to MSDN, +-variable to [~];path works */
5120 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
5122 res = ERROR_SUCCESS;
5123 goto done;
5126 data = msi_alloc(size);
5127 if (!data)
5129 RegCloseKey(env);
5130 return ERROR_OUTOFMEMORY;
5133 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5134 if (res != ERROR_SUCCESS)
5135 goto done;
5137 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5139 res = RegDeleteKeyW(env, name);
5140 goto done;
5143 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
5144 if (flags & ENV_MOD_MASK)
5146 DWORD mod_size;
5147 int multiplier = 0;
5148 if (flags & ENV_MOD_APPEND) multiplier++;
5149 if (flags & ENV_MOD_PREFIX) multiplier++;
5150 mod_size = lstrlenW(value) * multiplier;
5151 size += mod_size * sizeof(WCHAR);
5154 newval = msi_alloc(size);
5155 ptr = newval;
5156 if (!newval)
5158 res = ERROR_OUTOFMEMORY;
5159 goto done;
5162 if (flags & ENV_MOD_PREFIX)
5164 lstrcpyW(newval, value);
5165 ptr = newval + lstrlenW(value);
5168 lstrcpyW(ptr, data);
5170 if (flags & ENV_MOD_APPEND)
5172 lstrcatW(newval, value);
5175 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5176 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
5178 done:
5179 if (env) RegCloseKey(env);
5180 msi_free(deformatted);
5181 msi_free(data);
5182 msi_free(newval);
5183 return res;
5186 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5188 UINT rc;
5189 MSIQUERY * view;
5190 static const WCHAR ExecSeqQuery[] =
5191 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5192 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5193 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5194 if (rc != ERROR_SUCCESS)
5195 return ERROR_SUCCESS;
5197 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5198 msiobj_release(&view->hdr);
5200 return rc;
5203 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5205 typedef struct
5207 struct list entry;
5208 LPWSTR sourcename;
5209 LPWSTR destname;
5210 LPWSTR source;
5211 LPWSTR dest;
5212 } FILE_LIST;
5214 static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5216 BOOL ret;
5218 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5219 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5221 WARN("Source or dest is directory, not moving\n");
5222 return FALSE;
5225 if (options == msidbMoveFileOptionsMove)
5227 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5228 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5229 if (!ret)
5231 WARN("MoveFile failed: %d\n", GetLastError());
5232 return FALSE;
5235 else
5237 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5238 ret = CopyFileW(source, dest, FALSE);
5239 if (!ret)
5241 WARN("CopyFile failed: %d\n", GetLastError());
5242 return FALSE;
5246 return TRUE;
5249 static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5251 LPWSTR path, ptr;
5252 DWORD dirlen, pathlen;
5254 ptr = strrchrW(wildcard, '\\');
5255 dirlen = ptr - wildcard + 1;
5257 pathlen = dirlen + lstrlenW(filename) + 1;
5258 path = msi_alloc(pathlen * sizeof(WCHAR));
5260 lstrcpynW(path, wildcard, dirlen + 1);
5261 lstrcatW(path, filename);
5263 return path;
5266 static void free_file_entry(FILE_LIST *file)
5268 msi_free(file->source);
5269 msi_free(file->dest);
5270 msi_free(file);
5273 static void free_list(FILE_LIST *list)
5275 while (!list_empty(&list->entry))
5277 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5279 list_remove(&file->entry);
5280 free_file_entry(file);
5284 static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5286 FILE_LIST *new, *file;
5287 LPWSTR ptr, filename;
5288 DWORD size;
5290 new = msi_alloc_zero(sizeof(FILE_LIST));
5291 if (!new)
5292 return FALSE;
5294 new->source = strdupW(source);
5295 ptr = strrchrW(dest, '\\') + 1;
5296 filename = strrchrW(new->source, '\\') + 1;
5298 new->sourcename = filename;
5300 if (*ptr)
5301 new->destname = ptr;
5302 else
5303 new->destname = new->sourcename;
5305 size = (ptr - dest) + lstrlenW(filename) + 1;
5306 new->dest = msi_alloc(size * sizeof(WCHAR));
5307 if (!new->dest)
5309 free_file_entry(new);
5310 return FALSE;
5313 lstrcpynW(new->dest, dest, ptr - dest + 1);
5314 lstrcatW(new->dest, filename);
5316 if (list_empty(&files->entry))
5318 list_add_head(&files->entry, &new->entry);
5319 return TRUE;
5322 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5324 if (lstrcmpW(source, file->source) < 0)
5326 list_add_before(&file->entry, &new->entry);
5327 return TRUE;
5331 list_add_after(&file->entry, &new->entry);
5332 return TRUE;
5335 static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
5337 WIN32_FIND_DATAW wfd;
5338 HANDLE hfile;
5339 LPWSTR path;
5340 BOOL res;
5341 FILE_LIST files, *file;
5342 DWORD size;
5344 hfile = FindFirstFileW(source, &wfd);
5345 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5347 list_init(&files.entry);
5349 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5351 if (is_dot_dir(wfd.cFileName)) continue;
5353 path = wildcard_to_file(source, wfd.cFileName);
5354 if (!path)
5356 res = FALSE;
5357 goto done;
5360 add_wildcard(&files, path, dest);
5361 msi_free(path);
5364 /* no files match the wildcard */
5365 if (list_empty(&files.entry))
5366 goto done;
5368 /* only the first wildcard match gets renamed to dest */
5369 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5370 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5371 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5372 if (!file->dest)
5374 res = FALSE;
5375 goto done;
5378 /* file->dest may be shorter after the reallocation, so add a NULL
5379 * terminator. This is needed for the call to strrchrW, as there will no
5380 * longer be a NULL terminator within the bounds of the allocation in this case.
5382 file->dest[size - 1] = '\0';
5383 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5385 while (!list_empty(&files.entry))
5387 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5389 msi_move_file(file->source, file->dest, options);
5391 list_remove(&file->entry);
5392 free_file_entry(file);
5395 res = TRUE;
5397 done:
5398 free_list(&files);
5399 FindClose(hfile);
5400 return res;
5403 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5405 MSIPACKAGE *package = param;
5406 MSICOMPONENT *comp;
5407 LPCWSTR sourcename;
5408 LPWSTR destname = NULL;
5409 LPWSTR sourcedir = NULL, destdir = NULL;
5410 LPWSTR source = NULL, dest = NULL;
5411 int options;
5412 DWORD size;
5413 BOOL ret, wildcards;
5415 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5416 if (!comp || !comp->Enabled ||
5417 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5419 TRACE("Component not set for install, not moving file\n");
5420 return ERROR_SUCCESS;
5423 sourcename = MSI_RecordGetString(rec, 3);
5424 options = MSI_RecordGetInteger(rec, 7);
5426 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5427 if (!sourcedir)
5428 goto done;
5430 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5431 if (!destdir)
5432 goto done;
5434 if (!sourcename)
5436 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5437 goto done;
5439 source = strdupW(sourcedir);
5440 if (!source)
5441 goto done;
5443 else
5445 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5446 source = msi_alloc(size * sizeof(WCHAR));
5447 if (!source)
5448 goto done;
5450 lstrcpyW(source, sourcedir);
5451 if (source[lstrlenW(source) - 1] != '\\')
5452 lstrcatW(source, szBackSlash);
5453 lstrcatW(source, sourcename);
5456 wildcards = strchrW(source, '*') || strchrW(source, '?');
5458 if (MSI_RecordIsNull(rec, 4))
5460 if (!wildcards)
5462 destname = strdupW(sourcename);
5463 if (!destname)
5464 goto done;
5467 else
5469 destname = strdupW(MSI_RecordGetString(rec, 4));
5470 if (destname)
5471 reduce_to_longfilename(destname);
5474 size = 0;
5475 if (destname)
5476 size = lstrlenW(destname);
5478 size += lstrlenW(destdir) + 2;
5479 dest = msi_alloc(size * sizeof(WCHAR));
5480 if (!dest)
5481 goto done;
5483 lstrcpyW(dest, destdir);
5484 if (dest[lstrlenW(dest) - 1] != '\\')
5485 lstrcatW(dest, szBackSlash);
5487 if (destname)
5488 lstrcatW(dest, destname);
5490 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5492 ret = CreateDirectoryW(destdir, NULL);
5493 if (!ret)
5495 WARN("CreateDirectory failed: %d\n", GetLastError());
5496 return ERROR_SUCCESS;
5500 if (!wildcards)
5501 msi_move_file(source, dest, options);
5502 else
5503 move_files_wildcard(source, dest, options);
5505 done:
5506 msi_free(sourcedir);
5507 msi_free(destdir);
5508 msi_free(destname);
5509 msi_free(source);
5510 msi_free(dest);
5512 return ERROR_SUCCESS;
5515 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5517 UINT rc;
5518 MSIQUERY *view;
5520 static const WCHAR ExecSeqQuery[] =
5521 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5522 '`','M','o','v','e','F','i','l','e','`',0};
5524 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5525 if (rc != ERROR_SUCCESS)
5526 return ERROR_SUCCESS;
5528 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5529 msiobj_release(&view->hdr);
5531 return rc;
5534 typedef struct tagMSIASSEMBLY
5536 struct list entry;
5537 MSICOMPONENT *component;
5538 MSIFEATURE *feature;
5539 MSIFILE *file;
5540 LPWSTR manifest;
5541 LPWSTR application;
5542 DWORD attributes;
5543 BOOL installed;
5544 } MSIASSEMBLY;
5546 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
5547 DWORD dwReserved);
5548 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
5549 LPVOID pvReserved, HMODULE *phModDll);
5551 static BOOL init_functionpointers(void)
5553 HRESULT hr;
5554 HMODULE hfusion;
5555 HMODULE hmscoree;
5557 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
5559 hmscoree = LoadLibraryA("mscoree.dll");
5560 if (!hmscoree)
5562 WARN("mscoree.dll not available\n");
5563 return FALSE;
5566 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
5567 if (!pLoadLibraryShim)
5569 WARN("LoadLibraryShim not available\n");
5570 FreeLibrary(hmscoree);
5571 return FALSE;
5574 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
5575 if (FAILED(hr))
5577 WARN("fusion.dll not available\n");
5578 FreeLibrary(hmscoree);
5579 return FALSE;
5582 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
5584 FreeLibrary(hmscoree);
5585 return TRUE;
5588 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
5589 LPWSTR path)
5591 IAssemblyCache *cache;
5592 HRESULT hr;
5593 UINT r = ERROR_FUNCTION_FAILED;
5595 TRACE("installing assembly: %s\n", debugstr_w(path));
5597 if (assembly->feature)
5598 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
5600 if (assembly->manifest)
5601 FIXME("Manifest unhandled\n");
5603 if (assembly->application)
5605 FIXME("Assembly should be privately installed\n");
5606 return ERROR_SUCCESS;
5609 if (assembly->attributes == msidbAssemblyAttributesWin32)
5611 FIXME("Win32 assemblies not handled\n");
5612 return ERROR_SUCCESS;
5615 hr = pCreateAssemblyCache(&cache, 0);
5616 if (FAILED(hr))
5617 goto done;
5619 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
5620 if (FAILED(hr))
5621 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
5623 r = ERROR_SUCCESS;
5625 done:
5626 IAssemblyCache_Release(cache);
5627 return r;
5630 typedef struct tagASSEMBLY_LIST
5632 MSIPACKAGE *package;
5633 IAssemblyCache *cache;
5634 struct list *assemblies;
5635 } ASSEMBLY_LIST;
5637 typedef struct tagASSEMBLY_NAME
5639 LPWSTR name;
5640 LPWSTR version;
5641 LPWSTR culture;
5642 LPWSTR pubkeytoken;
5643 } ASSEMBLY_NAME;
5645 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
5647 ASSEMBLY_NAME *asmname = param;
5648 LPCWSTR name = MSI_RecordGetString(rec, 2);
5649 LPWSTR val = msi_dup_record_field(rec, 3);
5651 static const WCHAR Name[] = {'N','a','m','e',0};
5652 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
5653 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
5654 static const WCHAR PublicKeyToken[] = {
5655 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
5657 if (!strcmpiW(name, Name))
5658 asmname->name = val;
5659 else if (!strcmpiW(name, Version))
5660 asmname->version = val;
5661 else if (!strcmpiW(name, Culture))
5662 asmname->culture = val;
5663 else if (!strcmpiW(name, PublicKeyToken))
5664 asmname->pubkeytoken = val;
5665 else
5666 msi_free(val);
5668 return ERROR_SUCCESS;
5671 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
5673 if (!*str)
5675 *size = lstrlenW(append) + 1;
5676 *str = msi_alloc((*size) * sizeof(WCHAR));
5677 lstrcpyW(*str, append);
5678 return;
5681 (*size) += lstrlenW(append);
5682 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
5683 lstrcatW(*str, append);
5686 static BOOL check_assembly_installed(MSIDATABASE *db, IAssemblyCache *cache,
5687 MSICOMPONENT *comp)
5689 ASSEMBLY_INFO asminfo;
5690 ASSEMBLY_NAME name;
5691 MSIQUERY *view;
5692 LPWSTR disp;
5693 DWORD size;
5694 BOOL found;
5695 UINT r;
5697 static const WCHAR separator[] = {',',' ',0};
5698 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
5699 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
5700 static const WCHAR PublicKeyToken[] = {
5701 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
5702 static const WCHAR query[] = {
5703 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5704 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
5705 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
5706 '=','\'','%','s','\'',0};
5708 disp = NULL;
5709 found = FALSE;
5710 ZeroMemory(&name, sizeof(ASSEMBLY_NAME));
5711 ZeroMemory(&asminfo, sizeof(ASSEMBLY_INFO));
5713 r = MSI_OpenQuery(db, &view, query, comp->Component);
5714 if (r != ERROR_SUCCESS)
5715 return ERROR_SUCCESS;
5717 MSI_IterateRecords(view, NULL, parse_assembly_name, &name);
5718 msiobj_release(&view->hdr);
5720 if (!name.name)
5722 ERR("No assembly name specified!\n");
5723 goto done;
5726 append_str(&disp, &size, name.name);
5728 if (name.version)
5730 append_str(&disp, &size, separator);
5731 append_str(&disp, &size, Version);
5732 append_str(&disp, &size, name.version);
5735 if (name.culture)
5737 append_str(&disp, &size, separator);
5738 append_str(&disp, &size, Culture);
5739 append_str(&disp, &size, name.culture);
5742 if (name.pubkeytoken)
5744 append_str(&disp, &size, separator);
5745 append_str(&disp, &size, PublicKeyToken);
5746 append_str(&disp, &size, name.pubkeytoken);
5749 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
5750 IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE,
5751 disp, &asminfo);
5752 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
5754 done:
5755 msi_free(disp);
5756 msi_free(name.name);
5757 msi_free(name.version);
5758 msi_free(name.culture);
5759 msi_free(name.pubkeytoken);
5761 return found;
5764 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
5766 ASSEMBLY_LIST *list = param;
5767 MSIASSEMBLY *assembly;
5769 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
5770 if (!assembly)
5771 return ERROR_OUTOFMEMORY;
5773 assembly->component = get_loaded_component(list->package, MSI_RecordGetString(rec, 1));
5775 if (!assembly->component || !assembly->component->Enabled ||
5776 !(assembly->component->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5778 TRACE("Component not set for install, not publishing assembly\n");
5779 msi_free(assembly);
5780 return ERROR_SUCCESS;
5783 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
5784 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
5786 if (!assembly->file)
5788 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
5789 return ERROR_FUNCTION_FAILED;
5792 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
5793 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
5794 assembly->attributes = MSI_RecordGetInteger(rec, 5);
5796 if (assembly->application)
5798 WCHAR version[24];
5799 DWORD size = sizeof(version)/sizeof(WCHAR);
5801 /* FIXME: we should probably check the manifest file here */
5803 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
5804 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
5806 assembly->installed = TRUE;
5809 else
5810 assembly->installed = check_assembly_installed(list->package->db,
5811 list->cache,
5812 assembly->component);
5814 list_add_head(list->assemblies, &assembly->entry);
5815 return ERROR_SUCCESS;
5818 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
5820 IAssemblyCache *cache = NULL;
5821 ASSEMBLY_LIST list;
5822 MSIQUERY *view;
5823 HRESULT hr;
5824 UINT r;
5826 static const WCHAR query[] =
5827 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5828 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
5830 r = MSI_DatabaseOpenViewW(package->db, query, &view);
5831 if (r != ERROR_SUCCESS)
5832 return ERROR_SUCCESS;
5834 hr = pCreateAssemblyCache(&cache, 0);
5835 if (FAILED(hr))
5836 return ERROR_FUNCTION_FAILED;
5838 list.package = package;
5839 list.cache = cache;
5840 list.assemblies = assemblies;
5842 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
5843 msiobj_release(&view->hdr);
5845 IAssemblyCache_Release(cache);
5847 return r;
5850 static void free_assemblies(struct list *assemblies)
5852 struct list *item, *cursor;
5854 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
5856 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
5858 list_remove(&assembly->entry);
5859 msi_free(assembly->application);
5860 msi_free(assembly->manifest);
5861 msi_free(assembly);
5865 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
5867 MSIASSEMBLY *assembly;
5869 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
5871 if (!lstrcmpW(assembly->file->File, file))
5873 *out = assembly;
5874 return TRUE;
5878 return FALSE;
5881 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
5882 LPWSTR *path, DWORD *attrs, PVOID user)
5884 MSIASSEMBLY *assembly;
5885 WCHAR temppath[MAX_PATH];
5886 struct list *assemblies = user;
5887 UINT r;
5889 if (!find_assembly(assemblies, file, &assembly))
5890 return FALSE;
5892 GetTempPathW(MAX_PATH, temppath);
5893 PathAddBackslashW(temppath);
5894 lstrcatW(temppath, assembly->file->FileName);
5896 if (action == MSICABEXTRACT_BEGINEXTRACT)
5898 if (assembly->installed)
5899 return FALSE;
5901 *path = strdupW(temppath);
5902 *attrs = assembly->file->Attributes;
5904 else if (action == MSICABEXTRACT_FILEEXTRACTED)
5906 assembly->installed = TRUE;
5908 r = install_assembly(package, assembly, temppath);
5909 if (r != ERROR_SUCCESS)
5910 ERR("Failed to install assembly\n");
5913 return TRUE;
5916 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
5918 UINT r;
5919 struct list assemblies = LIST_INIT(assemblies);
5920 MSIASSEMBLY *assembly;
5921 MSIMEDIAINFO *mi;
5923 if (!init_functionpointers() || !pCreateAssemblyCache)
5924 return ERROR_FUNCTION_FAILED;
5926 r = load_assemblies(package, &assemblies);
5927 if (r != ERROR_SUCCESS)
5928 goto done;
5930 if (list_empty(&assemblies))
5931 goto done;
5933 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
5934 if (!mi)
5936 r = ERROR_OUTOFMEMORY;
5937 goto done;
5940 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
5942 if (assembly->installed && !mi->is_continuous)
5943 continue;
5945 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
5946 (assembly->file->IsCompressed && !mi->is_extracted))
5948 MSICABDATA data;
5950 r = ready_media(package, assembly->file, mi);
5951 if (r != ERROR_SUCCESS)
5953 ERR("Failed to ready media\n");
5954 break;
5957 data.mi = mi;
5958 data.package = package;
5959 data.cb = installassembly_cb;
5960 data.user = &assemblies;
5962 if (assembly->file->IsCompressed &&
5963 !msi_cabextract(package, mi, &data))
5965 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
5966 r = ERROR_FUNCTION_FAILED;
5967 break;
5971 if (!assembly->file->IsCompressed)
5973 LPWSTR source = resolve_file_source(package, assembly->file);
5975 r = install_assembly(package, assembly, source);
5976 if (r != ERROR_SUCCESS)
5977 ERR("Failed to install assembly\n");
5979 msi_free(source);
5982 /* FIXME: write Installer assembly reg values */
5985 done:
5986 free_assemblies(&assemblies);
5987 return r;
5990 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
5992 TRACE("\n");
5993 package->need_reboot = 1;
5994 return ERROR_SUCCESS;
5997 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
5998 LPCSTR action, LPCWSTR table )
6000 static const WCHAR query[] = {
6001 'S','E','L','E','C','T',' ','*',' ',
6002 'F','R','O','M',' ','`','%','s','`',0 };
6003 MSIQUERY *view = NULL;
6004 DWORD count = 0;
6005 UINT r;
6007 r = MSI_OpenQuery( package->db, &view, query, table );
6008 if (r == ERROR_SUCCESS)
6010 r = MSI_IterateRecords(view, &count, NULL, package);
6011 msiobj_release(&view->hdr);
6014 if (count)
6015 FIXME("%s -> %u ignored %s table values\n",
6016 action, count, debugstr_w(table));
6018 return ERROR_SUCCESS;
6021 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6023 TRACE("%p\n", package);
6024 return ERROR_SUCCESS;
6027 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
6029 static const WCHAR table[] =
6030 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
6031 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
6034 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6036 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6037 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6040 static UINT ACTION_BindImage( MSIPACKAGE *package )
6042 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6043 return msi_unimplemented_action_stub( package, "BindImage", table );
6046 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6048 static const WCHAR table[] = {
6049 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
6050 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6053 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6055 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6056 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6059 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
6061 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
6062 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
6065 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6067 static const WCHAR table[] = {
6068 'P','r','o','d','u','c','t','I','D',0 };
6069 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
6072 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6074 static const WCHAR table[] = {
6075 'E','n','v','i','r','o','n','m','e','n','t',0 };
6076 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
6079 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6081 static const WCHAR table[] = {
6082 'M','s','i','A','s','s','e','m','b','l','y',0 };
6083 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6086 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
6088 static const WCHAR table[] = { 'F','o','n','t',0 };
6089 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
6092 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6094 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6095 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6098 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6100 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6101 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6104 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6106 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6107 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6110 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6112 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6113 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6116 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
6118 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6119 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
6122 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6124 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6125 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6128 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
6130 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6131 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
6134 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6136 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6137 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
6140 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
6142 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6143 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
6146 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
6148 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
6149 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
6152 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6154 static const WCHAR table[] = { 'D','i','r','e','c','t','o','r','y',0 };
6155 return msi_unimplemented_action_stub( package, "SetODBCFolders", table );
6158 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
6160 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6161 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
6164 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6166 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6167 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6170 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6172 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6173 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6176 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6178 static const WCHAR table[] = { 'M','I','M','E',0 };
6179 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6182 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6184 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6185 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6188 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
6190 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
6191 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
6194 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6196 static const struct
6198 const WCHAR *action;
6199 UINT (*handler)(MSIPACKAGE *);
6201 StandardActions[] =
6203 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6204 { szAppSearch, ACTION_AppSearch },
6205 { szBindImage, ACTION_BindImage },
6206 { szCCPSearch, ACTION_CCPSearch },
6207 { szCostFinalize, ACTION_CostFinalize },
6208 { szCostInitialize, ACTION_CostInitialize },
6209 { szCreateFolders, ACTION_CreateFolders },
6210 { szCreateShortcuts, ACTION_CreateShortcuts },
6211 { szDeleteServices, ACTION_DeleteServices },
6212 { szDisableRollback, NULL },
6213 { szDuplicateFiles, ACTION_DuplicateFiles },
6214 { szExecuteAction, ACTION_ExecuteAction },
6215 { szFileCost, ACTION_FileCost },
6216 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6217 { szForceReboot, ACTION_ForceReboot },
6218 { szInstallAdminPackage, NULL },
6219 { szInstallExecute, ACTION_InstallExecute },
6220 { szInstallExecuteAgain, ACTION_InstallExecute },
6221 { szInstallFiles, ACTION_InstallFiles},
6222 { szInstallFinalize, ACTION_InstallFinalize },
6223 { szInstallInitialize, ACTION_InstallInitialize },
6224 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6225 { szInstallValidate, ACTION_InstallValidate },
6226 { szIsolateComponents, ACTION_IsolateComponents },
6227 { szLaunchConditions, ACTION_LaunchConditions },
6228 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6229 { szMoveFiles, ACTION_MoveFiles },
6230 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6231 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6232 { szInstallODBC, ACTION_InstallODBC },
6233 { szInstallServices, ACTION_InstallServices },
6234 { szPatchFiles, ACTION_PatchFiles },
6235 { szProcessComponents, ACTION_ProcessComponents },
6236 { szPublishComponents, ACTION_PublishComponents },
6237 { szPublishFeatures, ACTION_PublishFeatures },
6238 { szPublishProduct, ACTION_PublishProduct },
6239 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6240 { szRegisterComPlus, ACTION_RegisterComPlus},
6241 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6242 { szRegisterFonts, ACTION_RegisterFonts },
6243 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6244 { szRegisterProduct, ACTION_RegisterProduct },
6245 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6246 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6247 { szRegisterUser, ACTION_RegisterUser },
6248 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6249 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6250 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6251 { szRemoveFiles, ACTION_RemoveFiles },
6252 { szRemoveFolders, ACTION_RemoveFolders },
6253 { szRemoveIniValues, ACTION_RemoveIniValues },
6254 { szRemoveODBC, ACTION_RemoveODBC },
6255 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6256 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6257 { szResolveSource, ACTION_ResolveSource },
6258 { szRMCCPSearch, ACTION_RMCCPSearch },
6259 { szScheduleReboot, ACTION_ScheduleReboot },
6260 { szSelfRegModules, ACTION_SelfRegModules },
6261 { szSelfUnregModules, ACTION_SelfUnregModules },
6262 { szSetODBCFolders, ACTION_SetODBCFolders },
6263 { szStartServices, ACTION_StartServices },
6264 { szStopServices, ACTION_StopServices },
6265 { szUnpublishComponents, ACTION_UnpublishComponents },
6266 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6267 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6268 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6269 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6270 { szUnregisterFonts, ACTION_UnregisterFonts },
6271 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6272 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6273 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6274 { szValidateProductID, ACTION_ValidateProductID },
6275 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6276 { szWriteIniValues, ACTION_WriteIniValues },
6277 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6278 { NULL, NULL },
6281 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
6282 UINT* rc, BOOL force )
6284 BOOL ret = FALSE;
6285 BOOL run = force;
6286 int i;
6288 if (!run && !package->script->CurrentlyScripting)
6289 run = TRUE;
6291 if (!run)
6293 if (strcmpW(action,szInstallFinalize) == 0 ||
6294 strcmpW(action,szInstallExecute) == 0 ||
6295 strcmpW(action,szInstallExecuteAgain) == 0)
6296 run = TRUE;
6299 i = 0;
6300 while (StandardActions[i].action != NULL)
6302 if (strcmpW(StandardActions[i].action, action)==0)
6304 if (!run)
6306 ui_actioninfo(package, action, TRUE, 0);
6307 *rc = schedule_action(package,INSTALL_SCRIPT,action);
6308 ui_actioninfo(package, action, FALSE, *rc);
6310 else
6312 ui_actionstart(package, action);
6313 if (StandardActions[i].handler)
6315 *rc = StandardActions[i].handler(package);
6317 else
6319 FIXME("unhandled standard action %s\n",debugstr_w(action));
6320 *rc = ERROR_SUCCESS;
6323 ret = TRUE;
6324 break;
6326 i++;
6328 return ret;
6331 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
6333 UINT rc = ERROR_SUCCESS;
6334 BOOL handled;
6336 TRACE("Performing action (%s)\n", debugstr_w(action));
6338 handled = ACTION_HandleStandardAction(package, action, &rc, force);
6340 if (!handled)
6341 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
6343 if (!handled)
6345 WARN("unhandled msi action %s\n", debugstr_w(action));
6346 rc = ERROR_FUNCTION_NOT_CALLED;
6349 return rc;
6352 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
6354 UINT rc = ERROR_SUCCESS;
6355 BOOL handled = FALSE;
6357 TRACE("Performing action (%s)\n", debugstr_w(action));
6359 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
6361 if (!handled)
6362 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
6364 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
6365 handled = TRUE;
6367 if (!handled)
6369 WARN("unhandled msi action %s\n", debugstr_w(action));
6370 rc = ERROR_FUNCTION_NOT_CALLED;
6373 return rc;
6376 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
6378 UINT rc = ERROR_SUCCESS;
6379 MSIRECORD *row;
6381 static const WCHAR ExecSeqQuery[] =
6382 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6383 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
6384 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
6385 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
6386 static const WCHAR UISeqQuery[] =
6387 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6388 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
6389 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
6390 ' ', '=',' ','%','i',0};
6392 if (needs_ui_sequence(package))
6393 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
6394 else
6395 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
6397 if (row)
6399 LPCWSTR action, cond;
6401 TRACE("Running the actions\n");
6403 /* check conditions */
6404 cond = MSI_RecordGetString(row, 2);
6406 /* this is a hack to skip errors in the condition code */
6407 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
6409 msiobj_release(&row->hdr);
6410 return ERROR_SUCCESS;
6413 action = MSI_RecordGetString(row, 1);
6414 if (!action)
6416 ERR("failed to fetch action\n");
6417 msiobj_release(&row->hdr);
6418 return ERROR_FUNCTION_FAILED;
6421 if (needs_ui_sequence(package))
6422 rc = ACTION_PerformUIAction(package, action, -1);
6423 else
6424 rc = ACTION_PerformAction(package, action, -1, FALSE);
6426 msiobj_release(&row->hdr);
6429 return rc;
6432 /****************************************************
6433 * TOP level entry points
6434 *****************************************************/
6436 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
6437 LPCWSTR szCommandLine )
6439 UINT rc;
6440 BOOL ui_exists;
6442 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
6443 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
6445 MSI_SetPropertyW(package, szAction, szInstall);
6447 package->script->InWhatSequence = SEQUENCE_INSTALL;
6449 if (szPackagePath)
6451 LPWSTR p, dir;
6452 LPCWSTR file;
6454 dir = strdupW(szPackagePath);
6455 p = strrchrW(dir, '\\');
6456 if (p)
6458 *(++p) = 0;
6459 file = szPackagePath + (p - dir);
6461 else
6463 msi_free(dir);
6464 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
6465 GetCurrentDirectoryW(MAX_PATH, dir);
6466 lstrcatW(dir, szBackSlash);
6467 file = szPackagePath;
6470 msi_free( package->PackagePath );
6471 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
6472 if (!package->PackagePath)
6474 msi_free(dir);
6475 return ERROR_OUTOFMEMORY;
6478 lstrcpyW(package->PackagePath, dir);
6479 lstrcatW(package->PackagePath, file);
6480 msi_free(dir);
6482 msi_set_sourcedir_props(package, FALSE);
6485 msi_parse_command_line( package, szCommandLine, FALSE );
6487 msi_apply_transforms( package );
6488 msi_apply_patches( package );
6490 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
6492 TRACE("setting reinstall property\n");
6493 MSI_SetPropertyW( package, szReinstall, szAll );
6496 /* properties may have been added by a transform */
6497 msi_clone_properties( package );
6498 msi_set_context( package );
6500 if (needs_ui_sequence( package))
6502 package->script->InWhatSequence |= SEQUENCE_UI;
6503 rc = ACTION_ProcessUISequence(package);
6504 ui_exists = ui_sequence_exists(package);
6505 if (rc == ERROR_SUCCESS || !ui_exists)
6507 package->script->InWhatSequence |= SEQUENCE_EXEC;
6508 rc = ACTION_ProcessExecSequence(package, ui_exists);
6511 else
6512 rc = ACTION_ProcessExecSequence(package, FALSE);
6514 package->script->CurrentlyScripting = FALSE;
6516 /* process the ending type action */
6517 if (rc == ERROR_SUCCESS)
6518 ACTION_PerformActionSequence(package, -1);
6519 else if (rc == ERROR_INSTALL_USEREXIT)
6520 ACTION_PerformActionSequence(package, -2);
6521 else if (rc == ERROR_INSTALL_SUSPEND)
6522 ACTION_PerformActionSequence(package, -4);
6523 else /* failed */
6524 ACTION_PerformActionSequence(package, -3);
6526 /* finish up running custom actions */
6527 ACTION_FinishCustomActions(package);
6529 if (rc == ERROR_SUCCESS && package->need_reboot)
6530 return ERROR_SUCCESS_REBOOT_REQUIRED;
6532 return rc;