push 6e61d6ca5bcaf95ac09a664b4ba4f88238c927be
[wine/hacks.git] / dlls / msi / action.c
blob15730f098ad479197cec1a001bac93997f62d554
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 msi_free(FullName);
4157 /* the UI chunk */
4158 uirow = MSI_CreateRecord( 2 );
4159 uipath = strdupW( file->TargetPath );
4160 p = strrchrW(uipath,'\\');
4161 if (p)
4162 p[0]=0;
4163 MSI_RecordSetStringW( uirow, 1, &p[1] );
4164 MSI_RecordSetStringW( uirow, 2, uipath);
4165 ui_actiondata( package, szSelfRegModules, uirow);
4166 msiobj_release( &uirow->hdr );
4167 msi_free( uipath );
4168 /* FIXME: call ui_progress? */
4170 return ERROR_SUCCESS;
4173 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4175 UINT rc;
4176 MSIQUERY * view;
4177 static const WCHAR ExecSeqQuery[] =
4178 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4179 '`','S','e','l','f','R','e','g','`',0};
4181 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4182 if (rc != ERROR_SUCCESS)
4184 TRACE("no SelfReg table\n");
4185 return ERROR_SUCCESS;
4188 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4189 msiobj_release(&view->hdr);
4191 return ERROR_SUCCESS;
4194 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4196 static const WCHAR regsvr32[] =
4197 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4198 static const WCHAR close[] = {'\"',0};
4199 MSIPACKAGE *package = param;
4200 LPCWSTR filename;
4201 LPWSTR cmdline;
4202 MSIFILE *file;
4203 DWORD len;
4204 STARTUPINFOW si;
4205 PROCESS_INFORMATION pi;
4206 BOOL ret;
4207 MSIRECORD *uirow;
4208 LPWSTR uipath, p;
4210 memset( &si, 0, sizeof(STARTUPINFOW) );
4212 filename = MSI_RecordGetString( row, 1 );
4213 file = get_loaded_file( package, filename );
4215 if (!file)
4217 ERR("Unable to find file id %s\n", debugstr_w(filename));
4218 return ERROR_SUCCESS;
4221 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4223 cmdline = msi_alloc( len * sizeof(WCHAR) );
4224 strcpyW( cmdline, regsvr32 );
4225 strcatW( cmdline, file->TargetPath );
4226 strcatW( cmdline, close );
4228 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4230 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4231 if (ret)
4233 CloseHandle( pi.hThread );
4234 msi_dialog_check_messages( pi.hProcess );
4235 CloseHandle( pi.hProcess );
4238 msi_free( cmdline );
4240 uirow = MSI_CreateRecord( 2 );
4241 uipath = strdupW( file->TargetPath );
4242 if ((p = strrchrW( uipath, '\\' )))
4244 *p = 0;
4245 MSI_RecordSetStringW( uirow, 1, ++p );
4247 MSI_RecordSetStringW( uirow, 2, uipath );
4248 ui_actiondata( package, szSelfUnregModules, uirow );
4249 msiobj_release( &uirow->hdr );
4250 msi_free( uipath );
4251 /* FIXME call ui_progress? */
4253 return ERROR_SUCCESS;
4256 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4258 UINT rc;
4259 MSIQUERY *view;
4260 static const WCHAR query[] =
4261 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4262 '`','S','e','l','f','R','e','g','`',0};
4264 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4265 if (rc != ERROR_SUCCESS)
4267 TRACE("no SelfReg table\n");
4268 return ERROR_SUCCESS;
4271 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4272 msiobj_release( &view->hdr );
4274 return ERROR_SUCCESS;
4277 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4279 MSIFEATURE *feature;
4280 UINT rc;
4281 HKEY hkey = NULL, userdata = NULL;
4283 if (!msi_check_publish(package))
4284 return ERROR_SUCCESS;
4286 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4287 &hkey, TRUE);
4288 if (rc != ERROR_SUCCESS)
4289 goto end;
4291 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4292 &userdata, TRUE);
4293 if (rc != ERROR_SUCCESS)
4294 goto end;
4296 /* here the guids are base 85 encoded */
4297 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4299 ComponentList *cl;
4300 LPWSTR data = NULL;
4301 GUID clsid;
4302 INT size;
4303 BOOL absent = FALSE;
4304 MSIRECORD *uirow;
4306 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4307 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4308 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4310 size = 1;
4311 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4313 size += 21;
4315 if (feature->Feature_Parent)
4316 size += strlenW( feature->Feature_Parent )+2;
4318 data = msi_alloc(size * sizeof(WCHAR));
4320 data[0] = 0;
4321 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4323 MSICOMPONENT* component = cl->component;
4324 WCHAR buf[21];
4326 buf[0] = 0;
4327 if (component->ComponentId)
4329 TRACE("From %s\n",debugstr_w(component->ComponentId));
4330 CLSIDFromString(component->ComponentId, &clsid);
4331 encode_base85_guid(&clsid,buf);
4332 TRACE("to %s\n",debugstr_w(buf));
4333 strcatW(data,buf);
4337 if (feature->Feature_Parent)
4339 static const WCHAR sep[] = {'\2',0};
4340 strcatW(data,sep);
4341 strcatW(data,feature->Feature_Parent);
4344 msi_reg_set_val_str( userdata, feature->Feature, data );
4345 msi_free(data);
4347 size = 0;
4348 if (feature->Feature_Parent)
4349 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4350 if (!absent)
4352 size += sizeof(WCHAR);
4353 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4354 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4356 else
4358 size += 2*sizeof(WCHAR);
4359 data = msi_alloc(size);
4360 data[0] = 0x6;
4361 data[1] = 0;
4362 if (feature->Feature_Parent)
4363 strcpyW( &data[1], feature->Feature_Parent );
4364 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4365 (LPBYTE)data,size);
4366 msi_free(data);
4369 /* the UI chunk */
4370 uirow = MSI_CreateRecord( 1 );
4371 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4372 ui_actiondata( package, szPublishFeatures, uirow);
4373 msiobj_release( &uirow->hdr );
4374 /* FIXME: call ui_progress? */
4377 end:
4378 RegCloseKey(hkey);
4379 RegCloseKey(userdata);
4380 return rc;
4383 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4385 UINT r;
4386 HKEY hkey;
4388 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4390 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4391 &hkey, FALSE);
4392 if (r == ERROR_SUCCESS)
4394 RegDeleteValueW(hkey, feature->Feature);
4395 RegCloseKey(hkey);
4398 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4399 &hkey, FALSE);
4400 if (r == ERROR_SUCCESS)
4402 RegDeleteValueW(hkey, feature->Feature);
4403 RegCloseKey(hkey);
4406 return ERROR_SUCCESS;
4409 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4411 MSIFEATURE *feature;
4413 if (!msi_check_unpublish(package))
4414 return ERROR_SUCCESS;
4416 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4418 msi_unpublish_feature(package, feature);
4421 return ERROR_SUCCESS;
4424 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4426 LPWSTR prop, val, key;
4427 SYSTEMTIME systime;
4428 DWORD size, langid;
4429 WCHAR date[9];
4430 LPWSTR buffer;
4432 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4433 static const WCHAR szWindowsInstaller[] =
4434 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4435 static const WCHAR modpath_fmt[] =
4436 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4437 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4438 static const WCHAR szModifyPath[] =
4439 {'M','o','d','i','f','y','P','a','t','h',0};
4440 static const WCHAR szUninstallString[] =
4441 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4442 static const WCHAR szEstimatedSize[] =
4443 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4444 static const WCHAR szProductLanguage[] =
4445 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4446 static const WCHAR szProductVersion[] =
4447 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4448 static const WCHAR szProductName[] =
4449 {'P','r','o','d','u','c','t','N','a','m','e',0};
4450 static const WCHAR szDisplayName[] =
4451 {'D','i','s','p','l','a','y','N','a','m','e',0};
4452 static const WCHAR szDisplayVersion[] =
4453 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4454 static const WCHAR szManufacturer[] =
4455 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4457 static const LPCSTR propval[] = {
4458 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4459 "ARPCONTACT", "Contact",
4460 "ARPCOMMENTS", "Comments",
4461 "ProductName", "DisplayName",
4462 "ProductVersion", "DisplayVersion",
4463 "ARPHELPLINK", "HelpLink",
4464 "ARPHELPTELEPHONE", "HelpTelephone",
4465 "ARPINSTALLLOCATION", "InstallLocation",
4466 "SourceDir", "InstallSource",
4467 "Manufacturer", "Publisher",
4468 "ARPREADME", "Readme",
4469 "ARPSIZE", "Size",
4470 "ARPURLINFOABOUT", "URLInfoAbout",
4471 "ARPURLUPDATEINFO", "URLUpdateInfo",
4472 NULL,
4474 const LPCSTR *p = propval;
4476 while (*p)
4478 prop = strdupAtoW(*p++);
4479 key = strdupAtoW(*p++);
4480 val = msi_dup_property(package, prop);
4481 msi_reg_set_val_str(hkey, key, val);
4482 msi_free(val);
4483 msi_free(key);
4484 msi_free(prop);
4487 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4489 size = deformat_string(package, modpath_fmt, &buffer);
4490 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4491 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4492 msi_free(buffer);
4494 /* FIXME: Write real Estimated Size when we have it */
4495 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4497 buffer = msi_dup_property(package, szProductName);
4498 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4499 msi_free(buffer);
4501 buffer = msi_dup_property(package, cszSourceDir);
4502 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4503 msi_free(buffer);
4505 buffer = msi_dup_property(package, szManufacturer);
4506 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4507 msi_free(buffer);
4509 GetLocalTime(&systime);
4510 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4511 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4513 langid = msi_get_property_int(package, szProductLanguage, 0);
4514 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4516 buffer = msi_dup_property(package, szProductVersion);
4517 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4518 if (buffer)
4520 DWORD verdword = msi_version_str_to_dword(buffer);
4522 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4523 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4524 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4525 msi_free(buffer);
4528 return ERROR_SUCCESS;
4531 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4533 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4534 MSIRECORD *uirow;
4535 LPWSTR upgrade_code;
4536 HKEY hkey, props;
4537 HKEY upgrade;
4538 UINT rc;
4540 static const WCHAR szUpgradeCode[] = {
4541 'U','p','g','r','a','d','e','C','o','d','e',0};
4543 /* FIXME: also need to publish if the product is in advertise mode */
4544 if (!msi_check_publish(package))
4545 return ERROR_SUCCESS;
4547 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4548 if (rc != ERROR_SUCCESS)
4549 return rc;
4551 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4552 NULL, &props, TRUE);
4553 if (rc != ERROR_SUCCESS)
4554 goto done;
4556 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4557 msi_free( package->db->localfile );
4558 package->db->localfile = NULL;
4560 rc = msi_publish_install_properties(package, hkey);
4561 if (rc != ERROR_SUCCESS)
4562 goto done;
4564 rc = msi_publish_install_properties(package, props);
4565 if (rc != ERROR_SUCCESS)
4566 goto done;
4568 upgrade_code = msi_dup_property(package, szUpgradeCode);
4569 if (upgrade_code)
4571 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4572 squash_guid(package->ProductCode, squashed_pc);
4573 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4574 RegCloseKey(upgrade);
4575 msi_free(upgrade_code);
4578 done:
4579 uirow = MSI_CreateRecord( 1 );
4580 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4581 ui_actiondata( package, szRegisterProduct, uirow );
4582 msiobj_release( &uirow->hdr );
4584 RegCloseKey(hkey);
4585 return ERROR_SUCCESS;
4588 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4590 return execute_script(package,INSTALL_SCRIPT);
4593 static UINT msi_unpublish_product(MSIPACKAGE *package)
4595 LPWSTR upgrade;
4596 LPWSTR remove = NULL;
4597 LPWSTR *features = NULL;
4598 BOOL full_uninstall = TRUE;
4599 MSIFEATURE *feature;
4601 static const WCHAR szUpgradeCode[] =
4602 {'U','p','g','r','a','d','e','C','o','d','e',0};
4604 remove = msi_dup_property(package, szRemove);
4605 if (!remove)
4606 return ERROR_SUCCESS;
4608 features = msi_split_string(remove, ',');
4609 if (!features)
4611 msi_free(remove);
4612 ERR("REMOVE feature list is empty!\n");
4613 return ERROR_FUNCTION_FAILED;
4616 if (!lstrcmpW(features[0], szAll))
4617 full_uninstall = TRUE;
4618 else
4620 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4622 if (feature->Action != INSTALLSTATE_ABSENT)
4623 full_uninstall = FALSE;
4627 if (!full_uninstall)
4628 goto done;
4630 MSIREG_DeleteProductKey(package->ProductCode);
4631 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4632 MSIREG_DeleteUninstallKey(package->ProductCode);
4634 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4636 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4637 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4639 else
4641 MSIREG_DeleteUserProductKey(package->ProductCode);
4642 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4645 upgrade = msi_dup_property(package, szUpgradeCode);
4646 if (upgrade)
4648 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4649 msi_free(upgrade);
4652 done:
4653 msi_free(remove);
4654 msi_free(features);
4655 return ERROR_SUCCESS;
4658 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4660 UINT rc;
4662 rc = msi_unpublish_product(package);
4663 if (rc != ERROR_SUCCESS)
4664 return rc;
4666 /* turn off scheduling */
4667 package->script->CurrentlyScripting= FALSE;
4669 /* first do the same as an InstallExecute */
4670 rc = ACTION_InstallExecute(package);
4671 if (rc != ERROR_SUCCESS)
4672 return rc;
4674 /* then handle Commit Actions */
4675 rc = execute_script(package,COMMIT_SCRIPT);
4677 return rc;
4680 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4682 static const WCHAR RunOnce[] = {
4683 'S','o','f','t','w','a','r','e','\\',
4684 'M','i','c','r','o','s','o','f','t','\\',
4685 'W','i','n','d','o','w','s','\\',
4686 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4687 'R','u','n','O','n','c','e',0};
4688 static const WCHAR InstallRunOnce[] = {
4689 'S','o','f','t','w','a','r','e','\\',
4690 'M','i','c','r','o','s','o','f','t','\\',
4691 'W','i','n','d','o','w','s','\\',
4692 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4693 'I','n','s','t','a','l','l','e','r','\\',
4694 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4696 static const WCHAR msiexec_fmt[] = {
4697 '%','s',
4698 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4699 '\"','%','s','\"',0};
4700 static const WCHAR install_fmt[] = {
4701 '/','I',' ','\"','%','s','\"',' ',
4702 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4703 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4704 WCHAR buffer[256], sysdir[MAX_PATH];
4705 HKEY hkey;
4706 WCHAR squished_pc[100];
4708 squash_guid(package->ProductCode,squished_pc);
4710 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4711 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4712 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4713 squished_pc);
4715 msi_reg_set_val_str( hkey, squished_pc, buffer );
4716 RegCloseKey(hkey);
4718 TRACE("Reboot command %s\n",debugstr_w(buffer));
4720 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4721 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4723 msi_reg_set_val_str( hkey, squished_pc, buffer );
4724 RegCloseKey(hkey);
4726 return ERROR_INSTALL_SUSPEND;
4729 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4731 DWORD attrib;
4732 UINT rc;
4735 * We are currently doing what should be done here in the top level Install
4736 * however for Administrative and uninstalls this step will be needed
4738 if (!package->PackagePath)
4739 return ERROR_SUCCESS;
4741 msi_set_sourcedir_props(package, TRUE);
4743 attrib = GetFileAttributesW(package->db->path);
4744 if (attrib == INVALID_FILE_ATTRIBUTES)
4746 LPWSTR prompt;
4747 LPWSTR msg;
4748 DWORD size = 0;
4750 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4751 package->Context, MSICODE_PRODUCT,
4752 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4753 if (rc == ERROR_MORE_DATA)
4755 prompt = msi_alloc(size * sizeof(WCHAR));
4756 MsiSourceListGetInfoW(package->ProductCode, NULL,
4757 package->Context, MSICODE_PRODUCT,
4758 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4760 else
4761 prompt = strdupW(package->db->path);
4763 msg = generate_error_string(package,1302,1,prompt);
4764 while(attrib == INVALID_FILE_ATTRIBUTES)
4766 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4767 if (rc == IDCANCEL)
4769 rc = ERROR_INSTALL_USEREXIT;
4770 break;
4772 attrib = GetFileAttributesW(package->db->path);
4774 msi_free(prompt);
4775 rc = ERROR_SUCCESS;
4777 else
4778 return ERROR_SUCCESS;
4780 return rc;
4783 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4785 HKEY hkey = 0;
4786 LPWSTR buffer, productid = NULL;
4787 UINT i, rc = ERROR_SUCCESS;
4788 MSIRECORD *uirow;
4790 static const WCHAR szPropKeys[][80] =
4792 {'P','r','o','d','u','c','t','I','D',0},
4793 {'U','S','E','R','N','A','M','E',0},
4794 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4795 {0},
4798 static const WCHAR szRegKeys[][80] =
4800 {'P','r','o','d','u','c','t','I','D',0},
4801 {'R','e','g','O','w','n','e','r',0},
4802 {'R','e','g','C','o','m','p','a','n','y',0},
4803 {0},
4806 if (msi_check_unpublish(package))
4808 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4809 goto end;
4812 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4813 if (!productid)
4814 goto end;
4816 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4817 NULL, &hkey, TRUE);
4818 if (rc != ERROR_SUCCESS)
4819 goto end;
4821 for( i = 0; szPropKeys[i][0]; i++ )
4823 buffer = msi_dup_property( package, szPropKeys[i] );
4824 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4825 msi_free( buffer );
4828 end:
4829 uirow = MSI_CreateRecord( 1 );
4830 MSI_RecordSetStringW( uirow, 1, productid );
4831 ui_actiondata( package, szRegisterUser, uirow );
4832 msiobj_release( &uirow->hdr );
4834 msi_free(productid);
4835 RegCloseKey(hkey);
4836 return rc;
4840 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4842 UINT rc;
4844 package->script->InWhatSequence |= SEQUENCE_EXEC;
4845 rc = ACTION_ProcessExecSequence(package,FALSE);
4846 return rc;
4850 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4852 MSIPACKAGE *package = param;
4853 LPCWSTR compgroupid, component, feature, qualifier, text;
4854 LPWSTR advertise = NULL, output = NULL;
4855 HKEY hkey = NULL;
4856 UINT rc;
4857 MSICOMPONENT *comp;
4858 MSIFEATURE *feat;
4859 DWORD sz;
4860 MSIRECORD *uirow;
4862 feature = MSI_RecordGetString(rec, 5);
4863 feat = get_loaded_feature(package, feature);
4864 if (!feat)
4865 return ERROR_SUCCESS;
4867 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4868 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4869 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
4871 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4872 feat->Action = feat->Installed;
4873 return ERROR_SUCCESS;
4876 component = MSI_RecordGetString(rec, 3);
4877 comp = get_loaded_component(package, component);
4878 if (!comp)
4879 return ERROR_SUCCESS;
4881 compgroupid = MSI_RecordGetString(rec,1);
4882 qualifier = MSI_RecordGetString(rec,2);
4884 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4885 if (rc != ERROR_SUCCESS)
4886 goto end;
4888 text = MSI_RecordGetString(rec,4);
4889 advertise = create_component_advertise_string(package, comp, feature);
4891 sz = strlenW(advertise);
4893 if (text)
4894 sz += lstrlenW(text);
4896 sz+=3;
4897 sz *= sizeof(WCHAR);
4899 output = msi_alloc_zero(sz);
4900 strcpyW(output,advertise);
4901 msi_free(advertise);
4903 if (text)
4904 strcatW(output,text);
4906 msi_reg_set_val_multi_str( hkey, qualifier, output );
4908 end:
4909 RegCloseKey(hkey);
4910 msi_free(output);
4912 /* the UI chunk */
4913 uirow = MSI_CreateRecord( 2 );
4914 MSI_RecordSetStringW( uirow, 1, compgroupid );
4915 MSI_RecordSetStringW( uirow, 2, qualifier);
4916 ui_actiondata( package, szPublishComponents, uirow);
4917 msiobj_release( &uirow->hdr );
4918 /* FIXME: call ui_progress? */
4920 return rc;
4924 * At present I am ignorning the advertised components part of this and only
4925 * focusing on the qualified component sets
4927 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4929 UINT rc;
4930 MSIQUERY * view;
4931 static const WCHAR ExecSeqQuery[] =
4932 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4933 '`','P','u','b','l','i','s','h',
4934 'C','o','m','p','o','n','e','n','t','`',0};
4936 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4937 if (rc != ERROR_SUCCESS)
4938 return ERROR_SUCCESS;
4940 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4941 msiobj_release(&view->hdr);
4943 return rc;
4946 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
4948 static const WCHAR szInstallerComponents[] = {
4949 'S','o','f','t','w','a','r','e','\\',
4950 'M','i','c','r','o','s','o','f','t','\\',
4951 'I','n','s','t','a','l','l','e','r','\\',
4952 'C','o','m','p','o','n','e','n','t','s','\\',0};
4954 MSIPACKAGE *package = param;
4955 LPCWSTR compgroupid, component, feature, qualifier;
4956 MSICOMPONENT *comp;
4957 MSIFEATURE *feat;
4958 MSIRECORD *uirow;
4959 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
4960 LONG res;
4962 feature = MSI_RecordGetString( rec, 5 );
4963 feat = get_loaded_feature( package, feature );
4964 if (!feat)
4965 return ERROR_SUCCESS;
4967 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
4969 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
4970 feat->Action = feat->Installed;
4971 return ERROR_SUCCESS;
4974 component = MSI_RecordGetString( rec, 3 );
4975 comp = get_loaded_component( package, component );
4976 if (!comp)
4977 return ERROR_SUCCESS;
4979 compgroupid = MSI_RecordGetString( rec, 1 );
4980 qualifier = MSI_RecordGetString( rec, 2 );
4982 squash_guid( compgroupid, squashed );
4983 strcpyW( keypath, szInstallerComponents );
4984 strcatW( keypath, squashed );
4986 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
4987 if (res != ERROR_SUCCESS)
4989 WARN("Unable to delete component key %d\n", res);
4992 uirow = MSI_CreateRecord( 2 );
4993 MSI_RecordSetStringW( uirow, 1, compgroupid );
4994 MSI_RecordSetStringW( uirow, 2, qualifier );
4995 ui_actiondata( package, szUnpublishComponents, uirow );
4996 msiobj_release( &uirow->hdr );
4998 return ERROR_SUCCESS;
5001 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5003 UINT rc;
5004 MSIQUERY *view;
5005 static const WCHAR query[] =
5006 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5007 '`','P','u','b','l','i','s','h',
5008 'C','o','m','p','o','n','e','n','t','`',0};
5010 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5011 if (rc != ERROR_SUCCESS)
5012 return ERROR_SUCCESS;
5014 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5015 msiobj_release( &view->hdr );
5017 return rc;
5020 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5022 MSIPACKAGE *package = param;
5023 MSIRECORD *row;
5024 MSIFILE *file;
5025 SC_HANDLE hscm, service = NULL;
5026 LPCWSTR comp, depends, pass;
5027 LPWSTR name = NULL, disp = NULL;
5028 LPCWSTR load_order, serv_name, key;
5029 DWORD serv_type, start_type;
5030 DWORD err_control;
5032 static const WCHAR query[] =
5033 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5034 '`','C','o','m','p','o','n','e','n','t','`',' ',
5035 'W','H','E','R','E',' ',
5036 '`','C','o','m','p','o','n','e','n','t','`',' ',
5037 '=','\'','%','s','\'',0};
5039 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5040 if (!hscm)
5042 ERR("Failed to open the SC Manager!\n");
5043 goto done;
5046 start_type = MSI_RecordGetInteger(rec, 5);
5047 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5048 goto done;
5050 depends = MSI_RecordGetString(rec, 8);
5051 if (depends && *depends)
5052 FIXME("Dependency list unhandled!\n");
5054 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5055 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5056 serv_type = MSI_RecordGetInteger(rec, 4);
5057 err_control = MSI_RecordGetInteger(rec, 6);
5058 load_order = MSI_RecordGetString(rec, 7);
5059 serv_name = MSI_RecordGetString(rec, 9);
5060 pass = MSI_RecordGetString(rec, 10);
5061 comp = MSI_RecordGetString(rec, 12);
5063 /* fetch the service path */
5064 row = MSI_QueryGetRecord(package->db, query, comp);
5065 if (!row)
5067 ERR("Control query failed!\n");
5068 goto done;
5071 key = MSI_RecordGetString(row, 6);
5073 file = get_loaded_file(package, key);
5074 msiobj_release(&row->hdr);
5075 if (!file)
5077 ERR("Failed to load the service file\n");
5078 goto done;
5081 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5082 start_type, err_control, file->TargetPath,
5083 load_order, NULL, NULL, serv_name, pass);
5084 if (!service)
5086 if (GetLastError() != ERROR_SERVICE_EXISTS)
5087 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5090 done:
5091 CloseServiceHandle(service);
5092 CloseServiceHandle(hscm);
5093 msi_free(name);
5094 msi_free(disp);
5096 return ERROR_SUCCESS;
5099 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5101 UINT rc;
5102 MSIQUERY * view;
5103 static const WCHAR ExecSeqQuery[] =
5104 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5105 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5107 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5108 if (rc != ERROR_SUCCESS)
5109 return ERROR_SUCCESS;
5111 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5112 msiobj_release(&view->hdr);
5114 return rc;
5117 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5118 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5120 LPCWSTR *vector, *temp_vector;
5121 LPWSTR p, q;
5122 DWORD sep_len;
5124 static const WCHAR separator[] = {'[','~',']',0};
5126 *numargs = 0;
5127 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5129 if (!args)
5130 return NULL;
5132 vector = msi_alloc(sizeof(LPWSTR));
5133 if (!vector)
5134 return NULL;
5136 p = args;
5139 (*numargs)++;
5140 vector[*numargs - 1] = p;
5142 if ((q = strstrW(p, separator)))
5144 *q = '\0';
5146 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5147 if (!temp_vector)
5149 msi_free(vector);
5150 return NULL;
5152 vector = temp_vector;
5154 p = q + sep_len;
5156 } while (q);
5158 return vector;
5161 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5163 MSIPACKAGE *package = param;
5164 MSICOMPONENT *comp;
5165 SC_HANDLE scm = NULL, service = NULL;
5166 LPCWSTR component, *vector = NULL;
5167 LPWSTR name, args;
5168 DWORD event, numargs;
5169 UINT r = ERROR_FUNCTION_FAILED;
5171 component = MSI_RecordGetString(rec, 6);
5172 comp = get_loaded_component(package, component);
5173 if (!comp)
5174 return ERROR_SUCCESS;
5176 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5178 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5179 comp->Action = comp->Installed;
5180 return ERROR_SUCCESS;
5182 comp->Action = INSTALLSTATE_LOCAL;
5184 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5185 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5186 event = MSI_RecordGetInteger(rec, 3);
5188 if (!(event & msidbServiceControlEventStart))
5190 r = ERROR_SUCCESS;
5191 goto done;
5194 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5195 if (!scm)
5197 ERR("Failed to open the service control manager\n");
5198 goto done;
5201 service = OpenServiceW(scm, name, SERVICE_START);
5202 if (!service)
5204 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5205 goto done;
5208 vector = msi_service_args_to_vector(args, &numargs);
5210 if (!StartServiceW(service, numargs, vector) &&
5211 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5213 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5214 goto done;
5217 r = ERROR_SUCCESS;
5219 done:
5220 CloseServiceHandle(service);
5221 CloseServiceHandle(scm);
5223 msi_free(name);
5224 msi_free(args);
5225 msi_free(vector);
5226 return r;
5229 static UINT ACTION_StartServices( MSIPACKAGE *package )
5231 UINT rc;
5232 MSIQUERY *view;
5234 static const WCHAR query[] = {
5235 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5236 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5238 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5239 if (rc != ERROR_SUCCESS)
5240 return ERROR_SUCCESS;
5242 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5243 msiobj_release(&view->hdr);
5245 return rc;
5248 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5250 DWORD i, needed, count;
5251 ENUM_SERVICE_STATUSW *dependencies;
5252 SERVICE_STATUS ss;
5253 SC_HANDLE depserv;
5255 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5256 0, &needed, &count))
5257 return TRUE;
5259 if (GetLastError() != ERROR_MORE_DATA)
5260 return FALSE;
5262 dependencies = msi_alloc(needed);
5263 if (!dependencies)
5264 return FALSE;
5266 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5267 needed, &needed, &count))
5268 goto error;
5270 for (i = 0; i < count; i++)
5272 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5273 SERVICE_STOP | SERVICE_QUERY_STATUS);
5274 if (!depserv)
5275 goto error;
5277 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5278 goto error;
5281 return TRUE;
5283 error:
5284 msi_free(dependencies);
5285 return FALSE;
5288 static UINT stop_service( LPCWSTR name )
5290 SC_HANDLE scm = NULL, service = NULL;
5291 SERVICE_STATUS status;
5292 SERVICE_STATUS_PROCESS ssp;
5293 DWORD needed;
5295 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5296 if (!scm)
5298 WARN("Failed to open the SCM: %d\n", GetLastError());
5299 goto done;
5302 service = OpenServiceW(scm, name,
5303 SERVICE_STOP |
5304 SERVICE_QUERY_STATUS |
5305 SERVICE_ENUMERATE_DEPENDENTS);
5306 if (!service)
5308 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5309 goto done;
5312 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5313 sizeof(SERVICE_STATUS_PROCESS), &needed))
5315 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5316 goto done;
5319 if (ssp.dwCurrentState == SERVICE_STOPPED)
5320 goto done;
5322 stop_service_dependents(scm, service);
5324 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5325 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5327 done:
5328 CloseServiceHandle(service);
5329 CloseServiceHandle(scm);
5331 return ERROR_SUCCESS;
5334 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5336 MSIPACKAGE *package = param;
5337 MSICOMPONENT *comp;
5338 LPCWSTR component;
5339 LPWSTR name;
5340 DWORD event;
5342 event = MSI_RecordGetInteger( rec, 3 );
5343 if (!(event & msidbServiceControlEventStop))
5344 return ERROR_SUCCESS;
5346 component = MSI_RecordGetString( rec, 6 );
5347 comp = get_loaded_component( package, component );
5348 if (!comp)
5349 return ERROR_SUCCESS;
5351 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5353 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5354 comp->Action = comp->Installed;
5355 return ERROR_SUCCESS;
5357 comp->Action = INSTALLSTATE_ABSENT;
5359 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5360 stop_service( name );
5361 msi_free( name );
5363 return ERROR_SUCCESS;
5366 static UINT ACTION_StopServices( MSIPACKAGE *package )
5368 UINT rc;
5369 MSIQUERY *view;
5371 static const WCHAR query[] = {
5372 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5373 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5375 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5376 if (rc != ERROR_SUCCESS)
5377 return ERROR_SUCCESS;
5379 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5380 msiobj_release(&view->hdr);
5382 return rc;
5385 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5387 MSIPACKAGE *package = param;
5388 MSICOMPONENT *comp;
5389 MSIRECORD *uirow;
5390 LPCWSTR component;
5391 LPWSTR name = NULL, display_name = NULL;
5392 DWORD event, len;
5393 SC_HANDLE scm = NULL, service = NULL;
5395 event = MSI_RecordGetInteger( rec, 3 );
5396 if (!(event & msidbServiceControlEventDelete))
5397 return ERROR_SUCCESS;
5399 component = MSI_RecordGetString(rec, 6);
5400 comp = get_loaded_component(package, component);
5401 if (!comp)
5402 return ERROR_SUCCESS;
5404 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5406 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5407 comp->Action = comp->Installed;
5408 return ERROR_SUCCESS;
5410 comp->Action = INSTALLSTATE_ABSENT;
5412 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5413 stop_service( name );
5415 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5416 if (!scm)
5418 WARN("Failed to open the SCM: %d\n", GetLastError());
5419 goto done;
5422 len = 0;
5423 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5424 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5426 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5427 GetServiceDisplayNameW( scm, name, display_name, &len );
5430 service = OpenServiceW( scm, name, DELETE );
5431 if (!service)
5433 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5434 goto done;
5437 if (!DeleteService( service ))
5438 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5440 done:
5441 uirow = MSI_CreateRecord( 2 );
5442 MSI_RecordSetStringW( uirow, 1, display_name );
5443 MSI_RecordSetStringW( uirow, 2, name );
5444 ui_actiondata( package, szDeleteServices, uirow );
5445 msiobj_release( &uirow->hdr );
5447 CloseServiceHandle( service );
5448 CloseServiceHandle( scm );
5449 msi_free( name );
5450 msi_free( display_name );
5452 return ERROR_SUCCESS;
5455 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5457 UINT rc;
5458 MSIQUERY *view;
5460 static const WCHAR query[] = {
5461 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5462 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5464 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5465 if (rc != ERROR_SUCCESS)
5466 return ERROR_SUCCESS;
5468 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5469 msiobj_release( &view->hdr );
5471 return rc;
5474 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5476 MSIFILE *file;
5478 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5480 if (!lstrcmpW(file->File, filename))
5481 return file;
5484 return NULL;
5487 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5489 MSIPACKAGE *package = param;
5490 LPWSTR driver, driver_path, ptr;
5491 WCHAR outpath[MAX_PATH];
5492 MSIFILE *driver_file, *setup_file;
5493 MSIRECORD *uirow;
5494 LPCWSTR desc;
5495 DWORD len, usage;
5496 UINT r = ERROR_SUCCESS;
5498 static const WCHAR driver_fmt[] = {
5499 'D','r','i','v','e','r','=','%','s',0};
5500 static const WCHAR setup_fmt[] = {
5501 'S','e','t','u','p','=','%','s',0};
5502 static const WCHAR usage_fmt[] = {
5503 'F','i','l','e','U','s','a','g','e','=','1',0};
5505 desc = MSI_RecordGetString(rec, 3);
5507 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5508 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5510 if (!driver_file)
5512 ERR("ODBC Driver entry not found!\n");
5513 return ERROR_FUNCTION_FAILED;
5516 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5517 if (setup_file)
5518 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5519 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5521 driver = msi_alloc(len * sizeof(WCHAR));
5522 if (!driver)
5523 return ERROR_OUTOFMEMORY;
5525 ptr = driver;
5526 lstrcpyW(ptr, desc);
5527 ptr += lstrlenW(ptr) + 1;
5529 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5530 ptr += len + 1;
5532 if (setup_file)
5534 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5535 ptr += len + 1;
5538 lstrcpyW(ptr, usage_fmt);
5539 ptr += lstrlenW(ptr) + 1;
5540 *ptr = '\0';
5542 driver_path = strdupW(driver_file->TargetPath);
5543 ptr = strrchrW(driver_path, '\\');
5544 if (ptr) *ptr = '\0';
5546 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5547 NULL, ODBC_INSTALL_COMPLETE, &usage))
5549 ERR("Failed to install SQL driver!\n");
5550 r = ERROR_FUNCTION_FAILED;
5553 uirow = MSI_CreateRecord( 5 );
5554 MSI_RecordSetStringW( uirow, 1, desc );
5555 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5556 MSI_RecordSetStringW( uirow, 3, driver_path );
5557 ui_actiondata( package, szInstallODBC, uirow );
5558 msiobj_release( &uirow->hdr );
5560 msi_free(driver);
5561 msi_free(driver_path);
5563 return r;
5566 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5568 MSIPACKAGE *package = param;
5569 LPWSTR translator, translator_path, ptr;
5570 WCHAR outpath[MAX_PATH];
5571 MSIFILE *translator_file, *setup_file;
5572 MSIRECORD *uirow;
5573 LPCWSTR desc;
5574 DWORD len, usage;
5575 UINT r = ERROR_SUCCESS;
5577 static const WCHAR translator_fmt[] = {
5578 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5579 static const WCHAR setup_fmt[] = {
5580 'S','e','t','u','p','=','%','s',0};
5582 desc = MSI_RecordGetString(rec, 3);
5584 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5585 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5587 if (!translator_file)
5589 ERR("ODBC Translator entry not found!\n");
5590 return ERROR_FUNCTION_FAILED;
5593 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5594 if (setup_file)
5595 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5597 translator = msi_alloc(len * sizeof(WCHAR));
5598 if (!translator)
5599 return ERROR_OUTOFMEMORY;
5601 ptr = translator;
5602 lstrcpyW(ptr, desc);
5603 ptr += lstrlenW(ptr) + 1;
5605 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5606 ptr += len + 1;
5608 if (setup_file)
5610 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5611 ptr += len + 1;
5613 *ptr = '\0';
5615 translator_path = strdupW(translator_file->TargetPath);
5616 ptr = strrchrW(translator_path, '\\');
5617 if (ptr) *ptr = '\0';
5619 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5620 NULL, ODBC_INSTALL_COMPLETE, &usage))
5622 ERR("Failed to install SQL translator!\n");
5623 r = ERROR_FUNCTION_FAILED;
5626 uirow = MSI_CreateRecord( 5 );
5627 MSI_RecordSetStringW( uirow, 1, desc );
5628 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5629 MSI_RecordSetStringW( uirow, 3, translator_path );
5630 ui_actiondata( package, szInstallODBC, uirow );
5631 msiobj_release( &uirow->hdr );
5633 msi_free(translator);
5634 msi_free(translator_path);
5636 return r;
5639 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5641 MSIPACKAGE *package = param;
5642 LPWSTR attrs;
5643 LPCWSTR desc, driver;
5644 WORD request = ODBC_ADD_SYS_DSN;
5645 INT registration;
5646 DWORD len;
5647 UINT r = ERROR_SUCCESS;
5648 MSIRECORD *uirow;
5650 static const WCHAR attrs_fmt[] = {
5651 'D','S','N','=','%','s',0 };
5653 desc = MSI_RecordGetString(rec, 3);
5654 driver = MSI_RecordGetString(rec, 4);
5655 registration = MSI_RecordGetInteger(rec, 5);
5657 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5658 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5660 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5661 attrs = msi_alloc(len * sizeof(WCHAR));
5662 if (!attrs)
5663 return ERROR_OUTOFMEMORY;
5665 len = sprintfW(attrs, attrs_fmt, desc);
5666 attrs[len + 1] = 0;
5668 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5670 ERR("Failed to install SQL data source!\n");
5671 r = ERROR_FUNCTION_FAILED;
5674 uirow = MSI_CreateRecord( 5 );
5675 MSI_RecordSetStringW( uirow, 1, desc );
5676 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5677 MSI_RecordSetInteger( uirow, 3, request );
5678 ui_actiondata( package, szInstallODBC, uirow );
5679 msiobj_release( &uirow->hdr );
5681 msi_free(attrs);
5683 return r;
5686 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5688 UINT rc;
5689 MSIQUERY *view;
5691 static const WCHAR driver_query[] = {
5692 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5693 'O','D','B','C','D','r','i','v','e','r',0 };
5695 static const WCHAR translator_query[] = {
5696 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5697 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5699 static const WCHAR source_query[] = {
5700 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5701 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5703 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5704 if (rc != ERROR_SUCCESS)
5705 return ERROR_SUCCESS;
5707 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5708 msiobj_release(&view->hdr);
5710 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5711 if (rc != ERROR_SUCCESS)
5712 return ERROR_SUCCESS;
5714 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5715 msiobj_release(&view->hdr);
5717 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5718 if (rc != ERROR_SUCCESS)
5719 return ERROR_SUCCESS;
5721 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5722 msiobj_release(&view->hdr);
5724 return rc;
5727 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5729 MSIPACKAGE *package = param;
5730 MSIRECORD *uirow;
5731 DWORD usage;
5732 LPCWSTR desc;
5734 desc = MSI_RecordGetString( rec, 3 );
5735 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5737 WARN("Failed to remove ODBC driver\n");
5739 else if (!usage)
5741 FIXME("Usage count reached 0\n");
5744 uirow = MSI_CreateRecord( 2 );
5745 MSI_RecordSetStringW( uirow, 1, desc );
5746 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5747 ui_actiondata( package, szRemoveODBC, uirow );
5748 msiobj_release( &uirow->hdr );
5750 return ERROR_SUCCESS;
5753 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5755 MSIPACKAGE *package = param;
5756 MSIRECORD *uirow;
5757 DWORD usage;
5758 LPCWSTR desc;
5760 desc = MSI_RecordGetString( rec, 3 );
5761 if (!SQLRemoveTranslatorW( desc, &usage ))
5763 WARN("Failed to remove ODBC translator\n");
5765 else if (!usage)
5767 FIXME("Usage count reached 0\n");
5770 uirow = MSI_CreateRecord( 2 );
5771 MSI_RecordSetStringW( uirow, 1, desc );
5772 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5773 ui_actiondata( package, szRemoveODBC, uirow );
5774 msiobj_release( &uirow->hdr );
5776 return ERROR_SUCCESS;
5779 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5781 MSIPACKAGE *package = param;
5782 MSIRECORD *uirow;
5783 LPWSTR attrs;
5784 LPCWSTR desc, driver;
5785 WORD request = ODBC_REMOVE_SYS_DSN;
5786 INT registration;
5787 DWORD len;
5789 static const WCHAR attrs_fmt[] = {
5790 'D','S','N','=','%','s',0 };
5792 desc = MSI_RecordGetString( rec, 3 );
5793 driver = MSI_RecordGetString( rec, 4 );
5794 registration = MSI_RecordGetInteger( rec, 5 );
5796 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5797 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5799 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
5800 attrs = msi_alloc( len * sizeof(WCHAR) );
5801 if (!attrs)
5802 return ERROR_OUTOFMEMORY;
5804 FIXME("Use ODBCSourceAttribute table\n");
5806 len = sprintfW( attrs, attrs_fmt, desc );
5807 attrs[len + 1] = 0;
5809 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5811 WARN("Failed to remove ODBC data source\n");
5813 msi_free( attrs );
5815 uirow = MSI_CreateRecord( 3 );
5816 MSI_RecordSetStringW( uirow, 1, desc );
5817 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5818 MSI_RecordSetInteger( uirow, 3, request );
5819 ui_actiondata( package, szRemoveODBC, uirow );
5820 msiobj_release( &uirow->hdr );
5822 return ERROR_SUCCESS;
5825 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5827 UINT rc;
5828 MSIQUERY *view;
5830 static const WCHAR driver_query[] = {
5831 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5832 'O','D','B','C','D','r','i','v','e','r',0 };
5834 static const WCHAR translator_query[] = {
5835 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5836 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5838 static const WCHAR source_query[] = {
5839 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5840 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5842 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5843 if (rc != ERROR_SUCCESS)
5844 return ERROR_SUCCESS;
5846 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5847 msiobj_release( &view->hdr );
5849 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5850 if (rc != ERROR_SUCCESS)
5851 return ERROR_SUCCESS;
5853 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5854 msiobj_release( &view->hdr );
5856 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5857 if (rc != ERROR_SUCCESS)
5858 return ERROR_SUCCESS;
5860 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5861 msiobj_release( &view->hdr );
5863 return rc;
5866 #define ENV_ACT_SETALWAYS 0x1
5867 #define ENV_ACT_SETABSENT 0x2
5868 #define ENV_ACT_REMOVE 0x4
5869 #define ENV_ACT_REMOVEMATCH 0x8
5871 #define ENV_MOD_MACHINE 0x20000000
5872 #define ENV_MOD_APPEND 0x40000000
5873 #define ENV_MOD_PREFIX 0x80000000
5874 #define ENV_MOD_MASK 0xC0000000
5876 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5878 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5880 LPCWSTR cptr = *name;
5882 static const WCHAR prefix[] = {'[','~',']',0};
5883 static const int prefix_len = 3;
5885 *flags = 0;
5886 while (*cptr)
5888 if (*cptr == '=')
5889 *flags |= ENV_ACT_SETALWAYS;
5890 else if (*cptr == '+')
5891 *flags |= ENV_ACT_SETABSENT;
5892 else if (*cptr == '-')
5893 *flags |= ENV_ACT_REMOVE;
5894 else if (*cptr == '!')
5895 *flags |= ENV_ACT_REMOVEMATCH;
5896 else if (*cptr == '*')
5897 *flags |= ENV_MOD_MACHINE;
5898 else
5899 break;
5901 cptr++;
5902 (*name)++;
5905 if (!*cptr)
5907 ERR("Missing environment variable\n");
5908 return ERROR_FUNCTION_FAILED;
5911 if (*value)
5913 LPCWSTR ptr = *value;
5914 if (!strncmpW(ptr, prefix, prefix_len))
5916 if (ptr[prefix_len] == szSemiColon[0])
5918 *flags |= ENV_MOD_APPEND;
5919 *value += lstrlenW(prefix);
5921 else
5923 *value = NULL;
5926 else if (lstrlenW(*value) >= prefix_len)
5928 ptr += lstrlenW(ptr) - prefix_len;
5929 if (!lstrcmpW(ptr, prefix))
5931 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5933 *flags |= ENV_MOD_PREFIX;
5934 /* the "[~]" will be removed by deformat_string */;
5936 else
5938 *value = NULL;
5944 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5945 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5946 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5947 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5949 ERR("Invalid flags: %08x\n", *flags);
5950 return ERROR_FUNCTION_FAILED;
5953 if (!*flags)
5954 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5956 return ERROR_SUCCESS;
5959 static UINT open_env_key( DWORD flags, HKEY *key )
5961 static const WCHAR user_env[] =
5962 {'E','n','v','i','r','o','n','m','e','n','t',0};
5963 static const WCHAR machine_env[] =
5964 {'S','y','s','t','e','m','\\',
5965 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5966 'C','o','n','t','r','o','l','\\',
5967 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5968 'E','n','v','i','r','o','n','m','e','n','t',0};
5969 const WCHAR *env;
5970 HKEY root;
5971 LONG res;
5973 if (flags & ENV_MOD_MACHINE)
5975 env = machine_env;
5976 root = HKEY_LOCAL_MACHINE;
5978 else
5980 env = user_env;
5981 root = HKEY_CURRENT_USER;
5984 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
5985 if (res != ERROR_SUCCESS)
5987 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
5988 return ERROR_FUNCTION_FAILED;
5991 return ERROR_SUCCESS;
5994 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5996 MSIPACKAGE *package = param;
5997 LPCWSTR name, value, component;
5998 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
5999 DWORD flags, type, size;
6000 UINT res;
6001 HKEY env = NULL;
6002 MSICOMPONENT *comp;
6003 MSIRECORD *uirow;
6004 int action = 0;
6006 component = MSI_RecordGetString(rec, 4);
6007 comp = get_loaded_component(package, component);
6008 if (!comp)
6009 return ERROR_SUCCESS;
6011 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6013 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6014 comp->Action = comp->Installed;
6015 return ERROR_SUCCESS;
6017 comp->Action = INSTALLSTATE_LOCAL;
6019 name = MSI_RecordGetString(rec, 2);
6020 value = MSI_RecordGetString(rec, 3);
6022 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6024 res = env_parse_flags(&name, &value, &flags);
6025 if (res != ERROR_SUCCESS || !value)
6026 goto done;
6028 if (value && !deformat_string(package, value, &deformatted))
6030 res = ERROR_OUTOFMEMORY;
6031 goto done;
6034 value = deformatted;
6036 res = open_env_key( flags, &env );
6037 if (res != ERROR_SUCCESS)
6038 goto done;
6040 if (flags & ENV_MOD_MACHINE)
6041 action |= 0x20000000;
6043 size = 0;
6044 type = REG_SZ;
6045 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6046 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6047 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6048 goto done;
6050 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6052 action = 0x2;
6054 /* Nothing to do. */
6055 if (!value)
6057 res = ERROR_SUCCESS;
6058 goto done;
6061 /* If we are appending but the string was empty, strip ; */
6062 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6064 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6065 newval = strdupW(value);
6066 if (!newval)
6068 res = ERROR_OUTOFMEMORY;
6069 goto done;
6072 else
6074 action = 0x1;
6076 /* Contrary to MSDN, +-variable to [~];path works */
6077 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6079 res = ERROR_SUCCESS;
6080 goto done;
6083 data = msi_alloc(size);
6084 if (!data)
6086 RegCloseKey(env);
6087 return ERROR_OUTOFMEMORY;
6090 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6091 if (res != ERROR_SUCCESS)
6092 goto done;
6094 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6096 action = 0x4;
6097 res = RegDeleteValueW(env, name);
6098 if (res != ERROR_SUCCESS)
6099 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6100 goto done;
6103 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6104 if (flags & ENV_MOD_MASK)
6106 DWORD mod_size;
6107 int multiplier = 0;
6108 if (flags & ENV_MOD_APPEND) multiplier++;
6109 if (flags & ENV_MOD_PREFIX) multiplier++;
6110 mod_size = lstrlenW(value) * multiplier;
6111 size += mod_size * sizeof(WCHAR);
6114 newval = msi_alloc(size);
6115 ptr = newval;
6116 if (!newval)
6118 res = ERROR_OUTOFMEMORY;
6119 goto done;
6122 if (flags & ENV_MOD_PREFIX)
6124 lstrcpyW(newval, value);
6125 ptr = newval + lstrlenW(value);
6126 action |= 0x80000000;
6129 lstrcpyW(ptr, data);
6131 if (flags & ENV_MOD_APPEND)
6133 lstrcatW(newval, value);
6134 action |= 0x40000000;
6137 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6138 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6139 if (res)
6141 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6144 done:
6145 uirow = MSI_CreateRecord( 3 );
6146 MSI_RecordSetStringW( uirow, 1, name );
6147 MSI_RecordSetStringW( uirow, 2, newval );
6148 MSI_RecordSetInteger( uirow, 3, action );
6149 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6150 msiobj_release( &uirow->hdr );
6152 if (env) RegCloseKey(env);
6153 msi_free(deformatted);
6154 msi_free(data);
6155 msi_free(newval);
6156 return res;
6159 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6161 UINT rc;
6162 MSIQUERY * view;
6163 static const WCHAR ExecSeqQuery[] =
6164 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6165 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6166 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6167 if (rc != ERROR_SUCCESS)
6168 return ERROR_SUCCESS;
6170 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6171 msiobj_release(&view->hdr);
6173 return rc;
6176 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6178 MSIPACKAGE *package = param;
6179 LPCWSTR name, value, component;
6180 LPWSTR deformatted = NULL;
6181 DWORD flags;
6182 HKEY env;
6183 MSICOMPONENT *comp;
6184 MSIRECORD *uirow;
6185 int action = 0;
6186 LONG res;
6187 UINT r;
6189 component = MSI_RecordGetString( rec, 4 );
6190 comp = get_loaded_component( package, component );
6191 if (!comp)
6192 return ERROR_SUCCESS;
6194 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6196 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6197 comp->Action = comp->Installed;
6198 return ERROR_SUCCESS;
6200 comp->Action = INSTALLSTATE_ABSENT;
6202 name = MSI_RecordGetString( rec, 2 );
6203 value = MSI_RecordGetString( rec, 3 );
6205 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6207 r = env_parse_flags( &name, &value, &flags );
6208 if (r != ERROR_SUCCESS)
6209 return r;
6211 if (!(flags & ENV_ACT_REMOVE))
6213 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6214 return ERROR_SUCCESS;
6217 if (value && !deformat_string( package, value, &deformatted ))
6218 return ERROR_OUTOFMEMORY;
6220 value = deformatted;
6222 r = open_env_key( flags, &env );
6223 if (r != ERROR_SUCCESS)
6225 r = ERROR_SUCCESS;
6226 goto done;
6229 if (flags & ENV_MOD_MACHINE)
6230 action |= 0x20000000;
6232 TRACE("Removing %s\n", debugstr_w(name));
6234 res = RegDeleteValueW( env, name );
6235 if (res != ERROR_SUCCESS)
6237 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6238 r = ERROR_SUCCESS;
6241 done:
6242 uirow = MSI_CreateRecord( 3 );
6243 MSI_RecordSetStringW( uirow, 1, name );
6244 MSI_RecordSetStringW( uirow, 2, value );
6245 MSI_RecordSetInteger( uirow, 3, action );
6246 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6247 msiobj_release( &uirow->hdr );
6249 if (env) RegCloseKey( env );
6250 msi_free( deformatted );
6251 return r;
6254 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6256 UINT rc;
6257 MSIQUERY *view;
6258 static const WCHAR query[] =
6259 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6260 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6262 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6263 if (rc != ERROR_SUCCESS)
6264 return ERROR_SUCCESS;
6266 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6267 msiobj_release( &view->hdr );
6269 return rc;
6272 typedef struct tagMSIASSEMBLY
6274 struct list entry;
6275 MSICOMPONENT *component;
6276 MSIFEATURE *feature;
6277 MSIFILE *file;
6278 LPWSTR manifest;
6279 LPWSTR application;
6280 LPWSTR display_name;
6281 DWORD attributes;
6282 BOOL installed;
6283 } MSIASSEMBLY;
6285 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6286 DWORD dwReserved);
6287 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6288 LPVOID pvReserved, HMODULE *phModDll);
6290 static BOOL init_functionpointers(void)
6292 HRESULT hr;
6293 HMODULE hfusion;
6294 HMODULE hmscoree;
6296 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6298 hmscoree = LoadLibraryA("mscoree.dll");
6299 if (!hmscoree)
6301 WARN("mscoree.dll not available\n");
6302 return FALSE;
6305 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6306 if (!pLoadLibraryShim)
6308 WARN("LoadLibraryShim not available\n");
6309 FreeLibrary(hmscoree);
6310 return FALSE;
6313 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6314 if (FAILED(hr))
6316 WARN("fusion.dll not available\n");
6317 FreeLibrary(hmscoree);
6318 return FALSE;
6321 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6323 FreeLibrary(hmscoree);
6324 return TRUE;
6327 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6328 LPWSTR path)
6330 IAssemblyCache *cache;
6331 MSIRECORD *uirow;
6332 HRESULT hr;
6333 UINT r = ERROR_FUNCTION_FAILED;
6335 TRACE("installing assembly: %s\n", debugstr_w(path));
6337 uirow = MSI_CreateRecord( 2 );
6338 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6339 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6340 msiobj_release( &uirow->hdr );
6342 if (assembly->feature)
6343 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6345 if (assembly->manifest)
6346 FIXME("Manifest unhandled\n");
6348 if (assembly->application)
6350 FIXME("Assembly should be privately installed\n");
6351 return ERROR_SUCCESS;
6354 if (assembly->attributes == msidbAssemblyAttributesWin32)
6356 FIXME("Win32 assemblies not handled\n");
6357 return ERROR_SUCCESS;
6360 hr = pCreateAssemblyCache(&cache, 0);
6361 if (FAILED(hr))
6362 goto done;
6364 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6365 if (FAILED(hr))
6366 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6368 r = ERROR_SUCCESS;
6370 done:
6371 IAssemblyCache_Release(cache);
6372 return r;
6375 typedef struct tagASSEMBLY_LIST
6377 MSIPACKAGE *package;
6378 IAssemblyCache *cache;
6379 struct list *assemblies;
6380 } ASSEMBLY_LIST;
6382 typedef struct tagASSEMBLY_NAME
6384 LPWSTR name;
6385 LPWSTR version;
6386 LPWSTR culture;
6387 LPWSTR pubkeytoken;
6388 } ASSEMBLY_NAME;
6390 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6392 ASSEMBLY_NAME *asmname = param;
6393 LPCWSTR name = MSI_RecordGetString(rec, 2);
6394 LPWSTR val = msi_dup_record_field(rec, 3);
6396 static const WCHAR Name[] = {'N','a','m','e',0};
6397 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6398 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6399 static const WCHAR PublicKeyToken[] = {
6400 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6402 if (!strcmpiW(name, Name))
6403 asmname->name = val;
6404 else if (!strcmpiW(name, Version))
6405 asmname->version = val;
6406 else if (!strcmpiW(name, Culture))
6407 asmname->culture = val;
6408 else if (!strcmpiW(name, PublicKeyToken))
6409 asmname->pubkeytoken = val;
6410 else
6411 msi_free(val);
6413 return ERROR_SUCCESS;
6416 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6418 if (!*str)
6420 *size = lstrlenW(append) + 1;
6421 *str = msi_alloc((*size) * sizeof(WCHAR));
6422 lstrcpyW(*str, append);
6423 return;
6426 (*size) += lstrlenW(append);
6427 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6428 lstrcatW(*str, append);
6431 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6433 static const WCHAR separator[] = {',',' ',0};
6434 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6435 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6436 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6437 static const WCHAR query[] = {
6438 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6439 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6440 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6441 '=','\'','%','s','\'',0};
6442 ASSEMBLY_NAME name;
6443 MSIQUERY *view;
6444 LPWSTR display_name;
6445 DWORD size;
6446 UINT r;
6448 display_name = NULL;
6449 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6451 r = MSI_OpenQuery( db, &view, query, comp->Component );
6452 if (r != ERROR_SUCCESS)
6453 return NULL;
6455 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6456 msiobj_release( &view->hdr );
6458 if (!name.name)
6460 ERR("No assembly name specified!\n");
6461 return NULL;
6464 append_str( &display_name, &size, name.name );
6466 if (name.version)
6468 append_str( &display_name, &size, separator );
6469 append_str( &display_name, &size, Version );
6470 append_str( &display_name, &size, name.version );
6472 if (name.culture)
6474 append_str( &display_name, &size, separator );
6475 append_str( &display_name, &size, Culture );
6476 append_str( &display_name, &size, name.culture );
6478 if (name.pubkeytoken)
6480 append_str( &display_name, &size, separator );
6481 append_str( &display_name, &size, PublicKeyToken );
6482 append_str( &display_name, &size, name.pubkeytoken );
6485 msi_free( name.name );
6486 msi_free( name.version );
6487 msi_free( name.culture );
6488 msi_free( name.pubkeytoken );
6490 return display_name;
6493 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6495 ASSEMBLY_INFO asminfo;
6496 LPWSTR disp;
6497 BOOL found = FALSE;
6498 HRESULT hr;
6500 disp = get_assembly_display_name( db, comp );
6501 if (!disp)
6502 return FALSE;
6504 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6505 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6507 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6508 if (SUCCEEDED(hr))
6509 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6511 msi_free( disp );
6512 return found;
6515 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6517 ASSEMBLY_LIST *list = param;
6518 MSIASSEMBLY *assembly;
6519 LPCWSTR component;
6521 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6522 if (!assembly)
6523 return ERROR_OUTOFMEMORY;
6525 component = MSI_RecordGetString(rec, 1);
6526 assembly->component = get_loaded_component(list->package, component);
6527 if (!assembly->component)
6528 return ERROR_SUCCESS;
6530 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6531 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6533 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6534 assembly->component->Action = assembly->component->Installed;
6535 return ERROR_SUCCESS;
6537 assembly->component->Action = assembly->component->ActionRequest;
6539 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6540 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6542 if (!assembly->file)
6544 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6545 return ERROR_FUNCTION_FAILED;
6548 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6549 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6550 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6552 if (assembly->application)
6554 WCHAR version[24];
6555 DWORD size = sizeof(version)/sizeof(WCHAR);
6557 /* FIXME: we should probably check the manifest file here */
6559 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6560 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6562 assembly->installed = TRUE;
6565 else
6566 assembly->installed = check_assembly_installed(list->package->db,
6567 list->cache,
6568 assembly->component);
6570 list_add_head(list->assemblies, &assembly->entry);
6571 return ERROR_SUCCESS;
6574 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6576 IAssemblyCache *cache = NULL;
6577 ASSEMBLY_LIST list;
6578 MSIQUERY *view;
6579 HRESULT hr;
6580 UINT r;
6582 static const WCHAR query[] =
6583 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6584 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6586 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6587 if (r != ERROR_SUCCESS)
6588 return ERROR_SUCCESS;
6590 hr = pCreateAssemblyCache(&cache, 0);
6591 if (FAILED(hr))
6592 return ERROR_FUNCTION_FAILED;
6594 list.package = package;
6595 list.cache = cache;
6596 list.assemblies = assemblies;
6598 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6599 msiobj_release(&view->hdr);
6601 IAssemblyCache_Release(cache);
6603 return r;
6606 static void free_assemblies(struct list *assemblies)
6608 struct list *item, *cursor;
6610 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6612 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6614 list_remove(&assembly->entry);
6615 msi_free(assembly->application);
6616 msi_free(assembly->manifest);
6617 msi_free(assembly->display_name);
6618 msi_free(assembly);
6622 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6624 MSIASSEMBLY *assembly;
6626 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6628 if (!lstrcmpW(assembly->file->File, file))
6630 *out = assembly;
6631 return TRUE;
6635 return FALSE;
6638 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6639 LPWSTR *path, DWORD *attrs, PVOID user)
6641 MSIASSEMBLY *assembly;
6642 WCHAR temppath[MAX_PATH];
6643 struct list *assemblies = user;
6644 UINT r;
6646 if (!find_assembly(assemblies, file, &assembly))
6647 return FALSE;
6649 GetTempPathW(MAX_PATH, temppath);
6650 PathAddBackslashW(temppath);
6651 lstrcatW(temppath, assembly->file->FileName);
6653 if (action == MSICABEXTRACT_BEGINEXTRACT)
6655 if (assembly->installed)
6656 return FALSE;
6658 *path = strdupW(temppath);
6659 *attrs = assembly->file->Attributes;
6661 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6663 assembly->installed = TRUE;
6665 r = install_assembly(package, assembly, temppath);
6666 if (r != ERROR_SUCCESS)
6667 ERR("Failed to install assembly\n");
6670 return TRUE;
6673 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6675 UINT r;
6676 struct list assemblies = LIST_INIT(assemblies);
6677 MSIASSEMBLY *assembly;
6678 MSIMEDIAINFO *mi;
6680 if (!init_functionpointers() || !pCreateAssemblyCache)
6681 return ERROR_FUNCTION_FAILED;
6683 r = load_assemblies(package, &assemblies);
6684 if (r != ERROR_SUCCESS)
6685 goto done;
6687 if (list_empty(&assemblies))
6688 goto done;
6690 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6691 if (!mi)
6693 r = ERROR_OUTOFMEMORY;
6694 goto done;
6697 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6699 if (assembly->installed && !mi->is_continuous)
6700 continue;
6702 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6703 (assembly->file->IsCompressed && !mi->is_extracted))
6705 MSICABDATA data;
6707 r = ready_media(package, assembly->file, mi);
6708 if (r != ERROR_SUCCESS)
6710 ERR("Failed to ready media\n");
6711 break;
6714 data.mi = mi;
6715 data.package = package;
6716 data.cb = installassembly_cb;
6717 data.user = &assemblies;
6719 if (assembly->file->IsCompressed &&
6720 !msi_cabextract(package, mi, &data))
6722 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6723 r = ERROR_FUNCTION_FAILED;
6724 break;
6728 if (!assembly->file->IsCompressed)
6730 LPWSTR source = resolve_file_source(package, assembly->file);
6732 r = install_assembly(package, assembly, source);
6733 if (r != ERROR_SUCCESS)
6734 ERR("Failed to install assembly\n");
6736 msi_free(source);
6739 /* FIXME: write Installer assembly reg values */
6742 done:
6743 free_assemblies(&assemblies);
6744 return r;
6747 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6749 LPWSTR key, template, id;
6750 UINT r = ERROR_SUCCESS;
6752 id = msi_dup_property( package, szProductID );
6753 if (id)
6755 msi_free( id );
6756 return ERROR_SUCCESS;
6758 template = msi_dup_property( package, szPIDTemplate );
6759 key = msi_dup_property( package, szPIDKEY );
6761 if (key && template)
6763 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6764 r = MSI_SetPropertyW( package, szProductID, key );
6766 msi_free( template );
6767 msi_free( key );
6768 return r;
6771 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6773 TRACE("\n");
6774 package->need_reboot = 1;
6775 return ERROR_SUCCESS;
6778 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6780 static const WCHAR szAvailableFreeReg[] =
6781 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6782 MSIRECORD *uirow;
6783 int space = msi_get_property_int( package, szAvailableFreeReg, 0 );
6785 TRACE("%p %d kilobytes\n", package, space);
6787 uirow = MSI_CreateRecord( 1 );
6788 MSI_RecordSetInteger( uirow, 1, space );
6789 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6790 msiobj_release( &uirow->hdr );
6792 return ERROR_SUCCESS;
6795 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6797 FIXME("%p\n", package);
6798 return ERROR_SUCCESS;
6801 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6803 FIXME("%p\n", package);
6804 return ERROR_SUCCESS;
6807 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6808 LPCSTR action, LPCWSTR table )
6810 static const WCHAR query[] = {
6811 'S','E','L','E','C','T',' ','*',' ',
6812 'F','R','O','M',' ','`','%','s','`',0 };
6813 MSIQUERY *view = NULL;
6814 DWORD count = 0;
6815 UINT r;
6817 r = MSI_OpenQuery( package->db, &view, query, table );
6818 if (r == ERROR_SUCCESS)
6820 r = MSI_IterateRecords(view, &count, NULL, package);
6821 msiobj_release(&view->hdr);
6824 if (count)
6825 FIXME("%s -> %u ignored %s table values\n",
6826 action, count, debugstr_w(table));
6828 return ERROR_SUCCESS;
6831 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6833 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6834 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6837 static UINT ACTION_BindImage( MSIPACKAGE *package )
6839 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6840 return msi_unimplemented_action_stub( package, "BindImage", table );
6843 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6845 static const WCHAR table[] = {
6846 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6847 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6850 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6852 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6853 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6856 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6858 static const WCHAR table[] = {
6859 'M','s','i','A','s','s','e','m','b','l','y',0 };
6860 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6863 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6865 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6866 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6869 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6871 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6872 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6875 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6877 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6878 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6881 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6883 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6884 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6887 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6889 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6890 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6893 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6895 static const WCHAR table[] = { 'D','i','r','e','c','t','o','r','y',0 };
6896 return msi_unimplemented_action_stub( package, "SetODBCFolders", table );
6899 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6901 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6902 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6905 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6907 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6908 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6911 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6913 static const WCHAR table[] = { 'M','I','M','E',0 };
6914 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6917 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6919 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6920 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6923 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6925 static const struct
6927 const WCHAR *action;
6928 UINT (*handler)(MSIPACKAGE *);
6930 StandardActions[] =
6932 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6933 { szAppSearch, ACTION_AppSearch },
6934 { szBindImage, ACTION_BindImage },
6935 { szCCPSearch, ACTION_CCPSearch },
6936 { szCostFinalize, ACTION_CostFinalize },
6937 { szCostInitialize, ACTION_CostInitialize },
6938 { szCreateFolders, ACTION_CreateFolders },
6939 { szCreateShortcuts, ACTION_CreateShortcuts },
6940 { szDeleteServices, ACTION_DeleteServices },
6941 { szDisableRollback, ACTION_DisableRollback },
6942 { szDuplicateFiles, ACTION_DuplicateFiles },
6943 { szExecuteAction, ACTION_ExecuteAction },
6944 { szFileCost, ACTION_FileCost },
6945 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6946 { szForceReboot, ACTION_ForceReboot },
6947 { szInstallAdminPackage, ACTION_InstallAdminPackage },
6948 { szInstallExecute, ACTION_InstallExecute },
6949 { szInstallExecuteAgain, ACTION_InstallExecute },
6950 { szInstallFiles, ACTION_InstallFiles},
6951 { szInstallFinalize, ACTION_InstallFinalize },
6952 { szInstallInitialize, ACTION_InstallInitialize },
6953 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6954 { szInstallValidate, ACTION_InstallValidate },
6955 { szIsolateComponents, ACTION_IsolateComponents },
6956 { szLaunchConditions, ACTION_LaunchConditions },
6957 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6958 { szMoveFiles, ACTION_MoveFiles },
6959 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6960 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6961 { szInstallODBC, ACTION_InstallODBC },
6962 { szInstallServices, ACTION_InstallServices },
6963 { szPatchFiles, ACTION_PatchFiles },
6964 { szProcessComponents, ACTION_ProcessComponents },
6965 { szPublishComponents, ACTION_PublishComponents },
6966 { szPublishFeatures, ACTION_PublishFeatures },
6967 { szPublishProduct, ACTION_PublishProduct },
6968 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6969 { szRegisterComPlus, ACTION_RegisterComPlus},
6970 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6971 { szRegisterFonts, ACTION_RegisterFonts },
6972 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6973 { szRegisterProduct, ACTION_RegisterProduct },
6974 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6975 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6976 { szRegisterUser, ACTION_RegisterUser },
6977 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6978 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6979 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6980 { szRemoveFiles, ACTION_RemoveFiles },
6981 { szRemoveFolders, ACTION_RemoveFolders },
6982 { szRemoveIniValues, ACTION_RemoveIniValues },
6983 { szRemoveODBC, ACTION_RemoveODBC },
6984 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6985 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6986 { szResolveSource, ACTION_ResolveSource },
6987 { szRMCCPSearch, ACTION_RMCCPSearch },
6988 { szScheduleReboot, ACTION_ScheduleReboot },
6989 { szSelfRegModules, ACTION_SelfRegModules },
6990 { szSelfUnregModules, ACTION_SelfUnregModules },
6991 { szSetODBCFolders, ACTION_SetODBCFolders },
6992 { szStartServices, ACTION_StartServices },
6993 { szStopServices, ACTION_StopServices },
6994 { szUnpublishComponents, ACTION_UnpublishComponents },
6995 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6996 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6997 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6998 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6999 { szUnregisterFonts, ACTION_UnregisterFonts },
7000 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7001 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7002 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7003 { szValidateProductID, ACTION_ValidateProductID },
7004 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7005 { szWriteIniValues, ACTION_WriteIniValues },
7006 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7007 { NULL, NULL },
7010 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7011 UINT* rc, BOOL force )
7013 BOOL ret = FALSE;
7014 BOOL run = force;
7015 int i;
7017 if (!run && !package->script->CurrentlyScripting)
7018 run = TRUE;
7020 if (!run)
7022 if (strcmpW(action,szInstallFinalize) == 0 ||
7023 strcmpW(action,szInstallExecute) == 0 ||
7024 strcmpW(action,szInstallExecuteAgain) == 0)
7025 run = TRUE;
7028 i = 0;
7029 while (StandardActions[i].action != NULL)
7031 if (strcmpW(StandardActions[i].action, action)==0)
7033 if (!run)
7035 ui_actioninfo(package, action, TRUE, 0);
7036 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7037 ui_actioninfo(package, action, FALSE, *rc);
7039 else
7041 ui_actionstart(package, action);
7042 if (StandardActions[i].handler)
7044 *rc = StandardActions[i].handler(package);
7046 else
7048 FIXME("unhandled standard action %s\n",debugstr_w(action));
7049 *rc = ERROR_SUCCESS;
7052 ret = TRUE;
7053 break;
7055 i++;
7057 return ret;
7060 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7062 UINT rc = ERROR_SUCCESS;
7063 BOOL handled;
7065 TRACE("Performing action (%s)\n", debugstr_w(action));
7067 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7069 if (!handled)
7070 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7072 if (!handled)
7074 WARN("unhandled msi action %s\n", debugstr_w(action));
7075 rc = ERROR_FUNCTION_NOT_CALLED;
7078 return rc;
7081 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7083 UINT rc = ERROR_SUCCESS;
7084 BOOL handled = FALSE;
7086 TRACE("Performing action (%s)\n", debugstr_w(action));
7088 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7090 if (!handled)
7091 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7093 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7094 handled = TRUE;
7096 if (!handled)
7098 WARN("unhandled msi action %s\n", debugstr_w(action));
7099 rc = ERROR_FUNCTION_NOT_CALLED;
7102 return rc;
7105 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7107 UINT rc = ERROR_SUCCESS;
7108 MSIRECORD *row;
7110 static const WCHAR ExecSeqQuery[] =
7111 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7112 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7113 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7114 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7115 static const WCHAR UISeqQuery[] =
7116 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7117 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7118 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7119 ' ', '=',' ','%','i',0};
7121 if (needs_ui_sequence(package))
7122 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7123 else
7124 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7126 if (row)
7128 LPCWSTR action, cond;
7130 TRACE("Running the actions\n");
7132 /* check conditions */
7133 cond = MSI_RecordGetString(row, 2);
7135 /* this is a hack to skip errors in the condition code */
7136 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7138 msiobj_release(&row->hdr);
7139 return ERROR_SUCCESS;
7142 action = MSI_RecordGetString(row, 1);
7143 if (!action)
7145 ERR("failed to fetch action\n");
7146 msiobj_release(&row->hdr);
7147 return ERROR_FUNCTION_FAILED;
7150 if (needs_ui_sequence(package))
7151 rc = ACTION_PerformUIAction(package, action, -1);
7152 else
7153 rc = ACTION_PerformAction(package, action, -1, FALSE);
7155 msiobj_release(&row->hdr);
7158 return rc;
7161 /****************************************************
7162 * TOP level entry points
7163 *****************************************************/
7165 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7166 LPCWSTR szCommandLine )
7168 UINT rc;
7169 BOOL ui_exists;
7171 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7172 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7174 MSI_SetPropertyW(package, szAction, szInstall);
7176 package->script->InWhatSequence = SEQUENCE_INSTALL;
7178 if (szPackagePath)
7180 LPWSTR p, dir;
7181 LPCWSTR file;
7183 dir = strdupW(szPackagePath);
7184 p = strrchrW(dir, '\\');
7185 if (p)
7187 *(++p) = 0;
7188 file = szPackagePath + (p - dir);
7190 else
7192 msi_free(dir);
7193 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7194 GetCurrentDirectoryW(MAX_PATH, dir);
7195 lstrcatW(dir, szBackSlash);
7196 file = szPackagePath;
7199 msi_free( package->PackagePath );
7200 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7201 if (!package->PackagePath)
7203 msi_free(dir);
7204 return ERROR_OUTOFMEMORY;
7207 lstrcpyW(package->PackagePath, dir);
7208 lstrcatW(package->PackagePath, file);
7209 msi_free(dir);
7211 msi_set_sourcedir_props(package, FALSE);
7214 msi_parse_command_line( package, szCommandLine, FALSE );
7216 msi_apply_transforms( package );
7217 msi_apply_patches( package );
7219 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
7221 TRACE("setting reinstall property\n");
7222 MSI_SetPropertyW( package, szReinstall, szAll );
7225 /* properties may have been added by a transform */
7226 msi_clone_properties( package );
7227 msi_set_context( package );
7229 if (needs_ui_sequence( package))
7231 package->script->InWhatSequence |= SEQUENCE_UI;
7232 rc = ACTION_ProcessUISequence(package);
7233 ui_exists = ui_sequence_exists(package);
7234 if (rc == ERROR_SUCCESS || !ui_exists)
7236 package->script->InWhatSequence |= SEQUENCE_EXEC;
7237 rc = ACTION_ProcessExecSequence(package, ui_exists);
7240 else
7241 rc = ACTION_ProcessExecSequence(package, FALSE);
7243 package->script->CurrentlyScripting = FALSE;
7245 /* process the ending type action */
7246 if (rc == ERROR_SUCCESS)
7247 ACTION_PerformActionSequence(package, -1);
7248 else if (rc == ERROR_INSTALL_USEREXIT)
7249 ACTION_PerformActionSequence(package, -2);
7250 else if (rc == ERROR_INSTALL_SUSPEND)
7251 ACTION_PerformActionSequence(package, -4);
7252 else /* failed */
7253 ACTION_PerformActionSequence(package, -3);
7255 /* finish up running custom actions */
7256 ACTION_FinishCustomActions(package);
7258 if (rc == ERROR_SUCCESS && package->need_reboot)
7259 return ERROR_SUCCESS_REBOOT_REQUIRED;
7261 return rc;