msi: Display the file identifier instead of the filename in the SelfRegModules and...
[wine.git] / dlls / msi / action.c
blobdb6c2cdeb75c2a73be690e441fa320c217cd4cef
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 szAllocateRegistrySpace[] =
96 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
97 static const WCHAR szBindImage[] =
98 {'B','i','n','d','I','m','a','g','e',0};
99 static const WCHAR szCCPSearch[] =
100 {'C','C','P','S','e','a','r','c','h',0};
101 static const WCHAR szDeleteServices[] =
102 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
103 static const WCHAR szDisableRollback[] =
104 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
105 static const WCHAR szExecuteAction[] =
106 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
107 static const WCHAR szInstallAdminPackage[] =
108 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
109 static const WCHAR szInstallSFPCatalogFile[] =
110 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
111 static const WCHAR szIsolateComponents[] =
112 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
113 static const WCHAR szMigrateFeatureStates[] =
114 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
115 static const WCHAR szMsiPublishAssemblies[] =
116 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
117 static const WCHAR szMsiUnpublishAssemblies[] =
118 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
119 static const WCHAR szInstallODBC[] =
120 {'I','n','s','t','a','l','l','O','D','B','C',0};
121 static const WCHAR szInstallServices[] =
122 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
123 static const WCHAR szPatchFiles[] =
124 {'P','a','t','c','h','F','i','l','e','s',0};
125 static const WCHAR szPublishComponents[] =
126 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
127 static const WCHAR szRegisterComPlus[] =
128 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
129 static const WCHAR szRegisterFonts[] =
130 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
131 static const WCHAR szRegisterUser[] =
132 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
133 static const WCHAR szRemoveEnvironmentStrings[] =
134 {'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};
135 static const WCHAR szRemoveExistingProducts[] =
136 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
137 static const WCHAR szRemoveFolders[] =
138 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
139 static const WCHAR szRemoveIniValues[] =
140 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
141 static const WCHAR szRemoveODBC[] =
142 {'R','e','m','o','v','e','O','D','B','C',0};
143 static const WCHAR szRemoveRegistryValues[] =
144 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
145 static const WCHAR szRemoveShortcuts[] =
146 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
147 static const WCHAR szRMCCPSearch[] =
148 {'R','M','C','C','P','S','e','a','r','c','h',0};
149 static const WCHAR szScheduleReboot[] =
150 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
151 static const WCHAR szSelfUnregModules[] =
152 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
153 static const WCHAR szSetODBCFolders[] =
154 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
155 static const WCHAR szStartServices[] =
156 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
157 static const WCHAR szStopServices[] =
158 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
159 static const WCHAR szUnpublishComponents[] =
160 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szUnpublishFeatures[] =
162 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
163 static const WCHAR szUnregisterClassInfo[] =
164 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
165 static const WCHAR szUnregisterComPlus[] =
166 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
167 static const WCHAR szUnregisterExtensionInfo[] =
168 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
169 static const WCHAR szUnregisterFonts[] =
170 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
171 static const WCHAR szUnregisterMIMEInfo[] =
172 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
173 static const WCHAR szUnregisterProgIdInfo[] =
174 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
175 static const WCHAR szUnregisterTypeLibraries[] =
176 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
177 static const WCHAR szValidateProductID[] =
178 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
179 static const WCHAR szWriteEnvironmentStrings[] =
180 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
182 /********************************************************
183 * helper functions
184 ********************************************************/
186 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
188 static const WCHAR Query_t[] =
189 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
190 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
191 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
192 ' ','\'','%','s','\'',0};
193 MSIRECORD * row;
195 row = MSI_QueryGetRecord( package->db, Query_t, action );
196 if (!row)
197 return;
198 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
199 msiobj_release(&row->hdr);
202 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
203 UINT rc)
205 MSIRECORD * row;
206 static const WCHAR template_s[]=
207 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
208 '%','s', '.',0};
209 static const WCHAR template_e[]=
210 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
211 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
212 '%','i','.',0};
213 static const WCHAR format[] =
214 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
215 WCHAR message[1024];
216 WCHAR timet[0x100];
218 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
219 if (start)
220 sprintfW(message,template_s,timet,action);
221 else
222 sprintfW(message,template_e,timet,action,rc);
224 row = MSI_CreateRecord(1);
225 MSI_RecordSetStringW(row,1,message);
227 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
228 msiobj_release(&row->hdr);
231 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
232 BOOL preserve_case )
234 LPCWSTR ptr,ptr2;
235 BOOL quote;
236 DWORD len;
237 LPWSTR prop = NULL, val = NULL;
239 if (!szCommandLine)
240 return ERROR_SUCCESS;
242 ptr = szCommandLine;
244 while (*ptr)
246 if (*ptr==' ')
248 ptr++;
249 continue;
252 TRACE("Looking at %s\n",debugstr_w(ptr));
254 ptr2 = strchrW(ptr,'=');
255 if (!ptr2)
257 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
258 break;
261 quote = FALSE;
263 len = ptr2-ptr;
264 prop = msi_alloc((len+1)*sizeof(WCHAR));
265 memcpy(prop,ptr,len*sizeof(WCHAR));
266 prop[len]=0;
268 if (!preserve_case)
269 struprW(prop);
271 ptr2++;
273 len = 0;
274 ptr = ptr2;
275 while (*ptr && (quote || (!quote && *ptr!=' ')))
277 if (*ptr == '"')
278 quote = !quote;
279 ptr++;
280 len++;
283 if (*ptr2=='"')
285 ptr2++;
286 len -= 2;
288 val = msi_alloc((len+1)*sizeof(WCHAR));
289 memcpy(val,ptr2,len*sizeof(WCHAR));
290 val[len] = 0;
292 if (lstrlenW(prop) > 0)
294 TRACE("Found commandline property (%s) = (%s)\n",
295 debugstr_w(prop), debugstr_w(val));
296 MSI_SetPropertyW(package,prop,val);
298 msi_free(val);
299 msi_free(prop);
302 return ERROR_SUCCESS;
306 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
308 LPCWSTR pc;
309 LPWSTR p, *ret = NULL;
310 UINT count = 0;
312 if (!str)
313 return ret;
315 /* count the number of substrings */
316 for ( pc = str, count = 0; pc; count++ )
318 pc = strchrW( pc, sep );
319 if (pc)
320 pc++;
323 /* allocate space for an array of substring pointers and the substrings */
324 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
325 (lstrlenW(str)+1) * sizeof(WCHAR) );
326 if (!ret)
327 return ret;
329 /* copy the string and set the pointers */
330 p = (LPWSTR) &ret[count+1];
331 lstrcpyW( p, str );
332 for( count = 0; (ret[count] = p); count++ )
334 p = strchrW( p, sep );
335 if (p)
336 *p++ = 0;
339 return ret;
342 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
344 static const WCHAR szSystemLanguageID[] =
345 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
347 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
348 UINT ret = ERROR_FUNCTION_FAILED;
350 prod_code = msi_dup_property( package, szProductCode );
351 patch_product = msi_get_suminfo_product( patch );
353 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
355 if ( strstrW( patch_product, prod_code ) )
357 MSISUMMARYINFO *si;
358 const WCHAR *p;
360 si = MSI_GetSummaryInformationW( patch, 0 );
361 if (!si)
363 ERR("no summary information!\n");
364 goto end;
367 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
368 if (!template)
370 ERR("no template property!\n");
371 msiobj_release( &si->hdr );
372 goto end;
375 if (!template[0])
377 ret = ERROR_SUCCESS;
378 msiobj_release( &si->hdr );
379 goto end;
382 langid = msi_dup_property( package, szSystemLanguageID );
383 if (!langid)
385 msiobj_release( &si->hdr );
386 goto end;
389 p = strchrW( template, ';' );
390 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
392 TRACE("applicable transform\n");
393 ret = ERROR_SUCCESS;
396 /* FIXME: check platform */
398 msiobj_release( &si->hdr );
401 end:
402 msi_free( patch_product );
403 msi_free( prod_code );
404 msi_free( template );
405 msi_free( langid );
407 return ret;
410 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
411 MSIDATABASE *patch_db, LPCWSTR name )
413 UINT ret = ERROR_FUNCTION_FAILED;
414 IStorage *stg = NULL;
415 HRESULT r;
417 TRACE("%p %s\n", package, debugstr_w(name) );
419 if (*name++ != ':')
421 ERR("expected a colon in %s\n", debugstr_w(name));
422 return ERROR_FUNCTION_FAILED;
425 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
426 if (SUCCEEDED(r))
428 ret = msi_check_transform_applicable( package, stg );
429 if (ret == ERROR_SUCCESS)
430 msi_table_apply_transform( package->db, stg );
431 else
432 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
433 IStorage_Release( stg );
435 else
436 ERR("failed to open substorage %s\n", debugstr_w(name));
438 return ERROR_SUCCESS;
441 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
443 LPWSTR guid_list, *guids, product_code;
444 UINT i, ret = ERROR_FUNCTION_FAILED;
446 product_code = msi_dup_property( package, szProductCode );
447 if (!product_code)
449 /* FIXME: the property ProductCode should be written into the DB somewhere */
450 ERR("no product code to check\n");
451 return ERROR_SUCCESS;
454 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
455 guids = msi_split_string( guid_list, ';' );
456 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
458 if (!lstrcmpW( guids[i], product_code ))
459 ret = ERROR_SUCCESS;
461 msi_free( guids );
462 msi_free( guid_list );
463 msi_free( product_code );
465 return ret;
468 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
470 MSIQUERY *view;
471 MSIRECORD *rec = NULL;
472 LPWSTR patch;
473 LPCWSTR prop;
474 UINT r;
476 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
477 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
478 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
479 '`','S','o','u','r','c','e','`',' ','I','S',' ',
480 'N','O','T',' ','N','U','L','L',0};
482 r = MSI_DatabaseOpenViewW(package->db, query, &view);
483 if (r != ERROR_SUCCESS)
484 return r;
486 r = MSI_ViewExecute(view, 0);
487 if (r != ERROR_SUCCESS)
488 goto done;
490 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
492 prop = MSI_RecordGetString(rec, 1);
493 patch = msi_dup_property(package, szPatch);
494 MSI_SetPropertyW(package, prop, patch);
495 msi_free(patch);
498 done:
499 if (rec) msiobj_release(&rec->hdr);
500 msiobj_release(&view->hdr);
502 return r;
505 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
507 MSISUMMARYINFO *si;
508 LPWSTR str, *substorage;
509 UINT i, r = ERROR_SUCCESS;
511 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
512 if (!si)
513 return ERROR_FUNCTION_FAILED;
515 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
517 TRACE("Patch not applicable\n");
518 return ERROR_SUCCESS;
521 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
522 if (!package->patch)
523 return ERROR_OUTOFMEMORY;
525 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
526 if (!package->patch->patchcode)
527 return ERROR_OUTOFMEMORY;
529 /* enumerate the substorage */
530 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
531 package->patch->transforms = str;
533 substorage = msi_split_string( str, ';' );
534 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
535 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
537 msi_free( substorage );
538 msiobj_release( &si->hdr );
540 msi_set_media_source_prop(package);
542 return r;
545 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
547 MSIDATABASE *patch_db = NULL;
548 UINT r;
550 TRACE("%p %s\n", package, debugstr_w( file ) );
552 /* FIXME:
553 * We probably want to make sure we only open a patch collection here.
554 * Patch collections (.msp) and databases (.msi) have different GUIDs
555 * but currently MSI_OpenDatabaseW will accept both.
557 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
558 if ( r != ERROR_SUCCESS )
560 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
561 return r;
564 msi_parse_patch_summary( package, patch_db );
567 * There might be a CAB file in the patch package,
568 * so append it to the list of storage to search for streams.
570 append_storage_to_db( package->db, patch_db->storage );
572 msiobj_release( &patch_db->hdr );
574 return ERROR_SUCCESS;
577 /* get the PATCH property, and apply all the patches it specifies */
578 static UINT msi_apply_patches( MSIPACKAGE *package )
580 LPWSTR patch_list, *patches;
581 UINT i, r = ERROR_SUCCESS;
583 patch_list = msi_dup_property( package, szPatch );
585 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
587 patches = msi_split_string( patch_list, ';' );
588 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
589 r = msi_apply_patch_package( package, patches[i] );
591 msi_free( patches );
592 msi_free( patch_list );
594 return r;
597 static UINT msi_apply_transforms( MSIPACKAGE *package )
599 static const WCHAR szTransforms[] = {
600 'T','R','A','N','S','F','O','R','M','S',0 };
601 LPWSTR xform_list, *xforms;
602 UINT i, r = ERROR_SUCCESS;
604 xform_list = msi_dup_property( package, szTransforms );
605 xforms = msi_split_string( xform_list, ';' );
607 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
609 if (xforms[i][0] == ':')
610 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
611 else
612 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
615 msi_free( xforms );
616 msi_free( xform_list );
618 return r;
621 static BOOL ui_sequence_exists( MSIPACKAGE *package )
623 MSIQUERY *view;
624 UINT rc;
626 static const WCHAR ExecSeqQuery [] =
627 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
628 '`','I','n','s','t','a','l','l',
629 'U','I','S','e','q','u','e','n','c','e','`',
630 ' ','W','H','E','R','E',' ',
631 '`','S','e','q','u','e','n','c','e','`',' ',
632 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
633 '`','S','e','q','u','e','n','c','e','`',0};
635 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
636 if (rc == ERROR_SUCCESS)
638 msiobj_release(&view->hdr);
639 return TRUE;
642 return FALSE;
645 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
647 LPWSTR p, db;
648 LPWSTR source, check;
649 DWORD len;
651 static const WCHAR szOriginalDatabase[] =
652 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
654 db = msi_dup_property( package, szOriginalDatabase );
655 if (!db)
656 return ERROR_OUTOFMEMORY;
658 p = strrchrW( db, '\\' );
659 if (!p)
661 p = strrchrW( db, '/' );
662 if (!p)
664 msi_free(db);
665 return ERROR_SUCCESS;
669 len = p - db + 2;
670 source = msi_alloc( len * sizeof(WCHAR) );
671 lstrcpynW( source, db, len );
673 check = msi_dup_property( package, cszSourceDir );
674 if (!check || replace)
675 MSI_SetPropertyW( package, cszSourceDir, source );
677 msi_free( check );
679 check = msi_dup_property( package, cszSOURCEDIR );
680 if (!check || replace)
681 MSI_SetPropertyW( package, cszSOURCEDIR, source );
683 msi_free( check );
684 msi_free( source );
685 msi_free( db );
687 return ERROR_SUCCESS;
690 static BOOL needs_ui_sequence(MSIPACKAGE *package)
692 INT level = msi_get_property_int(package, szUILevel, 0);
693 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
696 static UINT msi_set_context(MSIPACKAGE *package)
698 WCHAR val[10];
699 DWORD sz = 10;
700 DWORD num;
701 UINT r;
703 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
705 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
706 if (r == ERROR_SUCCESS)
708 num = atolW(val);
709 if (num == 1 || num == 2)
710 package->Context = MSIINSTALLCONTEXT_MACHINE;
713 return ERROR_SUCCESS;
716 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
718 UINT rc;
719 LPCWSTR cond, action;
720 MSIPACKAGE *package = param;
722 action = MSI_RecordGetString(row,1);
723 if (!action)
725 ERR("Error is retrieving action name\n");
726 return ERROR_FUNCTION_FAILED;
729 /* check conditions */
730 cond = MSI_RecordGetString(row,2);
732 /* this is a hack to skip errors in the condition code */
733 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
735 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
736 return ERROR_SUCCESS;
739 if (needs_ui_sequence(package))
740 rc = ACTION_PerformUIAction(package, action, -1);
741 else
742 rc = ACTION_PerformAction(package, action, -1, FALSE);
744 msi_dialog_check_messages( NULL );
746 if (package->CurrentInstallState != ERROR_SUCCESS)
747 rc = package->CurrentInstallState;
749 if (rc == ERROR_FUNCTION_NOT_CALLED)
750 rc = ERROR_SUCCESS;
752 if (rc != ERROR_SUCCESS)
753 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
755 return rc;
758 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
760 MSIQUERY * view;
761 UINT r;
762 static const WCHAR query[] =
763 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
764 '`','%','s','`',
765 ' ','W','H','E','R','E',' ',
766 '`','S','e','q','u','e','n','c','e','`',' ',
767 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
768 '`','S','e','q','u','e','n','c','e','`',0};
770 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
772 r = MSI_OpenQuery( package->db, &view, query, szTable );
773 if (r == ERROR_SUCCESS)
775 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
776 msiobj_release(&view->hdr);
779 return r;
782 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
784 MSIQUERY * view;
785 UINT rc;
786 static const WCHAR ExecSeqQuery[] =
787 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
788 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
789 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
790 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
791 'O','R','D','E','R',' ', 'B','Y',' ',
792 '`','S','e','q','u','e','n','c','e','`',0 };
793 static const WCHAR IVQuery[] =
794 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
795 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
796 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
797 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
798 ' ','\'', 'I','n','s','t','a','l','l',
799 'V','a','l','i','d','a','t','e','\'', 0};
800 INT seq = 0;
802 if (package->script->ExecuteSequenceRun)
804 TRACE("Execute Sequence already Run\n");
805 return ERROR_SUCCESS;
808 package->script->ExecuteSequenceRun = TRUE;
810 /* get the sequence number */
811 if (UIran)
813 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
814 if( !row )
815 return ERROR_FUNCTION_FAILED;
816 seq = MSI_RecordGetInteger(row,1);
817 msiobj_release(&row->hdr);
820 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
821 if (rc == ERROR_SUCCESS)
823 TRACE("Running the actions\n");
825 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
826 msiobj_release(&view->hdr);
829 return rc;
832 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
834 MSIQUERY * view;
835 UINT rc;
836 static const WCHAR ExecSeqQuery [] =
837 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
838 '`','I','n','s','t','a','l','l',
839 'U','I','S','e','q','u','e','n','c','e','`',
840 ' ','W','H','E','R','E',' ',
841 '`','S','e','q','u','e','n','c','e','`',' ',
842 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
843 '`','S','e','q','u','e','n','c','e','`',0};
845 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
846 if (rc == ERROR_SUCCESS)
848 TRACE("Running the actions\n");
850 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
851 msiobj_release(&view->hdr);
854 return rc;
857 /********************************************************
858 * ACTION helper functions and functions that perform the actions
859 *******************************************************/
860 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
861 UINT* rc, UINT script, BOOL force )
863 BOOL ret=FALSE;
864 UINT arc;
866 arc = ACTION_CustomAction(package, action, script, force);
868 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
870 *rc = arc;
871 ret = TRUE;
873 return ret;
877 * Actual Action Handlers
880 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
882 MSIPACKAGE *package = param;
883 LPCWSTR dir, component;
884 LPWSTR full_path;
885 MSIRECORD *uirow;
886 MSIFOLDER *folder;
887 MSICOMPONENT *comp;
889 component = MSI_RecordGetString(row, 2);
890 comp = get_loaded_component(package, component);
891 if (!comp)
892 return ERROR_SUCCESS;
894 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
896 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
897 comp->Action = comp->Installed;
898 return ERROR_SUCCESS;
900 comp->Action = INSTALLSTATE_LOCAL;
902 dir = MSI_RecordGetString(row,1);
903 if (!dir)
905 ERR("Unable to get folder id\n");
906 return ERROR_SUCCESS;
909 uirow = MSI_CreateRecord(1);
910 MSI_RecordSetStringW(uirow, 1, dir);
911 ui_actiondata(package, szCreateFolders, uirow);
912 msiobj_release(&uirow->hdr);
914 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
915 if (!full_path)
917 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
918 return ERROR_SUCCESS;
921 TRACE("Folder is %s\n",debugstr_w(full_path));
923 if (folder->State == 0)
924 create_full_pathW(full_path);
926 folder->State = 3;
928 msi_free(full_path);
929 return ERROR_SUCCESS;
932 /* FIXME: probably should merge this with the above function */
933 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
935 UINT rc = ERROR_SUCCESS;
936 MSIFOLDER *folder;
937 LPWSTR install_path;
939 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
940 if (!install_path)
941 return ERROR_FUNCTION_FAILED;
943 /* create the path */
944 if (folder->State == 0)
946 create_full_pathW(install_path);
947 folder->State = 2;
949 msi_free(install_path);
951 return rc;
954 UINT msi_create_component_directories( MSIPACKAGE *package )
956 MSICOMPONENT *comp;
958 /* create all the folders required by the components are going to install */
959 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
961 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
962 continue;
963 msi_create_directory( package, comp->Directory );
966 return ERROR_SUCCESS;
969 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
971 static const WCHAR ExecSeqQuery[] =
972 {'S','E','L','E','C','T',' ',
973 '`','D','i','r','e','c','t','o','r','y','_','`',
974 ' ','F','R','O','M',' ',
975 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
976 UINT rc;
977 MSIQUERY *view;
979 /* create all the empty folders specified in the CreateFolder table */
980 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
981 if (rc != ERROR_SUCCESS)
982 return ERROR_SUCCESS;
984 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
985 msiobj_release(&view->hdr);
987 return rc;
990 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
992 MSIPACKAGE *package = param;
993 LPCWSTR dir, component;
994 LPWSTR full_path;
995 MSIRECORD *uirow;
996 MSIFOLDER *folder;
997 MSICOMPONENT *comp;
999 component = MSI_RecordGetString(row, 2);
1000 comp = get_loaded_component(package, component);
1001 if (!comp)
1002 return ERROR_SUCCESS;
1004 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1006 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1007 comp->Action = comp->Installed;
1008 return ERROR_SUCCESS;
1010 comp->Action = INSTALLSTATE_ABSENT;
1012 dir = MSI_RecordGetString( row, 1 );
1013 if (!dir)
1015 ERR("Unable to get folder id\n");
1016 return ERROR_SUCCESS;
1019 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1020 if (!full_path)
1022 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1023 return ERROR_SUCCESS;
1026 TRACE("folder is %s\n", debugstr_w(full_path));
1028 uirow = MSI_CreateRecord( 1 );
1029 MSI_RecordSetStringW( uirow, 1, full_path );
1030 ui_actiondata( package, szRemoveFolders, uirow );
1031 msiobj_release( &uirow->hdr );
1033 RemoveDirectoryW( full_path );
1034 folder->State = 0;
1036 msi_free( full_path );
1037 return ERROR_SUCCESS;
1040 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1042 static const WCHAR query[] =
1043 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1044 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1046 MSIQUERY *view;
1047 UINT rc;
1049 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1050 if (rc != ERROR_SUCCESS)
1051 return ERROR_SUCCESS;
1053 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1054 msiobj_release( &view->hdr );
1056 return rc;
1059 static UINT load_component( MSIRECORD *row, LPVOID param )
1061 MSIPACKAGE *package = param;
1062 MSICOMPONENT *comp;
1064 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1065 if (!comp)
1066 return ERROR_FUNCTION_FAILED;
1068 list_add_tail( &package->components, &comp->entry );
1070 /* fill in the data */
1071 comp->Component = msi_dup_record_field( row, 1 );
1073 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1075 comp->ComponentId = msi_dup_record_field( row, 2 );
1076 comp->Directory = msi_dup_record_field( row, 3 );
1077 comp->Attributes = MSI_RecordGetInteger(row,4);
1078 comp->Condition = msi_dup_record_field( row, 5 );
1079 comp->KeyPath = msi_dup_record_field( row, 6 );
1081 comp->Installed = INSTALLSTATE_UNKNOWN;
1082 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1084 return ERROR_SUCCESS;
1087 static UINT load_all_components( MSIPACKAGE *package )
1089 static const WCHAR query[] = {
1090 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1091 '`','C','o','m','p','o','n','e','n','t','`',0 };
1092 MSIQUERY *view;
1093 UINT r;
1095 if (!list_empty(&package->components))
1096 return ERROR_SUCCESS;
1098 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1099 if (r != ERROR_SUCCESS)
1100 return r;
1102 r = MSI_IterateRecords(view, NULL, load_component, package);
1103 msiobj_release(&view->hdr);
1104 return r;
1107 typedef struct {
1108 MSIPACKAGE *package;
1109 MSIFEATURE *feature;
1110 } _ilfs;
1112 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1114 ComponentList *cl;
1116 cl = msi_alloc( sizeof (*cl) );
1117 if ( !cl )
1118 return ERROR_NOT_ENOUGH_MEMORY;
1119 cl->component = comp;
1120 list_add_tail( &feature->Components, &cl->entry );
1122 return ERROR_SUCCESS;
1125 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1127 FeatureList *fl;
1129 fl = msi_alloc( sizeof(*fl) );
1130 if ( !fl )
1131 return ERROR_NOT_ENOUGH_MEMORY;
1132 fl->feature = child;
1133 list_add_tail( &parent->Children, &fl->entry );
1135 return ERROR_SUCCESS;
1138 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1140 _ilfs* ilfs = param;
1141 LPCWSTR component;
1142 MSICOMPONENT *comp;
1144 component = MSI_RecordGetString(row,1);
1146 /* check to see if the component is already loaded */
1147 comp = get_loaded_component( ilfs->package, component );
1148 if (!comp)
1150 ERR("unknown component %s\n", debugstr_w(component));
1151 return ERROR_FUNCTION_FAILED;
1154 add_feature_component( ilfs->feature, comp );
1155 comp->Enabled = TRUE;
1157 return ERROR_SUCCESS;
1160 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1162 MSIFEATURE *feature;
1164 if ( !name )
1165 return NULL;
1167 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1169 if ( !lstrcmpW( feature->Feature, name ) )
1170 return feature;
1173 return NULL;
1176 static UINT load_feature(MSIRECORD * row, LPVOID param)
1178 MSIPACKAGE* package = param;
1179 MSIFEATURE* feature;
1180 static const WCHAR Query1[] =
1181 {'S','E','L','E','C','T',' ',
1182 '`','C','o','m','p','o','n','e','n','t','_','`',
1183 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1184 'C','o','m','p','o','n','e','n','t','s','`',' ',
1185 'W','H','E','R','E',' ',
1186 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1187 MSIQUERY * view;
1188 UINT rc;
1189 _ilfs ilfs;
1191 /* fill in the data */
1193 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1194 if (!feature)
1195 return ERROR_NOT_ENOUGH_MEMORY;
1197 list_init( &feature->Children );
1198 list_init( &feature->Components );
1200 feature->Feature = msi_dup_record_field( row, 1 );
1202 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1204 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1205 feature->Title = msi_dup_record_field( row, 3 );
1206 feature->Description = msi_dup_record_field( row, 4 );
1208 if (!MSI_RecordIsNull(row,5))
1209 feature->Display = MSI_RecordGetInteger(row,5);
1211 feature->Level= MSI_RecordGetInteger(row,6);
1212 feature->Directory = msi_dup_record_field( row, 7 );
1213 feature->Attributes = MSI_RecordGetInteger(row,8);
1215 feature->Installed = INSTALLSTATE_UNKNOWN;
1216 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1218 list_add_tail( &package->features, &feature->entry );
1220 /* load feature components */
1222 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1223 if (rc != ERROR_SUCCESS)
1224 return ERROR_SUCCESS;
1226 ilfs.package = package;
1227 ilfs.feature = feature;
1229 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1230 msiobj_release(&view->hdr);
1232 return ERROR_SUCCESS;
1235 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1237 MSIPACKAGE* package = param;
1238 MSIFEATURE *parent, *child;
1240 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1241 if (!child)
1242 return ERROR_FUNCTION_FAILED;
1244 if (!child->Feature_Parent)
1245 return ERROR_SUCCESS;
1247 parent = find_feature_by_name( package, child->Feature_Parent );
1248 if (!parent)
1249 return ERROR_FUNCTION_FAILED;
1251 add_feature_child( parent, child );
1252 return ERROR_SUCCESS;
1255 static UINT load_all_features( MSIPACKAGE *package )
1257 static const WCHAR query[] = {
1258 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1259 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1260 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1261 MSIQUERY *view;
1262 UINT r;
1264 if (!list_empty(&package->features))
1265 return ERROR_SUCCESS;
1267 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1268 if (r != ERROR_SUCCESS)
1269 return r;
1271 r = MSI_IterateRecords( view, NULL, load_feature, package );
1272 if (r != ERROR_SUCCESS)
1273 return r;
1275 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1276 msiobj_release( &view->hdr );
1278 return r;
1281 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1283 if (!p)
1284 return p;
1285 p = strchrW(p, ch);
1286 if (!p)
1287 return p;
1288 *p = 0;
1289 return p+1;
1292 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1294 static const WCHAR query[] = {
1295 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1296 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1297 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1298 MSIQUERY *view = NULL;
1299 MSIRECORD *row = NULL;
1300 UINT r;
1302 TRACE("%s\n", debugstr_w(file->File));
1304 r = MSI_OpenQuery(package->db, &view, query, file->File);
1305 if (r != ERROR_SUCCESS)
1306 goto done;
1308 r = MSI_ViewExecute(view, NULL);
1309 if (r != ERROR_SUCCESS)
1310 goto done;
1312 r = MSI_ViewFetch(view, &row);
1313 if (r != ERROR_SUCCESS)
1314 goto done;
1316 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1317 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1318 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1319 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1320 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1322 done:
1323 if (view) msiobj_release(&view->hdr);
1324 if (row) msiobj_release(&row->hdr);
1325 return r;
1328 static UINT load_file(MSIRECORD *row, LPVOID param)
1330 MSIPACKAGE* package = param;
1331 LPCWSTR component;
1332 MSIFILE *file;
1334 /* fill in the data */
1336 file = msi_alloc_zero( sizeof (MSIFILE) );
1337 if (!file)
1338 return ERROR_NOT_ENOUGH_MEMORY;
1340 file->File = msi_dup_record_field( row, 1 );
1342 component = MSI_RecordGetString( row, 2 );
1343 file->Component = get_loaded_component( package, component );
1345 if (!file->Component)
1347 WARN("Component not found: %s\n", debugstr_w(component));
1348 msi_free(file->File);
1349 msi_free(file);
1350 return ERROR_SUCCESS;
1353 file->FileName = msi_dup_record_field( row, 3 );
1354 reduce_to_longfilename( file->FileName );
1356 file->ShortName = msi_dup_record_field( row, 3 );
1357 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1359 file->FileSize = MSI_RecordGetInteger( row, 4 );
1360 file->Version = msi_dup_record_field( row, 5 );
1361 file->Language = msi_dup_record_field( row, 6 );
1362 file->Attributes = MSI_RecordGetInteger( row, 7 );
1363 file->Sequence = MSI_RecordGetInteger( row, 8 );
1365 file->state = msifs_invalid;
1367 /* if the compressed bits are not set in the file attributes,
1368 * then read the information from the package word count property
1370 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1372 file->IsCompressed = FALSE;
1374 else if (file->Attributes &
1375 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1377 file->IsCompressed = TRUE;
1379 else if (file->Attributes & msidbFileAttributesNoncompressed)
1381 file->IsCompressed = FALSE;
1383 else
1385 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1388 load_file_hash(package, file);
1390 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1392 list_add_tail( &package->files, &file->entry );
1394 return ERROR_SUCCESS;
1397 static UINT load_all_files(MSIPACKAGE *package)
1399 MSIQUERY * view;
1400 UINT rc;
1401 static const WCHAR Query[] =
1402 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1403 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1404 '`','S','e','q','u','e','n','c','e','`', 0};
1406 if (!list_empty(&package->files))
1407 return ERROR_SUCCESS;
1409 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1410 if (rc != ERROR_SUCCESS)
1411 return ERROR_SUCCESS;
1413 rc = MSI_IterateRecords(view, NULL, load_file, package);
1414 msiobj_release(&view->hdr);
1416 return ERROR_SUCCESS;
1419 static UINT load_folder( MSIRECORD *row, LPVOID param )
1421 MSIPACKAGE *package = param;
1422 static WCHAR szEmpty[] = { 0 };
1423 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1424 MSIFOLDER *folder;
1426 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1427 if (!folder)
1428 return ERROR_NOT_ENOUGH_MEMORY;
1430 folder->Directory = msi_dup_record_field( row, 1 );
1432 TRACE("%s\n", debugstr_w(folder->Directory));
1434 p = msi_dup_record_field(row, 3);
1436 /* split src and target dir */
1437 tgt_short = p;
1438 src_short = folder_split_path( p, ':' );
1440 /* split the long and short paths */
1441 tgt_long = folder_split_path( tgt_short, '|' );
1442 src_long = folder_split_path( src_short, '|' );
1444 /* check for no-op dirs */
1445 if (!lstrcmpW(szDot, tgt_short))
1446 tgt_short = szEmpty;
1447 if (!lstrcmpW(szDot, src_short))
1448 src_short = szEmpty;
1450 if (!tgt_long)
1451 tgt_long = tgt_short;
1453 if (!src_short) {
1454 src_short = tgt_short;
1455 src_long = tgt_long;
1458 if (!src_long)
1459 src_long = src_short;
1461 /* FIXME: use the target short path too */
1462 folder->TargetDefault = strdupW(tgt_long);
1463 folder->SourceShortPath = strdupW(src_short);
1464 folder->SourceLongPath = strdupW(src_long);
1465 msi_free(p);
1467 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1468 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1469 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1471 folder->Parent = msi_dup_record_field( row, 2 );
1473 folder->Property = msi_dup_property( package, folder->Directory );
1475 list_add_tail( &package->folders, &folder->entry );
1477 TRACE("returning %p\n", folder);
1479 return ERROR_SUCCESS;
1482 static UINT load_all_folders( MSIPACKAGE *package )
1484 static const WCHAR query[] = {
1485 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1486 '`','D','i','r','e','c','t','o','r','y','`',0 };
1487 MSIQUERY *view;
1488 UINT r;
1490 if (!list_empty(&package->folders))
1491 return ERROR_SUCCESS;
1493 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1494 if (r != ERROR_SUCCESS)
1495 return r;
1497 r = MSI_IterateRecords(view, NULL, load_folder, package);
1498 msiobj_release(&view->hdr);
1499 return r;
1503 * I am not doing any of the costing functionality yet.
1504 * Mostly looking at doing the Component and Feature loading
1506 * The native MSI does A LOT of modification to tables here. Mostly adding
1507 * a lot of temporary columns to the Feature and Component tables.
1509 * note: Native msi also tracks the short filename. But I am only going to
1510 * track the long ones. Also looking at this directory table
1511 * it appears that the directory table does not get the parents
1512 * resolved base on property only based on their entries in the
1513 * directory table.
1515 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1517 static const WCHAR szCosting[] =
1518 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1520 MSI_SetPropertyW(package, szCosting, szZero);
1521 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1523 load_all_folders( package );
1524 load_all_components( package );
1525 load_all_features( package );
1526 load_all_files( package );
1528 return ERROR_SUCCESS;
1531 static UINT execute_script(MSIPACKAGE *package, UINT script )
1533 UINT i;
1534 UINT rc = ERROR_SUCCESS;
1536 TRACE("Executing Script %i\n",script);
1538 if (!package->script)
1540 ERR("no script!\n");
1541 return ERROR_FUNCTION_FAILED;
1544 for (i = 0; i < package->script->ActionCount[script]; i++)
1546 LPWSTR action;
1547 action = package->script->Actions[script][i];
1548 ui_actionstart(package, action);
1549 TRACE("Executing Action (%s)\n",debugstr_w(action));
1550 rc = ACTION_PerformAction(package, action, script, TRUE);
1551 if (rc != ERROR_SUCCESS)
1552 break;
1554 msi_free_action_script(package, script);
1555 return rc;
1558 static UINT ACTION_FileCost(MSIPACKAGE *package)
1560 return ERROR_SUCCESS;
1563 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1565 MSICOMPONENT *comp;
1566 INSTALLSTATE state;
1567 UINT r;
1569 state = MsiQueryProductStateW(package->ProductCode);
1571 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1573 if (!comp->ComponentId)
1574 continue;
1576 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1577 comp->Installed = INSTALLSTATE_ABSENT;
1578 else
1580 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1581 package->Context, comp->ComponentId,
1582 &comp->Installed);
1583 if (r != ERROR_SUCCESS)
1584 comp->Installed = INSTALLSTATE_ABSENT;
1589 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1591 MSIFEATURE *feature;
1592 INSTALLSTATE state;
1594 state = MsiQueryProductStateW(package->ProductCode);
1596 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1598 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1599 feature->Installed = INSTALLSTATE_ABSENT;
1600 else
1602 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1603 feature->Feature);
1608 static BOOL process_state_property(MSIPACKAGE* package, int level,
1609 LPCWSTR property, INSTALLSTATE state)
1611 LPWSTR override;
1612 MSIFEATURE *feature;
1614 override = msi_dup_property( package, property );
1615 if (!override)
1616 return FALSE;
1618 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1620 if (lstrcmpW(property, szRemove) &&
1621 (feature->Level <= 0 || feature->Level > level))
1622 continue;
1624 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1626 if (strcmpiW(override, szAll)==0)
1627 msi_feature_set_state(package, feature, state);
1628 else
1630 LPWSTR ptr = override;
1631 LPWSTR ptr2 = strchrW(override,',');
1633 while (ptr)
1635 int len = ptr2 - ptr;
1637 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1638 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1640 msi_feature_set_state(package, feature, state);
1641 break;
1643 if (ptr2)
1645 ptr=ptr2+1;
1646 ptr2 = strchrW(ptr,',');
1648 else
1649 break;
1653 msi_free(override);
1655 return TRUE;
1658 static BOOL process_overrides( MSIPACKAGE *package, int level )
1660 static const WCHAR szAddLocal[] =
1661 {'A','D','D','L','O','C','A','L',0};
1662 static const WCHAR szAddSource[] =
1663 {'A','D','D','S','O','U','R','C','E',0};
1664 static const WCHAR szAdvertise[] =
1665 {'A','D','V','E','R','T','I','S','E',0};
1666 BOOL ret = FALSE;
1668 /* all these activation/deactivation things happen in order and things
1669 * later on the list override things earlier on the list.
1671 * 0 INSTALLLEVEL processing
1672 * 1 ADDLOCAL
1673 * 2 REMOVE
1674 * 3 ADDSOURCE
1675 * 4 ADDDEFAULT
1676 * 5 REINSTALL
1677 * 6 ADVERTISE
1678 * 7 COMPADDLOCAL
1679 * 8 COMPADDSOURCE
1680 * 9 FILEADDLOCAL
1681 * 10 FILEADDSOURCE
1682 * 11 FILEADDDEFAULT
1684 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1685 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1686 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1687 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1688 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1690 if (ret)
1691 MSI_SetPropertyW( package, szPreselected, szOne );
1693 return ret;
1696 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1698 int level;
1699 static const WCHAR szlevel[] =
1700 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1701 MSICOMPONENT* component;
1702 MSIFEATURE *feature;
1704 TRACE("Checking Install Level\n");
1706 level = msi_get_property_int(package, szlevel, 1);
1708 if (!msi_get_property_int( package, szPreselected, 0 ))
1710 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1712 BOOL feature_state = ((feature->Level > 0) &&
1713 (feature->Level <= level));
1715 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1717 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1718 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1719 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1720 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1721 else
1722 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1726 /* disable child features of unselected parent features */
1727 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1729 FeatureList *fl;
1731 if (feature->Level > 0 && feature->Level <= level)
1732 continue;
1734 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1735 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1740 * now we want to enable or disable components base on feature
1743 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1745 ComponentList *cl;
1747 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1748 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1750 if (!feature->Level)
1751 continue;
1753 /* features with components that have compressed files are made local */
1754 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1756 if (cl->component->Enabled &&
1757 cl->component->ForceLocalState &&
1758 feature->Action == INSTALLSTATE_SOURCE)
1760 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1761 break;
1765 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1767 component = cl->component;
1769 if (!component->Enabled)
1770 continue;
1772 switch (feature->Action)
1774 case INSTALLSTATE_ABSENT:
1775 component->anyAbsent = 1;
1776 break;
1777 case INSTALLSTATE_ADVERTISED:
1778 component->hasAdvertiseFeature = 1;
1779 break;
1780 case INSTALLSTATE_SOURCE:
1781 component->hasSourceFeature = 1;
1782 break;
1783 case INSTALLSTATE_LOCAL:
1784 component->hasLocalFeature = 1;
1785 break;
1786 case INSTALLSTATE_DEFAULT:
1787 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1788 component->hasAdvertiseFeature = 1;
1789 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1790 component->hasSourceFeature = 1;
1791 else
1792 component->hasLocalFeature = 1;
1793 break;
1794 default:
1795 break;
1800 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1802 /* if the component isn't enabled, leave it alone */
1803 if (!component->Enabled)
1804 continue;
1806 /* check if it's local or source */
1807 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1808 (component->hasLocalFeature || component->hasSourceFeature))
1810 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1811 !component->ForceLocalState)
1812 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1813 else
1814 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1815 continue;
1818 /* if any feature is local, the component must be local too */
1819 if (component->hasLocalFeature)
1821 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1822 continue;
1825 if (component->hasSourceFeature)
1827 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1828 continue;
1831 if (component->hasAdvertiseFeature)
1833 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1834 continue;
1837 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1838 if (component->anyAbsent)
1839 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1842 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1844 if (component->Action == INSTALLSTATE_DEFAULT)
1846 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1847 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1850 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1851 debugstr_w(component->Component), component->Installed, component->Action);
1855 return ERROR_SUCCESS;
1858 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1860 MSIPACKAGE *package = param;
1861 LPCWSTR name;
1862 LPWSTR path;
1863 MSIFOLDER *f;
1865 name = MSI_RecordGetString(row,1);
1867 f = get_loaded_folder(package, name);
1868 if (!f) return ERROR_SUCCESS;
1870 /* reset the ResolvedTarget */
1871 msi_free(f->ResolvedTarget);
1872 f->ResolvedTarget = NULL;
1874 /* This helper function now does ALL the work */
1875 TRACE("Dir %s ...\n",debugstr_w(name));
1876 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1877 TRACE("resolves to %s\n",debugstr_w(path));
1878 msi_free(path);
1880 return ERROR_SUCCESS;
1883 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1885 MSIPACKAGE *package = param;
1886 LPCWSTR name;
1887 MSIFEATURE *feature;
1889 name = MSI_RecordGetString( row, 1 );
1891 feature = get_loaded_feature( package, name );
1892 if (!feature)
1893 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1894 else
1896 LPCWSTR Condition;
1897 Condition = MSI_RecordGetString(row,3);
1899 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1901 int level = MSI_RecordGetInteger(row,2);
1902 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1903 feature->Level = level;
1906 return ERROR_SUCCESS;
1909 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1911 static const WCHAR name_fmt[] =
1912 {'%','u','.','%','u','.','%','u','.','%','u',0};
1913 static const WCHAR name[] = {'\\',0};
1914 VS_FIXEDFILEINFO *lpVer;
1915 WCHAR filever[0x100];
1916 LPVOID version;
1917 DWORD versize;
1918 DWORD handle;
1919 UINT sz;
1921 TRACE("%s\n", debugstr_w(filename));
1923 versize = GetFileVersionInfoSizeW( filename, &handle );
1924 if (!versize)
1925 return NULL;
1927 version = msi_alloc( versize );
1928 GetFileVersionInfoW( filename, 0, versize, version );
1930 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1932 msi_free( version );
1933 return NULL;
1936 sprintfW( filever, name_fmt,
1937 HIWORD(lpVer->dwFileVersionMS),
1938 LOWORD(lpVer->dwFileVersionMS),
1939 HIWORD(lpVer->dwFileVersionLS),
1940 LOWORD(lpVer->dwFileVersionLS));
1942 msi_free( version );
1944 return strdupW( filever );
1947 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1949 LPWSTR file_version;
1950 MSIFILE *file;
1952 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1954 MSICOMPONENT* comp = file->Component;
1955 LPWSTR p;
1957 if (!comp)
1958 continue;
1960 if (file->IsCompressed)
1961 comp->ForceLocalState = TRUE;
1963 /* calculate target */
1964 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1966 msi_free(file->TargetPath);
1968 TRACE("file %s is named %s\n",
1969 debugstr_w(file->File), debugstr_w(file->FileName));
1971 file->TargetPath = build_directory_name(2, p, file->FileName);
1973 msi_free(p);
1975 TRACE("file %s resolves to %s\n",
1976 debugstr_w(file->File), debugstr_w(file->TargetPath));
1978 /* don't check files of components that aren't installed */
1979 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1980 comp->Installed == INSTALLSTATE_ABSENT)
1982 file->state = msifs_missing; /* assume files are missing */
1983 continue;
1986 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1988 file->state = msifs_missing;
1989 comp->Cost += file->FileSize;
1990 continue;
1993 if (file->Version &&
1994 (file_version = msi_get_disk_file_version( file->TargetPath )))
1996 TRACE("new %s old %s\n", debugstr_w(file->Version),
1997 debugstr_w(file_version));
1998 /* FIXME: seems like a bad way to compare version numbers */
1999 if (lstrcmpiW(file_version, file->Version)<0)
2001 file->state = msifs_overwrite;
2002 comp->Cost += file->FileSize;
2004 else
2005 file->state = msifs_present;
2006 msi_free( file_version );
2008 else
2009 file->state = msifs_present;
2012 return ERROR_SUCCESS;
2016 * A lot is done in this function aside from just the costing.
2017 * The costing needs to be implemented at some point but for now I am going
2018 * to focus on the directory building
2021 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2023 static const WCHAR ExecSeqQuery[] =
2024 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2025 '`','D','i','r','e','c','t','o','r','y','`',0};
2026 static const WCHAR ConditionQuery[] =
2027 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2028 '`','C','o','n','d','i','t','i','o','n','`',0};
2029 static const WCHAR szCosting[] =
2030 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2031 static const WCHAR szlevel[] =
2032 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2033 static const WCHAR szOutOfDiskSpace[] =
2034 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2035 MSICOMPONENT *comp;
2036 UINT rc = ERROR_SUCCESS;
2037 MSIQUERY * view;
2038 LPWSTR level;
2040 TRACE("Building Directory properties\n");
2042 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2043 if (rc == ERROR_SUCCESS)
2045 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2046 package);
2047 msiobj_release(&view->hdr);
2050 /* read components states from the registry */
2051 ACTION_GetComponentInstallStates(package);
2052 ACTION_GetFeatureInstallStates(package);
2054 TRACE("File calculations\n");
2055 msi_check_file_install_states( package );
2057 if (!process_overrides( package, msi_get_property_int( package, szlevel, 1 ) ))
2059 TRACE("Evaluating Condition Table\n");
2061 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2062 if (rc == ERROR_SUCCESS)
2064 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2065 msiobj_release( &view->hdr );
2068 TRACE("Enabling or Disabling Components\n");
2069 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2071 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2073 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2074 comp->Enabled = FALSE;
2076 else
2077 comp->Enabled = TRUE;
2081 MSI_SetPropertyW(package,szCosting,szOne);
2082 /* set default run level if not set */
2083 level = msi_dup_property( package, szlevel );
2084 if (!level)
2085 MSI_SetPropertyW(package,szlevel, szOne);
2086 msi_free(level);
2088 /* FIXME: check volume disk space */
2089 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2091 return MSI_SetFeatureStates(package);
2094 /* OK this value is "interpreted" and then formatted based on the
2095 first few characters */
2096 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2097 DWORD *size)
2099 LPSTR data = NULL;
2101 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2103 if (value[1]=='x')
2105 LPWSTR ptr;
2106 CHAR byte[5];
2107 LPWSTR deformated = NULL;
2108 int count;
2110 deformat_string(package, &value[2], &deformated);
2112 /* binary value type */
2113 ptr = deformated;
2114 *type = REG_BINARY;
2115 if (strlenW(ptr)%2)
2116 *size = (strlenW(ptr)/2)+1;
2117 else
2118 *size = strlenW(ptr)/2;
2120 data = msi_alloc(*size);
2122 byte[0] = '0';
2123 byte[1] = 'x';
2124 byte[4] = 0;
2125 count = 0;
2126 /* if uneven pad with a zero in front */
2127 if (strlenW(ptr)%2)
2129 byte[2]= '0';
2130 byte[3]= *ptr;
2131 ptr++;
2132 data[count] = (BYTE)strtol(byte,NULL,0);
2133 count ++;
2134 TRACE("Uneven byte count\n");
2136 while (*ptr)
2138 byte[2]= *ptr;
2139 ptr++;
2140 byte[3]= *ptr;
2141 ptr++;
2142 data[count] = (BYTE)strtol(byte,NULL,0);
2143 count ++;
2145 msi_free(deformated);
2147 TRACE("Data %i bytes(%i)\n",*size,count);
2149 else
2151 LPWSTR deformated;
2152 LPWSTR p;
2153 DWORD d = 0;
2154 deformat_string(package, &value[1], &deformated);
2156 *type=REG_DWORD;
2157 *size = sizeof(DWORD);
2158 data = msi_alloc(*size);
2159 p = deformated;
2160 if (*p == '-')
2161 p++;
2162 while (*p)
2164 if ( (*p < '0') || (*p > '9') )
2165 break;
2166 d *= 10;
2167 d += (*p - '0');
2168 p++;
2170 if (deformated[0] == '-')
2171 d = -d;
2172 *(LPDWORD)data = d;
2173 TRACE("DWORD %i\n",*(LPDWORD)data);
2175 msi_free(deformated);
2178 else
2180 static const WCHAR szMulti[] = {'[','~',']',0};
2181 LPCWSTR ptr;
2182 *type=REG_SZ;
2184 if (value[0]=='#')
2186 if (value[1]=='%')
2188 ptr = &value[2];
2189 *type=REG_EXPAND_SZ;
2191 else
2192 ptr = &value[1];
2194 else
2195 ptr=value;
2197 if (strstrW(value,szMulti))
2198 *type = REG_MULTI_SZ;
2200 /* remove initial delimiter */
2201 if (!strncmpW(value, szMulti, 3))
2202 ptr = value + 3;
2204 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2206 /* add double NULL terminator */
2207 if (*type == REG_MULTI_SZ)
2209 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2210 data = msi_realloc_zero(data, *size);
2213 return data;
2216 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2218 const WCHAR *ret;
2220 switch (root)
2222 case -1:
2223 if (msi_get_property_int( package, szAllUsers, 0 ))
2225 *root_key = HKEY_LOCAL_MACHINE;
2226 ret = szHLM;
2228 else
2230 *root_key = HKEY_CURRENT_USER;
2231 ret = szHCU;
2233 break;
2234 case 0:
2235 *root_key = HKEY_CLASSES_ROOT;
2236 ret = szHCR;
2237 break;
2238 case 1:
2239 *root_key = HKEY_CURRENT_USER;
2240 ret = szHCU;
2241 break;
2242 case 2:
2243 *root_key = HKEY_LOCAL_MACHINE;
2244 ret = szHLM;
2245 break;
2246 case 3:
2247 *root_key = HKEY_USERS;
2248 ret = szHU;
2249 break;
2250 default:
2251 ERR("Unknown root %i\n", root);
2252 return NULL;
2255 return ret;
2258 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2260 MSIPACKAGE *package = param;
2261 LPSTR value_data = NULL;
2262 HKEY root_key, hkey;
2263 DWORD type,size;
2264 LPWSTR deformated;
2265 LPCWSTR szRoot, component, name, key, value;
2266 MSICOMPONENT *comp;
2267 MSIRECORD * uirow;
2268 LPWSTR uikey;
2269 INT root;
2270 BOOL check_first = FALSE;
2271 UINT rc;
2273 ui_progress(package,2,0,0,0);
2275 value = NULL;
2276 key = NULL;
2277 uikey = NULL;
2278 name = NULL;
2280 component = MSI_RecordGetString(row, 6);
2281 comp = get_loaded_component(package,component);
2282 if (!comp)
2283 return ERROR_SUCCESS;
2285 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2287 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2288 comp->Action = comp->Installed;
2289 return ERROR_SUCCESS;
2291 comp->Action = INSTALLSTATE_LOCAL;
2293 name = MSI_RecordGetString(row, 4);
2294 if( MSI_RecordIsNull(row,5) && name )
2296 /* null values can have special meanings */
2297 if (name[0]=='-' && name[1] == 0)
2298 return ERROR_SUCCESS;
2299 else if ((name[0]=='+' && name[1] == 0) ||
2300 (name[0] == '*' && name[1] == 0))
2301 name = NULL;
2302 check_first = TRUE;
2305 root = MSI_RecordGetInteger(row,2);
2306 key = MSI_RecordGetString(row, 3);
2308 szRoot = get_root_key( package, root, &root_key );
2309 if (!szRoot)
2310 return ERROR_SUCCESS;
2312 deformat_string(package, key , &deformated);
2313 size = strlenW(deformated) + strlenW(szRoot) + 1;
2314 uikey = msi_alloc(size*sizeof(WCHAR));
2315 strcpyW(uikey,szRoot);
2316 strcatW(uikey,deformated);
2318 if (RegCreateKeyW( root_key, deformated, &hkey))
2320 ERR("Could not create key %s\n",debugstr_w(deformated));
2321 msi_free(deformated);
2322 msi_free(uikey);
2323 return ERROR_SUCCESS;
2325 msi_free(deformated);
2327 value = MSI_RecordGetString(row,5);
2328 if (value)
2329 value_data = parse_value(package, value, &type, &size);
2330 else
2332 value_data = (LPSTR)strdupW(szEmpty);
2333 size = sizeof(szEmpty);
2334 type = REG_SZ;
2337 deformat_string(package, name, &deformated);
2339 if (!check_first)
2341 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2342 debugstr_w(uikey));
2343 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2345 else
2347 DWORD sz = 0;
2348 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2349 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2351 TRACE("value %s of %s checked already exists\n",
2352 debugstr_w(deformated), debugstr_w(uikey));
2354 else
2356 TRACE("Checked and setting value %s of %s\n",
2357 debugstr_w(deformated), debugstr_w(uikey));
2358 if (deformated || size)
2359 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2362 RegCloseKey(hkey);
2364 uirow = MSI_CreateRecord(3);
2365 MSI_RecordSetStringW(uirow,2,deformated);
2366 MSI_RecordSetStringW(uirow,1,uikey);
2368 if (type == REG_SZ)
2369 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2370 else
2371 MSI_RecordSetStringW(uirow,3,value);
2373 ui_actiondata(package,szWriteRegistryValues,uirow);
2374 msiobj_release( &uirow->hdr );
2376 msi_free(value_data);
2377 msi_free(deformated);
2378 msi_free(uikey);
2380 return ERROR_SUCCESS;
2383 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2385 UINT rc;
2386 MSIQUERY * view;
2387 static const WCHAR ExecSeqQuery[] =
2388 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2389 '`','R','e','g','i','s','t','r','y','`',0 };
2391 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2392 if (rc != ERROR_SUCCESS)
2393 return ERROR_SUCCESS;
2395 /* increment progress bar each time action data is sent */
2396 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2398 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2400 msiobj_release(&view->hdr);
2401 return rc;
2404 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2406 LONG res;
2407 HKEY hkey;
2408 DWORD num_subkeys, num_values;
2410 if (delete_key)
2412 if ((res = RegDeleteTreeW( hkey_root, key )))
2414 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2416 return;
2419 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2421 if ((res = RegDeleteValueW( hkey, value )))
2423 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2425 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2426 NULL, NULL, NULL, NULL );
2427 RegCloseKey( hkey );
2429 if (!res && !num_subkeys && !num_values)
2431 TRACE("Removing empty key %s\n", debugstr_w(key));
2432 RegDeleteKeyW( hkey_root, key );
2434 return;
2436 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2440 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2442 MSIPACKAGE *package = param;
2443 LPCWSTR component, name, key_str, root_key_str;
2444 LPWSTR deformated_key, deformated_name, ui_key_str;
2445 MSICOMPONENT *comp;
2446 MSIRECORD *uirow;
2447 BOOL delete_key = FALSE;
2448 HKEY hkey_root;
2449 UINT size;
2450 INT root;
2452 ui_progress( package, 2, 0, 0, 0 );
2454 component = MSI_RecordGetString( row, 6 );
2455 comp = get_loaded_component( package, component );
2456 if (!comp)
2457 return ERROR_SUCCESS;
2459 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2461 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2462 comp->Action = comp->Installed;
2463 return ERROR_SUCCESS;
2465 comp->Action = INSTALLSTATE_ABSENT;
2467 name = MSI_RecordGetString( row, 4 );
2468 if (MSI_RecordIsNull( row, 5 ) && name )
2470 if (name[0] == '+' && !name[1])
2471 return ERROR_SUCCESS;
2472 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2474 delete_key = TRUE;
2475 name = NULL;
2479 root = MSI_RecordGetInteger( row, 2 );
2480 key_str = MSI_RecordGetString( row, 3 );
2482 root_key_str = get_root_key( package, root, &hkey_root );
2483 if (!root_key_str)
2484 return ERROR_SUCCESS;
2486 deformat_string( package, key_str, &deformated_key );
2487 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2488 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2489 strcpyW( ui_key_str, root_key_str );
2490 strcatW( ui_key_str, deformated_key );
2492 deformat_string( package, name, &deformated_name );
2494 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2495 msi_free( deformated_key );
2497 uirow = MSI_CreateRecord( 2 );
2498 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2499 MSI_RecordSetStringW( uirow, 2, deformated_name );
2501 ui_actiondata( package, szRemoveRegistryValues, uirow );
2502 msiobj_release( &uirow->hdr );
2504 msi_free( ui_key_str );
2505 msi_free( deformated_name );
2506 return ERROR_SUCCESS;
2509 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2511 MSIPACKAGE *package = param;
2512 LPCWSTR component, name, key_str, root_key_str;
2513 LPWSTR deformated_key, deformated_name, ui_key_str;
2514 MSICOMPONENT *comp;
2515 MSIRECORD *uirow;
2516 BOOL delete_key = FALSE;
2517 HKEY hkey_root;
2518 UINT size;
2519 INT root;
2521 ui_progress( package, 2, 0, 0, 0 );
2523 component = MSI_RecordGetString( row, 5 );
2524 comp = get_loaded_component( package, component );
2525 if (!comp)
2526 return ERROR_SUCCESS;
2528 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2530 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2531 comp->Action = comp->Installed;
2532 return ERROR_SUCCESS;
2534 comp->Action = INSTALLSTATE_LOCAL;
2536 if ((name = MSI_RecordGetString( row, 4 )))
2538 if (name[0] == '-' && !name[1])
2540 delete_key = TRUE;
2541 name = NULL;
2545 root = MSI_RecordGetInteger( row, 2 );
2546 key_str = MSI_RecordGetString( row, 3 );
2548 root_key_str = get_root_key( package, root, &hkey_root );
2549 if (!root_key_str)
2550 return ERROR_SUCCESS;
2552 deformat_string( package, key_str, &deformated_key );
2553 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2554 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2555 strcpyW( ui_key_str, root_key_str );
2556 strcatW( ui_key_str, deformated_key );
2558 deformat_string( package, name, &deformated_name );
2560 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2561 msi_free( deformated_key );
2563 uirow = MSI_CreateRecord( 2 );
2564 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2565 MSI_RecordSetStringW( uirow, 2, deformated_name );
2567 ui_actiondata( package, szRemoveRegistryValues, uirow );
2568 msiobj_release( &uirow->hdr );
2570 msi_free( ui_key_str );
2571 msi_free( deformated_name );
2572 return ERROR_SUCCESS;
2575 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2577 UINT rc;
2578 MSIQUERY *view;
2579 static const WCHAR registry_query[] =
2580 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2581 '`','R','e','g','i','s','t','r','y','`',0 };
2582 static const WCHAR remove_registry_query[] =
2583 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2584 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2586 /* increment progress bar each time action data is sent */
2587 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2589 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2590 if (rc == ERROR_SUCCESS)
2592 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2593 msiobj_release( &view->hdr );
2594 if (rc != ERROR_SUCCESS)
2595 return rc;
2598 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2599 if (rc == ERROR_SUCCESS)
2601 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2602 msiobj_release( &view->hdr );
2603 if (rc != ERROR_SUCCESS)
2604 return rc;
2607 return ERROR_SUCCESS;
2610 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2612 package->script->CurrentlyScripting = TRUE;
2614 return ERROR_SUCCESS;
2618 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2620 MSICOMPONENT *comp;
2621 DWORD progress = 0;
2622 DWORD total = 0;
2623 static const WCHAR q1[]=
2624 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2625 '`','R','e','g','i','s','t','r','y','`',0};
2626 UINT rc;
2627 MSIQUERY * view;
2628 MSIFEATURE *feature;
2629 MSIFILE *file;
2631 TRACE("InstallValidate\n");
2633 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2634 if (rc == ERROR_SUCCESS)
2636 MSI_IterateRecords( view, &progress, NULL, package );
2637 msiobj_release( &view->hdr );
2638 total += progress * REG_PROGRESS_VALUE;
2641 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2642 total += COMPONENT_PROGRESS_VALUE;
2644 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2645 total += file->FileSize;
2647 ui_progress(package,0,total,0,0);
2649 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2651 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2652 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2653 feature->ActionRequest);
2656 return ERROR_SUCCESS;
2659 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2661 MSIPACKAGE* package = param;
2662 LPCWSTR cond = NULL;
2663 LPCWSTR message = NULL;
2664 UINT r;
2666 static const WCHAR title[]=
2667 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2669 cond = MSI_RecordGetString(row,1);
2671 r = MSI_EvaluateConditionW(package,cond);
2672 if (r == MSICONDITION_FALSE)
2674 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2676 LPWSTR deformated;
2677 message = MSI_RecordGetString(row,2);
2678 deformat_string(package,message,&deformated);
2679 MessageBoxW(NULL,deformated,title,MB_OK);
2680 msi_free(deformated);
2683 return ERROR_INSTALL_FAILURE;
2686 return ERROR_SUCCESS;
2689 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2691 UINT rc;
2692 MSIQUERY * view = NULL;
2693 static const WCHAR ExecSeqQuery[] =
2694 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2695 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2697 TRACE("Checking launch conditions\n");
2699 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2700 if (rc != ERROR_SUCCESS)
2701 return ERROR_SUCCESS;
2703 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2704 msiobj_release(&view->hdr);
2706 return rc;
2709 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2712 if (!cmp->KeyPath)
2713 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2715 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2717 MSIRECORD * row = 0;
2718 UINT root,len;
2719 LPWSTR deformated,buffer,deformated_name;
2720 LPCWSTR key,name;
2721 static const WCHAR ExecSeqQuery[] =
2722 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2723 '`','R','e','g','i','s','t','r','y','`',' ',
2724 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2725 ' ','=',' ' ,'\'','%','s','\'',0 };
2726 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2727 static const WCHAR fmt2[]=
2728 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2730 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2731 if (!row)
2732 return NULL;
2734 root = MSI_RecordGetInteger(row,2);
2735 key = MSI_RecordGetString(row, 3);
2736 name = MSI_RecordGetString(row, 4);
2737 deformat_string(package, key , &deformated);
2738 deformat_string(package, name, &deformated_name);
2740 len = strlenW(deformated) + 6;
2741 if (deformated_name)
2742 len+=strlenW(deformated_name);
2744 buffer = msi_alloc( len *sizeof(WCHAR));
2746 if (deformated_name)
2747 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2748 else
2749 sprintfW(buffer,fmt,root,deformated);
2751 msi_free(deformated);
2752 msi_free(deformated_name);
2753 msiobj_release(&row->hdr);
2755 return buffer;
2757 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2759 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2760 return NULL;
2762 else
2764 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2766 if (file)
2767 return strdupW( file->TargetPath );
2769 return NULL;
2772 static HKEY openSharedDLLsKey(void)
2774 HKEY hkey=0;
2775 static const WCHAR path[] =
2776 {'S','o','f','t','w','a','r','e','\\',
2777 'M','i','c','r','o','s','o','f','t','\\',
2778 'W','i','n','d','o','w','s','\\',
2779 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2780 'S','h','a','r','e','d','D','L','L','s',0};
2782 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2783 return hkey;
2786 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2788 HKEY hkey;
2789 DWORD count=0;
2790 DWORD type;
2791 DWORD sz = sizeof(count);
2792 DWORD rc;
2794 hkey = openSharedDLLsKey();
2795 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2796 if (rc != ERROR_SUCCESS)
2797 count = 0;
2798 RegCloseKey(hkey);
2799 return count;
2802 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2804 HKEY hkey;
2806 hkey = openSharedDLLsKey();
2807 if (count > 0)
2808 msi_reg_set_val_dword( hkey, path, count );
2809 else
2810 RegDeleteValueW(hkey,path);
2811 RegCloseKey(hkey);
2812 return count;
2816 * Return TRUE if the count should be written out and FALSE if not
2818 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2820 MSIFEATURE *feature;
2821 INT count = 0;
2822 BOOL write = FALSE;
2824 /* only refcount DLLs */
2825 if (comp->KeyPath == NULL ||
2826 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2827 comp->Attributes & msidbComponentAttributesODBCDataSource)
2828 write = FALSE;
2829 else
2831 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2832 write = (count > 0);
2834 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2835 write = TRUE;
2838 /* increment counts */
2839 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2841 ComponentList *cl;
2843 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2844 continue;
2846 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2848 if ( cl->component == comp )
2849 count++;
2853 /* decrement counts */
2854 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2856 ComponentList *cl;
2858 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2859 continue;
2861 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2863 if ( cl->component == comp )
2864 count--;
2868 /* ref count all the files in the component */
2869 if (write)
2871 MSIFILE *file;
2873 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2875 if (file->Component == comp)
2876 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2880 /* add a count for permanent */
2881 if (comp->Attributes & msidbComponentAttributesPermanent)
2882 count ++;
2884 comp->RefCount = count;
2886 if (write)
2887 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2890 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2892 WCHAR squished_pc[GUID_SIZE];
2893 WCHAR squished_cc[GUID_SIZE];
2894 UINT rc;
2895 MSICOMPONENT *comp;
2896 HKEY hkey;
2898 TRACE("\n");
2900 squash_guid(package->ProductCode,squished_pc);
2901 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2903 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2905 MSIRECORD * uirow;
2907 ui_progress(package,2,0,0,0);
2908 if (!comp->ComponentId)
2909 continue;
2911 squash_guid(comp->ComponentId,squished_cc);
2913 msi_free(comp->FullKeypath);
2914 comp->FullKeypath = resolve_keypath( package, comp );
2916 ACTION_RefCountComponent( package, comp );
2918 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2919 debugstr_w(comp->Component),
2920 debugstr_w(squished_cc),
2921 debugstr_w(comp->FullKeypath),
2922 comp->RefCount);
2924 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2925 comp->ActionRequest == INSTALLSTATE_SOURCE)
2927 if (!comp->FullKeypath)
2928 continue;
2930 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2931 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2932 &hkey, TRUE);
2933 else
2934 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2935 &hkey, TRUE);
2937 if (rc != ERROR_SUCCESS)
2938 continue;
2940 if (comp->Attributes & msidbComponentAttributesPermanent)
2942 static const WCHAR szPermKey[] =
2943 { '0','0','0','0','0','0','0','0','0','0','0','0',
2944 '0','0','0','0','0','0','0','0','0','0','0','0',
2945 '0','0','0','0','0','0','0','0',0 };
2947 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2950 if (comp->Action == INSTALLSTATE_LOCAL)
2951 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2952 else
2954 MSIFILE *file;
2955 MSIRECORD *row;
2956 LPWSTR ptr, ptr2;
2957 WCHAR source[MAX_PATH];
2958 WCHAR base[MAX_PATH];
2959 LPWSTR sourcepath;
2961 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2962 static const WCHAR query[] = {
2963 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2964 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2965 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2966 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2967 '`','D','i','s','k','I','d','`',0};
2969 file = get_loaded_file(package, comp->KeyPath);
2970 if (!file)
2971 continue;
2973 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2974 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2975 ptr2 = strrchrW(source, '\\') + 1;
2976 msiobj_release(&row->hdr);
2978 lstrcpyW(base, package->PackagePath);
2979 ptr = strrchrW(base, '\\');
2980 *(ptr + 1) = '\0';
2982 sourcepath = resolve_file_source(package, file);
2983 ptr = sourcepath + lstrlenW(base);
2984 lstrcpyW(ptr2, ptr);
2985 msi_free(sourcepath);
2987 msi_reg_set_val_str(hkey, squished_pc, source);
2989 RegCloseKey(hkey);
2991 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
2993 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2994 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2995 else
2996 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2999 /* UI stuff */
3000 uirow = MSI_CreateRecord(3);
3001 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3002 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3003 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3004 ui_actiondata(package,szProcessComponents,uirow);
3005 msiobj_release( &uirow->hdr );
3008 return ERROR_SUCCESS;
3011 typedef struct {
3012 CLSID clsid;
3013 LPWSTR source;
3015 LPWSTR path;
3016 ITypeLib *ptLib;
3017 } typelib_struct;
3019 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3020 LPWSTR lpszName, LONG_PTR lParam)
3022 TLIBATTR *attr;
3023 typelib_struct *tl_struct = (typelib_struct*) lParam;
3024 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3025 int sz;
3026 HRESULT res;
3028 if (!IS_INTRESOURCE(lpszName))
3030 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3031 return TRUE;
3034 sz = strlenW(tl_struct->source)+4;
3035 sz *= sizeof(WCHAR);
3037 if ((INT_PTR)lpszName == 1)
3038 tl_struct->path = strdupW(tl_struct->source);
3039 else
3041 tl_struct->path = msi_alloc(sz);
3042 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3045 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3046 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3047 if (FAILED(res))
3049 msi_free(tl_struct->path);
3050 tl_struct->path = NULL;
3052 return TRUE;
3055 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3056 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3058 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3059 return FALSE;
3062 msi_free(tl_struct->path);
3063 tl_struct->path = NULL;
3065 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3066 ITypeLib_Release(tl_struct->ptLib);
3068 return TRUE;
3071 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3073 MSIPACKAGE* package = param;
3074 LPCWSTR component;
3075 MSICOMPONENT *comp;
3076 MSIFILE *file;
3077 typelib_struct tl_struct;
3078 ITypeLib *tlib;
3079 HMODULE module;
3080 HRESULT hr;
3082 component = MSI_RecordGetString(row,3);
3083 comp = get_loaded_component(package,component);
3084 if (!comp)
3085 return ERROR_SUCCESS;
3087 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3089 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3090 comp->Action = comp->Installed;
3091 return ERROR_SUCCESS;
3093 comp->Action = INSTALLSTATE_LOCAL;
3095 file = get_loaded_file( package, comp->KeyPath );
3096 if (!file)
3097 return ERROR_SUCCESS;
3099 ui_actiondata( package, szRegisterTypeLibraries, row );
3101 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3102 if (module)
3104 LPCWSTR guid;
3105 guid = MSI_RecordGetString(row,1);
3106 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
3107 tl_struct.source = strdupW( file->TargetPath );
3108 tl_struct.path = NULL;
3110 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3111 (LONG_PTR)&tl_struct);
3113 if (tl_struct.path)
3115 LPWSTR help = NULL;
3116 LPCWSTR helpid;
3117 HRESULT res;
3119 helpid = MSI_RecordGetString(row,6);
3121 if (helpid)
3122 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3123 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3124 msi_free(help);
3126 if (FAILED(res))
3127 ERR("Failed to register type library %s\n",
3128 debugstr_w(tl_struct.path));
3129 else
3130 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3132 ITypeLib_Release(tl_struct.ptLib);
3133 msi_free(tl_struct.path);
3135 else
3136 ERR("Failed to load type library %s\n",
3137 debugstr_w(tl_struct.source));
3139 FreeLibrary(module);
3140 msi_free(tl_struct.source);
3142 else
3144 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3145 if (FAILED(hr))
3147 ERR("Failed to load type library: %08x\n", hr);
3148 return ERROR_INSTALL_FAILURE;
3151 ITypeLib_Release(tlib);
3154 return ERROR_SUCCESS;
3157 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3160 * OK this is a bit confusing.. I am given a _Component key and I believe
3161 * that the file that is being registered as a type library is the "key file
3162 * of that component" which I interpret to mean "The file in the KeyPath of
3163 * that component".
3165 UINT rc;
3166 MSIQUERY * view;
3167 static const WCHAR Query[] =
3168 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3169 '`','T','y','p','e','L','i','b','`',0};
3171 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3172 if (rc != ERROR_SUCCESS)
3173 return ERROR_SUCCESS;
3175 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3176 msiobj_release(&view->hdr);
3177 return rc;
3180 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3182 MSIPACKAGE *package = param;
3183 LPCWSTR component, guid;
3184 MSICOMPONENT *comp;
3185 GUID libid;
3186 UINT version;
3187 LCID language;
3188 SYSKIND syskind;
3189 HRESULT hr;
3191 component = MSI_RecordGetString( row, 3 );
3192 comp = get_loaded_component( package, component );
3193 if (!comp)
3194 return ERROR_SUCCESS;
3196 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3198 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3199 comp->Action = comp->Installed;
3200 return ERROR_SUCCESS;
3202 comp->Action = INSTALLSTATE_ABSENT;
3204 ui_actiondata( package, szUnregisterTypeLibraries, row );
3206 guid = MSI_RecordGetString( row, 1 );
3207 CLSIDFromString( (LPWSTR)guid, &libid );
3208 version = MSI_RecordGetInteger( row, 4 );
3209 language = MSI_RecordGetInteger( row, 2 );
3211 #ifdef _WIN64
3212 syskind = SYS_WIN64;
3213 #else
3214 syskind = SYS_WIN32;
3215 #endif
3217 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3218 if (FAILED(hr))
3220 WARN("Failed to unregister typelib: %08x\n", hr);
3223 return ERROR_SUCCESS;
3226 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3228 UINT rc;
3229 MSIQUERY *view;
3230 static const WCHAR query[] =
3231 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3232 '`','T','y','p','e','L','i','b','`',0};
3234 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3235 if (rc != ERROR_SUCCESS)
3236 return ERROR_SUCCESS;
3238 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3239 msiobj_release( &view->hdr );
3240 return rc;
3243 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3245 static const WCHAR szlnk[] = {'.','l','n','k',0};
3246 LPCWSTR directory, extension;
3247 LPWSTR link_folder, link_file, filename;
3249 directory = MSI_RecordGetString( row, 2 );
3250 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3252 /* may be needed because of a bug somewhere else */
3253 create_full_pathW( link_folder );
3255 filename = msi_dup_record_field( row, 3 );
3256 reduce_to_longfilename( filename );
3258 extension = strchrW( filename, '.' );
3259 if (!extension || strcmpiW( extension, szlnk ))
3261 int len = strlenW( filename );
3262 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3263 memcpy( filename + len, szlnk, sizeof(szlnk) );
3265 link_file = build_directory_name( 2, link_folder, filename );
3266 msi_free( link_folder );
3267 msi_free( filename );
3269 return link_file;
3272 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3274 MSIPACKAGE *package = param;
3275 LPWSTR link_file, deformated, path;
3276 LPCWSTR component, target;
3277 MSICOMPONENT *comp;
3278 IShellLinkW *sl = NULL;
3279 IPersistFile *pf = NULL;
3280 HRESULT res;
3282 component = MSI_RecordGetString(row, 4);
3283 comp = get_loaded_component(package, component);
3284 if (!comp)
3285 return ERROR_SUCCESS;
3287 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3289 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3290 comp->Action = comp->Installed;
3291 return ERROR_SUCCESS;
3293 comp->Action = INSTALLSTATE_LOCAL;
3295 ui_actiondata(package,szCreateShortcuts,row);
3297 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3298 &IID_IShellLinkW, (LPVOID *) &sl );
3300 if (FAILED( res ))
3302 ERR("CLSID_ShellLink not available\n");
3303 goto err;
3306 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3307 if (FAILED( res ))
3309 ERR("QueryInterface(IID_IPersistFile) failed\n");
3310 goto err;
3313 target = MSI_RecordGetString(row, 5);
3314 if (strchrW(target, '['))
3316 deformat_string(package, target, &deformated);
3317 IShellLinkW_SetPath(sl,deformated);
3318 msi_free(deformated);
3320 else
3322 FIXME("poorly handled shortcut format, advertised shortcut\n");
3323 IShellLinkW_SetPath(sl,comp->FullKeypath);
3326 if (!MSI_RecordIsNull(row,6))
3328 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3329 deformat_string(package, arguments, &deformated);
3330 IShellLinkW_SetArguments(sl,deformated);
3331 msi_free(deformated);
3334 if (!MSI_RecordIsNull(row,7))
3336 LPCWSTR description = MSI_RecordGetString(row, 7);
3337 IShellLinkW_SetDescription(sl, description);
3340 if (!MSI_RecordIsNull(row,8))
3341 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3343 if (!MSI_RecordIsNull(row,9))
3345 INT index;
3346 LPCWSTR icon = MSI_RecordGetString(row, 9);
3348 path = build_icon_path(package, icon);
3349 index = MSI_RecordGetInteger(row,10);
3351 /* no value means 0 */
3352 if (index == MSI_NULL_INTEGER)
3353 index = 0;
3355 IShellLinkW_SetIconLocation(sl, path, index);
3356 msi_free(path);
3359 if (!MSI_RecordIsNull(row,11))
3360 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3362 if (!MSI_RecordIsNull(row,12))
3364 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3365 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3366 if (path)
3367 IShellLinkW_SetWorkingDirectory(sl, path);
3368 msi_free(path);
3371 link_file = get_link_file(package, row);
3373 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3374 IPersistFile_Save(pf, link_file, FALSE);
3376 msi_free(link_file);
3378 err:
3379 if (pf)
3380 IPersistFile_Release( pf );
3381 if (sl)
3382 IShellLinkW_Release( sl );
3384 return ERROR_SUCCESS;
3387 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3389 UINT rc;
3390 HRESULT res;
3391 MSIQUERY * view;
3392 static const WCHAR Query[] =
3393 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3394 '`','S','h','o','r','t','c','u','t','`',0};
3396 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3397 if (rc != ERROR_SUCCESS)
3398 return ERROR_SUCCESS;
3400 res = CoInitialize( NULL );
3402 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3403 msiobj_release(&view->hdr);
3405 if (SUCCEEDED(res))
3406 CoUninitialize();
3408 return rc;
3411 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3413 MSIPACKAGE *package = param;
3414 LPWSTR link_file;
3415 LPCWSTR component;
3416 MSICOMPONENT *comp;
3418 component = MSI_RecordGetString( row, 4 );
3419 comp = get_loaded_component( package, component );
3420 if (!comp)
3421 return ERROR_SUCCESS;
3423 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3425 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3426 comp->Action = comp->Installed;
3427 return ERROR_SUCCESS;
3429 comp->Action = INSTALLSTATE_ABSENT;
3431 ui_actiondata( package, szRemoveShortcuts, row );
3433 link_file = get_link_file( package, row );
3435 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3436 if (!DeleteFileW( link_file ))
3438 WARN("Failed to remove shortcut file %u\n", GetLastError());
3440 msi_free( link_file );
3442 return ERROR_SUCCESS;
3445 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3447 UINT rc;
3448 MSIQUERY *view;
3449 static const WCHAR query[] =
3450 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3451 '`','S','h','o','r','t','c','u','t','`',0};
3453 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3454 if (rc != ERROR_SUCCESS)
3455 return ERROR_SUCCESS;
3457 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3458 msiobj_release( &view->hdr );
3460 return rc;
3463 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3465 MSIPACKAGE* package = param;
3466 HANDLE the_file;
3467 LPWSTR FilePath;
3468 LPCWSTR FileName;
3469 CHAR buffer[1024];
3470 DWORD sz;
3471 UINT rc;
3473 FileName = MSI_RecordGetString(row,1);
3474 if (!FileName)
3476 ERR("Unable to get FileName\n");
3477 return ERROR_SUCCESS;
3480 FilePath = build_icon_path(package,FileName);
3482 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3484 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3485 FILE_ATTRIBUTE_NORMAL, NULL);
3487 if (the_file == INVALID_HANDLE_VALUE)
3489 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3490 msi_free(FilePath);
3491 return ERROR_SUCCESS;
3496 DWORD write;
3497 sz = 1024;
3498 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3499 if (rc != ERROR_SUCCESS)
3501 ERR("Failed to get stream\n");
3502 CloseHandle(the_file);
3503 DeleteFileW(FilePath);
3504 break;
3506 WriteFile(the_file,buffer,sz,&write,NULL);
3507 } while (sz == 1024);
3509 msi_free(FilePath);
3510 CloseHandle(the_file);
3512 return ERROR_SUCCESS;
3515 static UINT msi_publish_icons(MSIPACKAGE *package)
3517 UINT r;
3518 MSIQUERY *view;
3520 static const WCHAR query[]= {
3521 'S','E','L','E','C','T',' ','*',' ',
3522 'F','R','O','M',' ','`','I','c','o','n','`',0};
3524 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3525 if (r == ERROR_SUCCESS)
3527 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3528 msiobj_release(&view->hdr);
3531 return ERROR_SUCCESS;
3534 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3536 UINT r;
3537 HKEY source;
3538 LPWSTR buffer;
3539 MSIMEDIADISK *disk;
3540 MSISOURCELISTINFO *info;
3542 r = RegCreateKeyW(hkey, szSourceList, &source);
3543 if (r != ERROR_SUCCESS)
3544 return r;
3546 RegCloseKey(source);
3548 buffer = strrchrW(package->PackagePath, '\\') + 1;
3549 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3550 package->Context, MSICODE_PRODUCT,
3551 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3552 if (r != ERROR_SUCCESS)
3553 return r;
3555 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3556 package->Context, MSICODE_PRODUCT,
3557 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3558 if (r != ERROR_SUCCESS)
3559 return r;
3561 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3562 package->Context, MSICODE_PRODUCT,
3563 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3564 if (r != ERROR_SUCCESS)
3565 return r;
3567 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3569 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3570 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3571 info->options, info->value);
3572 else
3573 MsiSourceListSetInfoW(package->ProductCode, NULL,
3574 info->context, info->options,
3575 info->property, info->value);
3578 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3580 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3581 disk->context, disk->options,
3582 disk->disk_id, disk->volume_label, disk->disk_prompt);
3585 return ERROR_SUCCESS;
3588 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3590 MSIHANDLE hdb, suminfo;
3591 WCHAR guids[MAX_PATH];
3592 WCHAR packcode[SQUISH_GUID_SIZE];
3593 LPWSTR buffer;
3594 LPWSTR ptr;
3595 DWORD langid;
3596 DWORD size;
3597 UINT r;
3599 static const WCHAR szProductLanguage[] =
3600 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3601 static const WCHAR szARPProductIcon[] =
3602 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3603 static const WCHAR szProductVersion[] =
3604 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3605 static const WCHAR szAssignment[] =
3606 {'A','s','s','i','g','n','m','e','n','t',0};
3607 static const WCHAR szAdvertiseFlags[] =
3608 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3609 static const WCHAR szClients[] =
3610 {'C','l','i','e','n','t','s',0};
3611 static const WCHAR szColon[] = {':',0};
3613 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3614 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3615 msi_free(buffer);
3617 langid = msi_get_property_int(package, szProductLanguage, 0);
3618 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3620 /* FIXME */
3621 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3623 buffer = msi_dup_property(package, szARPProductIcon);
3624 if (buffer)
3626 LPWSTR path = build_icon_path(package,buffer);
3627 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3628 msi_free(path);
3629 msi_free(buffer);
3632 buffer = msi_dup_property(package, szProductVersion);
3633 if (buffer)
3635 DWORD verdword = msi_version_str_to_dword(buffer);
3636 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3637 msi_free(buffer);
3640 msi_reg_set_val_dword(hkey, szAssignment, 0);
3641 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3642 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3643 msi_reg_set_val_str(hkey, szClients, szColon);
3645 hdb = alloc_msihandle(&package->db->hdr);
3646 if (!hdb)
3647 return ERROR_NOT_ENOUGH_MEMORY;
3649 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3650 MsiCloseHandle(hdb);
3651 if (r != ERROR_SUCCESS)
3652 goto done;
3654 size = MAX_PATH;
3655 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3656 NULL, guids, &size);
3657 if (r != ERROR_SUCCESS)
3658 goto done;
3660 ptr = strchrW(guids, ';');
3661 if (ptr) *ptr = 0;
3662 squash_guid(guids, packcode);
3663 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3665 done:
3666 MsiCloseHandle(suminfo);
3667 return ERROR_SUCCESS;
3670 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3672 UINT r;
3673 HKEY hkey;
3674 LPWSTR upgrade;
3675 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3677 static const WCHAR szUpgradeCode[] =
3678 {'U','p','g','r','a','d','e','C','o','d','e',0};
3680 upgrade = msi_dup_property(package, szUpgradeCode);
3681 if (!upgrade)
3682 return ERROR_SUCCESS;
3684 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3686 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3687 if (r != ERROR_SUCCESS)
3688 goto done;
3690 else
3692 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3693 if (r != ERROR_SUCCESS)
3694 goto done;
3697 squash_guid(package->ProductCode, squashed_pc);
3698 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3700 RegCloseKey(hkey);
3702 done:
3703 msi_free(upgrade);
3704 return r;
3707 static BOOL msi_check_publish(MSIPACKAGE *package)
3709 MSIFEATURE *feature;
3711 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3713 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3714 return TRUE;
3717 return FALSE;
3720 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3722 MSIFEATURE *feature;
3724 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3726 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3727 return FALSE;
3730 return TRUE;
3733 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3735 WCHAR patch_squashed[GUID_SIZE];
3736 HKEY patches;
3737 LONG res;
3738 UINT r = ERROR_FUNCTION_FAILED;
3740 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3741 &patches, NULL);
3742 if (res != ERROR_SUCCESS)
3743 return ERROR_FUNCTION_FAILED;
3745 squash_guid(package->patch->patchcode, patch_squashed);
3747 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3748 (const BYTE *)patch_squashed,
3749 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3750 if (res != ERROR_SUCCESS)
3751 goto done;
3753 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3754 (const BYTE *)package->patch->transforms,
3755 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3756 if (res == ERROR_SUCCESS)
3757 r = ERROR_SUCCESS;
3759 done:
3760 RegCloseKey(patches);
3761 return r;
3765 * 99% of the work done here is only done for
3766 * advertised installs. However this is where the
3767 * Icon table is processed and written out
3768 * so that is what I am going to do here.
3770 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3772 UINT rc;
3773 HKEY hukey = NULL, hudkey = NULL;
3774 MSIRECORD *uirow;
3776 /* FIXME: also need to publish if the product is in advertise mode */
3777 if (!msi_check_publish(package))
3778 return ERROR_SUCCESS;
3780 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3781 &hukey, TRUE);
3782 if (rc != ERROR_SUCCESS)
3783 goto end;
3785 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3786 NULL, &hudkey, TRUE);
3787 if (rc != ERROR_SUCCESS)
3788 goto end;
3790 rc = msi_publish_upgrade_code(package);
3791 if (rc != ERROR_SUCCESS)
3792 goto end;
3794 if (package->patch)
3796 rc = msi_publish_patch(package, hukey, hudkey);
3797 if (rc != ERROR_SUCCESS)
3798 goto end;
3801 rc = msi_publish_product_properties(package, hukey);
3802 if (rc != ERROR_SUCCESS)
3803 goto end;
3805 rc = msi_publish_sourcelist(package, hukey);
3806 if (rc != ERROR_SUCCESS)
3807 goto end;
3809 rc = msi_publish_icons(package);
3811 end:
3812 uirow = MSI_CreateRecord( 1 );
3813 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3814 ui_actiondata( package, szPublishProduct, uirow );
3815 msiobj_release( &uirow->hdr );
3817 RegCloseKey(hukey);
3818 RegCloseKey(hudkey);
3820 return rc;
3823 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3825 WCHAR *filename, *ptr, *folder, *ret;
3826 const WCHAR *dirprop;
3828 filename = msi_dup_record_field( row, 2 );
3829 if (filename && (ptr = strchrW( filename, '|' )))
3830 ptr++;
3831 else
3832 ptr = filename;
3834 dirprop = MSI_RecordGetString( row, 3 );
3835 if (dirprop)
3837 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3838 if (!folder)
3839 folder = msi_dup_property( package, dirprop );
3841 else
3842 folder = msi_dup_property( package, szWindowsFolder );
3844 if (!folder)
3846 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3847 msi_free( filename );
3848 return NULL;
3851 ret = build_directory_name( 2, folder, ptr );
3853 msi_free( filename );
3854 msi_free( folder );
3855 return ret;
3858 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3860 MSIPACKAGE *package = param;
3861 LPCWSTR component, section, key, value, identifier;
3862 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
3863 MSIRECORD * uirow;
3864 INT action;
3865 MSICOMPONENT *comp;
3867 component = MSI_RecordGetString(row, 8);
3868 comp = get_loaded_component(package,component);
3869 if (!comp)
3870 return ERROR_SUCCESS;
3872 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3874 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3875 comp->Action = comp->Installed;
3876 return ERROR_SUCCESS;
3878 comp->Action = INSTALLSTATE_LOCAL;
3880 identifier = MSI_RecordGetString(row,1);
3881 section = MSI_RecordGetString(row,4);
3882 key = MSI_RecordGetString(row,5);
3883 value = MSI_RecordGetString(row,6);
3884 action = MSI_RecordGetInteger(row,7);
3886 deformat_string(package,section,&deformated_section);
3887 deformat_string(package,key,&deformated_key);
3888 deformat_string(package,value,&deformated_value);
3890 fullname = get_ini_file_name(package, row);
3892 if (action == 0)
3894 TRACE("Adding value %s to section %s in %s\n",
3895 debugstr_w(deformated_key), debugstr_w(deformated_section),
3896 debugstr_w(fullname));
3897 WritePrivateProfileStringW(deformated_section, deformated_key,
3898 deformated_value, fullname);
3900 else if (action == 1)
3902 WCHAR returned[10];
3903 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3904 returned, 10, fullname);
3905 if (returned[0] == 0)
3907 TRACE("Adding value %s to section %s in %s\n",
3908 debugstr_w(deformated_key), debugstr_w(deformated_section),
3909 debugstr_w(fullname));
3911 WritePrivateProfileStringW(deformated_section, deformated_key,
3912 deformated_value, fullname);
3915 else if (action == 3)
3916 FIXME("Append to existing section not yet implemented\n");
3918 uirow = MSI_CreateRecord(4);
3919 MSI_RecordSetStringW(uirow,1,identifier);
3920 MSI_RecordSetStringW(uirow,2,deformated_section);
3921 MSI_RecordSetStringW(uirow,3,deformated_key);
3922 MSI_RecordSetStringW(uirow,4,deformated_value);
3923 ui_actiondata(package,szWriteIniValues,uirow);
3924 msiobj_release( &uirow->hdr );
3926 msi_free(fullname);
3927 msi_free(deformated_key);
3928 msi_free(deformated_value);
3929 msi_free(deformated_section);
3930 return ERROR_SUCCESS;
3933 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3935 UINT rc;
3936 MSIQUERY * view;
3937 static const WCHAR ExecSeqQuery[] =
3938 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3939 '`','I','n','i','F','i','l','e','`',0};
3941 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3942 if (rc != ERROR_SUCCESS)
3944 TRACE("no IniFile table\n");
3945 return ERROR_SUCCESS;
3948 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3949 msiobj_release(&view->hdr);
3950 return rc;
3953 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
3955 MSIPACKAGE *package = param;
3956 LPCWSTR component, section, key, value, identifier;
3957 LPWSTR deformated_section, deformated_key, deformated_value, filename;
3958 MSICOMPONENT *comp;
3959 MSIRECORD *uirow;
3960 INT action;
3962 component = MSI_RecordGetString( row, 8 );
3963 comp = get_loaded_component( package, component );
3964 if (!comp)
3965 return ERROR_SUCCESS;
3967 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3969 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3970 comp->Action = comp->Installed;
3971 return ERROR_SUCCESS;
3973 comp->Action = INSTALLSTATE_ABSENT;
3975 identifier = MSI_RecordGetString( row, 1 );
3976 section = MSI_RecordGetString( row, 4 );
3977 key = MSI_RecordGetString( row, 5 );
3978 value = MSI_RecordGetString( row, 6 );
3979 action = MSI_RecordGetInteger( row, 7 );
3981 deformat_string( package, section, &deformated_section );
3982 deformat_string( package, key, &deformated_key );
3983 deformat_string( package, value, &deformated_value );
3985 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
3987 filename = get_ini_file_name( package, row );
3989 TRACE("Removing key %s from section %s in %s\n",
3990 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
3992 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
3994 WARN("Unable to remove key %u\n", GetLastError());
3996 msi_free( filename );
3998 else
3999 FIXME("Unsupported action %d\n", action);
4002 uirow = MSI_CreateRecord( 4 );
4003 MSI_RecordSetStringW( uirow, 1, identifier );
4004 MSI_RecordSetStringW( uirow, 2, deformated_section );
4005 MSI_RecordSetStringW( uirow, 3, deformated_key );
4006 MSI_RecordSetStringW( uirow, 4, deformated_value );
4007 ui_actiondata( package, szRemoveIniValues, uirow );
4008 msiobj_release( &uirow->hdr );
4010 msi_free( deformated_key );
4011 msi_free( deformated_value );
4012 msi_free( deformated_section );
4013 return ERROR_SUCCESS;
4016 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4018 MSIPACKAGE *package = param;
4019 LPCWSTR component, section, key, value, identifier;
4020 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4021 MSICOMPONENT *comp;
4022 MSIRECORD *uirow;
4023 INT action;
4025 component = MSI_RecordGetString( row, 8 );
4026 comp = get_loaded_component( package, component );
4027 if (!comp)
4028 return ERROR_SUCCESS;
4030 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4032 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4033 comp->Action = comp->Installed;
4034 return ERROR_SUCCESS;
4036 comp->Action = INSTALLSTATE_LOCAL;
4038 identifier = MSI_RecordGetString( row, 1 );
4039 section = MSI_RecordGetString( row, 4 );
4040 key = MSI_RecordGetString( row, 5 );
4041 value = MSI_RecordGetString( row, 6 );
4042 action = MSI_RecordGetInteger( row, 7 );
4044 deformat_string( package, section, &deformated_section );
4045 deformat_string( package, key, &deformated_key );
4046 deformat_string( package, value, &deformated_value );
4048 if (action == msidbIniFileActionRemoveLine)
4050 filename = get_ini_file_name( package, row );
4052 TRACE("Removing key %s from section %s in %s\n",
4053 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4055 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4057 WARN("Unable to remove key %u\n", GetLastError());
4059 msi_free( filename );
4061 else
4062 FIXME("Unsupported action %d\n", action);
4064 uirow = MSI_CreateRecord( 4 );
4065 MSI_RecordSetStringW( uirow, 1, identifier );
4066 MSI_RecordSetStringW( uirow, 2, deformated_section );
4067 MSI_RecordSetStringW( uirow, 3, deformated_key );
4068 MSI_RecordSetStringW( uirow, 4, deformated_value );
4069 ui_actiondata( package, szRemoveIniValues, uirow );
4070 msiobj_release( &uirow->hdr );
4072 msi_free( deformated_key );
4073 msi_free( deformated_value );
4074 msi_free( deformated_section );
4075 return ERROR_SUCCESS;
4078 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4080 UINT rc;
4081 MSIQUERY *view;
4082 static const WCHAR query[] =
4083 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4084 '`','I','n','i','F','i','l','e','`',0};
4085 static const WCHAR remove_query[] =
4086 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4087 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4089 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4090 if (rc == ERROR_SUCCESS)
4092 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4093 msiobj_release( &view->hdr );
4094 if (rc != ERROR_SUCCESS)
4095 return rc;
4098 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4099 if (rc == ERROR_SUCCESS)
4101 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4102 msiobj_release( &view->hdr );
4103 if (rc != ERROR_SUCCESS)
4104 return rc;
4107 return ERROR_SUCCESS;
4110 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4112 MSIPACKAGE *package = param;
4113 LPCWSTR filename;
4114 LPWSTR FullName;
4115 MSIFILE *file;
4116 DWORD len;
4117 static const WCHAR ExeStr[] =
4118 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4119 static const WCHAR close[] = {'\"',0};
4120 STARTUPINFOW si;
4121 PROCESS_INFORMATION info;
4122 BOOL brc;
4123 MSIRECORD *uirow;
4124 LPWSTR uipath, p;
4126 memset(&si,0,sizeof(STARTUPINFOW));
4128 filename = MSI_RecordGetString(row,1);
4129 file = get_loaded_file( package, filename );
4131 if (!file)
4133 ERR("Unable to find file id %s\n",debugstr_w(filename));
4134 return ERROR_SUCCESS;
4137 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4139 FullName = msi_alloc(len*sizeof(WCHAR));
4140 strcpyW(FullName,ExeStr);
4141 strcatW( FullName, file->TargetPath );
4142 strcatW(FullName,close);
4144 TRACE("Registering %s\n",debugstr_w(FullName));
4145 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4146 &si, &info);
4148 if (brc)
4150 CloseHandle(info.hThread);
4151 msi_dialog_check_messages(info.hProcess);
4152 CloseHandle(info.hProcess);
4155 uirow = MSI_CreateRecord( 2 );
4156 MSI_RecordSetStringW( uirow, 1, filename );
4157 uipath = strdupW( file->TargetPath );
4158 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4159 MSI_RecordSetStringW( uirow, 2, uipath );
4160 ui_actiondata( package, szSelfRegModules, uirow );
4161 msiobj_release( &uirow->hdr );
4163 msi_free( FullName );
4164 msi_free( uipath );
4165 return ERROR_SUCCESS;
4168 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4170 UINT rc;
4171 MSIQUERY * view;
4172 static const WCHAR ExecSeqQuery[] =
4173 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4174 '`','S','e','l','f','R','e','g','`',0};
4176 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4177 if (rc != ERROR_SUCCESS)
4179 TRACE("no SelfReg table\n");
4180 return ERROR_SUCCESS;
4183 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4184 msiobj_release(&view->hdr);
4186 return ERROR_SUCCESS;
4189 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4191 static const WCHAR regsvr32[] =
4192 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4193 static const WCHAR close[] = {'\"',0};
4194 MSIPACKAGE *package = param;
4195 LPCWSTR filename;
4196 LPWSTR cmdline;
4197 MSIFILE *file;
4198 DWORD len;
4199 STARTUPINFOW si;
4200 PROCESS_INFORMATION pi;
4201 BOOL ret;
4202 MSIRECORD *uirow;
4203 LPWSTR uipath, p;
4205 memset( &si, 0, sizeof(STARTUPINFOW) );
4207 filename = MSI_RecordGetString( row, 1 );
4208 file = get_loaded_file( package, filename );
4210 if (!file)
4212 ERR("Unable to find file id %s\n", debugstr_w(filename));
4213 return ERROR_SUCCESS;
4216 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4218 cmdline = msi_alloc( len * sizeof(WCHAR) );
4219 strcpyW( cmdline, regsvr32 );
4220 strcatW( cmdline, file->TargetPath );
4221 strcatW( cmdline, close );
4223 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4225 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4226 if (ret)
4228 CloseHandle( pi.hThread );
4229 msi_dialog_check_messages( pi.hProcess );
4230 CloseHandle( pi.hProcess );
4233 uirow = MSI_CreateRecord( 2 );
4234 MSI_RecordSetStringW( uirow, 1, filename );
4235 uipath = strdupW( file->TargetPath );
4236 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4237 MSI_RecordSetStringW( uirow, 2, uipath );
4238 ui_actiondata( package, szSelfUnregModules, uirow );
4239 msiobj_release( &uirow->hdr );
4241 msi_free( cmdline );
4242 msi_free( uipath );
4243 return ERROR_SUCCESS;
4246 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4248 UINT rc;
4249 MSIQUERY *view;
4250 static const WCHAR query[] =
4251 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4252 '`','S','e','l','f','R','e','g','`',0};
4254 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4255 if (rc != ERROR_SUCCESS)
4257 TRACE("no SelfReg table\n");
4258 return ERROR_SUCCESS;
4261 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4262 msiobj_release( &view->hdr );
4264 return ERROR_SUCCESS;
4267 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4269 MSIFEATURE *feature;
4270 UINT rc;
4271 HKEY hkey = NULL, userdata = NULL;
4273 if (!msi_check_publish(package))
4274 return ERROR_SUCCESS;
4276 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4277 &hkey, TRUE);
4278 if (rc != ERROR_SUCCESS)
4279 goto end;
4281 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4282 &userdata, TRUE);
4283 if (rc != ERROR_SUCCESS)
4284 goto end;
4286 /* here the guids are base 85 encoded */
4287 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4289 ComponentList *cl;
4290 LPWSTR data = NULL;
4291 GUID clsid;
4292 INT size;
4293 BOOL absent = FALSE;
4294 MSIRECORD *uirow;
4296 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4297 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4298 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4300 size = 1;
4301 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4303 size += 21;
4305 if (feature->Feature_Parent)
4306 size += strlenW( feature->Feature_Parent )+2;
4308 data = msi_alloc(size * sizeof(WCHAR));
4310 data[0] = 0;
4311 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4313 MSICOMPONENT* component = cl->component;
4314 WCHAR buf[21];
4316 buf[0] = 0;
4317 if (component->ComponentId)
4319 TRACE("From %s\n",debugstr_w(component->ComponentId));
4320 CLSIDFromString(component->ComponentId, &clsid);
4321 encode_base85_guid(&clsid,buf);
4322 TRACE("to %s\n",debugstr_w(buf));
4323 strcatW(data,buf);
4327 if (feature->Feature_Parent)
4329 static const WCHAR sep[] = {'\2',0};
4330 strcatW(data,sep);
4331 strcatW(data,feature->Feature_Parent);
4334 msi_reg_set_val_str( userdata, feature->Feature, data );
4335 msi_free(data);
4337 size = 0;
4338 if (feature->Feature_Parent)
4339 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4340 if (!absent)
4342 size += sizeof(WCHAR);
4343 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4344 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4346 else
4348 size += 2*sizeof(WCHAR);
4349 data = msi_alloc(size);
4350 data[0] = 0x6;
4351 data[1] = 0;
4352 if (feature->Feature_Parent)
4353 strcpyW( &data[1], feature->Feature_Parent );
4354 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4355 (LPBYTE)data,size);
4356 msi_free(data);
4359 /* the UI chunk */
4360 uirow = MSI_CreateRecord( 1 );
4361 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4362 ui_actiondata( package, szPublishFeatures, uirow);
4363 msiobj_release( &uirow->hdr );
4364 /* FIXME: call ui_progress? */
4367 end:
4368 RegCloseKey(hkey);
4369 RegCloseKey(userdata);
4370 return rc;
4373 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4375 UINT r;
4376 HKEY hkey;
4378 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4380 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4381 &hkey, FALSE);
4382 if (r == ERROR_SUCCESS)
4384 RegDeleteValueW(hkey, feature->Feature);
4385 RegCloseKey(hkey);
4388 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4389 &hkey, FALSE);
4390 if (r == ERROR_SUCCESS)
4392 RegDeleteValueW(hkey, feature->Feature);
4393 RegCloseKey(hkey);
4396 return ERROR_SUCCESS;
4399 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4401 MSIFEATURE *feature;
4403 if (!msi_check_unpublish(package))
4404 return ERROR_SUCCESS;
4406 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4408 msi_unpublish_feature(package, feature);
4411 return ERROR_SUCCESS;
4414 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4416 LPWSTR prop, val, key;
4417 SYSTEMTIME systime;
4418 DWORD size, langid;
4419 WCHAR date[9];
4420 LPWSTR buffer;
4422 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4423 static const WCHAR szWindowsInstaller[] =
4424 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4425 static const WCHAR modpath_fmt[] =
4426 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4427 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4428 static const WCHAR szModifyPath[] =
4429 {'M','o','d','i','f','y','P','a','t','h',0};
4430 static const WCHAR szUninstallString[] =
4431 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4432 static const WCHAR szEstimatedSize[] =
4433 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4434 static const WCHAR szProductLanguage[] =
4435 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4436 static const WCHAR szProductVersion[] =
4437 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4438 static const WCHAR szProductName[] =
4439 {'P','r','o','d','u','c','t','N','a','m','e',0};
4440 static const WCHAR szDisplayName[] =
4441 {'D','i','s','p','l','a','y','N','a','m','e',0};
4442 static const WCHAR szDisplayVersion[] =
4443 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4444 static const WCHAR szManufacturer[] =
4445 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4447 static const LPCSTR propval[] = {
4448 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4449 "ARPCONTACT", "Contact",
4450 "ARPCOMMENTS", "Comments",
4451 "ProductName", "DisplayName",
4452 "ProductVersion", "DisplayVersion",
4453 "ARPHELPLINK", "HelpLink",
4454 "ARPHELPTELEPHONE", "HelpTelephone",
4455 "ARPINSTALLLOCATION", "InstallLocation",
4456 "SourceDir", "InstallSource",
4457 "Manufacturer", "Publisher",
4458 "ARPREADME", "Readme",
4459 "ARPSIZE", "Size",
4460 "ARPURLINFOABOUT", "URLInfoAbout",
4461 "ARPURLUPDATEINFO", "URLUpdateInfo",
4462 NULL,
4464 const LPCSTR *p = propval;
4466 while (*p)
4468 prop = strdupAtoW(*p++);
4469 key = strdupAtoW(*p++);
4470 val = msi_dup_property(package, prop);
4471 msi_reg_set_val_str(hkey, key, val);
4472 msi_free(val);
4473 msi_free(key);
4474 msi_free(prop);
4477 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4479 size = deformat_string(package, modpath_fmt, &buffer);
4480 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4481 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4482 msi_free(buffer);
4484 /* FIXME: Write real Estimated Size when we have it */
4485 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4487 buffer = msi_dup_property(package, szProductName);
4488 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4489 msi_free(buffer);
4491 buffer = msi_dup_property(package, cszSourceDir);
4492 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4493 msi_free(buffer);
4495 buffer = msi_dup_property(package, szManufacturer);
4496 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4497 msi_free(buffer);
4499 GetLocalTime(&systime);
4500 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4501 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4503 langid = msi_get_property_int(package, szProductLanguage, 0);
4504 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4506 buffer = msi_dup_property(package, szProductVersion);
4507 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4508 if (buffer)
4510 DWORD verdword = msi_version_str_to_dword(buffer);
4512 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4513 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4514 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4515 msi_free(buffer);
4518 return ERROR_SUCCESS;
4521 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4523 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4524 MSIRECORD *uirow;
4525 LPWSTR upgrade_code;
4526 HKEY hkey, props;
4527 HKEY upgrade;
4528 UINT rc;
4530 static const WCHAR szUpgradeCode[] = {
4531 'U','p','g','r','a','d','e','C','o','d','e',0};
4533 /* FIXME: also need to publish if the product is in advertise mode */
4534 if (!msi_check_publish(package))
4535 return ERROR_SUCCESS;
4537 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4538 if (rc != ERROR_SUCCESS)
4539 return rc;
4541 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4542 NULL, &props, TRUE);
4543 if (rc != ERROR_SUCCESS)
4544 goto done;
4546 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4547 msi_free( package->db->localfile );
4548 package->db->localfile = NULL;
4550 rc = msi_publish_install_properties(package, hkey);
4551 if (rc != ERROR_SUCCESS)
4552 goto done;
4554 rc = msi_publish_install_properties(package, props);
4555 if (rc != ERROR_SUCCESS)
4556 goto done;
4558 upgrade_code = msi_dup_property(package, szUpgradeCode);
4559 if (upgrade_code)
4561 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4562 squash_guid(package->ProductCode, squashed_pc);
4563 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4564 RegCloseKey(upgrade);
4565 msi_free(upgrade_code);
4568 done:
4569 uirow = MSI_CreateRecord( 1 );
4570 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4571 ui_actiondata( package, szRegisterProduct, uirow );
4572 msiobj_release( &uirow->hdr );
4574 RegCloseKey(hkey);
4575 return ERROR_SUCCESS;
4578 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4580 return execute_script(package,INSTALL_SCRIPT);
4583 static UINT msi_unpublish_product(MSIPACKAGE *package)
4585 LPWSTR upgrade;
4586 LPWSTR remove = NULL;
4587 LPWSTR *features = NULL;
4588 BOOL full_uninstall = TRUE;
4589 MSIFEATURE *feature;
4591 static const WCHAR szUpgradeCode[] =
4592 {'U','p','g','r','a','d','e','C','o','d','e',0};
4594 remove = msi_dup_property(package, szRemove);
4595 if (!remove)
4596 return ERROR_SUCCESS;
4598 features = msi_split_string(remove, ',');
4599 if (!features)
4601 msi_free(remove);
4602 ERR("REMOVE feature list is empty!\n");
4603 return ERROR_FUNCTION_FAILED;
4606 if (!lstrcmpW(features[0], szAll))
4607 full_uninstall = TRUE;
4608 else
4610 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4612 if (feature->Action != INSTALLSTATE_ABSENT)
4613 full_uninstall = FALSE;
4617 if (!full_uninstall)
4618 goto done;
4620 MSIREG_DeleteProductKey(package->ProductCode);
4621 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4622 MSIREG_DeleteUninstallKey(package->ProductCode);
4624 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4626 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4627 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4629 else
4631 MSIREG_DeleteUserProductKey(package->ProductCode);
4632 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4635 upgrade = msi_dup_property(package, szUpgradeCode);
4636 if (upgrade)
4638 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4639 msi_free(upgrade);
4642 done:
4643 msi_free(remove);
4644 msi_free(features);
4645 return ERROR_SUCCESS;
4648 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4650 UINT rc;
4652 rc = msi_unpublish_product(package);
4653 if (rc != ERROR_SUCCESS)
4654 return rc;
4656 /* turn off scheduling */
4657 package->script->CurrentlyScripting= FALSE;
4659 /* first do the same as an InstallExecute */
4660 rc = ACTION_InstallExecute(package);
4661 if (rc != ERROR_SUCCESS)
4662 return rc;
4664 /* then handle Commit Actions */
4665 rc = execute_script(package,COMMIT_SCRIPT);
4667 return rc;
4670 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4672 static const WCHAR RunOnce[] = {
4673 'S','o','f','t','w','a','r','e','\\',
4674 'M','i','c','r','o','s','o','f','t','\\',
4675 'W','i','n','d','o','w','s','\\',
4676 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4677 'R','u','n','O','n','c','e',0};
4678 static const WCHAR InstallRunOnce[] = {
4679 'S','o','f','t','w','a','r','e','\\',
4680 'M','i','c','r','o','s','o','f','t','\\',
4681 'W','i','n','d','o','w','s','\\',
4682 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4683 'I','n','s','t','a','l','l','e','r','\\',
4684 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4686 static const WCHAR msiexec_fmt[] = {
4687 '%','s',
4688 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4689 '\"','%','s','\"',0};
4690 static const WCHAR install_fmt[] = {
4691 '/','I',' ','\"','%','s','\"',' ',
4692 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4693 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4694 WCHAR buffer[256], sysdir[MAX_PATH];
4695 HKEY hkey;
4696 WCHAR squished_pc[100];
4698 squash_guid(package->ProductCode,squished_pc);
4700 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4701 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4702 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4703 squished_pc);
4705 msi_reg_set_val_str( hkey, squished_pc, buffer );
4706 RegCloseKey(hkey);
4708 TRACE("Reboot command %s\n",debugstr_w(buffer));
4710 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4711 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4713 msi_reg_set_val_str( hkey, squished_pc, buffer );
4714 RegCloseKey(hkey);
4716 return ERROR_INSTALL_SUSPEND;
4719 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4721 DWORD attrib;
4722 UINT rc;
4725 * We are currently doing what should be done here in the top level Install
4726 * however for Administrative and uninstalls this step will be needed
4728 if (!package->PackagePath)
4729 return ERROR_SUCCESS;
4731 msi_set_sourcedir_props(package, TRUE);
4733 attrib = GetFileAttributesW(package->db->path);
4734 if (attrib == INVALID_FILE_ATTRIBUTES)
4736 LPWSTR prompt;
4737 LPWSTR msg;
4738 DWORD size = 0;
4740 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4741 package->Context, MSICODE_PRODUCT,
4742 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4743 if (rc == ERROR_MORE_DATA)
4745 prompt = msi_alloc(size * sizeof(WCHAR));
4746 MsiSourceListGetInfoW(package->ProductCode, NULL,
4747 package->Context, MSICODE_PRODUCT,
4748 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4750 else
4751 prompt = strdupW(package->db->path);
4753 msg = generate_error_string(package,1302,1,prompt);
4754 while(attrib == INVALID_FILE_ATTRIBUTES)
4756 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4757 if (rc == IDCANCEL)
4759 rc = ERROR_INSTALL_USEREXIT;
4760 break;
4762 attrib = GetFileAttributesW(package->db->path);
4764 msi_free(prompt);
4765 rc = ERROR_SUCCESS;
4767 else
4768 return ERROR_SUCCESS;
4770 return rc;
4773 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4775 HKEY hkey = 0;
4776 LPWSTR buffer, productid = NULL;
4777 UINT i, rc = ERROR_SUCCESS;
4778 MSIRECORD *uirow;
4780 static const WCHAR szPropKeys[][80] =
4782 {'P','r','o','d','u','c','t','I','D',0},
4783 {'U','S','E','R','N','A','M','E',0},
4784 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4785 {0},
4788 static const WCHAR szRegKeys[][80] =
4790 {'P','r','o','d','u','c','t','I','D',0},
4791 {'R','e','g','O','w','n','e','r',0},
4792 {'R','e','g','C','o','m','p','a','n','y',0},
4793 {0},
4796 if (msi_check_unpublish(package))
4798 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4799 goto end;
4802 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4803 if (!productid)
4804 goto end;
4806 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4807 NULL, &hkey, TRUE);
4808 if (rc != ERROR_SUCCESS)
4809 goto end;
4811 for( i = 0; szPropKeys[i][0]; i++ )
4813 buffer = msi_dup_property( package, szPropKeys[i] );
4814 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4815 msi_free( buffer );
4818 end:
4819 uirow = MSI_CreateRecord( 1 );
4820 MSI_RecordSetStringW( uirow, 1, productid );
4821 ui_actiondata( package, szRegisterUser, uirow );
4822 msiobj_release( &uirow->hdr );
4824 msi_free(productid);
4825 RegCloseKey(hkey);
4826 return rc;
4830 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4832 UINT rc;
4834 package->script->InWhatSequence |= SEQUENCE_EXEC;
4835 rc = ACTION_ProcessExecSequence(package,FALSE);
4836 return rc;
4840 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4842 MSIPACKAGE *package = param;
4843 LPCWSTR compgroupid, component, feature, qualifier, text;
4844 LPWSTR advertise = NULL, output = NULL;
4845 HKEY hkey = NULL;
4846 UINT rc;
4847 MSICOMPONENT *comp;
4848 MSIFEATURE *feat;
4849 DWORD sz;
4850 MSIRECORD *uirow;
4852 feature = MSI_RecordGetString(rec, 5);
4853 feat = get_loaded_feature(package, feature);
4854 if (!feat)
4855 return ERROR_SUCCESS;
4857 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4858 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4859 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
4861 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4862 feat->Action = feat->Installed;
4863 return ERROR_SUCCESS;
4866 component = MSI_RecordGetString(rec, 3);
4867 comp = get_loaded_component(package, component);
4868 if (!comp)
4869 return ERROR_SUCCESS;
4871 compgroupid = MSI_RecordGetString(rec,1);
4872 qualifier = MSI_RecordGetString(rec,2);
4874 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4875 if (rc != ERROR_SUCCESS)
4876 goto end;
4878 text = MSI_RecordGetString(rec,4);
4879 advertise = create_component_advertise_string(package, comp, feature);
4881 sz = strlenW(advertise);
4883 if (text)
4884 sz += lstrlenW(text);
4886 sz+=3;
4887 sz *= sizeof(WCHAR);
4889 output = msi_alloc_zero(sz);
4890 strcpyW(output,advertise);
4891 msi_free(advertise);
4893 if (text)
4894 strcatW(output,text);
4896 msi_reg_set_val_multi_str( hkey, qualifier, output );
4898 end:
4899 RegCloseKey(hkey);
4900 msi_free(output);
4902 /* the UI chunk */
4903 uirow = MSI_CreateRecord( 2 );
4904 MSI_RecordSetStringW( uirow, 1, compgroupid );
4905 MSI_RecordSetStringW( uirow, 2, qualifier);
4906 ui_actiondata( package, szPublishComponents, uirow);
4907 msiobj_release( &uirow->hdr );
4908 /* FIXME: call ui_progress? */
4910 return rc;
4914 * At present I am ignorning the advertised components part of this and only
4915 * focusing on the qualified component sets
4917 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4919 UINT rc;
4920 MSIQUERY * view;
4921 static const WCHAR ExecSeqQuery[] =
4922 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4923 '`','P','u','b','l','i','s','h',
4924 'C','o','m','p','o','n','e','n','t','`',0};
4926 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4927 if (rc != ERROR_SUCCESS)
4928 return ERROR_SUCCESS;
4930 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4931 msiobj_release(&view->hdr);
4933 return rc;
4936 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
4938 static const WCHAR szInstallerComponents[] = {
4939 'S','o','f','t','w','a','r','e','\\',
4940 'M','i','c','r','o','s','o','f','t','\\',
4941 'I','n','s','t','a','l','l','e','r','\\',
4942 'C','o','m','p','o','n','e','n','t','s','\\',0};
4944 MSIPACKAGE *package = param;
4945 LPCWSTR compgroupid, component, feature, qualifier;
4946 MSICOMPONENT *comp;
4947 MSIFEATURE *feat;
4948 MSIRECORD *uirow;
4949 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
4950 LONG res;
4952 feature = MSI_RecordGetString( rec, 5 );
4953 feat = get_loaded_feature( package, feature );
4954 if (!feat)
4955 return ERROR_SUCCESS;
4957 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
4959 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
4960 feat->Action = feat->Installed;
4961 return ERROR_SUCCESS;
4964 component = MSI_RecordGetString( rec, 3 );
4965 comp = get_loaded_component( package, component );
4966 if (!comp)
4967 return ERROR_SUCCESS;
4969 compgroupid = MSI_RecordGetString( rec, 1 );
4970 qualifier = MSI_RecordGetString( rec, 2 );
4972 squash_guid( compgroupid, squashed );
4973 strcpyW( keypath, szInstallerComponents );
4974 strcatW( keypath, squashed );
4976 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
4977 if (res != ERROR_SUCCESS)
4979 WARN("Unable to delete component key %d\n", res);
4982 uirow = MSI_CreateRecord( 2 );
4983 MSI_RecordSetStringW( uirow, 1, compgroupid );
4984 MSI_RecordSetStringW( uirow, 2, qualifier );
4985 ui_actiondata( package, szUnpublishComponents, uirow );
4986 msiobj_release( &uirow->hdr );
4988 return ERROR_SUCCESS;
4991 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
4993 UINT rc;
4994 MSIQUERY *view;
4995 static const WCHAR query[] =
4996 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4997 '`','P','u','b','l','i','s','h',
4998 'C','o','m','p','o','n','e','n','t','`',0};
5000 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5001 if (rc != ERROR_SUCCESS)
5002 return ERROR_SUCCESS;
5004 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5005 msiobj_release( &view->hdr );
5007 return rc;
5010 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5012 MSIPACKAGE *package = param;
5013 MSIRECORD *row;
5014 MSIFILE *file;
5015 SC_HANDLE hscm, service = NULL;
5016 LPCWSTR comp, depends, pass;
5017 LPWSTR name = NULL, disp = NULL;
5018 LPCWSTR load_order, serv_name, key;
5019 DWORD serv_type, start_type;
5020 DWORD err_control;
5022 static const WCHAR query[] =
5023 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5024 '`','C','o','m','p','o','n','e','n','t','`',' ',
5025 'W','H','E','R','E',' ',
5026 '`','C','o','m','p','o','n','e','n','t','`',' ',
5027 '=','\'','%','s','\'',0};
5029 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5030 if (!hscm)
5032 ERR("Failed to open the SC Manager!\n");
5033 goto done;
5036 start_type = MSI_RecordGetInteger(rec, 5);
5037 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5038 goto done;
5040 depends = MSI_RecordGetString(rec, 8);
5041 if (depends && *depends)
5042 FIXME("Dependency list unhandled!\n");
5044 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5045 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5046 serv_type = MSI_RecordGetInteger(rec, 4);
5047 err_control = MSI_RecordGetInteger(rec, 6);
5048 load_order = MSI_RecordGetString(rec, 7);
5049 serv_name = MSI_RecordGetString(rec, 9);
5050 pass = MSI_RecordGetString(rec, 10);
5051 comp = MSI_RecordGetString(rec, 12);
5053 /* fetch the service path */
5054 row = MSI_QueryGetRecord(package->db, query, comp);
5055 if (!row)
5057 ERR("Control query failed!\n");
5058 goto done;
5061 key = MSI_RecordGetString(row, 6);
5063 file = get_loaded_file(package, key);
5064 msiobj_release(&row->hdr);
5065 if (!file)
5067 ERR("Failed to load the service file\n");
5068 goto done;
5071 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5072 start_type, err_control, file->TargetPath,
5073 load_order, NULL, NULL, serv_name, pass);
5074 if (!service)
5076 if (GetLastError() != ERROR_SERVICE_EXISTS)
5077 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5080 done:
5081 CloseServiceHandle(service);
5082 CloseServiceHandle(hscm);
5083 msi_free(name);
5084 msi_free(disp);
5086 return ERROR_SUCCESS;
5089 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5091 UINT rc;
5092 MSIQUERY * view;
5093 static const WCHAR ExecSeqQuery[] =
5094 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5095 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5097 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5098 if (rc != ERROR_SUCCESS)
5099 return ERROR_SUCCESS;
5101 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5102 msiobj_release(&view->hdr);
5104 return rc;
5107 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5108 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5110 LPCWSTR *vector, *temp_vector;
5111 LPWSTR p, q;
5112 DWORD sep_len;
5114 static const WCHAR separator[] = {'[','~',']',0};
5116 *numargs = 0;
5117 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5119 if (!args)
5120 return NULL;
5122 vector = msi_alloc(sizeof(LPWSTR));
5123 if (!vector)
5124 return NULL;
5126 p = args;
5129 (*numargs)++;
5130 vector[*numargs - 1] = p;
5132 if ((q = strstrW(p, separator)))
5134 *q = '\0';
5136 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5137 if (!temp_vector)
5139 msi_free(vector);
5140 return NULL;
5142 vector = temp_vector;
5144 p = q + sep_len;
5146 } while (q);
5148 return vector;
5151 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5153 MSIPACKAGE *package = param;
5154 MSICOMPONENT *comp;
5155 SC_HANDLE scm = NULL, service = NULL;
5156 LPCWSTR component, *vector = NULL;
5157 LPWSTR name, args;
5158 DWORD event, numargs;
5159 UINT r = ERROR_FUNCTION_FAILED;
5161 component = MSI_RecordGetString(rec, 6);
5162 comp = get_loaded_component(package, component);
5163 if (!comp)
5164 return ERROR_SUCCESS;
5166 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5168 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5169 comp->Action = comp->Installed;
5170 return ERROR_SUCCESS;
5172 comp->Action = INSTALLSTATE_LOCAL;
5174 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5175 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5176 event = MSI_RecordGetInteger(rec, 3);
5178 if (!(event & msidbServiceControlEventStart))
5180 r = ERROR_SUCCESS;
5181 goto done;
5184 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5185 if (!scm)
5187 ERR("Failed to open the service control manager\n");
5188 goto done;
5191 service = OpenServiceW(scm, name, SERVICE_START);
5192 if (!service)
5194 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5195 goto done;
5198 vector = msi_service_args_to_vector(args, &numargs);
5200 if (!StartServiceW(service, numargs, vector) &&
5201 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5203 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5204 goto done;
5207 r = ERROR_SUCCESS;
5209 done:
5210 CloseServiceHandle(service);
5211 CloseServiceHandle(scm);
5213 msi_free(name);
5214 msi_free(args);
5215 msi_free(vector);
5216 return r;
5219 static UINT ACTION_StartServices( MSIPACKAGE *package )
5221 UINT rc;
5222 MSIQUERY *view;
5224 static const WCHAR query[] = {
5225 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5226 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5228 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5229 if (rc != ERROR_SUCCESS)
5230 return ERROR_SUCCESS;
5232 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5233 msiobj_release(&view->hdr);
5235 return rc;
5238 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5240 DWORD i, needed, count;
5241 ENUM_SERVICE_STATUSW *dependencies;
5242 SERVICE_STATUS ss;
5243 SC_HANDLE depserv;
5245 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5246 0, &needed, &count))
5247 return TRUE;
5249 if (GetLastError() != ERROR_MORE_DATA)
5250 return FALSE;
5252 dependencies = msi_alloc(needed);
5253 if (!dependencies)
5254 return FALSE;
5256 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5257 needed, &needed, &count))
5258 goto error;
5260 for (i = 0; i < count; i++)
5262 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5263 SERVICE_STOP | SERVICE_QUERY_STATUS);
5264 if (!depserv)
5265 goto error;
5267 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5268 goto error;
5271 return TRUE;
5273 error:
5274 msi_free(dependencies);
5275 return FALSE;
5278 static UINT stop_service( LPCWSTR name )
5280 SC_HANDLE scm = NULL, service = NULL;
5281 SERVICE_STATUS status;
5282 SERVICE_STATUS_PROCESS ssp;
5283 DWORD needed;
5285 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5286 if (!scm)
5288 WARN("Failed to open the SCM: %d\n", GetLastError());
5289 goto done;
5292 service = OpenServiceW(scm, name,
5293 SERVICE_STOP |
5294 SERVICE_QUERY_STATUS |
5295 SERVICE_ENUMERATE_DEPENDENTS);
5296 if (!service)
5298 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5299 goto done;
5302 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5303 sizeof(SERVICE_STATUS_PROCESS), &needed))
5305 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5306 goto done;
5309 if (ssp.dwCurrentState == SERVICE_STOPPED)
5310 goto done;
5312 stop_service_dependents(scm, service);
5314 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5315 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5317 done:
5318 CloseServiceHandle(service);
5319 CloseServiceHandle(scm);
5321 return ERROR_SUCCESS;
5324 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5326 MSIPACKAGE *package = param;
5327 MSICOMPONENT *comp;
5328 LPCWSTR component;
5329 LPWSTR name;
5330 DWORD event;
5332 event = MSI_RecordGetInteger( rec, 3 );
5333 if (!(event & msidbServiceControlEventStop))
5334 return ERROR_SUCCESS;
5336 component = MSI_RecordGetString( rec, 6 );
5337 comp = get_loaded_component( package, component );
5338 if (!comp)
5339 return ERROR_SUCCESS;
5341 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5343 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5344 comp->Action = comp->Installed;
5345 return ERROR_SUCCESS;
5347 comp->Action = INSTALLSTATE_ABSENT;
5349 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5350 stop_service( name );
5351 msi_free( name );
5353 return ERROR_SUCCESS;
5356 static UINT ACTION_StopServices( MSIPACKAGE *package )
5358 UINT rc;
5359 MSIQUERY *view;
5361 static const WCHAR query[] = {
5362 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5363 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5365 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5366 if (rc != ERROR_SUCCESS)
5367 return ERROR_SUCCESS;
5369 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5370 msiobj_release(&view->hdr);
5372 return rc;
5375 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5377 MSIPACKAGE *package = param;
5378 MSICOMPONENT *comp;
5379 MSIRECORD *uirow;
5380 LPCWSTR component;
5381 LPWSTR name = NULL, display_name = NULL;
5382 DWORD event, len;
5383 SC_HANDLE scm = NULL, service = NULL;
5385 event = MSI_RecordGetInteger( rec, 3 );
5386 if (!(event & msidbServiceControlEventDelete))
5387 return ERROR_SUCCESS;
5389 component = MSI_RecordGetString(rec, 6);
5390 comp = get_loaded_component(package, component);
5391 if (!comp)
5392 return ERROR_SUCCESS;
5394 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5396 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5397 comp->Action = comp->Installed;
5398 return ERROR_SUCCESS;
5400 comp->Action = INSTALLSTATE_ABSENT;
5402 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5403 stop_service( name );
5405 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5406 if (!scm)
5408 WARN("Failed to open the SCM: %d\n", GetLastError());
5409 goto done;
5412 len = 0;
5413 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5414 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5416 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5417 GetServiceDisplayNameW( scm, name, display_name, &len );
5420 service = OpenServiceW( scm, name, DELETE );
5421 if (!service)
5423 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5424 goto done;
5427 if (!DeleteService( service ))
5428 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5430 done:
5431 uirow = MSI_CreateRecord( 2 );
5432 MSI_RecordSetStringW( uirow, 1, display_name );
5433 MSI_RecordSetStringW( uirow, 2, name );
5434 ui_actiondata( package, szDeleteServices, uirow );
5435 msiobj_release( &uirow->hdr );
5437 CloseServiceHandle( service );
5438 CloseServiceHandle( scm );
5439 msi_free( name );
5440 msi_free( display_name );
5442 return ERROR_SUCCESS;
5445 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5447 UINT rc;
5448 MSIQUERY *view;
5450 static const WCHAR query[] = {
5451 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5452 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5454 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5455 if (rc != ERROR_SUCCESS)
5456 return ERROR_SUCCESS;
5458 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5459 msiobj_release( &view->hdr );
5461 return rc;
5464 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5466 MSIFILE *file;
5468 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5470 if (!lstrcmpW(file->File, filename))
5471 return file;
5474 return NULL;
5477 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5479 MSIPACKAGE *package = param;
5480 LPWSTR driver, driver_path, ptr;
5481 WCHAR outpath[MAX_PATH];
5482 MSIFILE *driver_file, *setup_file;
5483 MSIRECORD *uirow;
5484 LPCWSTR desc;
5485 DWORD len, usage;
5486 UINT r = ERROR_SUCCESS;
5488 static const WCHAR driver_fmt[] = {
5489 'D','r','i','v','e','r','=','%','s',0};
5490 static const WCHAR setup_fmt[] = {
5491 'S','e','t','u','p','=','%','s',0};
5492 static const WCHAR usage_fmt[] = {
5493 'F','i','l','e','U','s','a','g','e','=','1',0};
5495 desc = MSI_RecordGetString(rec, 3);
5497 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5498 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5500 if (!driver_file)
5502 ERR("ODBC Driver entry not found!\n");
5503 return ERROR_FUNCTION_FAILED;
5506 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5507 if (setup_file)
5508 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5509 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5511 driver = msi_alloc(len * sizeof(WCHAR));
5512 if (!driver)
5513 return ERROR_OUTOFMEMORY;
5515 ptr = driver;
5516 lstrcpyW(ptr, desc);
5517 ptr += lstrlenW(ptr) + 1;
5519 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5520 ptr += len + 1;
5522 if (setup_file)
5524 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5525 ptr += len + 1;
5528 lstrcpyW(ptr, usage_fmt);
5529 ptr += lstrlenW(ptr) + 1;
5530 *ptr = '\0';
5532 driver_path = strdupW(driver_file->TargetPath);
5533 ptr = strrchrW(driver_path, '\\');
5534 if (ptr) *ptr = '\0';
5536 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5537 NULL, ODBC_INSTALL_COMPLETE, &usage))
5539 ERR("Failed to install SQL driver!\n");
5540 r = ERROR_FUNCTION_FAILED;
5543 uirow = MSI_CreateRecord( 5 );
5544 MSI_RecordSetStringW( uirow, 1, desc );
5545 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5546 MSI_RecordSetStringW( uirow, 3, driver_path );
5547 ui_actiondata( package, szInstallODBC, uirow );
5548 msiobj_release( &uirow->hdr );
5550 msi_free(driver);
5551 msi_free(driver_path);
5553 return r;
5556 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5558 MSIPACKAGE *package = param;
5559 LPWSTR translator, translator_path, ptr;
5560 WCHAR outpath[MAX_PATH];
5561 MSIFILE *translator_file, *setup_file;
5562 MSIRECORD *uirow;
5563 LPCWSTR desc;
5564 DWORD len, usage;
5565 UINT r = ERROR_SUCCESS;
5567 static const WCHAR translator_fmt[] = {
5568 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5569 static const WCHAR setup_fmt[] = {
5570 'S','e','t','u','p','=','%','s',0};
5572 desc = MSI_RecordGetString(rec, 3);
5574 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5575 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5577 if (!translator_file)
5579 ERR("ODBC Translator entry not found!\n");
5580 return ERROR_FUNCTION_FAILED;
5583 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5584 if (setup_file)
5585 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5587 translator = msi_alloc(len * sizeof(WCHAR));
5588 if (!translator)
5589 return ERROR_OUTOFMEMORY;
5591 ptr = translator;
5592 lstrcpyW(ptr, desc);
5593 ptr += lstrlenW(ptr) + 1;
5595 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5596 ptr += len + 1;
5598 if (setup_file)
5600 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5601 ptr += len + 1;
5603 *ptr = '\0';
5605 translator_path = strdupW(translator_file->TargetPath);
5606 ptr = strrchrW(translator_path, '\\');
5607 if (ptr) *ptr = '\0';
5609 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5610 NULL, ODBC_INSTALL_COMPLETE, &usage))
5612 ERR("Failed to install SQL translator!\n");
5613 r = ERROR_FUNCTION_FAILED;
5616 uirow = MSI_CreateRecord( 5 );
5617 MSI_RecordSetStringW( uirow, 1, desc );
5618 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5619 MSI_RecordSetStringW( uirow, 3, translator_path );
5620 ui_actiondata( package, szInstallODBC, uirow );
5621 msiobj_release( &uirow->hdr );
5623 msi_free(translator);
5624 msi_free(translator_path);
5626 return r;
5629 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5631 MSIPACKAGE *package = param;
5632 LPWSTR attrs;
5633 LPCWSTR desc, driver;
5634 WORD request = ODBC_ADD_SYS_DSN;
5635 INT registration;
5636 DWORD len;
5637 UINT r = ERROR_SUCCESS;
5638 MSIRECORD *uirow;
5640 static const WCHAR attrs_fmt[] = {
5641 'D','S','N','=','%','s',0 };
5643 desc = MSI_RecordGetString(rec, 3);
5644 driver = MSI_RecordGetString(rec, 4);
5645 registration = MSI_RecordGetInteger(rec, 5);
5647 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5648 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5650 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5651 attrs = msi_alloc(len * sizeof(WCHAR));
5652 if (!attrs)
5653 return ERROR_OUTOFMEMORY;
5655 len = sprintfW(attrs, attrs_fmt, desc);
5656 attrs[len + 1] = 0;
5658 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5660 ERR("Failed to install SQL data source!\n");
5661 r = ERROR_FUNCTION_FAILED;
5664 uirow = MSI_CreateRecord( 5 );
5665 MSI_RecordSetStringW( uirow, 1, desc );
5666 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5667 MSI_RecordSetInteger( uirow, 3, request );
5668 ui_actiondata( package, szInstallODBC, uirow );
5669 msiobj_release( &uirow->hdr );
5671 msi_free(attrs);
5673 return r;
5676 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5678 UINT rc;
5679 MSIQUERY *view;
5681 static const WCHAR driver_query[] = {
5682 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5683 'O','D','B','C','D','r','i','v','e','r',0 };
5685 static const WCHAR translator_query[] = {
5686 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5687 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5689 static const WCHAR source_query[] = {
5690 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5691 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5693 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5694 if (rc != ERROR_SUCCESS)
5695 return ERROR_SUCCESS;
5697 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5698 msiobj_release(&view->hdr);
5700 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5701 if (rc != ERROR_SUCCESS)
5702 return ERROR_SUCCESS;
5704 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5705 msiobj_release(&view->hdr);
5707 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5708 if (rc != ERROR_SUCCESS)
5709 return ERROR_SUCCESS;
5711 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5712 msiobj_release(&view->hdr);
5714 return rc;
5717 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5719 MSIPACKAGE *package = param;
5720 MSIRECORD *uirow;
5721 DWORD usage;
5722 LPCWSTR desc;
5724 desc = MSI_RecordGetString( rec, 3 );
5725 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5727 WARN("Failed to remove ODBC driver\n");
5729 else if (!usage)
5731 FIXME("Usage count reached 0\n");
5734 uirow = MSI_CreateRecord( 2 );
5735 MSI_RecordSetStringW( uirow, 1, desc );
5736 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5737 ui_actiondata( package, szRemoveODBC, uirow );
5738 msiobj_release( &uirow->hdr );
5740 return ERROR_SUCCESS;
5743 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5745 MSIPACKAGE *package = param;
5746 MSIRECORD *uirow;
5747 DWORD usage;
5748 LPCWSTR desc;
5750 desc = MSI_RecordGetString( rec, 3 );
5751 if (!SQLRemoveTranslatorW( desc, &usage ))
5753 WARN("Failed to remove ODBC translator\n");
5755 else if (!usage)
5757 FIXME("Usage count reached 0\n");
5760 uirow = MSI_CreateRecord( 2 );
5761 MSI_RecordSetStringW( uirow, 1, desc );
5762 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5763 ui_actiondata( package, szRemoveODBC, uirow );
5764 msiobj_release( &uirow->hdr );
5766 return ERROR_SUCCESS;
5769 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5771 MSIPACKAGE *package = param;
5772 MSIRECORD *uirow;
5773 LPWSTR attrs;
5774 LPCWSTR desc, driver;
5775 WORD request = ODBC_REMOVE_SYS_DSN;
5776 INT registration;
5777 DWORD len;
5779 static const WCHAR attrs_fmt[] = {
5780 'D','S','N','=','%','s',0 };
5782 desc = MSI_RecordGetString( rec, 3 );
5783 driver = MSI_RecordGetString( rec, 4 );
5784 registration = MSI_RecordGetInteger( rec, 5 );
5786 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5787 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5789 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
5790 attrs = msi_alloc( len * sizeof(WCHAR) );
5791 if (!attrs)
5792 return ERROR_OUTOFMEMORY;
5794 FIXME("Use ODBCSourceAttribute table\n");
5796 len = sprintfW( attrs, attrs_fmt, desc );
5797 attrs[len + 1] = 0;
5799 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5801 WARN("Failed to remove ODBC data source\n");
5803 msi_free( attrs );
5805 uirow = MSI_CreateRecord( 3 );
5806 MSI_RecordSetStringW( uirow, 1, desc );
5807 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5808 MSI_RecordSetInteger( uirow, 3, request );
5809 ui_actiondata( package, szRemoveODBC, uirow );
5810 msiobj_release( &uirow->hdr );
5812 return ERROR_SUCCESS;
5815 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5817 UINT rc;
5818 MSIQUERY *view;
5820 static const WCHAR driver_query[] = {
5821 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5822 'O','D','B','C','D','r','i','v','e','r',0 };
5824 static const WCHAR translator_query[] = {
5825 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5826 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5828 static const WCHAR source_query[] = {
5829 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5830 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5832 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5833 if (rc != ERROR_SUCCESS)
5834 return ERROR_SUCCESS;
5836 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5837 msiobj_release( &view->hdr );
5839 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5840 if (rc != ERROR_SUCCESS)
5841 return ERROR_SUCCESS;
5843 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5844 msiobj_release( &view->hdr );
5846 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5847 if (rc != ERROR_SUCCESS)
5848 return ERROR_SUCCESS;
5850 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5851 msiobj_release( &view->hdr );
5853 return rc;
5856 #define ENV_ACT_SETALWAYS 0x1
5857 #define ENV_ACT_SETABSENT 0x2
5858 #define ENV_ACT_REMOVE 0x4
5859 #define ENV_ACT_REMOVEMATCH 0x8
5861 #define ENV_MOD_MACHINE 0x20000000
5862 #define ENV_MOD_APPEND 0x40000000
5863 #define ENV_MOD_PREFIX 0x80000000
5864 #define ENV_MOD_MASK 0xC0000000
5866 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5868 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5870 LPCWSTR cptr = *name;
5872 static const WCHAR prefix[] = {'[','~',']',0};
5873 static const int prefix_len = 3;
5875 *flags = 0;
5876 while (*cptr)
5878 if (*cptr == '=')
5879 *flags |= ENV_ACT_SETALWAYS;
5880 else if (*cptr == '+')
5881 *flags |= ENV_ACT_SETABSENT;
5882 else if (*cptr == '-')
5883 *flags |= ENV_ACT_REMOVE;
5884 else if (*cptr == '!')
5885 *flags |= ENV_ACT_REMOVEMATCH;
5886 else if (*cptr == '*')
5887 *flags |= ENV_MOD_MACHINE;
5888 else
5889 break;
5891 cptr++;
5892 (*name)++;
5895 if (!*cptr)
5897 ERR("Missing environment variable\n");
5898 return ERROR_FUNCTION_FAILED;
5901 if (*value)
5903 LPCWSTR ptr = *value;
5904 if (!strncmpW(ptr, prefix, prefix_len))
5906 if (ptr[prefix_len] == szSemiColon[0])
5908 *flags |= ENV_MOD_APPEND;
5909 *value += lstrlenW(prefix);
5911 else
5913 *value = NULL;
5916 else if (lstrlenW(*value) >= prefix_len)
5918 ptr += lstrlenW(ptr) - prefix_len;
5919 if (!lstrcmpW(ptr, prefix))
5921 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5923 *flags |= ENV_MOD_PREFIX;
5924 /* the "[~]" will be removed by deformat_string */;
5926 else
5928 *value = NULL;
5934 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5935 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5936 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5937 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5939 ERR("Invalid flags: %08x\n", *flags);
5940 return ERROR_FUNCTION_FAILED;
5943 if (!*flags)
5944 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5946 return ERROR_SUCCESS;
5949 static UINT open_env_key( DWORD flags, HKEY *key )
5951 static const WCHAR user_env[] =
5952 {'E','n','v','i','r','o','n','m','e','n','t',0};
5953 static const WCHAR machine_env[] =
5954 {'S','y','s','t','e','m','\\',
5955 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5956 'C','o','n','t','r','o','l','\\',
5957 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5958 'E','n','v','i','r','o','n','m','e','n','t',0};
5959 const WCHAR *env;
5960 HKEY root;
5961 LONG res;
5963 if (flags & ENV_MOD_MACHINE)
5965 env = machine_env;
5966 root = HKEY_LOCAL_MACHINE;
5968 else
5970 env = user_env;
5971 root = HKEY_CURRENT_USER;
5974 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
5975 if (res != ERROR_SUCCESS)
5977 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
5978 return ERROR_FUNCTION_FAILED;
5981 return ERROR_SUCCESS;
5984 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5986 MSIPACKAGE *package = param;
5987 LPCWSTR name, value, component;
5988 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
5989 DWORD flags, type, size;
5990 UINT res;
5991 HKEY env = NULL;
5992 MSICOMPONENT *comp;
5993 MSIRECORD *uirow;
5994 int action = 0;
5996 component = MSI_RecordGetString(rec, 4);
5997 comp = get_loaded_component(package, component);
5998 if (!comp)
5999 return ERROR_SUCCESS;
6001 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6003 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6004 comp->Action = comp->Installed;
6005 return ERROR_SUCCESS;
6007 comp->Action = INSTALLSTATE_LOCAL;
6009 name = MSI_RecordGetString(rec, 2);
6010 value = MSI_RecordGetString(rec, 3);
6012 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6014 res = env_parse_flags(&name, &value, &flags);
6015 if (res != ERROR_SUCCESS || !value)
6016 goto done;
6018 if (value && !deformat_string(package, value, &deformatted))
6020 res = ERROR_OUTOFMEMORY;
6021 goto done;
6024 value = deformatted;
6026 res = open_env_key( flags, &env );
6027 if (res != ERROR_SUCCESS)
6028 goto done;
6030 if (flags & ENV_MOD_MACHINE)
6031 action |= 0x20000000;
6033 size = 0;
6034 type = REG_SZ;
6035 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6036 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6037 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6038 goto done;
6040 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6042 action = 0x2;
6044 /* Nothing to do. */
6045 if (!value)
6047 res = ERROR_SUCCESS;
6048 goto done;
6051 /* If we are appending but the string was empty, strip ; */
6052 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6054 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6055 newval = strdupW(value);
6056 if (!newval)
6058 res = ERROR_OUTOFMEMORY;
6059 goto done;
6062 else
6064 action = 0x1;
6066 /* Contrary to MSDN, +-variable to [~];path works */
6067 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6069 res = ERROR_SUCCESS;
6070 goto done;
6073 data = msi_alloc(size);
6074 if (!data)
6076 RegCloseKey(env);
6077 return ERROR_OUTOFMEMORY;
6080 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6081 if (res != ERROR_SUCCESS)
6082 goto done;
6084 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6086 action = 0x4;
6087 res = RegDeleteValueW(env, name);
6088 if (res != ERROR_SUCCESS)
6089 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6090 goto done;
6093 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6094 if (flags & ENV_MOD_MASK)
6096 DWORD mod_size;
6097 int multiplier = 0;
6098 if (flags & ENV_MOD_APPEND) multiplier++;
6099 if (flags & ENV_MOD_PREFIX) multiplier++;
6100 mod_size = lstrlenW(value) * multiplier;
6101 size += mod_size * sizeof(WCHAR);
6104 newval = msi_alloc(size);
6105 ptr = newval;
6106 if (!newval)
6108 res = ERROR_OUTOFMEMORY;
6109 goto done;
6112 if (flags & ENV_MOD_PREFIX)
6114 lstrcpyW(newval, value);
6115 ptr = newval + lstrlenW(value);
6116 action |= 0x80000000;
6119 lstrcpyW(ptr, data);
6121 if (flags & ENV_MOD_APPEND)
6123 lstrcatW(newval, value);
6124 action |= 0x40000000;
6127 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6128 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6129 if (res)
6131 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6134 done:
6135 uirow = MSI_CreateRecord( 3 );
6136 MSI_RecordSetStringW( uirow, 1, name );
6137 MSI_RecordSetStringW( uirow, 2, newval );
6138 MSI_RecordSetInteger( uirow, 3, action );
6139 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6140 msiobj_release( &uirow->hdr );
6142 if (env) RegCloseKey(env);
6143 msi_free(deformatted);
6144 msi_free(data);
6145 msi_free(newval);
6146 return res;
6149 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6151 UINT rc;
6152 MSIQUERY * view;
6153 static const WCHAR ExecSeqQuery[] =
6154 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6155 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6156 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6157 if (rc != ERROR_SUCCESS)
6158 return ERROR_SUCCESS;
6160 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6161 msiobj_release(&view->hdr);
6163 return rc;
6166 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6168 MSIPACKAGE *package = param;
6169 LPCWSTR name, value, component;
6170 LPWSTR deformatted = NULL;
6171 DWORD flags;
6172 HKEY env;
6173 MSICOMPONENT *comp;
6174 MSIRECORD *uirow;
6175 int action = 0;
6176 LONG res;
6177 UINT r;
6179 component = MSI_RecordGetString( rec, 4 );
6180 comp = get_loaded_component( package, component );
6181 if (!comp)
6182 return ERROR_SUCCESS;
6184 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6186 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6187 comp->Action = comp->Installed;
6188 return ERROR_SUCCESS;
6190 comp->Action = INSTALLSTATE_ABSENT;
6192 name = MSI_RecordGetString( rec, 2 );
6193 value = MSI_RecordGetString( rec, 3 );
6195 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6197 r = env_parse_flags( &name, &value, &flags );
6198 if (r != ERROR_SUCCESS)
6199 return r;
6201 if (!(flags & ENV_ACT_REMOVE))
6203 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6204 return ERROR_SUCCESS;
6207 if (value && !deformat_string( package, value, &deformatted ))
6208 return ERROR_OUTOFMEMORY;
6210 value = deformatted;
6212 r = open_env_key( flags, &env );
6213 if (r != ERROR_SUCCESS)
6215 r = ERROR_SUCCESS;
6216 goto done;
6219 if (flags & ENV_MOD_MACHINE)
6220 action |= 0x20000000;
6222 TRACE("Removing %s\n", debugstr_w(name));
6224 res = RegDeleteValueW( env, name );
6225 if (res != ERROR_SUCCESS)
6227 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6228 r = ERROR_SUCCESS;
6231 done:
6232 uirow = MSI_CreateRecord( 3 );
6233 MSI_RecordSetStringW( uirow, 1, name );
6234 MSI_RecordSetStringW( uirow, 2, value );
6235 MSI_RecordSetInteger( uirow, 3, action );
6236 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6237 msiobj_release( &uirow->hdr );
6239 if (env) RegCloseKey( env );
6240 msi_free( deformatted );
6241 return r;
6244 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6246 UINT rc;
6247 MSIQUERY *view;
6248 static const WCHAR query[] =
6249 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6250 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6252 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6253 if (rc != ERROR_SUCCESS)
6254 return ERROR_SUCCESS;
6256 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6257 msiobj_release( &view->hdr );
6259 return rc;
6262 typedef struct tagMSIASSEMBLY
6264 struct list entry;
6265 MSICOMPONENT *component;
6266 MSIFEATURE *feature;
6267 MSIFILE *file;
6268 LPWSTR manifest;
6269 LPWSTR application;
6270 LPWSTR display_name;
6271 DWORD attributes;
6272 BOOL installed;
6273 } MSIASSEMBLY;
6275 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6276 DWORD dwReserved);
6277 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6278 LPVOID pvReserved, HMODULE *phModDll);
6280 static BOOL init_functionpointers(void)
6282 HRESULT hr;
6283 HMODULE hfusion;
6284 HMODULE hmscoree;
6286 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6288 hmscoree = LoadLibraryA("mscoree.dll");
6289 if (!hmscoree)
6291 WARN("mscoree.dll not available\n");
6292 return FALSE;
6295 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6296 if (!pLoadLibraryShim)
6298 WARN("LoadLibraryShim not available\n");
6299 FreeLibrary(hmscoree);
6300 return FALSE;
6303 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6304 if (FAILED(hr))
6306 WARN("fusion.dll not available\n");
6307 FreeLibrary(hmscoree);
6308 return FALSE;
6311 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6313 FreeLibrary(hmscoree);
6314 return TRUE;
6317 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6318 LPWSTR path)
6320 IAssemblyCache *cache;
6321 MSIRECORD *uirow;
6322 HRESULT hr;
6323 UINT r = ERROR_FUNCTION_FAILED;
6325 TRACE("installing assembly: %s\n", debugstr_w(path));
6327 uirow = MSI_CreateRecord( 2 );
6328 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6329 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6330 msiobj_release( &uirow->hdr );
6332 if (assembly->feature)
6333 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6335 if (assembly->manifest)
6336 FIXME("Manifest unhandled\n");
6338 if (assembly->application)
6340 FIXME("Assembly should be privately installed\n");
6341 return ERROR_SUCCESS;
6344 if (assembly->attributes == msidbAssemblyAttributesWin32)
6346 FIXME("Win32 assemblies not handled\n");
6347 return ERROR_SUCCESS;
6350 hr = pCreateAssemblyCache(&cache, 0);
6351 if (FAILED(hr))
6352 goto done;
6354 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6355 if (FAILED(hr))
6356 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6358 r = ERROR_SUCCESS;
6360 done:
6361 IAssemblyCache_Release(cache);
6362 return r;
6365 typedef struct tagASSEMBLY_LIST
6367 MSIPACKAGE *package;
6368 IAssemblyCache *cache;
6369 struct list *assemblies;
6370 } ASSEMBLY_LIST;
6372 typedef struct tagASSEMBLY_NAME
6374 LPWSTR name;
6375 LPWSTR version;
6376 LPWSTR culture;
6377 LPWSTR pubkeytoken;
6378 } ASSEMBLY_NAME;
6380 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6382 ASSEMBLY_NAME *asmname = param;
6383 LPCWSTR name = MSI_RecordGetString(rec, 2);
6384 LPWSTR val = msi_dup_record_field(rec, 3);
6386 static const WCHAR Name[] = {'N','a','m','e',0};
6387 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6388 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6389 static const WCHAR PublicKeyToken[] = {
6390 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6392 if (!strcmpiW(name, Name))
6393 asmname->name = val;
6394 else if (!strcmpiW(name, Version))
6395 asmname->version = val;
6396 else if (!strcmpiW(name, Culture))
6397 asmname->culture = val;
6398 else if (!strcmpiW(name, PublicKeyToken))
6399 asmname->pubkeytoken = val;
6400 else
6401 msi_free(val);
6403 return ERROR_SUCCESS;
6406 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6408 if (!*str)
6410 *size = lstrlenW(append) + 1;
6411 *str = msi_alloc((*size) * sizeof(WCHAR));
6412 lstrcpyW(*str, append);
6413 return;
6416 (*size) += lstrlenW(append);
6417 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6418 lstrcatW(*str, append);
6421 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6423 static const WCHAR separator[] = {',',' ',0};
6424 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6425 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6426 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6427 static const WCHAR query[] = {
6428 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6429 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6430 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6431 '=','\'','%','s','\'',0};
6432 ASSEMBLY_NAME name;
6433 MSIQUERY *view;
6434 LPWSTR display_name;
6435 DWORD size;
6436 UINT r;
6438 display_name = NULL;
6439 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6441 r = MSI_OpenQuery( db, &view, query, comp->Component );
6442 if (r != ERROR_SUCCESS)
6443 return NULL;
6445 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6446 msiobj_release( &view->hdr );
6448 if (!name.name)
6450 ERR("No assembly name specified!\n");
6451 return NULL;
6454 append_str( &display_name, &size, name.name );
6456 if (name.version)
6458 append_str( &display_name, &size, separator );
6459 append_str( &display_name, &size, Version );
6460 append_str( &display_name, &size, name.version );
6462 if (name.culture)
6464 append_str( &display_name, &size, separator );
6465 append_str( &display_name, &size, Culture );
6466 append_str( &display_name, &size, name.culture );
6468 if (name.pubkeytoken)
6470 append_str( &display_name, &size, separator );
6471 append_str( &display_name, &size, PublicKeyToken );
6472 append_str( &display_name, &size, name.pubkeytoken );
6475 msi_free( name.name );
6476 msi_free( name.version );
6477 msi_free( name.culture );
6478 msi_free( name.pubkeytoken );
6480 return display_name;
6483 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6485 ASSEMBLY_INFO asminfo;
6486 LPWSTR disp;
6487 BOOL found = FALSE;
6488 HRESULT hr;
6490 disp = get_assembly_display_name( db, comp );
6491 if (!disp)
6492 return FALSE;
6494 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6495 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6497 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6498 if (SUCCEEDED(hr))
6499 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6501 msi_free( disp );
6502 return found;
6505 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6507 ASSEMBLY_LIST *list = param;
6508 MSIASSEMBLY *assembly;
6509 LPCWSTR component;
6511 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6512 if (!assembly)
6513 return ERROR_OUTOFMEMORY;
6515 component = MSI_RecordGetString(rec, 1);
6516 assembly->component = get_loaded_component(list->package, component);
6517 if (!assembly->component)
6518 return ERROR_SUCCESS;
6520 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6521 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6523 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6524 assembly->component->Action = assembly->component->Installed;
6525 return ERROR_SUCCESS;
6527 assembly->component->Action = assembly->component->ActionRequest;
6529 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6530 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6532 if (!assembly->file)
6534 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6535 return ERROR_FUNCTION_FAILED;
6538 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6539 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6540 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6542 if (assembly->application)
6544 WCHAR version[24];
6545 DWORD size = sizeof(version)/sizeof(WCHAR);
6547 /* FIXME: we should probably check the manifest file here */
6549 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6550 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6552 assembly->installed = TRUE;
6555 else
6556 assembly->installed = check_assembly_installed(list->package->db,
6557 list->cache,
6558 assembly->component);
6560 list_add_head(list->assemblies, &assembly->entry);
6561 return ERROR_SUCCESS;
6564 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6566 IAssemblyCache *cache = NULL;
6567 ASSEMBLY_LIST list;
6568 MSIQUERY *view;
6569 HRESULT hr;
6570 UINT r;
6572 static const WCHAR query[] =
6573 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6574 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6576 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6577 if (r != ERROR_SUCCESS)
6578 return ERROR_SUCCESS;
6580 hr = pCreateAssemblyCache(&cache, 0);
6581 if (FAILED(hr))
6582 return ERROR_FUNCTION_FAILED;
6584 list.package = package;
6585 list.cache = cache;
6586 list.assemblies = assemblies;
6588 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6589 msiobj_release(&view->hdr);
6591 IAssemblyCache_Release(cache);
6593 return r;
6596 static void free_assemblies(struct list *assemblies)
6598 struct list *item, *cursor;
6600 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6602 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6604 list_remove(&assembly->entry);
6605 msi_free(assembly->application);
6606 msi_free(assembly->manifest);
6607 msi_free(assembly->display_name);
6608 msi_free(assembly);
6612 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6614 MSIASSEMBLY *assembly;
6616 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6618 if (!lstrcmpW(assembly->file->File, file))
6620 *out = assembly;
6621 return TRUE;
6625 return FALSE;
6628 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6629 LPWSTR *path, DWORD *attrs, PVOID user)
6631 MSIASSEMBLY *assembly;
6632 WCHAR temppath[MAX_PATH];
6633 struct list *assemblies = user;
6634 UINT r;
6636 if (!find_assembly(assemblies, file, &assembly))
6637 return FALSE;
6639 GetTempPathW(MAX_PATH, temppath);
6640 PathAddBackslashW(temppath);
6641 lstrcatW(temppath, assembly->file->FileName);
6643 if (action == MSICABEXTRACT_BEGINEXTRACT)
6645 if (assembly->installed)
6646 return FALSE;
6648 *path = strdupW(temppath);
6649 *attrs = assembly->file->Attributes;
6651 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6653 assembly->installed = TRUE;
6655 r = install_assembly(package, assembly, temppath);
6656 if (r != ERROR_SUCCESS)
6657 ERR("Failed to install assembly\n");
6660 return TRUE;
6663 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6665 UINT r;
6666 struct list assemblies = LIST_INIT(assemblies);
6667 MSIASSEMBLY *assembly;
6668 MSIMEDIAINFO *mi;
6670 if (!init_functionpointers() || !pCreateAssemblyCache)
6671 return ERROR_FUNCTION_FAILED;
6673 r = load_assemblies(package, &assemblies);
6674 if (r != ERROR_SUCCESS)
6675 goto done;
6677 if (list_empty(&assemblies))
6678 goto done;
6680 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6681 if (!mi)
6683 r = ERROR_OUTOFMEMORY;
6684 goto done;
6687 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6689 if (assembly->installed && !mi->is_continuous)
6690 continue;
6692 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6693 (assembly->file->IsCompressed && !mi->is_extracted))
6695 MSICABDATA data;
6697 r = ready_media(package, assembly->file, mi);
6698 if (r != ERROR_SUCCESS)
6700 ERR("Failed to ready media\n");
6701 break;
6704 data.mi = mi;
6705 data.package = package;
6706 data.cb = installassembly_cb;
6707 data.user = &assemblies;
6709 if (assembly->file->IsCompressed &&
6710 !msi_cabextract(package, mi, &data))
6712 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6713 r = ERROR_FUNCTION_FAILED;
6714 break;
6718 if (!assembly->file->IsCompressed)
6720 LPWSTR source = resolve_file_source(package, assembly->file);
6722 r = install_assembly(package, assembly, source);
6723 if (r != ERROR_SUCCESS)
6724 ERR("Failed to install assembly\n");
6726 msi_free(source);
6729 /* FIXME: write Installer assembly reg values */
6732 done:
6733 free_assemblies(&assemblies);
6734 return r;
6737 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6739 LPWSTR key, template, id;
6740 UINT r = ERROR_SUCCESS;
6742 id = msi_dup_property( package, szProductID );
6743 if (id)
6745 msi_free( id );
6746 return ERROR_SUCCESS;
6748 template = msi_dup_property( package, szPIDTemplate );
6749 key = msi_dup_property( package, szPIDKEY );
6751 if (key && template)
6753 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6754 r = MSI_SetPropertyW( package, szProductID, key );
6756 msi_free( template );
6757 msi_free( key );
6758 return r;
6761 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6763 TRACE("\n");
6764 package->need_reboot = 1;
6765 return ERROR_SUCCESS;
6768 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6770 static const WCHAR szAvailableFreeReg[] =
6771 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6772 MSIRECORD *uirow;
6773 int space = msi_get_property_int( package, szAvailableFreeReg, 0 );
6775 TRACE("%p %d kilobytes\n", package, space);
6777 uirow = MSI_CreateRecord( 1 );
6778 MSI_RecordSetInteger( uirow, 1, space );
6779 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6780 msiobj_release( &uirow->hdr );
6782 return ERROR_SUCCESS;
6785 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6787 FIXME("%p\n", package);
6788 return ERROR_SUCCESS;
6791 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6793 FIXME("%p\n", package);
6794 return ERROR_SUCCESS;
6797 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6798 LPCSTR action, LPCWSTR table )
6800 static const WCHAR query[] = {
6801 'S','E','L','E','C','T',' ','*',' ',
6802 'F','R','O','M',' ','`','%','s','`',0 };
6803 MSIQUERY *view = NULL;
6804 DWORD count = 0;
6805 UINT r;
6807 r = MSI_OpenQuery( package->db, &view, query, table );
6808 if (r == ERROR_SUCCESS)
6810 r = MSI_IterateRecords(view, &count, NULL, package);
6811 msiobj_release(&view->hdr);
6814 if (count)
6815 FIXME("%s -> %u ignored %s table values\n",
6816 action, count, debugstr_w(table));
6818 return ERROR_SUCCESS;
6821 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6823 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6824 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6827 static UINT ACTION_BindImage( MSIPACKAGE *package )
6829 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6830 return msi_unimplemented_action_stub( package, "BindImage", table );
6833 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6835 static const WCHAR table[] = {
6836 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6837 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6840 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6842 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6843 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6846 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6848 static const WCHAR table[] = {
6849 'M','s','i','A','s','s','e','m','b','l','y',0 };
6850 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6853 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6855 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6856 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6859 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6861 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6862 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6865 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6867 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6868 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6871 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6873 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6874 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6877 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6879 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6880 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6883 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6885 static const WCHAR table[] = { 'D','i','r','e','c','t','o','r','y',0 };
6886 return msi_unimplemented_action_stub( package, "SetODBCFolders", table );
6889 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6891 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6892 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6895 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6897 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6898 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6901 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6903 static const WCHAR table[] = { 'M','I','M','E',0 };
6904 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6907 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6909 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6910 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6913 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6915 static const struct
6917 const WCHAR *action;
6918 UINT (*handler)(MSIPACKAGE *);
6920 StandardActions[] =
6922 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6923 { szAppSearch, ACTION_AppSearch },
6924 { szBindImage, ACTION_BindImage },
6925 { szCCPSearch, ACTION_CCPSearch },
6926 { szCostFinalize, ACTION_CostFinalize },
6927 { szCostInitialize, ACTION_CostInitialize },
6928 { szCreateFolders, ACTION_CreateFolders },
6929 { szCreateShortcuts, ACTION_CreateShortcuts },
6930 { szDeleteServices, ACTION_DeleteServices },
6931 { szDisableRollback, ACTION_DisableRollback },
6932 { szDuplicateFiles, ACTION_DuplicateFiles },
6933 { szExecuteAction, ACTION_ExecuteAction },
6934 { szFileCost, ACTION_FileCost },
6935 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6936 { szForceReboot, ACTION_ForceReboot },
6937 { szInstallAdminPackage, ACTION_InstallAdminPackage },
6938 { szInstallExecute, ACTION_InstallExecute },
6939 { szInstallExecuteAgain, ACTION_InstallExecute },
6940 { szInstallFiles, ACTION_InstallFiles},
6941 { szInstallFinalize, ACTION_InstallFinalize },
6942 { szInstallInitialize, ACTION_InstallInitialize },
6943 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6944 { szInstallValidate, ACTION_InstallValidate },
6945 { szIsolateComponents, ACTION_IsolateComponents },
6946 { szLaunchConditions, ACTION_LaunchConditions },
6947 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6948 { szMoveFiles, ACTION_MoveFiles },
6949 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6950 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6951 { szInstallODBC, ACTION_InstallODBC },
6952 { szInstallServices, ACTION_InstallServices },
6953 { szPatchFiles, ACTION_PatchFiles },
6954 { szProcessComponents, ACTION_ProcessComponents },
6955 { szPublishComponents, ACTION_PublishComponents },
6956 { szPublishFeatures, ACTION_PublishFeatures },
6957 { szPublishProduct, ACTION_PublishProduct },
6958 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6959 { szRegisterComPlus, ACTION_RegisterComPlus},
6960 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6961 { szRegisterFonts, ACTION_RegisterFonts },
6962 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6963 { szRegisterProduct, ACTION_RegisterProduct },
6964 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6965 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6966 { szRegisterUser, ACTION_RegisterUser },
6967 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6968 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6969 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6970 { szRemoveFiles, ACTION_RemoveFiles },
6971 { szRemoveFolders, ACTION_RemoveFolders },
6972 { szRemoveIniValues, ACTION_RemoveIniValues },
6973 { szRemoveODBC, ACTION_RemoveODBC },
6974 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6975 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6976 { szResolveSource, ACTION_ResolveSource },
6977 { szRMCCPSearch, ACTION_RMCCPSearch },
6978 { szScheduleReboot, ACTION_ScheduleReboot },
6979 { szSelfRegModules, ACTION_SelfRegModules },
6980 { szSelfUnregModules, ACTION_SelfUnregModules },
6981 { szSetODBCFolders, ACTION_SetODBCFolders },
6982 { szStartServices, ACTION_StartServices },
6983 { szStopServices, ACTION_StopServices },
6984 { szUnpublishComponents, ACTION_UnpublishComponents },
6985 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6986 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6987 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6988 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6989 { szUnregisterFonts, ACTION_UnregisterFonts },
6990 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6991 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6992 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6993 { szValidateProductID, ACTION_ValidateProductID },
6994 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6995 { szWriteIniValues, ACTION_WriteIniValues },
6996 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6997 { NULL, NULL },
7000 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7001 UINT* rc, BOOL force )
7003 BOOL ret = FALSE;
7004 BOOL run = force;
7005 int i;
7007 if (!run && !package->script->CurrentlyScripting)
7008 run = TRUE;
7010 if (!run)
7012 if (strcmpW(action,szInstallFinalize) == 0 ||
7013 strcmpW(action,szInstallExecute) == 0 ||
7014 strcmpW(action,szInstallExecuteAgain) == 0)
7015 run = TRUE;
7018 i = 0;
7019 while (StandardActions[i].action != NULL)
7021 if (strcmpW(StandardActions[i].action, action)==0)
7023 if (!run)
7025 ui_actioninfo(package, action, TRUE, 0);
7026 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7027 ui_actioninfo(package, action, FALSE, *rc);
7029 else
7031 ui_actionstart(package, action);
7032 if (StandardActions[i].handler)
7034 *rc = StandardActions[i].handler(package);
7036 else
7038 FIXME("unhandled standard action %s\n",debugstr_w(action));
7039 *rc = ERROR_SUCCESS;
7042 ret = TRUE;
7043 break;
7045 i++;
7047 return ret;
7050 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7052 UINT rc = ERROR_SUCCESS;
7053 BOOL handled;
7055 TRACE("Performing action (%s)\n", debugstr_w(action));
7057 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7059 if (!handled)
7060 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7062 if (!handled)
7064 WARN("unhandled msi action %s\n", debugstr_w(action));
7065 rc = ERROR_FUNCTION_NOT_CALLED;
7068 return rc;
7071 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7073 UINT rc = ERROR_SUCCESS;
7074 BOOL handled = FALSE;
7076 TRACE("Performing action (%s)\n", debugstr_w(action));
7078 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7080 if (!handled)
7081 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7083 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7084 handled = TRUE;
7086 if (!handled)
7088 WARN("unhandled msi action %s\n", debugstr_w(action));
7089 rc = ERROR_FUNCTION_NOT_CALLED;
7092 return rc;
7095 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7097 UINT rc = ERROR_SUCCESS;
7098 MSIRECORD *row;
7100 static const WCHAR ExecSeqQuery[] =
7101 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7102 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7103 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7104 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7105 static const WCHAR UISeqQuery[] =
7106 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7107 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7108 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7109 ' ', '=',' ','%','i',0};
7111 if (needs_ui_sequence(package))
7112 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7113 else
7114 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7116 if (row)
7118 LPCWSTR action, cond;
7120 TRACE("Running the actions\n");
7122 /* check conditions */
7123 cond = MSI_RecordGetString(row, 2);
7125 /* this is a hack to skip errors in the condition code */
7126 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7128 msiobj_release(&row->hdr);
7129 return ERROR_SUCCESS;
7132 action = MSI_RecordGetString(row, 1);
7133 if (!action)
7135 ERR("failed to fetch action\n");
7136 msiobj_release(&row->hdr);
7137 return ERROR_FUNCTION_FAILED;
7140 if (needs_ui_sequence(package))
7141 rc = ACTION_PerformUIAction(package, action, -1);
7142 else
7143 rc = ACTION_PerformAction(package, action, -1, FALSE);
7145 msiobj_release(&row->hdr);
7148 return rc;
7151 /****************************************************
7152 * TOP level entry points
7153 *****************************************************/
7155 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7156 LPCWSTR szCommandLine )
7158 UINT rc;
7159 BOOL ui_exists;
7161 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7162 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7164 MSI_SetPropertyW(package, szAction, szInstall);
7166 package->script->InWhatSequence = SEQUENCE_INSTALL;
7168 if (szPackagePath)
7170 LPWSTR p, dir;
7171 LPCWSTR file;
7173 dir = strdupW(szPackagePath);
7174 p = strrchrW(dir, '\\');
7175 if (p)
7177 *(++p) = 0;
7178 file = szPackagePath + (p - dir);
7180 else
7182 msi_free(dir);
7183 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7184 GetCurrentDirectoryW(MAX_PATH, dir);
7185 lstrcatW(dir, szBackSlash);
7186 file = szPackagePath;
7189 msi_free( package->PackagePath );
7190 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7191 if (!package->PackagePath)
7193 msi_free(dir);
7194 return ERROR_OUTOFMEMORY;
7197 lstrcpyW(package->PackagePath, dir);
7198 lstrcatW(package->PackagePath, file);
7199 msi_free(dir);
7201 msi_set_sourcedir_props(package, FALSE);
7204 msi_parse_command_line( package, szCommandLine, FALSE );
7206 msi_apply_transforms( package );
7207 msi_apply_patches( package );
7209 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
7211 TRACE("setting reinstall property\n");
7212 MSI_SetPropertyW( package, szReinstall, szAll );
7215 /* properties may have been added by a transform */
7216 msi_clone_properties( package );
7217 msi_set_context( package );
7219 if (needs_ui_sequence( package))
7221 package->script->InWhatSequence |= SEQUENCE_UI;
7222 rc = ACTION_ProcessUISequence(package);
7223 ui_exists = ui_sequence_exists(package);
7224 if (rc == ERROR_SUCCESS || !ui_exists)
7226 package->script->InWhatSequence |= SEQUENCE_EXEC;
7227 rc = ACTION_ProcessExecSequence(package, ui_exists);
7230 else
7231 rc = ACTION_ProcessExecSequence(package, FALSE);
7233 package->script->CurrentlyScripting = FALSE;
7235 /* process the ending type action */
7236 if (rc == ERROR_SUCCESS)
7237 ACTION_PerformActionSequence(package, -1);
7238 else if (rc == ERROR_INSTALL_USEREXIT)
7239 ACTION_PerformActionSequence(package, -2);
7240 else if (rc == ERROR_INSTALL_SUSPEND)
7241 ACTION_PerformActionSequence(package, -4);
7242 else /* failed */
7243 ACTION_PerformActionSequence(package, -3);
7245 /* finish up running custom actions */
7246 ACTION_FinishCustomActions(package);
7248 if (rc == ERROR_SUCCESS && package->need_reboot)
7249 return ERROR_SUCCESS_REBOOT_REQUIRED;
7251 return rc;