msi: Move application of substorage transforms out of msi_parse_patch_summary.
[wine/multimedia.git] / dlls / msi / action.c
bloba4af27c462ecfd5c07bdf859d12580cc96df0903
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 szDeleteServices[] =
100 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
101 static const WCHAR szDisableRollback[] =
102 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
103 static const WCHAR szExecuteAction[] =
104 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
105 static const WCHAR szInstallAdminPackage[] =
106 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
107 static const WCHAR szInstallSFPCatalogFile[] =
108 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
109 static const WCHAR szIsolateComponents[] =
110 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
111 static const WCHAR szMigrateFeatureStates[] =
112 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
113 static const WCHAR szMsiPublishAssemblies[] =
114 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
115 static const WCHAR szMsiUnpublishAssemblies[] =
116 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
117 static const WCHAR szInstallODBC[] =
118 {'I','n','s','t','a','l','l','O','D','B','C',0};
119 static const WCHAR szInstallServices[] =
120 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
121 static const WCHAR szPatchFiles[] =
122 {'P','a','t','c','h','F','i','l','e','s',0};
123 static const WCHAR szPublishComponents[] =
124 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
125 static const WCHAR szRegisterComPlus[] =
126 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
127 static const WCHAR szRegisterUser[] =
128 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
129 static const WCHAR szRemoveEnvironmentStrings[] =
130 {'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};
131 static const WCHAR szRemoveExistingProducts[] =
132 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
133 static const WCHAR szRemoveFolders[] =
134 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
135 static const WCHAR szRemoveIniValues[] =
136 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
137 static const WCHAR szRemoveODBC[] =
138 {'R','e','m','o','v','e','O','D','B','C',0};
139 static const WCHAR szRemoveRegistryValues[] =
140 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
141 static const WCHAR szRemoveShortcuts[] =
142 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
143 static const WCHAR szRMCCPSearch[] =
144 {'R','M','C','C','P','S','e','a','r','c','h',0};
145 static const WCHAR szScheduleReboot[] =
146 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
147 static const WCHAR szSelfUnregModules[] =
148 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
149 static const WCHAR szSetODBCFolders[] =
150 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
151 static const WCHAR szStartServices[] =
152 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
153 static const WCHAR szStopServices[] =
154 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
155 static const WCHAR szUnpublishComponents[] =
156 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
157 static const WCHAR szUnpublishFeatures[] =
158 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
159 static const WCHAR szUnregisterComPlus[] =
160 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
161 static const WCHAR szUnregisterTypeLibraries[] =
162 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
163 static const WCHAR szValidateProductID[] =
164 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
165 static const WCHAR szWriteEnvironmentStrings[] =
166 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
168 /********************************************************
169 * helper functions
170 ********************************************************/
172 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
174 static const WCHAR Query_t[] =
175 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
176 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
177 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
178 ' ','\'','%','s','\'',0};
179 MSIRECORD * row;
181 row = MSI_QueryGetRecord( package->db, Query_t, action );
182 if (!row)
183 return;
184 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
185 msiobj_release(&row->hdr);
188 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
189 UINT rc)
191 MSIRECORD * row;
192 static const WCHAR template_s[]=
193 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
194 '%','s', '.',0};
195 static const WCHAR template_e[]=
196 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
197 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
198 '%','i','.',0};
199 static const WCHAR format[] =
200 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
201 WCHAR message[1024];
202 WCHAR timet[0x100];
204 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
205 if (start)
206 sprintfW(message,template_s,timet,action);
207 else
208 sprintfW(message,template_e,timet,action,rc);
210 row = MSI_CreateRecord(1);
211 MSI_RecordSetStringW(row,1,message);
213 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
214 msiobj_release(&row->hdr);
217 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
218 BOOL preserve_case )
220 LPCWSTR ptr,ptr2;
221 BOOL quote;
222 DWORD len;
223 LPWSTR prop = NULL, val = NULL;
225 if (!szCommandLine)
226 return ERROR_SUCCESS;
228 ptr = szCommandLine;
230 while (*ptr)
232 if (*ptr==' ')
234 ptr++;
235 continue;
238 TRACE("Looking at %s\n",debugstr_w(ptr));
240 ptr2 = strchrW(ptr,'=');
241 if (!ptr2)
243 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
244 break;
247 quote = FALSE;
249 len = ptr2-ptr;
250 prop = msi_alloc((len+1)*sizeof(WCHAR));
251 memcpy(prop,ptr,len*sizeof(WCHAR));
252 prop[len]=0;
254 if (!preserve_case)
255 struprW(prop);
257 ptr2++;
259 len = 0;
260 ptr = ptr2;
261 while (*ptr && (quote || (!quote && *ptr!=' ')))
263 if (*ptr == '"')
264 quote = !quote;
265 ptr++;
266 len++;
269 if (*ptr2=='"')
271 ptr2++;
272 len -= 2;
274 val = msi_alloc((len+1)*sizeof(WCHAR));
275 memcpy(val,ptr2,len*sizeof(WCHAR));
276 val[len] = 0;
278 if (lstrlenW(prop) > 0)
280 TRACE("Found commandline property (%s) = (%s)\n",
281 debugstr_w(prop), debugstr_w(val));
282 MSI_SetPropertyW(package,prop,val);
284 msi_free(val);
285 msi_free(prop);
288 return ERROR_SUCCESS;
292 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
294 LPCWSTR pc;
295 LPWSTR p, *ret = NULL;
296 UINT count = 0;
298 if (!str)
299 return ret;
301 /* count the number of substrings */
302 for ( pc = str, count = 0; pc; count++ )
304 pc = strchrW( pc, sep );
305 if (pc)
306 pc++;
309 /* allocate space for an array of substring pointers and the substrings */
310 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
311 (lstrlenW(str)+1) * sizeof(WCHAR) );
312 if (!ret)
313 return ret;
315 /* copy the string and set the pointers */
316 p = (LPWSTR) &ret[count+1];
317 lstrcpyW( p, str );
318 for( count = 0; (ret[count] = p); count++ )
320 p = strchrW( p, sep );
321 if (p)
322 *p++ = 0;
325 return ret;
328 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
330 static const WCHAR szSystemLanguageID[] =
331 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
333 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
334 UINT ret = ERROR_FUNCTION_FAILED;
336 prod_code = msi_dup_property( package, szProductCode );
337 patch_product = msi_get_suminfo_product( patch );
339 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
341 if ( strstrW( patch_product, prod_code ) )
343 MSISUMMARYINFO *si;
344 const WCHAR *p;
346 si = MSI_GetSummaryInformationW( patch, 0 );
347 if (!si)
349 ERR("no summary information!\n");
350 goto end;
353 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
354 if (!template)
356 ERR("no template property!\n");
357 msiobj_release( &si->hdr );
358 goto end;
361 if (!template[0])
363 ret = ERROR_SUCCESS;
364 msiobj_release( &si->hdr );
365 goto end;
368 langid = msi_dup_property( package, szSystemLanguageID );
369 if (!langid)
371 msiobj_release( &si->hdr );
372 goto end;
375 p = strchrW( template, ';' );
376 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
378 TRACE("applicable transform\n");
379 ret = ERROR_SUCCESS;
382 /* FIXME: check platform */
384 msiobj_release( &si->hdr );
387 end:
388 msi_free( patch_product );
389 msi_free( prod_code );
390 msi_free( template );
391 msi_free( langid );
393 return ret;
396 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
397 MSIDATABASE *patch_db, LPCWSTR name )
399 UINT ret = ERROR_FUNCTION_FAILED;
400 IStorage *stg = NULL;
401 HRESULT r;
403 TRACE("%p %s\n", package, debugstr_w(name) );
405 if (*name++ != ':')
407 ERR("expected a colon in %s\n", debugstr_w(name));
408 return ERROR_FUNCTION_FAILED;
411 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
412 if (SUCCEEDED(r))
414 ret = msi_check_transform_applicable( package, stg );
415 if (ret == ERROR_SUCCESS)
416 msi_table_apply_transform( package->db, stg );
417 else
418 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
419 IStorage_Release( stg );
421 else
422 ERR("failed to open substorage %s\n", debugstr_w(name));
424 return ERROR_SUCCESS;
427 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
429 LPWSTR guid_list, *guids, product_code;
430 UINT i, ret = ERROR_FUNCTION_FAILED;
432 product_code = msi_dup_property( package, szProductCode );
433 if (!product_code)
435 /* FIXME: the property ProductCode should be written into the DB somewhere */
436 ERR("no product code to check\n");
437 return ERROR_SUCCESS;
440 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
441 guids = msi_split_string( guid_list, ';' );
442 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
444 if (!lstrcmpW( guids[i], product_code ))
445 ret = ERROR_SUCCESS;
447 msi_free( guids );
448 msi_free( guid_list );
449 msi_free( product_code );
451 return ret;
454 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
456 MSIQUERY *view;
457 MSIRECORD *rec = NULL;
458 LPWSTR patch;
459 LPCWSTR prop;
460 UINT r;
462 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
463 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
464 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
465 '`','S','o','u','r','c','e','`',' ','I','S',' ',
466 'N','O','T',' ','N','U','L','L',0};
468 r = MSI_DatabaseOpenViewW(package->db, query, &view);
469 if (r != ERROR_SUCCESS)
470 return r;
472 r = MSI_ViewExecute(view, 0);
473 if (r != ERROR_SUCCESS)
474 goto done;
476 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
478 prop = MSI_RecordGetString(rec, 1);
479 patch = msi_dup_property(package, szPatch);
480 MSI_SetPropertyW(package, prop, patch);
481 msi_free(patch);
484 done:
485 if (rec) msiobj_release(&rec->hdr);
486 msiobj_release(&view->hdr);
488 return r;
491 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
493 MSISUMMARYINFO *si;
494 UINT r = ERROR_SUCCESS;
496 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
497 if (!si)
498 return ERROR_FUNCTION_FAILED;
500 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
502 TRACE("Patch not applicable\n");
503 msiobj_release( &si->hdr );
504 return ERROR_SUCCESS;
507 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
508 if (!package->patch)
510 msiobj_release( &si->hdr );
511 return ERROR_OUTOFMEMORY;
514 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
515 if (!package->patch->patchcode)
517 msiobj_release( &si->hdr );
518 return ERROR_OUTOFMEMORY;
521 package->patch->transforms = msi_suminfo_dup_string(si, PID_LASTAUTHOR);
522 if (!package->patch->transforms)
524 msiobj_release( &si->hdr );
525 return ERROR_OUTOFMEMORY;
528 msiobj_release( &si->hdr );
529 return r;
532 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
534 MSIDATABASE *patch_db = NULL;
535 LPWSTR *substorage;
536 UINT i, r;
538 TRACE("%p %s\n", package, debugstr_w( file ) );
540 /* FIXME:
541 * We probably want to make sure we only open a patch collection here.
542 * Patch collections (.msp) and databases (.msi) have different GUIDs
543 * but currently MSI_OpenDatabaseW will accept both.
545 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
546 if ( r != ERROR_SUCCESS )
548 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
549 return r;
552 msi_parse_patch_summary( package, patch_db );
554 /* apply substorage transforms */
555 substorage = msi_split_string( package->patch->transforms, ';' );
556 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
557 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
559 msi_free( substorage );
560 msi_set_media_source_prop( package );
563 * There might be a CAB file in the patch package,
564 * so append it to the list of storage to search for streams.
566 append_storage_to_db( package->db, patch_db->storage );
568 msiobj_release( &patch_db->hdr );
570 return ERROR_SUCCESS;
573 /* get the PATCH property, and apply all the patches it specifies */
574 static UINT msi_apply_patches( MSIPACKAGE *package )
576 LPWSTR patch_list, *patches;
577 UINT i, r = ERROR_SUCCESS;
579 patch_list = msi_dup_property( package, szPatch );
581 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
583 patches = msi_split_string( patch_list, ';' );
584 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
585 r = msi_apply_patch_package( package, patches[i] );
587 msi_free( patches );
588 msi_free( patch_list );
590 return r;
593 static UINT msi_apply_transforms( MSIPACKAGE *package )
595 static const WCHAR szTransforms[] = {
596 'T','R','A','N','S','F','O','R','M','S',0 };
597 LPWSTR xform_list, *xforms;
598 UINT i, r = ERROR_SUCCESS;
600 xform_list = msi_dup_property( package, szTransforms );
601 xforms = msi_split_string( xform_list, ';' );
603 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
605 if (xforms[i][0] == ':')
606 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
607 else
608 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
611 msi_free( xforms );
612 msi_free( xform_list );
614 return r;
617 static BOOL ui_sequence_exists( MSIPACKAGE *package )
619 MSIQUERY *view;
620 UINT rc;
622 static const WCHAR ExecSeqQuery [] =
623 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
624 '`','I','n','s','t','a','l','l',
625 'U','I','S','e','q','u','e','n','c','e','`',
626 ' ','W','H','E','R','E',' ',
627 '`','S','e','q','u','e','n','c','e','`',' ',
628 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
629 '`','S','e','q','u','e','n','c','e','`',0};
631 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
632 if (rc == ERROR_SUCCESS)
634 msiobj_release(&view->hdr);
635 return TRUE;
638 return FALSE;
641 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
643 LPWSTR p, db;
644 LPWSTR source, check;
645 DWORD len;
647 static const WCHAR szOriginalDatabase[] =
648 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
650 db = msi_dup_property( package, szOriginalDatabase );
651 if (!db)
652 return ERROR_OUTOFMEMORY;
654 p = strrchrW( db, '\\' );
655 if (!p)
657 p = strrchrW( db, '/' );
658 if (!p)
660 msi_free(db);
661 return ERROR_SUCCESS;
665 len = p - db + 2;
666 source = msi_alloc( len * sizeof(WCHAR) );
667 lstrcpynW( source, db, len );
669 check = msi_dup_property( package, cszSourceDir );
670 if (!check || replace)
671 MSI_SetPropertyW( package, cszSourceDir, source );
673 msi_free( check );
675 check = msi_dup_property( package, cszSOURCEDIR );
676 if (!check || replace)
677 MSI_SetPropertyW( package, cszSOURCEDIR, source );
679 msi_free( check );
680 msi_free( source );
681 msi_free( db );
683 return ERROR_SUCCESS;
686 static BOOL needs_ui_sequence(MSIPACKAGE *package)
688 INT level = msi_get_property_int(package, szUILevel, 0);
689 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
692 static UINT msi_set_context(MSIPACKAGE *package)
694 WCHAR val[10];
695 DWORD sz = 10;
696 DWORD num;
697 UINT r;
699 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
701 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
702 if (r == ERROR_SUCCESS)
704 num = atolW(val);
705 if (num == 1 || num == 2)
706 package->Context = MSIINSTALLCONTEXT_MACHINE;
709 return ERROR_SUCCESS;
712 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
714 UINT rc;
715 LPCWSTR cond, action;
716 MSIPACKAGE *package = param;
718 action = MSI_RecordGetString(row,1);
719 if (!action)
721 ERR("Error is retrieving action name\n");
722 return ERROR_FUNCTION_FAILED;
725 /* check conditions */
726 cond = MSI_RecordGetString(row,2);
728 /* this is a hack to skip errors in the condition code */
729 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
731 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
732 return ERROR_SUCCESS;
735 if (needs_ui_sequence(package))
736 rc = ACTION_PerformUIAction(package, action, -1);
737 else
738 rc = ACTION_PerformAction(package, action, -1, FALSE);
740 msi_dialog_check_messages( NULL );
742 if (package->CurrentInstallState != ERROR_SUCCESS)
743 rc = package->CurrentInstallState;
745 if (rc == ERROR_FUNCTION_NOT_CALLED)
746 rc = ERROR_SUCCESS;
748 if (rc != ERROR_SUCCESS)
749 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
751 return rc;
754 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
756 MSIQUERY * view;
757 UINT r;
758 static const WCHAR query[] =
759 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
760 '`','%','s','`',
761 ' ','W','H','E','R','E',' ',
762 '`','S','e','q','u','e','n','c','e','`',' ',
763 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
764 '`','S','e','q','u','e','n','c','e','`',0};
766 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
768 r = MSI_OpenQuery( package->db, &view, query, szTable );
769 if (r == ERROR_SUCCESS)
771 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
772 msiobj_release(&view->hdr);
775 return r;
778 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
780 MSIQUERY * view;
781 UINT rc;
782 static const WCHAR ExecSeqQuery[] =
783 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
784 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
785 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
786 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
787 'O','R','D','E','R',' ', 'B','Y',' ',
788 '`','S','e','q','u','e','n','c','e','`',0 };
789 static const WCHAR IVQuery[] =
790 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
791 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
792 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
793 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
794 ' ','\'', 'I','n','s','t','a','l','l',
795 'V','a','l','i','d','a','t','e','\'', 0};
796 INT seq = 0;
798 if (package->script->ExecuteSequenceRun)
800 TRACE("Execute Sequence already Run\n");
801 return ERROR_SUCCESS;
804 package->script->ExecuteSequenceRun = TRUE;
806 /* get the sequence number */
807 if (UIran)
809 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
810 if( !row )
811 return ERROR_FUNCTION_FAILED;
812 seq = MSI_RecordGetInteger(row,1);
813 msiobj_release(&row->hdr);
816 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
817 if (rc == ERROR_SUCCESS)
819 TRACE("Running the actions\n");
821 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
822 msiobj_release(&view->hdr);
825 return rc;
828 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
830 MSIQUERY * view;
831 UINT rc;
832 static const WCHAR ExecSeqQuery [] =
833 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
834 '`','I','n','s','t','a','l','l',
835 'U','I','S','e','q','u','e','n','c','e','`',
836 ' ','W','H','E','R','E',' ',
837 '`','S','e','q','u','e','n','c','e','`',' ',
838 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
839 '`','S','e','q','u','e','n','c','e','`',0};
841 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
842 if (rc == ERROR_SUCCESS)
844 TRACE("Running the actions\n");
846 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
847 msiobj_release(&view->hdr);
850 return rc;
853 /********************************************************
854 * ACTION helper functions and functions that perform the actions
855 *******************************************************/
856 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
857 UINT* rc, UINT script, BOOL force )
859 BOOL ret=FALSE;
860 UINT arc;
862 arc = ACTION_CustomAction(package, action, script, force);
864 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
866 *rc = arc;
867 ret = TRUE;
869 return ret;
873 * Actual Action Handlers
876 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
878 MSIPACKAGE *package = param;
879 LPCWSTR dir, component;
880 LPWSTR full_path;
881 MSIRECORD *uirow;
882 MSIFOLDER *folder;
883 MSICOMPONENT *comp;
885 component = MSI_RecordGetString(row, 2);
886 comp = get_loaded_component(package, component);
887 if (!comp)
888 return ERROR_SUCCESS;
890 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
892 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
893 comp->Action = comp->Installed;
894 return ERROR_SUCCESS;
896 comp->Action = INSTALLSTATE_LOCAL;
898 dir = MSI_RecordGetString(row,1);
899 if (!dir)
901 ERR("Unable to get folder id\n");
902 return ERROR_SUCCESS;
905 uirow = MSI_CreateRecord(1);
906 MSI_RecordSetStringW(uirow, 1, dir);
907 ui_actiondata(package, szCreateFolders, uirow);
908 msiobj_release(&uirow->hdr);
910 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
911 if (!full_path)
913 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
914 return ERROR_SUCCESS;
917 TRACE("Folder is %s\n",debugstr_w(full_path));
919 if (folder->State == 0)
920 create_full_pathW(full_path);
922 folder->State = 3;
924 msi_free(full_path);
925 return ERROR_SUCCESS;
928 /* FIXME: probably should merge this with the above function */
929 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
931 UINT rc = ERROR_SUCCESS;
932 MSIFOLDER *folder;
933 LPWSTR install_path;
935 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
936 if (!install_path)
937 return ERROR_FUNCTION_FAILED;
939 /* create the path */
940 if (folder->State == 0)
942 create_full_pathW(install_path);
943 folder->State = 2;
945 msi_free(install_path);
947 return rc;
950 UINT msi_create_component_directories( MSIPACKAGE *package )
952 MSICOMPONENT *comp;
954 /* create all the folders required by the components are going to install */
955 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
957 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
958 continue;
959 msi_create_directory( package, comp->Directory );
962 return ERROR_SUCCESS;
965 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
967 static const WCHAR ExecSeqQuery[] =
968 {'S','E','L','E','C','T',' ',
969 '`','D','i','r','e','c','t','o','r','y','_','`',
970 ' ','F','R','O','M',' ',
971 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
972 UINT rc;
973 MSIQUERY *view;
975 /* create all the empty folders specified in the CreateFolder table */
976 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
977 if (rc != ERROR_SUCCESS)
978 return ERROR_SUCCESS;
980 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
981 msiobj_release(&view->hdr);
983 return rc;
986 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
988 MSIPACKAGE *package = param;
989 LPCWSTR dir, component;
990 LPWSTR full_path;
991 MSIRECORD *uirow;
992 MSIFOLDER *folder;
993 MSICOMPONENT *comp;
995 component = MSI_RecordGetString(row, 2);
996 comp = get_loaded_component(package, component);
997 if (!comp)
998 return ERROR_SUCCESS;
1000 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1002 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1003 comp->Action = comp->Installed;
1004 return ERROR_SUCCESS;
1006 comp->Action = INSTALLSTATE_ABSENT;
1008 dir = MSI_RecordGetString( row, 1 );
1009 if (!dir)
1011 ERR("Unable to get folder id\n");
1012 return ERROR_SUCCESS;
1015 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1016 if (!full_path)
1018 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1019 return ERROR_SUCCESS;
1022 TRACE("folder is %s\n", debugstr_w(full_path));
1024 uirow = MSI_CreateRecord( 1 );
1025 MSI_RecordSetStringW( uirow, 1, full_path );
1026 ui_actiondata( package, szRemoveFolders, uirow );
1027 msiobj_release( &uirow->hdr );
1029 RemoveDirectoryW( full_path );
1030 folder->State = 0;
1032 msi_free( full_path );
1033 return ERROR_SUCCESS;
1036 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1038 static const WCHAR query[] =
1039 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1040 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1042 MSIQUERY *view;
1043 UINT rc;
1045 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1046 if (rc != ERROR_SUCCESS)
1047 return ERROR_SUCCESS;
1049 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1050 msiobj_release( &view->hdr );
1052 return rc;
1055 static UINT load_component( MSIRECORD *row, LPVOID param )
1057 MSIPACKAGE *package = param;
1058 MSICOMPONENT *comp;
1060 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1061 if (!comp)
1062 return ERROR_FUNCTION_FAILED;
1064 list_add_tail( &package->components, &comp->entry );
1066 /* fill in the data */
1067 comp->Component = msi_dup_record_field( row, 1 );
1069 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1071 comp->ComponentId = msi_dup_record_field( row, 2 );
1072 comp->Directory = msi_dup_record_field( row, 3 );
1073 comp->Attributes = MSI_RecordGetInteger(row,4);
1074 comp->Condition = msi_dup_record_field( row, 5 );
1075 comp->KeyPath = msi_dup_record_field( row, 6 );
1077 comp->Installed = INSTALLSTATE_UNKNOWN;
1078 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1080 return ERROR_SUCCESS;
1083 static UINT load_all_components( MSIPACKAGE *package )
1085 static const WCHAR query[] = {
1086 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1087 '`','C','o','m','p','o','n','e','n','t','`',0 };
1088 MSIQUERY *view;
1089 UINT r;
1091 if (!list_empty(&package->components))
1092 return ERROR_SUCCESS;
1094 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1095 if (r != ERROR_SUCCESS)
1096 return r;
1098 r = MSI_IterateRecords(view, NULL, load_component, package);
1099 msiobj_release(&view->hdr);
1100 return r;
1103 typedef struct {
1104 MSIPACKAGE *package;
1105 MSIFEATURE *feature;
1106 } _ilfs;
1108 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1110 ComponentList *cl;
1112 cl = msi_alloc( sizeof (*cl) );
1113 if ( !cl )
1114 return ERROR_NOT_ENOUGH_MEMORY;
1115 cl->component = comp;
1116 list_add_tail( &feature->Components, &cl->entry );
1118 return ERROR_SUCCESS;
1121 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1123 FeatureList *fl;
1125 fl = msi_alloc( sizeof(*fl) );
1126 if ( !fl )
1127 return ERROR_NOT_ENOUGH_MEMORY;
1128 fl->feature = child;
1129 list_add_tail( &parent->Children, &fl->entry );
1131 return ERROR_SUCCESS;
1134 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1136 _ilfs* ilfs = param;
1137 LPCWSTR component;
1138 MSICOMPONENT *comp;
1140 component = MSI_RecordGetString(row,1);
1142 /* check to see if the component is already loaded */
1143 comp = get_loaded_component( ilfs->package, component );
1144 if (!comp)
1146 ERR("unknown component %s\n", debugstr_w(component));
1147 return ERROR_FUNCTION_FAILED;
1150 add_feature_component( ilfs->feature, comp );
1151 comp->Enabled = TRUE;
1153 return ERROR_SUCCESS;
1156 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1158 MSIFEATURE *feature;
1160 if ( !name )
1161 return NULL;
1163 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1165 if ( !lstrcmpW( feature->Feature, name ) )
1166 return feature;
1169 return NULL;
1172 static UINT load_feature(MSIRECORD * row, LPVOID param)
1174 MSIPACKAGE* package = param;
1175 MSIFEATURE* feature;
1176 static const WCHAR Query1[] =
1177 {'S','E','L','E','C','T',' ',
1178 '`','C','o','m','p','o','n','e','n','t','_','`',
1179 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1180 'C','o','m','p','o','n','e','n','t','s','`',' ',
1181 'W','H','E','R','E',' ',
1182 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1183 MSIQUERY * view;
1184 UINT rc;
1185 _ilfs ilfs;
1187 /* fill in the data */
1189 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1190 if (!feature)
1191 return ERROR_NOT_ENOUGH_MEMORY;
1193 list_init( &feature->Children );
1194 list_init( &feature->Components );
1196 feature->Feature = msi_dup_record_field( row, 1 );
1198 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1200 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1201 feature->Title = msi_dup_record_field( row, 3 );
1202 feature->Description = msi_dup_record_field( row, 4 );
1204 if (!MSI_RecordIsNull(row,5))
1205 feature->Display = MSI_RecordGetInteger(row,5);
1207 feature->Level= MSI_RecordGetInteger(row,6);
1208 feature->Directory = msi_dup_record_field( row, 7 );
1209 feature->Attributes = MSI_RecordGetInteger(row,8);
1211 feature->Installed = INSTALLSTATE_UNKNOWN;
1212 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1214 list_add_tail( &package->features, &feature->entry );
1216 /* load feature components */
1218 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1219 if (rc != ERROR_SUCCESS)
1220 return ERROR_SUCCESS;
1222 ilfs.package = package;
1223 ilfs.feature = feature;
1225 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1226 msiobj_release(&view->hdr);
1228 return ERROR_SUCCESS;
1231 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1233 MSIPACKAGE* package = param;
1234 MSIFEATURE *parent, *child;
1236 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1237 if (!child)
1238 return ERROR_FUNCTION_FAILED;
1240 if (!child->Feature_Parent)
1241 return ERROR_SUCCESS;
1243 parent = find_feature_by_name( package, child->Feature_Parent );
1244 if (!parent)
1245 return ERROR_FUNCTION_FAILED;
1247 add_feature_child( parent, child );
1248 return ERROR_SUCCESS;
1251 static UINT load_all_features( MSIPACKAGE *package )
1253 static const WCHAR query[] = {
1254 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1255 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1256 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1257 MSIQUERY *view;
1258 UINT r;
1260 if (!list_empty(&package->features))
1261 return ERROR_SUCCESS;
1263 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1264 if (r != ERROR_SUCCESS)
1265 return r;
1267 r = MSI_IterateRecords( view, NULL, load_feature, package );
1268 if (r != ERROR_SUCCESS)
1269 return r;
1271 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1272 msiobj_release( &view->hdr );
1274 return r;
1277 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1279 if (!p)
1280 return p;
1281 p = strchrW(p, ch);
1282 if (!p)
1283 return p;
1284 *p = 0;
1285 return p+1;
1288 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1290 static const WCHAR query[] = {
1291 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1292 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1293 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1294 MSIQUERY *view = NULL;
1295 MSIRECORD *row = NULL;
1296 UINT r;
1298 TRACE("%s\n", debugstr_w(file->File));
1300 r = MSI_OpenQuery(package->db, &view, query, file->File);
1301 if (r != ERROR_SUCCESS)
1302 goto done;
1304 r = MSI_ViewExecute(view, NULL);
1305 if (r != ERROR_SUCCESS)
1306 goto done;
1308 r = MSI_ViewFetch(view, &row);
1309 if (r != ERROR_SUCCESS)
1310 goto done;
1312 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1313 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1314 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1315 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1316 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1318 done:
1319 if (view) msiobj_release(&view->hdr);
1320 if (row) msiobj_release(&row->hdr);
1321 return r;
1324 static UINT load_file(MSIRECORD *row, LPVOID param)
1326 MSIPACKAGE* package = param;
1327 LPCWSTR component;
1328 MSIFILE *file;
1330 /* fill in the data */
1332 file = msi_alloc_zero( sizeof (MSIFILE) );
1333 if (!file)
1334 return ERROR_NOT_ENOUGH_MEMORY;
1336 file->File = msi_dup_record_field( row, 1 );
1338 component = MSI_RecordGetString( row, 2 );
1339 file->Component = get_loaded_component( package, component );
1341 if (!file->Component)
1343 WARN("Component not found: %s\n", debugstr_w(component));
1344 msi_free(file->File);
1345 msi_free(file);
1346 return ERROR_SUCCESS;
1349 file->FileName = msi_dup_record_field( row, 3 );
1350 reduce_to_longfilename( file->FileName );
1352 file->ShortName = msi_dup_record_field( row, 3 );
1353 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1355 file->FileSize = MSI_RecordGetInteger( row, 4 );
1356 file->Version = msi_dup_record_field( row, 5 );
1357 file->Language = msi_dup_record_field( row, 6 );
1358 file->Attributes = MSI_RecordGetInteger( row, 7 );
1359 file->Sequence = MSI_RecordGetInteger( row, 8 );
1361 file->state = msifs_invalid;
1363 /* if the compressed bits are not set in the file attributes,
1364 * then read the information from the package word count property
1366 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1368 file->IsCompressed = FALSE;
1370 else if (file->Attributes &
1371 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1373 file->IsCompressed = TRUE;
1375 else if (file->Attributes & msidbFileAttributesNoncompressed)
1377 file->IsCompressed = FALSE;
1379 else
1381 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1384 load_file_hash(package, file);
1386 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1388 list_add_tail( &package->files, &file->entry );
1390 return ERROR_SUCCESS;
1393 static UINT load_all_files(MSIPACKAGE *package)
1395 MSIQUERY * view;
1396 UINT rc;
1397 static const WCHAR Query[] =
1398 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1399 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1400 '`','S','e','q','u','e','n','c','e','`', 0};
1402 if (!list_empty(&package->files))
1403 return ERROR_SUCCESS;
1405 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1406 if (rc != ERROR_SUCCESS)
1407 return ERROR_SUCCESS;
1409 rc = MSI_IterateRecords(view, NULL, load_file, package);
1410 msiobj_release(&view->hdr);
1412 return ERROR_SUCCESS;
1415 static UINT load_folder( MSIRECORD *row, LPVOID param )
1417 MSIPACKAGE *package = param;
1418 static WCHAR szEmpty[] = { 0 };
1419 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1420 MSIFOLDER *folder;
1422 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1423 if (!folder)
1424 return ERROR_NOT_ENOUGH_MEMORY;
1426 folder->Directory = msi_dup_record_field( row, 1 );
1428 TRACE("%s\n", debugstr_w(folder->Directory));
1430 p = msi_dup_record_field(row, 3);
1432 /* split src and target dir */
1433 tgt_short = p;
1434 src_short = folder_split_path( p, ':' );
1436 /* split the long and short paths */
1437 tgt_long = folder_split_path( tgt_short, '|' );
1438 src_long = folder_split_path( src_short, '|' );
1440 /* check for no-op dirs */
1441 if (!lstrcmpW(szDot, tgt_short))
1442 tgt_short = szEmpty;
1443 if (!lstrcmpW(szDot, src_short))
1444 src_short = szEmpty;
1446 if (!tgt_long)
1447 tgt_long = tgt_short;
1449 if (!src_short) {
1450 src_short = tgt_short;
1451 src_long = tgt_long;
1454 if (!src_long)
1455 src_long = src_short;
1457 /* FIXME: use the target short path too */
1458 folder->TargetDefault = strdupW(tgt_long);
1459 folder->SourceShortPath = strdupW(src_short);
1460 folder->SourceLongPath = strdupW(src_long);
1461 msi_free(p);
1463 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1464 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1465 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1467 folder->Parent = msi_dup_record_field( row, 2 );
1469 folder->Property = msi_dup_property( package, folder->Directory );
1471 list_add_tail( &package->folders, &folder->entry );
1473 TRACE("returning %p\n", folder);
1475 return ERROR_SUCCESS;
1478 static UINT load_all_folders( MSIPACKAGE *package )
1480 static const WCHAR query[] = {
1481 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1482 '`','D','i','r','e','c','t','o','r','y','`',0 };
1483 MSIQUERY *view;
1484 UINT r;
1486 if (!list_empty(&package->folders))
1487 return ERROR_SUCCESS;
1489 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1490 if (r != ERROR_SUCCESS)
1491 return r;
1493 r = MSI_IterateRecords(view, NULL, load_folder, package);
1494 msiobj_release(&view->hdr);
1495 return r;
1499 * I am not doing any of the costing functionality yet.
1500 * Mostly looking at doing the Component and Feature loading
1502 * The native MSI does A LOT of modification to tables here. Mostly adding
1503 * a lot of temporary columns to the Feature and Component tables.
1505 * note: Native msi also tracks the short filename. But I am only going to
1506 * track the long ones. Also looking at this directory table
1507 * it appears that the directory table does not get the parents
1508 * resolved base on property only based on their entries in the
1509 * directory table.
1511 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1513 static const WCHAR szCosting[] =
1514 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1516 MSI_SetPropertyW(package, szCosting, szZero);
1517 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1519 load_all_folders( package );
1520 load_all_components( package );
1521 load_all_features( package );
1522 load_all_files( package );
1524 return ERROR_SUCCESS;
1527 static UINT execute_script(MSIPACKAGE *package, UINT script )
1529 UINT i;
1530 UINT rc = ERROR_SUCCESS;
1532 TRACE("Executing Script %i\n",script);
1534 if (!package->script)
1536 ERR("no script!\n");
1537 return ERROR_FUNCTION_FAILED;
1540 for (i = 0; i < package->script->ActionCount[script]; i++)
1542 LPWSTR action;
1543 action = package->script->Actions[script][i];
1544 ui_actionstart(package, action);
1545 TRACE("Executing Action (%s)\n",debugstr_w(action));
1546 rc = ACTION_PerformAction(package, action, script, TRUE);
1547 if (rc != ERROR_SUCCESS)
1548 break;
1550 msi_free_action_script(package, script);
1551 return rc;
1554 static UINT ACTION_FileCost(MSIPACKAGE *package)
1556 return ERROR_SUCCESS;
1559 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1561 MSICOMPONENT *comp;
1562 INSTALLSTATE state;
1563 UINT r;
1565 state = MsiQueryProductStateW(package->ProductCode);
1567 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1569 if (!comp->ComponentId)
1570 continue;
1572 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1573 comp->Installed = INSTALLSTATE_ABSENT;
1574 else
1576 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1577 package->Context, comp->ComponentId,
1578 &comp->Installed);
1579 if (r != ERROR_SUCCESS)
1580 comp->Installed = INSTALLSTATE_ABSENT;
1585 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1587 MSIFEATURE *feature;
1588 INSTALLSTATE state;
1590 state = MsiQueryProductStateW(package->ProductCode);
1592 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1594 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1595 feature->Installed = INSTALLSTATE_ABSENT;
1596 else
1598 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1599 feature->Feature);
1604 static BOOL process_state_property(MSIPACKAGE* package, int level,
1605 LPCWSTR property, INSTALLSTATE state)
1607 LPWSTR override;
1608 MSIFEATURE *feature;
1610 override = msi_dup_property( package, property );
1611 if (!override)
1612 return FALSE;
1614 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1616 if (lstrcmpW(property, szRemove) &&
1617 (feature->Level <= 0 || feature->Level > level))
1618 continue;
1620 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1622 if (strcmpiW(override, szAll)==0)
1623 msi_feature_set_state(package, feature, state);
1624 else
1626 LPWSTR ptr = override;
1627 LPWSTR ptr2 = strchrW(override,',');
1629 while (ptr)
1631 int len = ptr2 - ptr;
1633 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1634 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1636 msi_feature_set_state(package, feature, state);
1637 break;
1639 if (ptr2)
1641 ptr=ptr2+1;
1642 ptr2 = strchrW(ptr,',');
1644 else
1645 break;
1649 msi_free(override);
1651 return TRUE;
1654 static BOOL process_overrides( MSIPACKAGE *package, int level )
1656 static const WCHAR szAddLocal[] =
1657 {'A','D','D','L','O','C','A','L',0};
1658 static const WCHAR szAddSource[] =
1659 {'A','D','D','S','O','U','R','C','E',0};
1660 static const WCHAR szAdvertise[] =
1661 {'A','D','V','E','R','T','I','S','E',0};
1662 BOOL ret = FALSE;
1664 /* all these activation/deactivation things happen in order and things
1665 * later on the list override things earlier on the list.
1667 * 0 INSTALLLEVEL processing
1668 * 1 ADDLOCAL
1669 * 2 REMOVE
1670 * 3 ADDSOURCE
1671 * 4 ADDDEFAULT
1672 * 5 REINSTALL
1673 * 6 ADVERTISE
1674 * 7 COMPADDLOCAL
1675 * 8 COMPADDSOURCE
1676 * 9 FILEADDLOCAL
1677 * 10 FILEADDSOURCE
1678 * 11 FILEADDDEFAULT
1680 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1681 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1682 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1683 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1684 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1686 if (ret)
1687 MSI_SetPropertyW( package, szPreselected, szOne );
1689 return ret;
1692 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1694 int level;
1695 static const WCHAR szlevel[] =
1696 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1697 MSICOMPONENT* component;
1698 MSIFEATURE *feature;
1700 TRACE("Checking Install Level\n");
1702 level = msi_get_property_int(package, szlevel, 1);
1704 if (!msi_get_property_int( package, szPreselected, 0 ))
1706 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1708 BOOL feature_state = ((feature->Level > 0) &&
1709 (feature->Level <= level));
1711 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1713 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1714 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1715 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1716 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1717 else
1718 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1722 /* disable child features of unselected parent features */
1723 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1725 FeatureList *fl;
1727 if (feature->Level > 0 && feature->Level <= level)
1728 continue;
1730 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1731 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1736 * now we want to enable or disable components base on feature
1739 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1741 ComponentList *cl;
1743 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1744 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1746 if (!feature->Level)
1747 continue;
1749 /* features with components that have compressed files are made local */
1750 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1752 if (cl->component->Enabled &&
1753 cl->component->ForceLocalState &&
1754 feature->Action == INSTALLSTATE_SOURCE)
1756 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1757 break;
1761 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1763 component = cl->component;
1765 if (!component->Enabled)
1766 continue;
1768 switch (feature->Action)
1770 case INSTALLSTATE_ABSENT:
1771 component->anyAbsent = 1;
1772 break;
1773 case INSTALLSTATE_ADVERTISED:
1774 component->hasAdvertiseFeature = 1;
1775 break;
1776 case INSTALLSTATE_SOURCE:
1777 component->hasSourceFeature = 1;
1778 break;
1779 case INSTALLSTATE_LOCAL:
1780 component->hasLocalFeature = 1;
1781 break;
1782 case INSTALLSTATE_DEFAULT:
1783 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1784 component->hasAdvertiseFeature = 1;
1785 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1786 component->hasSourceFeature = 1;
1787 else
1788 component->hasLocalFeature = 1;
1789 break;
1790 default:
1791 break;
1796 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1798 /* if the component isn't enabled, leave it alone */
1799 if (!component->Enabled)
1800 continue;
1802 /* check if it's local or source */
1803 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1804 (component->hasLocalFeature || component->hasSourceFeature))
1806 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1807 !component->ForceLocalState)
1808 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1809 else
1810 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1811 continue;
1814 /* if any feature is local, the component must be local too */
1815 if (component->hasLocalFeature)
1817 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1818 continue;
1821 if (component->hasSourceFeature)
1823 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1824 continue;
1827 if (component->hasAdvertiseFeature)
1829 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1830 continue;
1833 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1834 if (component->anyAbsent)
1835 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1838 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1840 if (component->Action == INSTALLSTATE_DEFAULT)
1842 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1843 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1846 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1847 debugstr_w(component->Component), component->Installed, component->Action);
1851 return ERROR_SUCCESS;
1854 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1856 MSIPACKAGE *package = param;
1857 LPCWSTR name;
1858 LPWSTR path;
1859 MSIFOLDER *f;
1861 name = MSI_RecordGetString(row,1);
1863 f = get_loaded_folder(package, name);
1864 if (!f) return ERROR_SUCCESS;
1866 /* reset the ResolvedTarget */
1867 msi_free(f->ResolvedTarget);
1868 f->ResolvedTarget = NULL;
1870 /* This helper function now does ALL the work */
1871 TRACE("Dir %s ...\n",debugstr_w(name));
1872 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1873 TRACE("resolves to %s\n",debugstr_w(path));
1874 msi_free(path);
1876 return ERROR_SUCCESS;
1879 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1881 MSIPACKAGE *package = param;
1882 LPCWSTR name;
1883 MSIFEATURE *feature;
1885 name = MSI_RecordGetString( row, 1 );
1887 feature = get_loaded_feature( package, name );
1888 if (!feature)
1889 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1890 else
1892 LPCWSTR Condition;
1893 Condition = MSI_RecordGetString(row,3);
1895 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1897 int level = MSI_RecordGetInteger(row,2);
1898 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1899 feature->Level = level;
1902 return ERROR_SUCCESS;
1905 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1907 static const WCHAR name_fmt[] =
1908 {'%','u','.','%','u','.','%','u','.','%','u',0};
1909 static const WCHAR name[] = {'\\',0};
1910 VS_FIXEDFILEINFO *lpVer;
1911 WCHAR filever[0x100];
1912 LPVOID version;
1913 DWORD versize;
1914 DWORD handle;
1915 UINT sz;
1917 TRACE("%s\n", debugstr_w(filename));
1919 versize = GetFileVersionInfoSizeW( filename, &handle );
1920 if (!versize)
1921 return NULL;
1923 version = msi_alloc( versize );
1924 GetFileVersionInfoW( filename, 0, versize, version );
1926 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1928 msi_free( version );
1929 return NULL;
1932 sprintfW( filever, name_fmt,
1933 HIWORD(lpVer->dwFileVersionMS),
1934 LOWORD(lpVer->dwFileVersionMS),
1935 HIWORD(lpVer->dwFileVersionLS),
1936 LOWORD(lpVer->dwFileVersionLS));
1938 msi_free( version );
1940 return strdupW( filever );
1943 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1945 LPWSTR file_version;
1946 MSIFILE *file;
1948 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1950 MSICOMPONENT* comp = file->Component;
1951 LPWSTR p;
1953 if (!comp)
1954 continue;
1956 if (file->IsCompressed)
1957 comp->ForceLocalState = TRUE;
1959 /* calculate target */
1960 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1962 msi_free(file->TargetPath);
1964 TRACE("file %s is named %s\n",
1965 debugstr_w(file->File), debugstr_w(file->FileName));
1967 file->TargetPath = build_directory_name(2, p, file->FileName);
1969 msi_free(p);
1971 TRACE("file %s resolves to %s\n",
1972 debugstr_w(file->File), debugstr_w(file->TargetPath));
1974 /* don't check files of components that aren't installed */
1975 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1976 comp->Installed == INSTALLSTATE_ABSENT)
1978 file->state = msifs_missing; /* assume files are missing */
1979 continue;
1982 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1984 file->state = msifs_missing;
1985 comp->Cost += file->FileSize;
1986 continue;
1989 if (file->Version &&
1990 (file_version = msi_get_disk_file_version( file->TargetPath )))
1992 TRACE("new %s old %s\n", debugstr_w(file->Version),
1993 debugstr_w(file_version));
1994 /* FIXME: seems like a bad way to compare version numbers */
1995 if (lstrcmpiW(file_version, file->Version)<0)
1997 file->state = msifs_overwrite;
1998 comp->Cost += file->FileSize;
2000 else
2001 file->state = msifs_present;
2002 msi_free( file_version );
2004 else
2005 file->state = msifs_present;
2008 return ERROR_SUCCESS;
2012 * A lot is done in this function aside from just the costing.
2013 * The costing needs to be implemented at some point but for now I am going
2014 * to focus on the directory building
2017 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2019 static const WCHAR ExecSeqQuery[] =
2020 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2021 '`','D','i','r','e','c','t','o','r','y','`',0};
2022 static const WCHAR ConditionQuery[] =
2023 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2024 '`','C','o','n','d','i','t','i','o','n','`',0};
2025 static const WCHAR szCosting[] =
2026 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2027 static const WCHAR szlevel[] =
2028 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2029 static const WCHAR szOutOfDiskSpace[] =
2030 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2031 MSICOMPONENT *comp;
2032 UINT rc = ERROR_SUCCESS;
2033 MSIQUERY * view;
2034 LPWSTR level;
2036 TRACE("Building Directory properties\n");
2038 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2039 if (rc == ERROR_SUCCESS)
2041 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2042 package);
2043 msiobj_release(&view->hdr);
2046 /* read components states from the registry */
2047 ACTION_GetComponentInstallStates(package);
2048 ACTION_GetFeatureInstallStates(package);
2050 TRACE("File calculations\n");
2051 msi_check_file_install_states( package );
2053 if (!process_overrides( package, msi_get_property_int( package, szlevel, 1 ) ))
2055 TRACE("Evaluating Condition Table\n");
2057 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2058 if (rc == ERROR_SUCCESS)
2060 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2061 msiobj_release( &view->hdr );
2064 TRACE("Enabling or Disabling Components\n");
2065 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2067 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2069 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2070 comp->Enabled = FALSE;
2072 else
2073 comp->Enabled = TRUE;
2077 MSI_SetPropertyW(package,szCosting,szOne);
2078 /* set default run level if not set */
2079 level = msi_dup_property( package, szlevel );
2080 if (!level)
2081 MSI_SetPropertyW(package,szlevel, szOne);
2082 msi_free(level);
2084 /* FIXME: check volume disk space */
2085 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2087 return MSI_SetFeatureStates(package);
2090 /* OK this value is "interpreted" and then formatted based on the
2091 first few characters */
2092 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2093 DWORD *size)
2095 LPSTR data = NULL;
2097 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2099 if (value[1]=='x')
2101 LPWSTR ptr;
2102 CHAR byte[5];
2103 LPWSTR deformated = NULL;
2104 int count;
2106 deformat_string(package, &value[2], &deformated);
2108 /* binary value type */
2109 ptr = deformated;
2110 *type = REG_BINARY;
2111 if (strlenW(ptr)%2)
2112 *size = (strlenW(ptr)/2)+1;
2113 else
2114 *size = strlenW(ptr)/2;
2116 data = msi_alloc(*size);
2118 byte[0] = '0';
2119 byte[1] = 'x';
2120 byte[4] = 0;
2121 count = 0;
2122 /* if uneven pad with a zero in front */
2123 if (strlenW(ptr)%2)
2125 byte[2]= '0';
2126 byte[3]= *ptr;
2127 ptr++;
2128 data[count] = (BYTE)strtol(byte,NULL,0);
2129 count ++;
2130 TRACE("Uneven byte count\n");
2132 while (*ptr)
2134 byte[2]= *ptr;
2135 ptr++;
2136 byte[3]= *ptr;
2137 ptr++;
2138 data[count] = (BYTE)strtol(byte,NULL,0);
2139 count ++;
2141 msi_free(deformated);
2143 TRACE("Data %i bytes(%i)\n",*size,count);
2145 else
2147 LPWSTR deformated;
2148 LPWSTR p;
2149 DWORD d = 0;
2150 deformat_string(package, &value[1], &deformated);
2152 *type=REG_DWORD;
2153 *size = sizeof(DWORD);
2154 data = msi_alloc(*size);
2155 p = deformated;
2156 if (*p == '-')
2157 p++;
2158 while (*p)
2160 if ( (*p < '0') || (*p > '9') )
2161 break;
2162 d *= 10;
2163 d += (*p - '0');
2164 p++;
2166 if (deformated[0] == '-')
2167 d = -d;
2168 *(LPDWORD)data = d;
2169 TRACE("DWORD %i\n",*(LPDWORD)data);
2171 msi_free(deformated);
2174 else
2176 static const WCHAR szMulti[] = {'[','~',']',0};
2177 LPCWSTR ptr;
2178 *type=REG_SZ;
2180 if (value[0]=='#')
2182 if (value[1]=='%')
2184 ptr = &value[2];
2185 *type=REG_EXPAND_SZ;
2187 else
2188 ptr = &value[1];
2190 else
2191 ptr=value;
2193 if (strstrW(value,szMulti))
2194 *type = REG_MULTI_SZ;
2196 /* remove initial delimiter */
2197 if (!strncmpW(value, szMulti, 3))
2198 ptr = value + 3;
2200 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2202 /* add double NULL terminator */
2203 if (*type == REG_MULTI_SZ)
2205 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2206 data = msi_realloc_zero(data, *size);
2209 return data;
2212 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2214 const WCHAR *ret;
2216 switch (root)
2218 case -1:
2219 if (msi_get_property_int( package, szAllUsers, 0 ))
2221 *root_key = HKEY_LOCAL_MACHINE;
2222 ret = szHLM;
2224 else
2226 *root_key = HKEY_CURRENT_USER;
2227 ret = szHCU;
2229 break;
2230 case 0:
2231 *root_key = HKEY_CLASSES_ROOT;
2232 ret = szHCR;
2233 break;
2234 case 1:
2235 *root_key = HKEY_CURRENT_USER;
2236 ret = szHCU;
2237 break;
2238 case 2:
2239 *root_key = HKEY_LOCAL_MACHINE;
2240 ret = szHLM;
2241 break;
2242 case 3:
2243 *root_key = HKEY_USERS;
2244 ret = szHU;
2245 break;
2246 default:
2247 ERR("Unknown root %i\n", root);
2248 return NULL;
2251 return ret;
2254 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2256 MSIPACKAGE *package = param;
2257 LPSTR value_data = NULL;
2258 HKEY root_key, hkey;
2259 DWORD type,size;
2260 LPWSTR deformated;
2261 LPCWSTR szRoot, component, name, key, value;
2262 MSICOMPONENT *comp;
2263 MSIRECORD * uirow;
2264 LPWSTR uikey;
2265 INT root;
2266 BOOL check_first = FALSE;
2267 UINT rc;
2269 ui_progress(package,2,0,0,0);
2271 value = NULL;
2272 key = NULL;
2273 uikey = NULL;
2274 name = NULL;
2276 component = MSI_RecordGetString(row, 6);
2277 comp = get_loaded_component(package,component);
2278 if (!comp)
2279 return ERROR_SUCCESS;
2281 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2283 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2284 comp->Action = comp->Installed;
2285 return ERROR_SUCCESS;
2287 comp->Action = INSTALLSTATE_LOCAL;
2289 name = MSI_RecordGetString(row, 4);
2290 if( MSI_RecordIsNull(row,5) && name )
2292 /* null values can have special meanings */
2293 if (name[0]=='-' && name[1] == 0)
2294 return ERROR_SUCCESS;
2295 else if ((name[0]=='+' && name[1] == 0) ||
2296 (name[0] == '*' && name[1] == 0))
2297 name = NULL;
2298 check_first = TRUE;
2301 root = MSI_RecordGetInteger(row,2);
2302 key = MSI_RecordGetString(row, 3);
2304 szRoot = get_root_key( package, root, &root_key );
2305 if (!szRoot)
2306 return ERROR_SUCCESS;
2308 deformat_string(package, key , &deformated);
2309 size = strlenW(deformated) + strlenW(szRoot) + 1;
2310 uikey = msi_alloc(size*sizeof(WCHAR));
2311 strcpyW(uikey,szRoot);
2312 strcatW(uikey,deformated);
2314 if (RegCreateKeyW( root_key, deformated, &hkey))
2316 ERR("Could not create key %s\n",debugstr_w(deformated));
2317 msi_free(deformated);
2318 msi_free(uikey);
2319 return ERROR_SUCCESS;
2321 msi_free(deformated);
2323 value = MSI_RecordGetString(row,5);
2324 if (value)
2325 value_data = parse_value(package, value, &type, &size);
2326 else
2328 value_data = (LPSTR)strdupW(szEmpty);
2329 size = sizeof(szEmpty);
2330 type = REG_SZ;
2333 deformat_string(package, name, &deformated);
2335 if (!check_first)
2337 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2338 debugstr_w(uikey));
2339 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2341 else
2343 DWORD sz = 0;
2344 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2345 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2347 TRACE("value %s of %s checked already exists\n",
2348 debugstr_w(deformated), debugstr_w(uikey));
2350 else
2352 TRACE("Checked and setting value %s of %s\n",
2353 debugstr_w(deformated), debugstr_w(uikey));
2354 if (deformated || size)
2355 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2358 RegCloseKey(hkey);
2360 uirow = MSI_CreateRecord(3);
2361 MSI_RecordSetStringW(uirow,2,deformated);
2362 MSI_RecordSetStringW(uirow,1,uikey);
2363 if (type == REG_SZ || type == REG_EXPAND_SZ)
2364 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2365 ui_actiondata(package,szWriteRegistryValues,uirow);
2366 msiobj_release( &uirow->hdr );
2368 msi_free(value_data);
2369 msi_free(deformated);
2370 msi_free(uikey);
2372 return ERROR_SUCCESS;
2375 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2377 UINT rc;
2378 MSIQUERY * view;
2379 static const WCHAR ExecSeqQuery[] =
2380 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2381 '`','R','e','g','i','s','t','r','y','`',0 };
2383 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2384 if (rc != ERROR_SUCCESS)
2385 return ERROR_SUCCESS;
2387 /* increment progress bar each time action data is sent */
2388 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2390 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2392 msiobj_release(&view->hdr);
2393 return rc;
2396 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2398 LONG res;
2399 HKEY hkey;
2400 DWORD num_subkeys, num_values;
2402 if (delete_key)
2404 if ((res = RegDeleteTreeW( hkey_root, key )))
2406 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2408 return;
2411 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2413 if ((res = RegDeleteValueW( hkey, value )))
2415 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2417 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2418 NULL, NULL, NULL, NULL );
2419 RegCloseKey( hkey );
2421 if (!res && !num_subkeys && !num_values)
2423 TRACE("Removing empty key %s\n", debugstr_w(key));
2424 RegDeleteKeyW( hkey_root, key );
2426 return;
2428 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2432 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2434 MSIPACKAGE *package = param;
2435 LPCWSTR component, name, key_str, root_key_str;
2436 LPWSTR deformated_key, deformated_name, ui_key_str;
2437 MSICOMPONENT *comp;
2438 MSIRECORD *uirow;
2439 BOOL delete_key = FALSE;
2440 HKEY hkey_root;
2441 UINT size;
2442 INT root;
2444 ui_progress( package, 2, 0, 0, 0 );
2446 component = MSI_RecordGetString( row, 6 );
2447 comp = get_loaded_component( package, component );
2448 if (!comp)
2449 return ERROR_SUCCESS;
2451 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2453 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2454 comp->Action = comp->Installed;
2455 return ERROR_SUCCESS;
2457 comp->Action = INSTALLSTATE_ABSENT;
2459 name = MSI_RecordGetString( row, 4 );
2460 if (MSI_RecordIsNull( row, 5 ) && name )
2462 if (name[0] == '+' && !name[1])
2463 return ERROR_SUCCESS;
2464 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2466 delete_key = TRUE;
2467 name = NULL;
2471 root = MSI_RecordGetInteger( row, 2 );
2472 key_str = MSI_RecordGetString( row, 3 );
2474 root_key_str = get_root_key( package, root, &hkey_root );
2475 if (!root_key_str)
2476 return ERROR_SUCCESS;
2478 deformat_string( package, key_str, &deformated_key );
2479 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2480 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2481 strcpyW( ui_key_str, root_key_str );
2482 strcatW( ui_key_str, deformated_key );
2484 deformat_string( package, name, &deformated_name );
2486 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2487 msi_free( deformated_key );
2489 uirow = MSI_CreateRecord( 2 );
2490 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2491 MSI_RecordSetStringW( uirow, 2, deformated_name );
2493 ui_actiondata( package, szRemoveRegistryValues, uirow );
2494 msiobj_release( &uirow->hdr );
2496 msi_free( ui_key_str );
2497 msi_free( deformated_name );
2498 return ERROR_SUCCESS;
2501 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2503 MSIPACKAGE *package = param;
2504 LPCWSTR component, name, key_str, root_key_str;
2505 LPWSTR deformated_key, deformated_name, ui_key_str;
2506 MSICOMPONENT *comp;
2507 MSIRECORD *uirow;
2508 BOOL delete_key = FALSE;
2509 HKEY hkey_root;
2510 UINT size;
2511 INT root;
2513 ui_progress( package, 2, 0, 0, 0 );
2515 component = MSI_RecordGetString( row, 5 );
2516 comp = get_loaded_component( package, component );
2517 if (!comp)
2518 return ERROR_SUCCESS;
2520 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2522 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2523 comp->Action = comp->Installed;
2524 return ERROR_SUCCESS;
2526 comp->Action = INSTALLSTATE_LOCAL;
2528 if ((name = MSI_RecordGetString( row, 4 )))
2530 if (name[0] == '-' && !name[1])
2532 delete_key = TRUE;
2533 name = NULL;
2537 root = MSI_RecordGetInteger( row, 2 );
2538 key_str = MSI_RecordGetString( row, 3 );
2540 root_key_str = get_root_key( package, root, &hkey_root );
2541 if (!root_key_str)
2542 return ERROR_SUCCESS;
2544 deformat_string( package, key_str, &deformated_key );
2545 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2546 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2547 strcpyW( ui_key_str, root_key_str );
2548 strcatW( ui_key_str, deformated_key );
2550 deformat_string( package, name, &deformated_name );
2552 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2553 msi_free( deformated_key );
2555 uirow = MSI_CreateRecord( 2 );
2556 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2557 MSI_RecordSetStringW( uirow, 2, deformated_name );
2559 ui_actiondata( package, szRemoveRegistryValues, uirow );
2560 msiobj_release( &uirow->hdr );
2562 msi_free( ui_key_str );
2563 msi_free( deformated_name );
2564 return ERROR_SUCCESS;
2567 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2569 UINT rc;
2570 MSIQUERY *view;
2571 static const WCHAR registry_query[] =
2572 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2573 '`','R','e','g','i','s','t','r','y','`',0 };
2574 static const WCHAR remove_registry_query[] =
2575 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2576 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2578 /* increment progress bar each time action data is sent */
2579 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2581 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2582 if (rc == ERROR_SUCCESS)
2584 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2585 msiobj_release( &view->hdr );
2586 if (rc != ERROR_SUCCESS)
2587 return rc;
2590 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2591 if (rc == ERROR_SUCCESS)
2593 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2594 msiobj_release( &view->hdr );
2595 if (rc != ERROR_SUCCESS)
2596 return rc;
2599 return ERROR_SUCCESS;
2602 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2604 package->script->CurrentlyScripting = TRUE;
2606 return ERROR_SUCCESS;
2610 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2612 MSICOMPONENT *comp;
2613 DWORD progress = 0;
2614 DWORD total = 0;
2615 static const WCHAR q1[]=
2616 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2617 '`','R','e','g','i','s','t','r','y','`',0};
2618 UINT rc;
2619 MSIQUERY * view;
2620 MSIFEATURE *feature;
2621 MSIFILE *file;
2623 TRACE("InstallValidate\n");
2625 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2626 if (rc == ERROR_SUCCESS)
2628 MSI_IterateRecords( view, &progress, NULL, package );
2629 msiobj_release( &view->hdr );
2630 total += progress * REG_PROGRESS_VALUE;
2633 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2634 total += COMPONENT_PROGRESS_VALUE;
2636 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2637 total += file->FileSize;
2639 ui_progress(package,0,total,0,0);
2641 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2643 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2644 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2645 feature->ActionRequest);
2648 return ERROR_SUCCESS;
2651 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2653 MSIPACKAGE* package = param;
2654 LPCWSTR cond = NULL;
2655 LPCWSTR message = NULL;
2656 UINT r;
2658 static const WCHAR title[]=
2659 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2661 cond = MSI_RecordGetString(row,1);
2663 r = MSI_EvaluateConditionW(package,cond);
2664 if (r == MSICONDITION_FALSE)
2666 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2668 LPWSTR deformated;
2669 message = MSI_RecordGetString(row,2);
2670 deformat_string(package,message,&deformated);
2671 MessageBoxW(NULL,deformated,title,MB_OK);
2672 msi_free(deformated);
2675 return ERROR_INSTALL_FAILURE;
2678 return ERROR_SUCCESS;
2681 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2683 UINT rc;
2684 MSIQUERY * view = NULL;
2685 static const WCHAR ExecSeqQuery[] =
2686 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2687 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2689 TRACE("Checking launch conditions\n");
2691 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2692 if (rc != ERROR_SUCCESS)
2693 return ERROR_SUCCESS;
2695 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2696 msiobj_release(&view->hdr);
2698 return rc;
2701 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2704 if (!cmp->KeyPath)
2705 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2707 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2709 MSIRECORD * row = 0;
2710 UINT root,len;
2711 LPWSTR deformated,buffer,deformated_name;
2712 LPCWSTR key,name;
2713 static const WCHAR ExecSeqQuery[] =
2714 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2715 '`','R','e','g','i','s','t','r','y','`',' ',
2716 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2717 ' ','=',' ' ,'\'','%','s','\'',0 };
2718 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2719 static const WCHAR fmt2[]=
2720 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2722 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2723 if (!row)
2724 return NULL;
2726 root = MSI_RecordGetInteger(row,2);
2727 key = MSI_RecordGetString(row, 3);
2728 name = MSI_RecordGetString(row, 4);
2729 deformat_string(package, key , &deformated);
2730 deformat_string(package, name, &deformated_name);
2732 len = strlenW(deformated) + 6;
2733 if (deformated_name)
2734 len+=strlenW(deformated_name);
2736 buffer = msi_alloc( len *sizeof(WCHAR));
2738 if (deformated_name)
2739 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2740 else
2741 sprintfW(buffer,fmt,root,deformated);
2743 msi_free(deformated);
2744 msi_free(deformated_name);
2745 msiobj_release(&row->hdr);
2747 return buffer;
2749 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2751 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2752 return NULL;
2754 else
2756 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2758 if (file)
2759 return strdupW( file->TargetPath );
2761 return NULL;
2764 static HKEY openSharedDLLsKey(void)
2766 HKEY hkey=0;
2767 static const WCHAR path[] =
2768 {'S','o','f','t','w','a','r','e','\\',
2769 'M','i','c','r','o','s','o','f','t','\\',
2770 'W','i','n','d','o','w','s','\\',
2771 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2772 'S','h','a','r','e','d','D','L','L','s',0};
2774 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2775 return hkey;
2778 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2780 HKEY hkey;
2781 DWORD count=0;
2782 DWORD type;
2783 DWORD sz = sizeof(count);
2784 DWORD rc;
2786 hkey = openSharedDLLsKey();
2787 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2788 if (rc != ERROR_SUCCESS)
2789 count = 0;
2790 RegCloseKey(hkey);
2791 return count;
2794 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2796 HKEY hkey;
2798 hkey = openSharedDLLsKey();
2799 if (count > 0)
2800 msi_reg_set_val_dword( hkey, path, count );
2801 else
2802 RegDeleteValueW(hkey,path);
2803 RegCloseKey(hkey);
2804 return count;
2808 * Return TRUE if the count should be written out and FALSE if not
2810 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2812 MSIFEATURE *feature;
2813 INT count = 0;
2814 BOOL write = FALSE;
2816 /* only refcount DLLs */
2817 if (comp->KeyPath == NULL ||
2818 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2819 comp->Attributes & msidbComponentAttributesODBCDataSource)
2820 write = FALSE;
2821 else
2823 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2824 write = (count > 0);
2826 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2827 write = TRUE;
2830 /* increment counts */
2831 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2833 ComponentList *cl;
2835 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2836 continue;
2838 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2840 if ( cl->component == comp )
2841 count++;
2845 /* decrement counts */
2846 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2848 ComponentList *cl;
2850 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2851 continue;
2853 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2855 if ( cl->component == comp )
2856 count--;
2860 /* ref count all the files in the component */
2861 if (write)
2863 MSIFILE *file;
2865 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2867 if (file->Component == comp)
2868 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2872 /* add a count for permanent */
2873 if (comp->Attributes & msidbComponentAttributesPermanent)
2874 count ++;
2876 comp->RefCount = count;
2878 if (write)
2879 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2882 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2884 WCHAR squished_pc[GUID_SIZE];
2885 WCHAR squished_cc[GUID_SIZE];
2886 UINT rc;
2887 MSICOMPONENT *comp;
2888 HKEY hkey;
2890 TRACE("\n");
2892 squash_guid(package->ProductCode,squished_pc);
2893 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2895 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2897 MSIRECORD * uirow;
2899 ui_progress(package,2,0,0,0);
2900 if (!comp->ComponentId)
2901 continue;
2903 squash_guid(comp->ComponentId,squished_cc);
2905 msi_free(comp->FullKeypath);
2906 comp->FullKeypath = resolve_keypath( package, comp );
2908 ACTION_RefCountComponent( package, comp );
2910 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2911 debugstr_w(comp->Component),
2912 debugstr_w(squished_cc),
2913 debugstr_w(comp->FullKeypath),
2914 comp->RefCount);
2916 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2917 comp->ActionRequest == INSTALLSTATE_SOURCE)
2919 if (!comp->FullKeypath)
2920 continue;
2922 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2923 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2924 &hkey, TRUE);
2925 else
2926 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2927 &hkey, TRUE);
2929 if (rc != ERROR_SUCCESS)
2930 continue;
2932 if (comp->Attributes & msidbComponentAttributesPermanent)
2934 static const WCHAR szPermKey[] =
2935 { '0','0','0','0','0','0','0','0','0','0','0','0',
2936 '0','0','0','0','0','0','0','0','0','0','0','0',
2937 '0','0','0','0','0','0','0','0',0 };
2939 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2942 if (comp->Action == INSTALLSTATE_LOCAL)
2943 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2944 else
2946 MSIFILE *file;
2947 MSIRECORD *row;
2948 LPWSTR ptr, ptr2;
2949 WCHAR source[MAX_PATH];
2950 WCHAR base[MAX_PATH];
2951 LPWSTR sourcepath;
2953 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2954 static const WCHAR query[] = {
2955 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2956 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2957 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2958 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2959 '`','D','i','s','k','I','d','`',0};
2961 file = get_loaded_file(package, comp->KeyPath);
2962 if (!file)
2963 continue;
2965 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2966 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2967 ptr2 = strrchrW(source, '\\') + 1;
2968 msiobj_release(&row->hdr);
2970 lstrcpyW(base, package->PackagePath);
2971 ptr = strrchrW(base, '\\');
2972 *(ptr + 1) = '\0';
2974 sourcepath = resolve_file_source(package, file);
2975 ptr = sourcepath + lstrlenW(base);
2976 lstrcpyW(ptr2, ptr);
2977 msi_free(sourcepath);
2979 msi_reg_set_val_str(hkey, squished_pc, source);
2981 RegCloseKey(hkey);
2983 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
2985 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2986 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2987 else
2988 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2990 comp->Action = comp->ActionRequest;
2992 /* UI stuff */
2993 uirow = MSI_CreateRecord(3);
2994 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2995 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2996 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2997 ui_actiondata(package,szProcessComponents,uirow);
2998 msiobj_release( &uirow->hdr );
3001 return ERROR_SUCCESS;
3004 typedef struct {
3005 CLSID clsid;
3006 LPWSTR source;
3008 LPWSTR path;
3009 ITypeLib *ptLib;
3010 } typelib_struct;
3012 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3013 LPWSTR lpszName, LONG_PTR lParam)
3015 TLIBATTR *attr;
3016 typelib_struct *tl_struct = (typelib_struct*) lParam;
3017 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3018 int sz;
3019 HRESULT res;
3021 if (!IS_INTRESOURCE(lpszName))
3023 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3024 return TRUE;
3027 sz = strlenW(tl_struct->source)+4;
3028 sz *= sizeof(WCHAR);
3030 if ((INT_PTR)lpszName == 1)
3031 tl_struct->path = strdupW(tl_struct->source);
3032 else
3034 tl_struct->path = msi_alloc(sz);
3035 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3038 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3039 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3040 if (FAILED(res))
3042 msi_free(tl_struct->path);
3043 tl_struct->path = NULL;
3045 return TRUE;
3048 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3049 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3051 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3052 return FALSE;
3055 msi_free(tl_struct->path);
3056 tl_struct->path = NULL;
3058 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3059 ITypeLib_Release(tl_struct->ptLib);
3061 return TRUE;
3064 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3066 MSIPACKAGE* package = param;
3067 LPCWSTR component;
3068 MSICOMPONENT *comp;
3069 MSIFILE *file;
3070 typelib_struct tl_struct;
3071 ITypeLib *tlib;
3072 HMODULE module;
3073 HRESULT hr;
3075 component = MSI_RecordGetString(row,3);
3076 comp = get_loaded_component(package,component);
3077 if (!comp)
3078 return ERROR_SUCCESS;
3080 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3082 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3083 comp->Action = comp->Installed;
3084 return ERROR_SUCCESS;
3086 comp->Action = INSTALLSTATE_LOCAL;
3088 file = get_loaded_file( package, comp->KeyPath );
3089 if (!file)
3090 return ERROR_SUCCESS;
3092 ui_actiondata( package, szRegisterTypeLibraries, row );
3094 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3095 if (module)
3097 LPCWSTR guid;
3098 guid = MSI_RecordGetString(row,1);
3099 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3100 tl_struct.source = strdupW( file->TargetPath );
3101 tl_struct.path = NULL;
3103 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3104 (LONG_PTR)&tl_struct);
3106 if (tl_struct.path)
3108 LPWSTR help = NULL;
3109 LPCWSTR helpid;
3110 HRESULT res;
3112 helpid = MSI_RecordGetString(row,6);
3114 if (helpid)
3115 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3116 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3117 msi_free(help);
3119 if (FAILED(res))
3120 ERR("Failed to register type library %s\n",
3121 debugstr_w(tl_struct.path));
3122 else
3123 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3125 ITypeLib_Release(tl_struct.ptLib);
3126 msi_free(tl_struct.path);
3128 else
3129 ERR("Failed to load type library %s\n",
3130 debugstr_w(tl_struct.source));
3132 FreeLibrary(module);
3133 msi_free(tl_struct.source);
3135 else
3137 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3138 if (FAILED(hr))
3140 ERR("Failed to load type library: %08x\n", hr);
3141 return ERROR_INSTALL_FAILURE;
3144 ITypeLib_Release(tlib);
3147 return ERROR_SUCCESS;
3150 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3153 * OK this is a bit confusing.. I am given a _Component key and I believe
3154 * that the file that is being registered as a type library is the "key file
3155 * of that component" which I interpret to mean "The file in the KeyPath of
3156 * that component".
3158 UINT rc;
3159 MSIQUERY * view;
3160 static const WCHAR Query[] =
3161 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3162 '`','T','y','p','e','L','i','b','`',0};
3164 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3165 if (rc != ERROR_SUCCESS)
3166 return ERROR_SUCCESS;
3168 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3169 msiobj_release(&view->hdr);
3170 return rc;
3173 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3175 MSIPACKAGE *package = param;
3176 LPCWSTR component, guid;
3177 MSICOMPONENT *comp;
3178 GUID libid;
3179 UINT version;
3180 LCID language;
3181 SYSKIND syskind;
3182 HRESULT hr;
3184 component = MSI_RecordGetString( row, 3 );
3185 comp = get_loaded_component( package, component );
3186 if (!comp)
3187 return ERROR_SUCCESS;
3189 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3191 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3192 comp->Action = comp->Installed;
3193 return ERROR_SUCCESS;
3195 comp->Action = INSTALLSTATE_ABSENT;
3197 ui_actiondata( package, szUnregisterTypeLibraries, row );
3199 guid = MSI_RecordGetString( row, 1 );
3200 CLSIDFromString( (LPCWSTR)guid, &libid );
3201 version = MSI_RecordGetInteger( row, 4 );
3202 language = MSI_RecordGetInteger( row, 2 );
3204 #ifdef _WIN64
3205 syskind = SYS_WIN64;
3206 #else
3207 syskind = SYS_WIN32;
3208 #endif
3210 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3211 if (FAILED(hr))
3213 WARN("Failed to unregister typelib: %08x\n", hr);
3216 return ERROR_SUCCESS;
3219 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3221 UINT rc;
3222 MSIQUERY *view;
3223 static const WCHAR query[] =
3224 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3225 '`','T','y','p','e','L','i','b','`',0};
3227 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3228 if (rc != ERROR_SUCCESS)
3229 return ERROR_SUCCESS;
3231 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3232 msiobj_release( &view->hdr );
3233 return rc;
3236 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3238 static const WCHAR szlnk[] = {'.','l','n','k',0};
3239 LPCWSTR directory, extension;
3240 LPWSTR link_folder, link_file, filename;
3242 directory = MSI_RecordGetString( row, 2 );
3243 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3245 /* may be needed because of a bug somewhere else */
3246 create_full_pathW( link_folder );
3248 filename = msi_dup_record_field( row, 3 );
3249 reduce_to_longfilename( filename );
3251 extension = strchrW( filename, '.' );
3252 if (!extension || strcmpiW( extension, szlnk ))
3254 int len = strlenW( filename );
3255 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3256 memcpy( filename + len, szlnk, sizeof(szlnk) );
3258 link_file = build_directory_name( 2, link_folder, filename );
3259 msi_free( link_folder );
3260 msi_free( filename );
3262 return link_file;
3265 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3267 MSIPACKAGE *package = param;
3268 LPWSTR link_file, deformated, path;
3269 LPCWSTR component, target;
3270 MSICOMPONENT *comp;
3271 IShellLinkW *sl = NULL;
3272 IPersistFile *pf = NULL;
3273 HRESULT res;
3275 component = MSI_RecordGetString(row, 4);
3276 comp = get_loaded_component(package, component);
3277 if (!comp)
3278 return ERROR_SUCCESS;
3280 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3282 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3283 comp->Action = comp->Installed;
3284 return ERROR_SUCCESS;
3286 comp->Action = INSTALLSTATE_LOCAL;
3288 ui_actiondata(package,szCreateShortcuts,row);
3290 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3291 &IID_IShellLinkW, (LPVOID *) &sl );
3293 if (FAILED( res ))
3295 ERR("CLSID_ShellLink not available\n");
3296 goto err;
3299 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3300 if (FAILED( res ))
3302 ERR("QueryInterface(IID_IPersistFile) failed\n");
3303 goto err;
3306 target = MSI_RecordGetString(row, 5);
3307 if (strchrW(target, '['))
3309 deformat_string(package, target, &deformated);
3310 IShellLinkW_SetPath(sl,deformated);
3311 msi_free(deformated);
3313 else
3315 FIXME("poorly handled shortcut format, advertised shortcut\n");
3316 IShellLinkW_SetPath(sl,comp->FullKeypath);
3319 if (!MSI_RecordIsNull(row,6))
3321 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3322 deformat_string(package, arguments, &deformated);
3323 IShellLinkW_SetArguments(sl,deformated);
3324 msi_free(deformated);
3327 if (!MSI_RecordIsNull(row,7))
3329 LPCWSTR description = MSI_RecordGetString(row, 7);
3330 IShellLinkW_SetDescription(sl, description);
3333 if (!MSI_RecordIsNull(row,8))
3334 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3336 if (!MSI_RecordIsNull(row,9))
3338 INT index;
3339 LPCWSTR icon = MSI_RecordGetString(row, 9);
3341 path = build_icon_path(package, icon);
3342 index = MSI_RecordGetInteger(row,10);
3344 /* no value means 0 */
3345 if (index == MSI_NULL_INTEGER)
3346 index = 0;
3348 IShellLinkW_SetIconLocation(sl, path, index);
3349 msi_free(path);
3352 if (!MSI_RecordIsNull(row,11))
3353 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3355 if (!MSI_RecordIsNull(row,12))
3357 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3358 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3359 if (path)
3360 IShellLinkW_SetWorkingDirectory(sl, path);
3361 msi_free(path);
3364 link_file = get_link_file(package, row);
3366 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3367 IPersistFile_Save(pf, link_file, FALSE);
3369 msi_free(link_file);
3371 err:
3372 if (pf)
3373 IPersistFile_Release( pf );
3374 if (sl)
3375 IShellLinkW_Release( sl );
3377 return ERROR_SUCCESS;
3380 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3382 UINT rc;
3383 HRESULT res;
3384 MSIQUERY * view;
3385 static const WCHAR Query[] =
3386 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3387 '`','S','h','o','r','t','c','u','t','`',0};
3389 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3390 if (rc != ERROR_SUCCESS)
3391 return ERROR_SUCCESS;
3393 res = CoInitialize( NULL );
3395 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3396 msiobj_release(&view->hdr);
3398 if (SUCCEEDED(res))
3399 CoUninitialize();
3401 return rc;
3404 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3406 MSIPACKAGE *package = param;
3407 LPWSTR link_file;
3408 LPCWSTR component;
3409 MSICOMPONENT *comp;
3411 component = MSI_RecordGetString( row, 4 );
3412 comp = get_loaded_component( package, component );
3413 if (!comp)
3414 return ERROR_SUCCESS;
3416 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3418 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3419 comp->Action = comp->Installed;
3420 return ERROR_SUCCESS;
3422 comp->Action = INSTALLSTATE_ABSENT;
3424 ui_actiondata( package, szRemoveShortcuts, row );
3426 link_file = get_link_file( package, row );
3428 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3429 if (!DeleteFileW( link_file ))
3431 WARN("Failed to remove shortcut file %u\n", GetLastError());
3433 msi_free( link_file );
3435 return ERROR_SUCCESS;
3438 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3440 UINT rc;
3441 MSIQUERY *view;
3442 static const WCHAR query[] =
3443 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3444 '`','S','h','o','r','t','c','u','t','`',0};
3446 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3447 if (rc != ERROR_SUCCESS)
3448 return ERROR_SUCCESS;
3450 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3451 msiobj_release( &view->hdr );
3453 return rc;
3456 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3458 MSIPACKAGE* package = param;
3459 HANDLE the_file;
3460 LPWSTR FilePath;
3461 LPCWSTR FileName;
3462 CHAR buffer[1024];
3463 DWORD sz;
3464 UINT rc;
3466 FileName = MSI_RecordGetString(row,1);
3467 if (!FileName)
3469 ERR("Unable to get FileName\n");
3470 return ERROR_SUCCESS;
3473 FilePath = build_icon_path(package,FileName);
3475 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3477 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3478 FILE_ATTRIBUTE_NORMAL, NULL);
3480 if (the_file == INVALID_HANDLE_VALUE)
3482 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3483 msi_free(FilePath);
3484 return ERROR_SUCCESS;
3489 DWORD write;
3490 sz = 1024;
3491 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3492 if (rc != ERROR_SUCCESS)
3494 ERR("Failed to get stream\n");
3495 CloseHandle(the_file);
3496 DeleteFileW(FilePath);
3497 break;
3499 WriteFile(the_file,buffer,sz,&write,NULL);
3500 } while (sz == 1024);
3502 msi_free(FilePath);
3503 CloseHandle(the_file);
3505 return ERROR_SUCCESS;
3508 static UINT msi_publish_icons(MSIPACKAGE *package)
3510 UINT r;
3511 MSIQUERY *view;
3513 static const WCHAR query[]= {
3514 'S','E','L','E','C','T',' ','*',' ',
3515 'F','R','O','M',' ','`','I','c','o','n','`',0};
3517 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3518 if (r == ERROR_SUCCESS)
3520 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3521 msiobj_release(&view->hdr);
3524 return ERROR_SUCCESS;
3527 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3529 UINT r;
3530 HKEY source;
3531 LPWSTR buffer;
3532 MSIMEDIADISK *disk;
3533 MSISOURCELISTINFO *info;
3535 r = RegCreateKeyW(hkey, szSourceList, &source);
3536 if (r != ERROR_SUCCESS)
3537 return r;
3539 RegCloseKey(source);
3541 buffer = strrchrW(package->PackagePath, '\\') + 1;
3542 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3543 package->Context, MSICODE_PRODUCT,
3544 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3545 if (r != ERROR_SUCCESS)
3546 return r;
3548 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3549 package->Context, MSICODE_PRODUCT,
3550 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3551 if (r != ERROR_SUCCESS)
3552 return r;
3554 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3555 package->Context, MSICODE_PRODUCT,
3556 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3557 if (r != ERROR_SUCCESS)
3558 return r;
3560 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3562 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3563 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3564 info->options, info->value);
3565 else
3566 MsiSourceListSetInfoW(package->ProductCode, NULL,
3567 info->context, info->options,
3568 info->property, info->value);
3571 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3573 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3574 disk->context, disk->options,
3575 disk->disk_id, disk->volume_label, disk->disk_prompt);
3578 return ERROR_SUCCESS;
3581 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3583 MSIHANDLE hdb, suminfo;
3584 WCHAR guids[MAX_PATH];
3585 WCHAR packcode[SQUISH_GUID_SIZE];
3586 LPWSTR buffer;
3587 LPWSTR ptr;
3588 DWORD langid;
3589 DWORD size;
3590 UINT r;
3592 static const WCHAR szProductLanguage[] =
3593 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3594 static const WCHAR szARPProductIcon[] =
3595 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3596 static const WCHAR szProductVersion[] =
3597 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3598 static const WCHAR szAssignment[] =
3599 {'A','s','s','i','g','n','m','e','n','t',0};
3600 static const WCHAR szAdvertiseFlags[] =
3601 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3602 static const WCHAR szClients[] =
3603 {'C','l','i','e','n','t','s',0};
3604 static const WCHAR szColon[] = {':',0};
3606 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3607 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3608 msi_free(buffer);
3610 langid = msi_get_property_int(package, szProductLanguage, 0);
3611 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3613 /* FIXME */
3614 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3616 buffer = msi_dup_property(package, szARPProductIcon);
3617 if (buffer)
3619 LPWSTR path = build_icon_path(package,buffer);
3620 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3621 msi_free(path);
3622 msi_free(buffer);
3625 buffer = msi_dup_property(package, szProductVersion);
3626 if (buffer)
3628 DWORD verdword = msi_version_str_to_dword(buffer);
3629 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3630 msi_free(buffer);
3633 msi_reg_set_val_dword(hkey, szAssignment, 0);
3634 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3635 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3636 msi_reg_set_val_str(hkey, szClients, szColon);
3638 hdb = alloc_msihandle(&package->db->hdr);
3639 if (!hdb)
3640 return ERROR_NOT_ENOUGH_MEMORY;
3642 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3643 MsiCloseHandle(hdb);
3644 if (r != ERROR_SUCCESS)
3645 goto done;
3647 size = MAX_PATH;
3648 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3649 NULL, guids, &size);
3650 if (r != ERROR_SUCCESS)
3651 goto done;
3653 ptr = strchrW(guids, ';');
3654 if (ptr) *ptr = 0;
3655 squash_guid(guids, packcode);
3656 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3658 done:
3659 MsiCloseHandle(suminfo);
3660 return ERROR_SUCCESS;
3663 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3665 UINT r;
3666 HKEY hkey;
3667 LPWSTR upgrade;
3668 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3670 static const WCHAR szUpgradeCode[] =
3671 {'U','p','g','r','a','d','e','C','o','d','e',0};
3673 upgrade = msi_dup_property(package, szUpgradeCode);
3674 if (!upgrade)
3675 return ERROR_SUCCESS;
3677 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3679 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3680 if (r != ERROR_SUCCESS)
3681 goto done;
3683 else
3685 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3686 if (r != ERROR_SUCCESS)
3687 goto done;
3690 squash_guid(package->ProductCode, squashed_pc);
3691 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3693 RegCloseKey(hkey);
3695 done:
3696 msi_free(upgrade);
3697 return r;
3700 static BOOL msi_check_publish(MSIPACKAGE *package)
3702 MSIFEATURE *feature;
3704 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3706 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3707 return TRUE;
3710 return FALSE;
3713 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3715 MSIFEATURE *feature;
3717 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3719 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3720 return FALSE;
3723 return TRUE;
3726 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3728 WCHAR patch_squashed[GUID_SIZE];
3729 HKEY patches;
3730 LONG res;
3731 UINT r = ERROR_FUNCTION_FAILED;
3733 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3734 &patches, NULL);
3735 if (res != ERROR_SUCCESS)
3736 return ERROR_FUNCTION_FAILED;
3738 squash_guid(package->patch->patchcode, patch_squashed);
3740 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3741 (const BYTE *)patch_squashed,
3742 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3743 if (res != ERROR_SUCCESS)
3744 goto done;
3746 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3747 (const BYTE *)package->patch->transforms,
3748 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3749 if (res == ERROR_SUCCESS)
3750 r = ERROR_SUCCESS;
3752 done:
3753 RegCloseKey(patches);
3754 return r;
3758 * 99% of the work done here is only done for
3759 * advertised installs. However this is where the
3760 * Icon table is processed and written out
3761 * so that is what I am going to do here.
3763 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3765 UINT rc;
3766 HKEY hukey = NULL, hudkey = NULL;
3767 MSIRECORD *uirow;
3769 /* FIXME: also need to publish if the product is in advertise mode */
3770 if (!msi_check_publish(package))
3771 return ERROR_SUCCESS;
3773 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3774 &hukey, TRUE);
3775 if (rc != ERROR_SUCCESS)
3776 goto end;
3778 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3779 NULL, &hudkey, TRUE);
3780 if (rc != ERROR_SUCCESS)
3781 goto end;
3783 rc = msi_publish_upgrade_code(package);
3784 if (rc != ERROR_SUCCESS)
3785 goto end;
3787 if (package->patch)
3789 rc = msi_publish_patch(package, hukey, hudkey);
3790 if (rc != ERROR_SUCCESS)
3791 goto end;
3794 rc = msi_publish_product_properties(package, hukey);
3795 if (rc != ERROR_SUCCESS)
3796 goto end;
3798 rc = msi_publish_sourcelist(package, hukey);
3799 if (rc != ERROR_SUCCESS)
3800 goto end;
3802 rc = msi_publish_icons(package);
3804 end:
3805 uirow = MSI_CreateRecord( 1 );
3806 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3807 ui_actiondata( package, szPublishProduct, uirow );
3808 msiobj_release( &uirow->hdr );
3810 RegCloseKey(hukey);
3811 RegCloseKey(hudkey);
3813 return rc;
3816 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3818 WCHAR *filename, *ptr, *folder, *ret;
3819 const WCHAR *dirprop;
3821 filename = msi_dup_record_field( row, 2 );
3822 if (filename && (ptr = strchrW( filename, '|' )))
3823 ptr++;
3824 else
3825 ptr = filename;
3827 dirprop = MSI_RecordGetString( row, 3 );
3828 if (dirprop)
3830 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3831 if (!folder)
3832 folder = msi_dup_property( package, dirprop );
3834 else
3835 folder = msi_dup_property( package, szWindowsFolder );
3837 if (!folder)
3839 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3840 msi_free( filename );
3841 return NULL;
3844 ret = build_directory_name( 2, folder, ptr );
3846 msi_free( filename );
3847 msi_free( folder );
3848 return ret;
3851 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3853 MSIPACKAGE *package = param;
3854 LPCWSTR component, section, key, value, identifier;
3855 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
3856 MSIRECORD * uirow;
3857 INT action;
3858 MSICOMPONENT *comp;
3860 component = MSI_RecordGetString(row, 8);
3861 comp = get_loaded_component(package,component);
3862 if (!comp)
3863 return ERROR_SUCCESS;
3865 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3867 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3868 comp->Action = comp->Installed;
3869 return ERROR_SUCCESS;
3871 comp->Action = INSTALLSTATE_LOCAL;
3873 identifier = MSI_RecordGetString(row,1);
3874 section = MSI_RecordGetString(row,4);
3875 key = MSI_RecordGetString(row,5);
3876 value = MSI_RecordGetString(row,6);
3877 action = MSI_RecordGetInteger(row,7);
3879 deformat_string(package,section,&deformated_section);
3880 deformat_string(package,key,&deformated_key);
3881 deformat_string(package,value,&deformated_value);
3883 fullname = get_ini_file_name(package, row);
3885 if (action == 0)
3887 TRACE("Adding value %s to section %s in %s\n",
3888 debugstr_w(deformated_key), debugstr_w(deformated_section),
3889 debugstr_w(fullname));
3890 WritePrivateProfileStringW(deformated_section, deformated_key,
3891 deformated_value, fullname);
3893 else if (action == 1)
3895 WCHAR returned[10];
3896 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3897 returned, 10, fullname);
3898 if (returned[0] == 0)
3900 TRACE("Adding value %s to section %s in %s\n",
3901 debugstr_w(deformated_key), debugstr_w(deformated_section),
3902 debugstr_w(fullname));
3904 WritePrivateProfileStringW(deformated_section, deformated_key,
3905 deformated_value, fullname);
3908 else if (action == 3)
3909 FIXME("Append to existing section not yet implemented\n");
3911 uirow = MSI_CreateRecord(4);
3912 MSI_RecordSetStringW(uirow,1,identifier);
3913 MSI_RecordSetStringW(uirow,2,deformated_section);
3914 MSI_RecordSetStringW(uirow,3,deformated_key);
3915 MSI_RecordSetStringW(uirow,4,deformated_value);
3916 ui_actiondata(package,szWriteIniValues,uirow);
3917 msiobj_release( &uirow->hdr );
3919 msi_free(fullname);
3920 msi_free(deformated_key);
3921 msi_free(deformated_value);
3922 msi_free(deformated_section);
3923 return ERROR_SUCCESS;
3926 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3928 UINT rc;
3929 MSIQUERY * view;
3930 static const WCHAR ExecSeqQuery[] =
3931 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3932 '`','I','n','i','F','i','l','e','`',0};
3934 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3935 if (rc != ERROR_SUCCESS)
3937 TRACE("no IniFile table\n");
3938 return ERROR_SUCCESS;
3941 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3942 msiobj_release(&view->hdr);
3943 return rc;
3946 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
3948 MSIPACKAGE *package = param;
3949 LPCWSTR component, section, key, value, identifier;
3950 LPWSTR deformated_section, deformated_key, deformated_value, filename;
3951 MSICOMPONENT *comp;
3952 MSIRECORD *uirow;
3953 INT action;
3955 component = MSI_RecordGetString( row, 8 );
3956 comp = get_loaded_component( package, component );
3957 if (!comp)
3958 return ERROR_SUCCESS;
3960 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3962 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3963 comp->Action = comp->Installed;
3964 return ERROR_SUCCESS;
3966 comp->Action = INSTALLSTATE_ABSENT;
3968 identifier = MSI_RecordGetString( row, 1 );
3969 section = MSI_RecordGetString( row, 4 );
3970 key = MSI_RecordGetString( row, 5 );
3971 value = MSI_RecordGetString( row, 6 );
3972 action = MSI_RecordGetInteger( row, 7 );
3974 deformat_string( package, section, &deformated_section );
3975 deformat_string( package, key, &deformated_key );
3976 deformat_string( package, value, &deformated_value );
3978 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
3980 filename = get_ini_file_name( package, row );
3982 TRACE("Removing key %s from section %s in %s\n",
3983 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
3985 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
3987 WARN("Unable to remove key %u\n", GetLastError());
3989 msi_free( filename );
3991 else
3992 FIXME("Unsupported action %d\n", action);
3995 uirow = MSI_CreateRecord( 4 );
3996 MSI_RecordSetStringW( uirow, 1, identifier );
3997 MSI_RecordSetStringW( uirow, 2, deformated_section );
3998 MSI_RecordSetStringW( uirow, 3, deformated_key );
3999 MSI_RecordSetStringW( uirow, 4, deformated_value );
4000 ui_actiondata( package, szRemoveIniValues, uirow );
4001 msiobj_release( &uirow->hdr );
4003 msi_free( deformated_key );
4004 msi_free( deformated_value );
4005 msi_free( deformated_section );
4006 return ERROR_SUCCESS;
4009 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4011 MSIPACKAGE *package = param;
4012 LPCWSTR component, section, key, value, identifier;
4013 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4014 MSICOMPONENT *comp;
4015 MSIRECORD *uirow;
4016 INT action;
4018 component = MSI_RecordGetString( row, 8 );
4019 comp = get_loaded_component( package, component );
4020 if (!comp)
4021 return ERROR_SUCCESS;
4023 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4025 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4026 comp->Action = comp->Installed;
4027 return ERROR_SUCCESS;
4029 comp->Action = INSTALLSTATE_LOCAL;
4031 identifier = MSI_RecordGetString( row, 1 );
4032 section = MSI_RecordGetString( row, 4 );
4033 key = MSI_RecordGetString( row, 5 );
4034 value = MSI_RecordGetString( row, 6 );
4035 action = MSI_RecordGetInteger( row, 7 );
4037 deformat_string( package, section, &deformated_section );
4038 deformat_string( package, key, &deformated_key );
4039 deformat_string( package, value, &deformated_value );
4041 if (action == msidbIniFileActionRemoveLine)
4043 filename = get_ini_file_name( package, row );
4045 TRACE("Removing key %s from section %s in %s\n",
4046 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4048 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4050 WARN("Unable to remove key %u\n", GetLastError());
4052 msi_free( filename );
4054 else
4055 FIXME("Unsupported action %d\n", action);
4057 uirow = MSI_CreateRecord( 4 );
4058 MSI_RecordSetStringW( uirow, 1, identifier );
4059 MSI_RecordSetStringW( uirow, 2, deformated_section );
4060 MSI_RecordSetStringW( uirow, 3, deformated_key );
4061 MSI_RecordSetStringW( uirow, 4, deformated_value );
4062 ui_actiondata( package, szRemoveIniValues, uirow );
4063 msiobj_release( &uirow->hdr );
4065 msi_free( deformated_key );
4066 msi_free( deformated_value );
4067 msi_free( deformated_section );
4068 return ERROR_SUCCESS;
4071 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4073 UINT rc;
4074 MSIQUERY *view;
4075 static const WCHAR query[] =
4076 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4077 '`','I','n','i','F','i','l','e','`',0};
4078 static const WCHAR remove_query[] =
4079 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4080 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4082 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4083 if (rc == ERROR_SUCCESS)
4085 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4086 msiobj_release( &view->hdr );
4087 if (rc != ERROR_SUCCESS)
4088 return rc;
4091 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4092 if (rc == ERROR_SUCCESS)
4094 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4095 msiobj_release( &view->hdr );
4096 if (rc != ERROR_SUCCESS)
4097 return rc;
4100 return ERROR_SUCCESS;
4103 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4105 MSIPACKAGE *package = param;
4106 LPCWSTR filename;
4107 LPWSTR FullName;
4108 MSIFILE *file;
4109 DWORD len;
4110 static const WCHAR ExeStr[] =
4111 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4112 static const WCHAR close[] = {'\"',0};
4113 STARTUPINFOW si;
4114 PROCESS_INFORMATION info;
4115 BOOL brc;
4116 MSIRECORD *uirow;
4117 LPWSTR uipath, p;
4119 memset(&si,0,sizeof(STARTUPINFOW));
4121 filename = MSI_RecordGetString(row,1);
4122 file = get_loaded_file( package, filename );
4124 if (!file)
4126 ERR("Unable to find file id %s\n",debugstr_w(filename));
4127 return ERROR_SUCCESS;
4130 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4132 FullName = msi_alloc(len*sizeof(WCHAR));
4133 strcpyW(FullName,ExeStr);
4134 strcatW( FullName, file->TargetPath );
4135 strcatW(FullName,close);
4137 TRACE("Registering %s\n",debugstr_w(FullName));
4138 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4139 &si, &info);
4141 if (brc)
4143 CloseHandle(info.hThread);
4144 msi_dialog_check_messages(info.hProcess);
4145 CloseHandle(info.hProcess);
4148 uirow = MSI_CreateRecord( 2 );
4149 MSI_RecordSetStringW( uirow, 1, filename );
4150 uipath = strdupW( file->TargetPath );
4151 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4152 MSI_RecordSetStringW( uirow, 2, uipath );
4153 ui_actiondata( package, szSelfRegModules, uirow );
4154 msiobj_release( &uirow->hdr );
4156 msi_free( FullName );
4157 msi_free( uipath );
4158 return ERROR_SUCCESS;
4161 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4163 UINT rc;
4164 MSIQUERY * view;
4165 static const WCHAR ExecSeqQuery[] =
4166 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4167 '`','S','e','l','f','R','e','g','`',0};
4169 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4170 if (rc != ERROR_SUCCESS)
4172 TRACE("no SelfReg table\n");
4173 return ERROR_SUCCESS;
4176 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4177 msiobj_release(&view->hdr);
4179 return ERROR_SUCCESS;
4182 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4184 static const WCHAR regsvr32[] =
4185 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4186 static const WCHAR close[] = {'\"',0};
4187 MSIPACKAGE *package = param;
4188 LPCWSTR filename;
4189 LPWSTR cmdline;
4190 MSIFILE *file;
4191 DWORD len;
4192 STARTUPINFOW si;
4193 PROCESS_INFORMATION pi;
4194 BOOL ret;
4195 MSIRECORD *uirow;
4196 LPWSTR uipath, p;
4198 memset( &si, 0, sizeof(STARTUPINFOW) );
4200 filename = MSI_RecordGetString( row, 1 );
4201 file = get_loaded_file( package, filename );
4203 if (!file)
4205 ERR("Unable to find file id %s\n", debugstr_w(filename));
4206 return ERROR_SUCCESS;
4209 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4211 cmdline = msi_alloc( len * sizeof(WCHAR) );
4212 strcpyW( cmdline, regsvr32 );
4213 strcatW( cmdline, file->TargetPath );
4214 strcatW( cmdline, close );
4216 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4218 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4219 if (ret)
4221 CloseHandle( pi.hThread );
4222 msi_dialog_check_messages( pi.hProcess );
4223 CloseHandle( pi.hProcess );
4226 uirow = MSI_CreateRecord( 2 );
4227 MSI_RecordSetStringW( uirow, 1, filename );
4228 uipath = strdupW( file->TargetPath );
4229 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4230 MSI_RecordSetStringW( uirow, 2, uipath );
4231 ui_actiondata( package, szSelfUnregModules, uirow );
4232 msiobj_release( &uirow->hdr );
4234 msi_free( cmdline );
4235 msi_free( uipath );
4236 return ERROR_SUCCESS;
4239 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4241 UINT rc;
4242 MSIQUERY *view;
4243 static const WCHAR query[] =
4244 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4245 '`','S','e','l','f','R','e','g','`',0};
4247 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4248 if (rc != ERROR_SUCCESS)
4250 TRACE("no SelfReg table\n");
4251 return ERROR_SUCCESS;
4254 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4255 msiobj_release( &view->hdr );
4257 return ERROR_SUCCESS;
4260 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4262 MSIFEATURE *feature;
4263 UINT rc;
4264 HKEY hkey = NULL, userdata = NULL;
4266 if (!msi_check_publish(package))
4267 return ERROR_SUCCESS;
4269 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4270 &hkey, TRUE);
4271 if (rc != ERROR_SUCCESS)
4272 goto end;
4274 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4275 &userdata, TRUE);
4276 if (rc != ERROR_SUCCESS)
4277 goto end;
4279 /* here the guids are base 85 encoded */
4280 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4282 ComponentList *cl;
4283 LPWSTR data = NULL;
4284 GUID clsid;
4285 INT size;
4286 BOOL absent = FALSE;
4287 MSIRECORD *uirow;
4289 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4290 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4291 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4293 size = 1;
4294 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4296 size += 21;
4298 if (feature->Feature_Parent)
4299 size += strlenW( feature->Feature_Parent )+2;
4301 data = msi_alloc(size * sizeof(WCHAR));
4303 data[0] = 0;
4304 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4306 MSICOMPONENT* component = cl->component;
4307 WCHAR buf[21];
4309 buf[0] = 0;
4310 if (component->ComponentId)
4312 TRACE("From %s\n",debugstr_w(component->ComponentId));
4313 CLSIDFromString(component->ComponentId, &clsid);
4314 encode_base85_guid(&clsid,buf);
4315 TRACE("to %s\n",debugstr_w(buf));
4316 strcatW(data,buf);
4320 if (feature->Feature_Parent)
4322 static const WCHAR sep[] = {'\2',0};
4323 strcatW(data,sep);
4324 strcatW(data,feature->Feature_Parent);
4327 msi_reg_set_val_str( userdata, feature->Feature, data );
4328 msi_free(data);
4330 size = 0;
4331 if (feature->Feature_Parent)
4332 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4333 if (!absent)
4335 size += sizeof(WCHAR);
4336 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4337 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4339 else
4341 size += 2*sizeof(WCHAR);
4342 data = msi_alloc(size);
4343 data[0] = 0x6;
4344 data[1] = 0;
4345 if (feature->Feature_Parent)
4346 strcpyW( &data[1], feature->Feature_Parent );
4347 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4348 (LPBYTE)data,size);
4349 msi_free(data);
4352 /* the UI chunk */
4353 uirow = MSI_CreateRecord( 1 );
4354 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4355 ui_actiondata( package, szPublishFeatures, uirow);
4356 msiobj_release( &uirow->hdr );
4357 /* FIXME: call ui_progress? */
4360 end:
4361 RegCloseKey(hkey);
4362 RegCloseKey(userdata);
4363 return rc;
4366 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4368 UINT r;
4369 HKEY hkey;
4370 MSIRECORD *uirow;
4372 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4374 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4375 &hkey, FALSE);
4376 if (r == ERROR_SUCCESS)
4378 RegDeleteValueW(hkey, feature->Feature);
4379 RegCloseKey(hkey);
4382 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4383 &hkey, FALSE);
4384 if (r == ERROR_SUCCESS)
4386 RegDeleteValueW(hkey, feature->Feature);
4387 RegCloseKey(hkey);
4390 uirow = MSI_CreateRecord( 1 );
4391 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4392 ui_actiondata( package, szUnpublishFeatures, uirow );
4393 msiobj_release( &uirow->hdr );
4395 return ERROR_SUCCESS;
4398 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4400 MSIFEATURE *feature;
4402 if (!msi_check_unpublish(package))
4403 return ERROR_SUCCESS;
4405 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4407 msi_unpublish_feature(package, feature);
4410 return ERROR_SUCCESS;
4413 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4415 LPWSTR prop, val, key;
4416 SYSTEMTIME systime;
4417 DWORD size, langid;
4418 WCHAR date[9];
4419 LPWSTR buffer;
4421 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4422 static const WCHAR szWindowsInstaller[] =
4423 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4424 static const WCHAR modpath_fmt[] =
4425 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4426 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4427 static const WCHAR szModifyPath[] =
4428 {'M','o','d','i','f','y','P','a','t','h',0};
4429 static const WCHAR szUninstallString[] =
4430 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4431 static const WCHAR szEstimatedSize[] =
4432 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4433 static const WCHAR szProductLanguage[] =
4434 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4435 static const WCHAR szProductVersion[] =
4436 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4437 static const WCHAR szProductName[] =
4438 {'P','r','o','d','u','c','t','N','a','m','e',0};
4439 static const WCHAR szDisplayName[] =
4440 {'D','i','s','p','l','a','y','N','a','m','e',0};
4441 static const WCHAR szDisplayVersion[] =
4442 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4443 static const WCHAR szManufacturer[] =
4444 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4446 static const LPCSTR propval[] = {
4447 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4448 "ARPCONTACT", "Contact",
4449 "ARPCOMMENTS", "Comments",
4450 "ProductName", "DisplayName",
4451 "ProductVersion", "DisplayVersion",
4452 "ARPHELPLINK", "HelpLink",
4453 "ARPHELPTELEPHONE", "HelpTelephone",
4454 "ARPINSTALLLOCATION", "InstallLocation",
4455 "SourceDir", "InstallSource",
4456 "Manufacturer", "Publisher",
4457 "ARPREADME", "Readme",
4458 "ARPSIZE", "Size",
4459 "ARPURLINFOABOUT", "URLInfoAbout",
4460 "ARPURLUPDATEINFO", "URLUpdateInfo",
4461 NULL,
4463 const LPCSTR *p = propval;
4465 while (*p)
4467 prop = strdupAtoW(*p++);
4468 key = strdupAtoW(*p++);
4469 val = msi_dup_property(package, prop);
4470 msi_reg_set_val_str(hkey, key, val);
4471 msi_free(val);
4472 msi_free(key);
4473 msi_free(prop);
4476 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4478 size = deformat_string(package, modpath_fmt, &buffer);
4479 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4480 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4481 msi_free(buffer);
4483 /* FIXME: Write real Estimated Size when we have it */
4484 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4486 buffer = msi_dup_property(package, szProductName);
4487 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4488 msi_free(buffer);
4490 buffer = msi_dup_property(package, cszSourceDir);
4491 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4492 msi_free(buffer);
4494 buffer = msi_dup_property(package, szManufacturer);
4495 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4496 msi_free(buffer);
4498 GetLocalTime(&systime);
4499 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4500 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4502 langid = msi_get_property_int(package, szProductLanguage, 0);
4503 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4505 buffer = msi_dup_property(package, szProductVersion);
4506 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4507 if (buffer)
4509 DWORD verdword = msi_version_str_to_dword(buffer);
4511 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4512 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4513 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4514 msi_free(buffer);
4517 return ERROR_SUCCESS;
4520 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4522 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4523 MSIRECORD *uirow;
4524 LPWSTR upgrade_code;
4525 HKEY hkey, props;
4526 HKEY upgrade;
4527 UINT rc;
4529 static const WCHAR szUpgradeCode[] = {
4530 'U','p','g','r','a','d','e','C','o','d','e',0};
4532 /* FIXME: also need to publish if the product is in advertise mode */
4533 if (!msi_check_publish(package))
4534 return ERROR_SUCCESS;
4536 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4537 if (rc != ERROR_SUCCESS)
4538 return rc;
4540 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4541 NULL, &props, TRUE);
4542 if (rc != ERROR_SUCCESS)
4543 goto done;
4545 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4546 msi_free( package->db->localfile );
4547 package->db->localfile = NULL;
4549 rc = msi_publish_install_properties(package, hkey);
4550 if (rc != ERROR_SUCCESS)
4551 goto done;
4553 rc = msi_publish_install_properties(package, props);
4554 if (rc != ERROR_SUCCESS)
4555 goto done;
4557 upgrade_code = msi_dup_property(package, szUpgradeCode);
4558 if (upgrade_code)
4560 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4561 squash_guid(package->ProductCode, squashed_pc);
4562 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4563 RegCloseKey(upgrade);
4564 msi_free(upgrade_code);
4567 done:
4568 uirow = MSI_CreateRecord( 1 );
4569 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4570 ui_actiondata( package, szRegisterProduct, uirow );
4571 msiobj_release( &uirow->hdr );
4573 RegCloseKey(hkey);
4574 return ERROR_SUCCESS;
4577 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4579 return execute_script(package,INSTALL_SCRIPT);
4582 static UINT msi_unpublish_product(MSIPACKAGE *package)
4584 LPWSTR upgrade;
4585 LPWSTR remove = NULL;
4586 LPWSTR *features = NULL;
4587 BOOL full_uninstall = TRUE;
4588 MSIFEATURE *feature;
4590 static const WCHAR szUpgradeCode[] =
4591 {'U','p','g','r','a','d','e','C','o','d','e',0};
4593 remove = msi_dup_property(package, szRemove);
4594 if (!remove)
4595 return ERROR_SUCCESS;
4597 features = msi_split_string(remove, ',');
4598 if (!features)
4600 msi_free(remove);
4601 ERR("REMOVE feature list is empty!\n");
4602 return ERROR_FUNCTION_FAILED;
4605 if (!lstrcmpW(features[0], szAll))
4606 full_uninstall = TRUE;
4607 else
4609 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4611 if (feature->Action != INSTALLSTATE_ABSENT)
4612 full_uninstall = FALSE;
4616 if (!full_uninstall)
4617 goto done;
4619 MSIREG_DeleteProductKey(package->ProductCode);
4620 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4621 MSIREG_DeleteUninstallKey(package->ProductCode);
4623 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4625 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4626 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4628 else
4630 MSIREG_DeleteUserProductKey(package->ProductCode);
4631 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4634 upgrade = msi_dup_property(package, szUpgradeCode);
4635 if (upgrade)
4637 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4638 msi_free(upgrade);
4641 done:
4642 msi_free(remove);
4643 msi_free(features);
4644 return ERROR_SUCCESS;
4647 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4649 UINT rc;
4651 rc = msi_unpublish_product(package);
4652 if (rc != ERROR_SUCCESS)
4653 return rc;
4655 /* turn off scheduling */
4656 package->script->CurrentlyScripting= FALSE;
4658 /* first do the same as an InstallExecute */
4659 rc = ACTION_InstallExecute(package);
4660 if (rc != ERROR_SUCCESS)
4661 return rc;
4663 /* then handle Commit Actions */
4664 rc = execute_script(package,COMMIT_SCRIPT);
4666 return rc;
4669 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4671 static const WCHAR RunOnce[] = {
4672 'S','o','f','t','w','a','r','e','\\',
4673 'M','i','c','r','o','s','o','f','t','\\',
4674 'W','i','n','d','o','w','s','\\',
4675 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4676 'R','u','n','O','n','c','e',0};
4677 static const WCHAR InstallRunOnce[] = {
4678 'S','o','f','t','w','a','r','e','\\',
4679 'M','i','c','r','o','s','o','f','t','\\',
4680 'W','i','n','d','o','w','s','\\',
4681 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4682 'I','n','s','t','a','l','l','e','r','\\',
4683 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4685 static const WCHAR msiexec_fmt[] = {
4686 '%','s',
4687 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4688 '\"','%','s','\"',0};
4689 static const WCHAR install_fmt[] = {
4690 '/','I',' ','\"','%','s','\"',' ',
4691 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4692 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4693 WCHAR buffer[256], sysdir[MAX_PATH];
4694 HKEY hkey;
4695 WCHAR squished_pc[100];
4697 squash_guid(package->ProductCode,squished_pc);
4699 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4700 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4701 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4702 squished_pc);
4704 msi_reg_set_val_str( hkey, squished_pc, buffer );
4705 RegCloseKey(hkey);
4707 TRACE("Reboot command %s\n",debugstr_w(buffer));
4709 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4710 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4712 msi_reg_set_val_str( hkey, squished_pc, buffer );
4713 RegCloseKey(hkey);
4715 return ERROR_INSTALL_SUSPEND;
4718 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4720 DWORD attrib;
4721 UINT rc;
4724 * We are currently doing what should be done here in the top level Install
4725 * however for Administrative and uninstalls this step will be needed
4727 if (!package->PackagePath)
4728 return ERROR_SUCCESS;
4730 msi_set_sourcedir_props(package, TRUE);
4732 attrib = GetFileAttributesW(package->db->path);
4733 if (attrib == INVALID_FILE_ATTRIBUTES)
4735 LPWSTR prompt;
4736 LPWSTR msg;
4737 DWORD size = 0;
4739 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4740 package->Context, MSICODE_PRODUCT,
4741 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4742 if (rc == ERROR_MORE_DATA)
4744 prompt = msi_alloc(size * sizeof(WCHAR));
4745 MsiSourceListGetInfoW(package->ProductCode, NULL,
4746 package->Context, MSICODE_PRODUCT,
4747 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4749 else
4750 prompt = strdupW(package->db->path);
4752 msg = generate_error_string(package,1302,1,prompt);
4753 while(attrib == INVALID_FILE_ATTRIBUTES)
4755 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4756 if (rc == IDCANCEL)
4758 rc = ERROR_INSTALL_USEREXIT;
4759 break;
4761 attrib = GetFileAttributesW(package->db->path);
4763 msi_free(prompt);
4764 rc = ERROR_SUCCESS;
4766 else
4767 return ERROR_SUCCESS;
4769 return rc;
4772 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4774 HKEY hkey = 0;
4775 LPWSTR buffer, productid = NULL;
4776 UINT i, rc = ERROR_SUCCESS;
4777 MSIRECORD *uirow;
4779 static const WCHAR szPropKeys[][80] =
4781 {'P','r','o','d','u','c','t','I','D',0},
4782 {'U','S','E','R','N','A','M','E',0},
4783 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4784 {0},
4787 static const WCHAR szRegKeys[][80] =
4789 {'P','r','o','d','u','c','t','I','D',0},
4790 {'R','e','g','O','w','n','e','r',0},
4791 {'R','e','g','C','o','m','p','a','n','y',0},
4792 {0},
4795 if (msi_check_unpublish(package))
4797 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4798 goto end;
4801 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4802 if (!productid)
4803 goto end;
4805 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4806 NULL, &hkey, TRUE);
4807 if (rc != ERROR_SUCCESS)
4808 goto end;
4810 for( i = 0; szPropKeys[i][0]; i++ )
4812 buffer = msi_dup_property( package, szPropKeys[i] );
4813 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4814 msi_free( buffer );
4817 end:
4818 uirow = MSI_CreateRecord( 1 );
4819 MSI_RecordSetStringW( uirow, 1, productid );
4820 ui_actiondata( package, szRegisterUser, uirow );
4821 msiobj_release( &uirow->hdr );
4823 msi_free(productid);
4824 RegCloseKey(hkey);
4825 return rc;
4829 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4831 UINT rc;
4833 package->script->InWhatSequence |= SEQUENCE_EXEC;
4834 rc = ACTION_ProcessExecSequence(package,FALSE);
4835 return rc;
4839 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4841 MSIPACKAGE *package = param;
4842 LPCWSTR compgroupid, component, feature, qualifier, text;
4843 LPWSTR advertise = NULL, output = NULL;
4844 HKEY hkey = NULL;
4845 UINT rc;
4846 MSICOMPONENT *comp;
4847 MSIFEATURE *feat;
4848 DWORD sz;
4849 MSIRECORD *uirow;
4851 feature = MSI_RecordGetString(rec, 5);
4852 feat = get_loaded_feature(package, feature);
4853 if (!feat)
4854 return ERROR_SUCCESS;
4856 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4857 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4858 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
4860 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4861 feat->Action = feat->Installed;
4862 return ERROR_SUCCESS;
4865 component = MSI_RecordGetString(rec, 3);
4866 comp = get_loaded_component(package, component);
4867 if (!comp)
4868 return ERROR_SUCCESS;
4870 compgroupid = MSI_RecordGetString(rec,1);
4871 qualifier = MSI_RecordGetString(rec,2);
4873 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4874 if (rc != ERROR_SUCCESS)
4875 goto end;
4877 text = MSI_RecordGetString(rec,4);
4878 advertise = create_component_advertise_string(package, comp, feature);
4880 sz = strlenW(advertise);
4882 if (text)
4883 sz += lstrlenW(text);
4885 sz+=3;
4886 sz *= sizeof(WCHAR);
4888 output = msi_alloc_zero(sz);
4889 strcpyW(output,advertise);
4890 msi_free(advertise);
4892 if (text)
4893 strcatW(output,text);
4895 msi_reg_set_val_multi_str( hkey, qualifier, output );
4897 end:
4898 RegCloseKey(hkey);
4899 msi_free(output);
4901 /* the UI chunk */
4902 uirow = MSI_CreateRecord( 2 );
4903 MSI_RecordSetStringW( uirow, 1, compgroupid );
4904 MSI_RecordSetStringW( uirow, 2, qualifier);
4905 ui_actiondata( package, szPublishComponents, uirow);
4906 msiobj_release( &uirow->hdr );
4907 /* FIXME: call ui_progress? */
4909 return rc;
4913 * At present I am ignorning the advertised components part of this and only
4914 * focusing on the qualified component sets
4916 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4918 UINT rc;
4919 MSIQUERY * view;
4920 static const WCHAR ExecSeqQuery[] =
4921 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4922 '`','P','u','b','l','i','s','h',
4923 'C','o','m','p','o','n','e','n','t','`',0};
4925 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4926 if (rc != ERROR_SUCCESS)
4927 return ERROR_SUCCESS;
4929 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4930 msiobj_release(&view->hdr);
4932 return rc;
4935 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
4937 static const WCHAR szInstallerComponents[] = {
4938 'S','o','f','t','w','a','r','e','\\',
4939 'M','i','c','r','o','s','o','f','t','\\',
4940 'I','n','s','t','a','l','l','e','r','\\',
4941 'C','o','m','p','o','n','e','n','t','s','\\',0};
4943 MSIPACKAGE *package = param;
4944 LPCWSTR compgroupid, component, feature, qualifier;
4945 MSICOMPONENT *comp;
4946 MSIFEATURE *feat;
4947 MSIRECORD *uirow;
4948 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
4949 LONG res;
4951 feature = MSI_RecordGetString( rec, 5 );
4952 feat = get_loaded_feature( package, feature );
4953 if (!feat)
4954 return ERROR_SUCCESS;
4956 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
4958 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
4959 feat->Action = feat->Installed;
4960 return ERROR_SUCCESS;
4963 component = MSI_RecordGetString( rec, 3 );
4964 comp = get_loaded_component( package, component );
4965 if (!comp)
4966 return ERROR_SUCCESS;
4968 compgroupid = MSI_RecordGetString( rec, 1 );
4969 qualifier = MSI_RecordGetString( rec, 2 );
4971 squash_guid( compgroupid, squashed );
4972 strcpyW( keypath, szInstallerComponents );
4973 strcatW( keypath, squashed );
4975 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
4976 if (res != ERROR_SUCCESS)
4978 WARN("Unable to delete component key %d\n", res);
4981 uirow = MSI_CreateRecord( 2 );
4982 MSI_RecordSetStringW( uirow, 1, compgroupid );
4983 MSI_RecordSetStringW( uirow, 2, qualifier );
4984 ui_actiondata( package, szUnpublishComponents, uirow );
4985 msiobj_release( &uirow->hdr );
4987 return ERROR_SUCCESS;
4990 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
4992 UINT rc;
4993 MSIQUERY *view;
4994 static const WCHAR query[] =
4995 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4996 '`','P','u','b','l','i','s','h',
4997 'C','o','m','p','o','n','e','n','t','`',0};
4999 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5000 if (rc != ERROR_SUCCESS)
5001 return ERROR_SUCCESS;
5003 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5004 msiobj_release( &view->hdr );
5006 return rc;
5009 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5011 MSIPACKAGE *package = param;
5012 MSIRECORD *row;
5013 MSIFILE *file;
5014 SC_HANDLE hscm, service = NULL;
5015 LPCWSTR comp, depends, pass;
5016 LPWSTR name = NULL, disp = NULL;
5017 LPCWSTR load_order, serv_name, key;
5018 DWORD serv_type, start_type;
5019 DWORD err_control;
5021 static const WCHAR query[] =
5022 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5023 '`','C','o','m','p','o','n','e','n','t','`',' ',
5024 'W','H','E','R','E',' ',
5025 '`','C','o','m','p','o','n','e','n','t','`',' ',
5026 '=','\'','%','s','\'',0};
5028 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5029 if (!hscm)
5031 ERR("Failed to open the SC Manager!\n");
5032 goto done;
5035 start_type = MSI_RecordGetInteger(rec, 5);
5036 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5037 goto done;
5039 depends = MSI_RecordGetString(rec, 8);
5040 if (depends && *depends)
5041 FIXME("Dependency list unhandled!\n");
5043 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5044 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5045 serv_type = MSI_RecordGetInteger(rec, 4);
5046 err_control = MSI_RecordGetInteger(rec, 6);
5047 load_order = MSI_RecordGetString(rec, 7);
5048 serv_name = MSI_RecordGetString(rec, 9);
5049 pass = MSI_RecordGetString(rec, 10);
5050 comp = MSI_RecordGetString(rec, 12);
5052 /* fetch the service path */
5053 row = MSI_QueryGetRecord(package->db, query, comp);
5054 if (!row)
5056 ERR("Control query failed!\n");
5057 goto done;
5060 key = MSI_RecordGetString(row, 6);
5062 file = get_loaded_file(package, key);
5063 msiobj_release(&row->hdr);
5064 if (!file)
5066 ERR("Failed to load the service file\n");
5067 goto done;
5070 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5071 start_type, err_control, file->TargetPath,
5072 load_order, NULL, NULL, serv_name, pass);
5073 if (!service)
5075 if (GetLastError() != ERROR_SERVICE_EXISTS)
5076 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5079 done:
5080 CloseServiceHandle(service);
5081 CloseServiceHandle(hscm);
5082 msi_free(name);
5083 msi_free(disp);
5085 return ERROR_SUCCESS;
5088 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5090 UINT rc;
5091 MSIQUERY * view;
5092 static const WCHAR ExecSeqQuery[] =
5093 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5094 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5096 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5097 if (rc != ERROR_SUCCESS)
5098 return ERROR_SUCCESS;
5100 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5101 msiobj_release(&view->hdr);
5103 return rc;
5106 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5107 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5109 LPCWSTR *vector, *temp_vector;
5110 LPWSTR p, q;
5111 DWORD sep_len;
5113 static const WCHAR separator[] = {'[','~',']',0};
5115 *numargs = 0;
5116 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5118 if (!args)
5119 return NULL;
5121 vector = msi_alloc(sizeof(LPWSTR));
5122 if (!vector)
5123 return NULL;
5125 p = args;
5128 (*numargs)++;
5129 vector[*numargs - 1] = p;
5131 if ((q = strstrW(p, separator)))
5133 *q = '\0';
5135 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5136 if (!temp_vector)
5138 msi_free(vector);
5139 return NULL;
5141 vector = temp_vector;
5143 p = q + sep_len;
5145 } while (q);
5147 return vector;
5150 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5152 MSIPACKAGE *package = param;
5153 MSICOMPONENT *comp;
5154 MSIRECORD *uirow;
5155 SC_HANDLE scm = NULL, service = NULL;
5156 LPCWSTR component, *vector = NULL;
5157 LPWSTR name, args, display_name = NULL;
5158 DWORD event, numargs, len;
5159 UINT r = ERROR_FUNCTION_FAILED;
5161 component = MSI_RecordGetString(rec, 6);
5162 comp = get_loaded_component(package, component);
5163 if (!comp)
5164 return ERROR_SUCCESS;
5166 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5168 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5169 comp->Action = comp->Installed;
5170 return ERROR_SUCCESS;
5172 comp->Action = INSTALLSTATE_LOCAL;
5174 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5175 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5176 event = MSI_RecordGetInteger(rec, 3);
5178 if (!(event & msidbServiceControlEventStart))
5180 r = ERROR_SUCCESS;
5181 goto done;
5184 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5185 if (!scm)
5187 ERR("Failed to open the service control manager\n");
5188 goto done;
5191 len = 0;
5192 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5193 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5195 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5196 GetServiceDisplayNameW( scm, name, display_name, &len );
5199 service = OpenServiceW(scm, name, SERVICE_START);
5200 if (!service)
5202 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5203 goto done;
5206 vector = msi_service_args_to_vector(args, &numargs);
5208 if (!StartServiceW(service, numargs, vector) &&
5209 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5211 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5212 goto done;
5215 r = ERROR_SUCCESS;
5217 done:
5218 uirow = MSI_CreateRecord( 2 );
5219 MSI_RecordSetStringW( uirow, 1, display_name );
5220 MSI_RecordSetStringW( uirow, 2, name );
5221 ui_actiondata( package, szStartServices, uirow );
5222 msiobj_release( &uirow->hdr );
5224 CloseServiceHandle(service);
5225 CloseServiceHandle(scm);
5227 msi_free(name);
5228 msi_free(args);
5229 msi_free(vector);
5230 msi_free(display_name);
5231 return r;
5234 static UINT ACTION_StartServices( MSIPACKAGE *package )
5236 UINT rc;
5237 MSIQUERY *view;
5239 static const WCHAR query[] = {
5240 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5241 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5243 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5244 if (rc != ERROR_SUCCESS)
5245 return ERROR_SUCCESS;
5247 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5248 msiobj_release(&view->hdr);
5250 return rc;
5253 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5255 DWORD i, needed, count;
5256 ENUM_SERVICE_STATUSW *dependencies;
5257 SERVICE_STATUS ss;
5258 SC_HANDLE depserv;
5260 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5261 0, &needed, &count))
5262 return TRUE;
5264 if (GetLastError() != ERROR_MORE_DATA)
5265 return FALSE;
5267 dependencies = msi_alloc(needed);
5268 if (!dependencies)
5269 return FALSE;
5271 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5272 needed, &needed, &count))
5273 goto error;
5275 for (i = 0; i < count; i++)
5277 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5278 SERVICE_STOP | SERVICE_QUERY_STATUS);
5279 if (!depserv)
5280 goto error;
5282 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5283 goto error;
5286 return TRUE;
5288 error:
5289 msi_free(dependencies);
5290 return FALSE;
5293 static UINT stop_service( LPCWSTR name )
5295 SC_HANDLE scm = NULL, service = NULL;
5296 SERVICE_STATUS status;
5297 SERVICE_STATUS_PROCESS ssp;
5298 DWORD needed;
5300 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5301 if (!scm)
5303 WARN("Failed to open the SCM: %d\n", GetLastError());
5304 goto done;
5307 service = OpenServiceW(scm, name,
5308 SERVICE_STOP |
5309 SERVICE_QUERY_STATUS |
5310 SERVICE_ENUMERATE_DEPENDENTS);
5311 if (!service)
5313 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5314 goto done;
5317 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5318 sizeof(SERVICE_STATUS_PROCESS), &needed))
5320 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5321 goto done;
5324 if (ssp.dwCurrentState == SERVICE_STOPPED)
5325 goto done;
5327 stop_service_dependents(scm, service);
5329 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5330 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5332 done:
5333 CloseServiceHandle(service);
5334 CloseServiceHandle(scm);
5336 return ERROR_SUCCESS;
5339 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5341 MSIPACKAGE *package = param;
5342 MSICOMPONENT *comp;
5343 MSIRECORD *uirow;
5344 LPCWSTR component;
5345 LPWSTR name = NULL, display_name = NULL;
5346 DWORD event, len;
5347 SC_HANDLE scm;
5349 event = MSI_RecordGetInteger( rec, 3 );
5350 if (!(event & msidbServiceControlEventStop))
5351 return ERROR_SUCCESS;
5353 component = MSI_RecordGetString( rec, 6 );
5354 comp = get_loaded_component( package, component );
5355 if (!comp)
5356 return ERROR_SUCCESS;
5358 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5360 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5361 comp->Action = comp->Installed;
5362 return ERROR_SUCCESS;
5364 comp->Action = INSTALLSTATE_ABSENT;
5366 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5367 if (!scm)
5369 ERR("Failed to open the service control manager\n");
5370 goto done;
5373 len = 0;
5374 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5375 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5377 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5378 GetServiceDisplayNameW( scm, name, display_name, &len );
5380 CloseServiceHandle( scm );
5382 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5383 stop_service( name );
5385 done:
5386 uirow = MSI_CreateRecord( 2 );
5387 MSI_RecordSetStringW( uirow, 1, display_name );
5388 MSI_RecordSetStringW( uirow, 2, name );
5389 ui_actiondata( package, szStopServices, uirow );
5390 msiobj_release( &uirow->hdr );
5392 msi_free( name );
5393 msi_free( display_name );
5394 return ERROR_SUCCESS;
5397 static UINT ACTION_StopServices( MSIPACKAGE *package )
5399 UINT rc;
5400 MSIQUERY *view;
5402 static const WCHAR query[] = {
5403 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5404 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5406 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5407 if (rc != ERROR_SUCCESS)
5408 return ERROR_SUCCESS;
5410 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5411 msiobj_release(&view->hdr);
5413 return rc;
5416 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5418 MSIPACKAGE *package = param;
5419 MSICOMPONENT *comp;
5420 MSIRECORD *uirow;
5421 LPCWSTR component;
5422 LPWSTR name = NULL, display_name = NULL;
5423 DWORD event, len;
5424 SC_HANDLE scm = NULL, service = NULL;
5426 event = MSI_RecordGetInteger( rec, 3 );
5427 if (!(event & msidbServiceControlEventDelete))
5428 return ERROR_SUCCESS;
5430 component = MSI_RecordGetString(rec, 6);
5431 comp = get_loaded_component(package, component);
5432 if (!comp)
5433 return ERROR_SUCCESS;
5435 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5437 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5438 comp->Action = comp->Installed;
5439 return ERROR_SUCCESS;
5441 comp->Action = INSTALLSTATE_ABSENT;
5443 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5444 stop_service( name );
5446 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5447 if (!scm)
5449 WARN("Failed to open the SCM: %d\n", GetLastError());
5450 goto done;
5453 len = 0;
5454 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5455 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5457 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5458 GetServiceDisplayNameW( scm, name, display_name, &len );
5461 service = OpenServiceW( scm, name, DELETE );
5462 if (!service)
5464 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5465 goto done;
5468 if (!DeleteService( service ))
5469 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5471 done:
5472 uirow = MSI_CreateRecord( 2 );
5473 MSI_RecordSetStringW( uirow, 1, display_name );
5474 MSI_RecordSetStringW( uirow, 2, name );
5475 ui_actiondata( package, szDeleteServices, uirow );
5476 msiobj_release( &uirow->hdr );
5478 CloseServiceHandle( service );
5479 CloseServiceHandle( scm );
5480 msi_free( name );
5481 msi_free( display_name );
5483 return ERROR_SUCCESS;
5486 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5488 UINT rc;
5489 MSIQUERY *view;
5491 static const WCHAR query[] = {
5492 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5493 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5495 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5496 if (rc != ERROR_SUCCESS)
5497 return ERROR_SUCCESS;
5499 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5500 msiobj_release( &view->hdr );
5502 return rc;
5505 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5507 MSIFILE *file;
5509 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5511 if (!lstrcmpW(file->File, filename))
5512 return file;
5515 return NULL;
5518 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5520 MSIPACKAGE *package = param;
5521 LPWSTR driver, driver_path, ptr;
5522 WCHAR outpath[MAX_PATH];
5523 MSIFILE *driver_file, *setup_file;
5524 MSIRECORD *uirow;
5525 LPCWSTR desc;
5526 DWORD len, usage;
5527 UINT r = ERROR_SUCCESS;
5529 static const WCHAR driver_fmt[] = {
5530 'D','r','i','v','e','r','=','%','s',0};
5531 static const WCHAR setup_fmt[] = {
5532 'S','e','t','u','p','=','%','s',0};
5533 static const WCHAR usage_fmt[] = {
5534 'F','i','l','e','U','s','a','g','e','=','1',0};
5536 desc = MSI_RecordGetString(rec, 3);
5538 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5539 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5541 if (!driver_file)
5543 ERR("ODBC Driver entry not found!\n");
5544 return ERROR_FUNCTION_FAILED;
5547 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5548 if (setup_file)
5549 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5550 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5552 driver = msi_alloc(len * sizeof(WCHAR));
5553 if (!driver)
5554 return ERROR_OUTOFMEMORY;
5556 ptr = driver;
5557 lstrcpyW(ptr, desc);
5558 ptr += lstrlenW(ptr) + 1;
5560 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5561 ptr += len + 1;
5563 if (setup_file)
5565 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5566 ptr += len + 1;
5569 lstrcpyW(ptr, usage_fmt);
5570 ptr += lstrlenW(ptr) + 1;
5571 *ptr = '\0';
5573 driver_path = strdupW(driver_file->TargetPath);
5574 ptr = strrchrW(driver_path, '\\');
5575 if (ptr) *ptr = '\0';
5577 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5578 NULL, ODBC_INSTALL_COMPLETE, &usage))
5580 ERR("Failed to install SQL driver!\n");
5581 r = ERROR_FUNCTION_FAILED;
5584 uirow = MSI_CreateRecord( 5 );
5585 MSI_RecordSetStringW( uirow, 1, desc );
5586 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5587 MSI_RecordSetStringW( uirow, 3, driver_path );
5588 ui_actiondata( package, szInstallODBC, uirow );
5589 msiobj_release( &uirow->hdr );
5591 msi_free(driver);
5592 msi_free(driver_path);
5594 return r;
5597 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5599 MSIPACKAGE *package = param;
5600 LPWSTR translator, translator_path, ptr;
5601 WCHAR outpath[MAX_PATH];
5602 MSIFILE *translator_file, *setup_file;
5603 MSIRECORD *uirow;
5604 LPCWSTR desc;
5605 DWORD len, usage;
5606 UINT r = ERROR_SUCCESS;
5608 static const WCHAR translator_fmt[] = {
5609 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5610 static const WCHAR setup_fmt[] = {
5611 'S','e','t','u','p','=','%','s',0};
5613 desc = MSI_RecordGetString(rec, 3);
5615 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5616 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5618 if (!translator_file)
5620 ERR("ODBC Translator entry not found!\n");
5621 return ERROR_FUNCTION_FAILED;
5624 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5625 if (setup_file)
5626 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5628 translator = msi_alloc(len * sizeof(WCHAR));
5629 if (!translator)
5630 return ERROR_OUTOFMEMORY;
5632 ptr = translator;
5633 lstrcpyW(ptr, desc);
5634 ptr += lstrlenW(ptr) + 1;
5636 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5637 ptr += len + 1;
5639 if (setup_file)
5641 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5642 ptr += len + 1;
5644 *ptr = '\0';
5646 translator_path = strdupW(translator_file->TargetPath);
5647 ptr = strrchrW(translator_path, '\\');
5648 if (ptr) *ptr = '\0';
5650 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5651 NULL, ODBC_INSTALL_COMPLETE, &usage))
5653 ERR("Failed to install SQL translator!\n");
5654 r = ERROR_FUNCTION_FAILED;
5657 uirow = MSI_CreateRecord( 5 );
5658 MSI_RecordSetStringW( uirow, 1, desc );
5659 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5660 MSI_RecordSetStringW( uirow, 3, translator_path );
5661 ui_actiondata( package, szInstallODBC, uirow );
5662 msiobj_release( &uirow->hdr );
5664 msi_free(translator);
5665 msi_free(translator_path);
5667 return r;
5670 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5672 MSIPACKAGE *package = param;
5673 LPWSTR attrs;
5674 LPCWSTR desc, driver;
5675 WORD request = ODBC_ADD_SYS_DSN;
5676 INT registration;
5677 DWORD len;
5678 UINT r = ERROR_SUCCESS;
5679 MSIRECORD *uirow;
5681 static const WCHAR attrs_fmt[] = {
5682 'D','S','N','=','%','s',0 };
5684 desc = MSI_RecordGetString(rec, 3);
5685 driver = MSI_RecordGetString(rec, 4);
5686 registration = MSI_RecordGetInteger(rec, 5);
5688 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5689 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5691 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5692 attrs = msi_alloc(len * sizeof(WCHAR));
5693 if (!attrs)
5694 return ERROR_OUTOFMEMORY;
5696 len = sprintfW(attrs, attrs_fmt, desc);
5697 attrs[len + 1] = 0;
5699 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5701 ERR("Failed to install SQL data source!\n");
5702 r = ERROR_FUNCTION_FAILED;
5705 uirow = MSI_CreateRecord( 5 );
5706 MSI_RecordSetStringW( uirow, 1, desc );
5707 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5708 MSI_RecordSetInteger( uirow, 3, request );
5709 ui_actiondata( package, szInstallODBC, uirow );
5710 msiobj_release( &uirow->hdr );
5712 msi_free(attrs);
5714 return r;
5717 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5719 UINT rc;
5720 MSIQUERY *view;
5722 static const WCHAR driver_query[] = {
5723 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5724 'O','D','B','C','D','r','i','v','e','r',0 };
5726 static const WCHAR translator_query[] = {
5727 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5728 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5730 static const WCHAR source_query[] = {
5731 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5732 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5734 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5735 if (rc != ERROR_SUCCESS)
5736 return ERROR_SUCCESS;
5738 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5739 msiobj_release(&view->hdr);
5741 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5742 if (rc != ERROR_SUCCESS)
5743 return ERROR_SUCCESS;
5745 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5746 msiobj_release(&view->hdr);
5748 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5749 if (rc != ERROR_SUCCESS)
5750 return ERROR_SUCCESS;
5752 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5753 msiobj_release(&view->hdr);
5755 return rc;
5758 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5760 MSIPACKAGE *package = param;
5761 MSIRECORD *uirow;
5762 DWORD usage;
5763 LPCWSTR desc;
5765 desc = MSI_RecordGetString( rec, 3 );
5766 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5768 WARN("Failed to remove ODBC driver\n");
5770 else if (!usage)
5772 FIXME("Usage count reached 0\n");
5775 uirow = MSI_CreateRecord( 2 );
5776 MSI_RecordSetStringW( uirow, 1, desc );
5777 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5778 ui_actiondata( package, szRemoveODBC, uirow );
5779 msiobj_release( &uirow->hdr );
5781 return ERROR_SUCCESS;
5784 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5786 MSIPACKAGE *package = param;
5787 MSIRECORD *uirow;
5788 DWORD usage;
5789 LPCWSTR desc;
5791 desc = MSI_RecordGetString( rec, 3 );
5792 if (!SQLRemoveTranslatorW( desc, &usage ))
5794 WARN("Failed to remove ODBC translator\n");
5796 else if (!usage)
5798 FIXME("Usage count reached 0\n");
5801 uirow = MSI_CreateRecord( 2 );
5802 MSI_RecordSetStringW( uirow, 1, desc );
5803 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5804 ui_actiondata( package, szRemoveODBC, uirow );
5805 msiobj_release( &uirow->hdr );
5807 return ERROR_SUCCESS;
5810 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5812 MSIPACKAGE *package = param;
5813 MSIRECORD *uirow;
5814 LPWSTR attrs;
5815 LPCWSTR desc, driver;
5816 WORD request = ODBC_REMOVE_SYS_DSN;
5817 INT registration;
5818 DWORD len;
5820 static const WCHAR attrs_fmt[] = {
5821 'D','S','N','=','%','s',0 };
5823 desc = MSI_RecordGetString( rec, 3 );
5824 driver = MSI_RecordGetString( rec, 4 );
5825 registration = MSI_RecordGetInteger( rec, 5 );
5827 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5828 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5830 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
5831 attrs = msi_alloc( len * sizeof(WCHAR) );
5832 if (!attrs)
5833 return ERROR_OUTOFMEMORY;
5835 FIXME("Use ODBCSourceAttribute table\n");
5837 len = sprintfW( attrs, attrs_fmt, desc );
5838 attrs[len + 1] = 0;
5840 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5842 WARN("Failed to remove ODBC data source\n");
5844 msi_free( attrs );
5846 uirow = MSI_CreateRecord( 3 );
5847 MSI_RecordSetStringW( uirow, 1, desc );
5848 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5849 MSI_RecordSetInteger( uirow, 3, request );
5850 ui_actiondata( package, szRemoveODBC, uirow );
5851 msiobj_release( &uirow->hdr );
5853 return ERROR_SUCCESS;
5856 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5858 UINT rc;
5859 MSIQUERY *view;
5861 static const WCHAR driver_query[] = {
5862 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5863 'O','D','B','C','D','r','i','v','e','r',0 };
5865 static const WCHAR translator_query[] = {
5866 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5867 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5869 static const WCHAR source_query[] = {
5870 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5871 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5873 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5874 if (rc != ERROR_SUCCESS)
5875 return ERROR_SUCCESS;
5877 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5878 msiobj_release( &view->hdr );
5880 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5881 if (rc != ERROR_SUCCESS)
5882 return ERROR_SUCCESS;
5884 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5885 msiobj_release( &view->hdr );
5887 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5888 if (rc != ERROR_SUCCESS)
5889 return ERROR_SUCCESS;
5891 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5892 msiobj_release( &view->hdr );
5894 return rc;
5897 #define ENV_ACT_SETALWAYS 0x1
5898 #define ENV_ACT_SETABSENT 0x2
5899 #define ENV_ACT_REMOVE 0x4
5900 #define ENV_ACT_REMOVEMATCH 0x8
5902 #define ENV_MOD_MACHINE 0x20000000
5903 #define ENV_MOD_APPEND 0x40000000
5904 #define ENV_MOD_PREFIX 0x80000000
5905 #define ENV_MOD_MASK 0xC0000000
5907 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5909 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5911 LPCWSTR cptr = *name;
5913 static const WCHAR prefix[] = {'[','~',']',0};
5914 static const int prefix_len = 3;
5916 *flags = 0;
5917 while (*cptr)
5919 if (*cptr == '=')
5920 *flags |= ENV_ACT_SETALWAYS;
5921 else if (*cptr == '+')
5922 *flags |= ENV_ACT_SETABSENT;
5923 else if (*cptr == '-')
5924 *flags |= ENV_ACT_REMOVE;
5925 else if (*cptr == '!')
5926 *flags |= ENV_ACT_REMOVEMATCH;
5927 else if (*cptr == '*')
5928 *flags |= ENV_MOD_MACHINE;
5929 else
5930 break;
5932 cptr++;
5933 (*name)++;
5936 if (!*cptr)
5938 ERR("Missing environment variable\n");
5939 return ERROR_FUNCTION_FAILED;
5942 if (*value)
5944 LPCWSTR ptr = *value;
5945 if (!strncmpW(ptr, prefix, prefix_len))
5947 if (ptr[prefix_len] == szSemiColon[0])
5949 *flags |= ENV_MOD_APPEND;
5950 *value += lstrlenW(prefix);
5952 else
5954 *value = NULL;
5957 else if (lstrlenW(*value) >= prefix_len)
5959 ptr += lstrlenW(ptr) - prefix_len;
5960 if (!lstrcmpW(ptr, prefix))
5962 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5964 *flags |= ENV_MOD_PREFIX;
5965 /* the "[~]" will be removed by deformat_string */;
5967 else
5969 *value = NULL;
5975 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5976 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5977 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5978 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5980 ERR("Invalid flags: %08x\n", *flags);
5981 return ERROR_FUNCTION_FAILED;
5984 if (!*flags)
5985 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5987 return ERROR_SUCCESS;
5990 static UINT open_env_key( DWORD flags, HKEY *key )
5992 static const WCHAR user_env[] =
5993 {'E','n','v','i','r','o','n','m','e','n','t',0};
5994 static const WCHAR machine_env[] =
5995 {'S','y','s','t','e','m','\\',
5996 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5997 'C','o','n','t','r','o','l','\\',
5998 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5999 'E','n','v','i','r','o','n','m','e','n','t',0};
6000 const WCHAR *env;
6001 HKEY root;
6002 LONG res;
6004 if (flags & ENV_MOD_MACHINE)
6006 env = machine_env;
6007 root = HKEY_LOCAL_MACHINE;
6009 else
6011 env = user_env;
6012 root = HKEY_CURRENT_USER;
6015 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6016 if (res != ERROR_SUCCESS)
6018 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6019 return ERROR_FUNCTION_FAILED;
6022 return ERROR_SUCCESS;
6025 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6027 MSIPACKAGE *package = param;
6028 LPCWSTR name, value, component;
6029 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6030 DWORD flags, type, size;
6031 UINT res;
6032 HKEY env = NULL;
6033 MSICOMPONENT *comp;
6034 MSIRECORD *uirow;
6035 int action = 0;
6037 component = MSI_RecordGetString(rec, 4);
6038 comp = get_loaded_component(package, component);
6039 if (!comp)
6040 return ERROR_SUCCESS;
6042 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6044 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6045 comp->Action = comp->Installed;
6046 return ERROR_SUCCESS;
6048 comp->Action = INSTALLSTATE_LOCAL;
6050 name = MSI_RecordGetString(rec, 2);
6051 value = MSI_RecordGetString(rec, 3);
6053 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6055 res = env_parse_flags(&name, &value, &flags);
6056 if (res != ERROR_SUCCESS || !value)
6057 goto done;
6059 if (value && !deformat_string(package, value, &deformatted))
6061 res = ERROR_OUTOFMEMORY;
6062 goto done;
6065 value = deformatted;
6067 res = open_env_key( flags, &env );
6068 if (res != ERROR_SUCCESS)
6069 goto done;
6071 if (flags & ENV_MOD_MACHINE)
6072 action |= 0x20000000;
6074 size = 0;
6075 type = REG_SZ;
6076 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6077 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6078 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6079 goto done;
6081 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6083 action = 0x2;
6085 /* Nothing to do. */
6086 if (!value)
6088 res = ERROR_SUCCESS;
6089 goto done;
6092 /* If we are appending but the string was empty, strip ; */
6093 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6095 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6096 newval = strdupW(value);
6097 if (!newval)
6099 res = ERROR_OUTOFMEMORY;
6100 goto done;
6103 else
6105 action = 0x1;
6107 /* Contrary to MSDN, +-variable to [~];path works */
6108 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6110 res = ERROR_SUCCESS;
6111 goto done;
6114 data = msi_alloc(size);
6115 if (!data)
6117 RegCloseKey(env);
6118 return ERROR_OUTOFMEMORY;
6121 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6122 if (res != ERROR_SUCCESS)
6123 goto done;
6125 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6127 action = 0x4;
6128 res = RegDeleteValueW(env, name);
6129 if (res != ERROR_SUCCESS)
6130 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6131 goto done;
6134 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6135 if (flags & ENV_MOD_MASK)
6137 DWORD mod_size;
6138 int multiplier = 0;
6139 if (flags & ENV_MOD_APPEND) multiplier++;
6140 if (flags & ENV_MOD_PREFIX) multiplier++;
6141 mod_size = lstrlenW(value) * multiplier;
6142 size += mod_size * sizeof(WCHAR);
6145 newval = msi_alloc(size);
6146 ptr = newval;
6147 if (!newval)
6149 res = ERROR_OUTOFMEMORY;
6150 goto done;
6153 if (flags & ENV_MOD_PREFIX)
6155 lstrcpyW(newval, value);
6156 ptr = newval + lstrlenW(value);
6157 action |= 0x80000000;
6160 lstrcpyW(ptr, data);
6162 if (flags & ENV_MOD_APPEND)
6164 lstrcatW(newval, value);
6165 action |= 0x40000000;
6168 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6169 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6170 if (res)
6172 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6175 done:
6176 uirow = MSI_CreateRecord( 3 );
6177 MSI_RecordSetStringW( uirow, 1, name );
6178 MSI_RecordSetStringW( uirow, 2, newval );
6179 MSI_RecordSetInteger( uirow, 3, action );
6180 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6181 msiobj_release( &uirow->hdr );
6183 if (env) RegCloseKey(env);
6184 msi_free(deformatted);
6185 msi_free(data);
6186 msi_free(newval);
6187 return res;
6190 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6192 UINT rc;
6193 MSIQUERY * view;
6194 static const WCHAR ExecSeqQuery[] =
6195 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6196 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6197 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6198 if (rc != ERROR_SUCCESS)
6199 return ERROR_SUCCESS;
6201 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6202 msiobj_release(&view->hdr);
6204 return rc;
6207 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6209 MSIPACKAGE *package = param;
6210 LPCWSTR name, value, component;
6211 LPWSTR deformatted = NULL;
6212 DWORD flags;
6213 HKEY env;
6214 MSICOMPONENT *comp;
6215 MSIRECORD *uirow;
6216 int action = 0;
6217 LONG res;
6218 UINT r;
6220 component = MSI_RecordGetString( rec, 4 );
6221 comp = get_loaded_component( package, component );
6222 if (!comp)
6223 return ERROR_SUCCESS;
6225 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6227 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6228 comp->Action = comp->Installed;
6229 return ERROR_SUCCESS;
6231 comp->Action = INSTALLSTATE_ABSENT;
6233 name = MSI_RecordGetString( rec, 2 );
6234 value = MSI_RecordGetString( rec, 3 );
6236 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6238 r = env_parse_flags( &name, &value, &flags );
6239 if (r != ERROR_SUCCESS)
6240 return r;
6242 if (!(flags & ENV_ACT_REMOVE))
6244 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6245 return ERROR_SUCCESS;
6248 if (value && !deformat_string( package, value, &deformatted ))
6249 return ERROR_OUTOFMEMORY;
6251 value = deformatted;
6253 r = open_env_key( flags, &env );
6254 if (r != ERROR_SUCCESS)
6256 r = ERROR_SUCCESS;
6257 goto done;
6260 if (flags & ENV_MOD_MACHINE)
6261 action |= 0x20000000;
6263 TRACE("Removing %s\n", debugstr_w(name));
6265 res = RegDeleteValueW( env, name );
6266 if (res != ERROR_SUCCESS)
6268 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6269 r = ERROR_SUCCESS;
6272 done:
6273 uirow = MSI_CreateRecord( 3 );
6274 MSI_RecordSetStringW( uirow, 1, name );
6275 MSI_RecordSetStringW( uirow, 2, value );
6276 MSI_RecordSetInteger( uirow, 3, action );
6277 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6278 msiobj_release( &uirow->hdr );
6280 if (env) RegCloseKey( env );
6281 msi_free( deformatted );
6282 return r;
6285 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6287 UINT rc;
6288 MSIQUERY *view;
6289 static const WCHAR query[] =
6290 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6291 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6293 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6294 if (rc != ERROR_SUCCESS)
6295 return ERROR_SUCCESS;
6297 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6298 msiobj_release( &view->hdr );
6300 return rc;
6303 typedef struct tagMSIASSEMBLY
6305 struct list entry;
6306 MSICOMPONENT *component;
6307 MSIFEATURE *feature;
6308 MSIFILE *file;
6309 LPWSTR manifest;
6310 LPWSTR application;
6311 LPWSTR display_name;
6312 DWORD attributes;
6313 BOOL installed;
6314 } MSIASSEMBLY;
6316 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6317 DWORD dwReserved);
6318 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6319 LPVOID pvReserved, HMODULE *phModDll);
6321 static BOOL init_functionpointers(void)
6323 HRESULT hr;
6324 HMODULE hfusion;
6325 HMODULE hmscoree;
6327 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6329 hmscoree = LoadLibraryA("mscoree.dll");
6330 if (!hmscoree)
6332 WARN("mscoree.dll not available\n");
6333 return FALSE;
6336 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6337 if (!pLoadLibraryShim)
6339 WARN("LoadLibraryShim not available\n");
6340 FreeLibrary(hmscoree);
6341 return FALSE;
6344 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6345 if (FAILED(hr))
6347 WARN("fusion.dll not available\n");
6348 FreeLibrary(hmscoree);
6349 return FALSE;
6352 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6354 FreeLibrary(hmscoree);
6355 return TRUE;
6358 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6359 LPWSTR path)
6361 IAssemblyCache *cache;
6362 MSIRECORD *uirow;
6363 HRESULT hr;
6364 UINT r = ERROR_FUNCTION_FAILED;
6366 TRACE("installing assembly: %s\n", debugstr_w(path));
6368 uirow = MSI_CreateRecord( 2 );
6369 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6370 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6371 msiobj_release( &uirow->hdr );
6373 if (assembly->feature)
6374 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6376 if (assembly->manifest)
6377 FIXME("Manifest unhandled\n");
6379 if (assembly->application)
6381 FIXME("Assembly should be privately installed\n");
6382 return ERROR_SUCCESS;
6385 if (assembly->attributes == msidbAssemblyAttributesWin32)
6387 FIXME("Win32 assemblies not handled\n");
6388 return ERROR_SUCCESS;
6391 hr = pCreateAssemblyCache(&cache, 0);
6392 if (FAILED(hr))
6393 goto done;
6395 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6396 if (FAILED(hr))
6397 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6399 r = ERROR_SUCCESS;
6401 done:
6402 IAssemblyCache_Release(cache);
6403 return r;
6406 typedef struct tagASSEMBLY_LIST
6408 MSIPACKAGE *package;
6409 IAssemblyCache *cache;
6410 struct list *assemblies;
6411 } ASSEMBLY_LIST;
6413 typedef struct tagASSEMBLY_NAME
6415 LPWSTR name;
6416 LPWSTR version;
6417 LPWSTR culture;
6418 LPWSTR pubkeytoken;
6419 } ASSEMBLY_NAME;
6421 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6423 ASSEMBLY_NAME *asmname = param;
6424 LPCWSTR name = MSI_RecordGetString(rec, 2);
6425 LPWSTR val = msi_dup_record_field(rec, 3);
6427 static const WCHAR Name[] = {'N','a','m','e',0};
6428 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6429 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6430 static const WCHAR PublicKeyToken[] = {
6431 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6433 if (!strcmpiW(name, Name))
6434 asmname->name = val;
6435 else if (!strcmpiW(name, Version))
6436 asmname->version = val;
6437 else if (!strcmpiW(name, Culture))
6438 asmname->culture = val;
6439 else if (!strcmpiW(name, PublicKeyToken))
6440 asmname->pubkeytoken = val;
6441 else
6442 msi_free(val);
6444 return ERROR_SUCCESS;
6447 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6449 if (!*str)
6451 *size = lstrlenW(append) + 1;
6452 *str = msi_alloc((*size) * sizeof(WCHAR));
6453 lstrcpyW(*str, append);
6454 return;
6457 (*size) += lstrlenW(append);
6458 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6459 lstrcatW(*str, append);
6462 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6464 static const WCHAR separator[] = {',',' ',0};
6465 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6466 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6467 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6468 static const WCHAR query[] = {
6469 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6470 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6471 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6472 '=','\'','%','s','\'',0};
6473 ASSEMBLY_NAME name;
6474 MSIQUERY *view;
6475 LPWSTR display_name;
6476 DWORD size;
6477 UINT r;
6479 display_name = NULL;
6480 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6482 r = MSI_OpenQuery( db, &view, query, comp->Component );
6483 if (r != ERROR_SUCCESS)
6484 return NULL;
6486 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6487 msiobj_release( &view->hdr );
6489 if (!name.name)
6491 ERR("No assembly name specified!\n");
6492 return NULL;
6495 append_str( &display_name, &size, name.name );
6497 if (name.version)
6499 append_str( &display_name, &size, separator );
6500 append_str( &display_name, &size, Version );
6501 append_str( &display_name, &size, name.version );
6503 if (name.culture)
6505 append_str( &display_name, &size, separator );
6506 append_str( &display_name, &size, Culture );
6507 append_str( &display_name, &size, name.culture );
6509 if (name.pubkeytoken)
6511 append_str( &display_name, &size, separator );
6512 append_str( &display_name, &size, PublicKeyToken );
6513 append_str( &display_name, &size, name.pubkeytoken );
6516 msi_free( name.name );
6517 msi_free( name.version );
6518 msi_free( name.culture );
6519 msi_free( name.pubkeytoken );
6521 return display_name;
6524 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6526 ASSEMBLY_INFO asminfo;
6527 LPWSTR disp;
6528 BOOL found = FALSE;
6529 HRESULT hr;
6531 disp = get_assembly_display_name( db, comp );
6532 if (!disp)
6533 return FALSE;
6535 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6536 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6538 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6539 if (SUCCEEDED(hr))
6540 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6542 msi_free( disp );
6543 return found;
6546 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6548 ASSEMBLY_LIST *list = param;
6549 MSIASSEMBLY *assembly;
6550 LPCWSTR component;
6552 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6553 if (!assembly)
6554 return ERROR_OUTOFMEMORY;
6556 component = MSI_RecordGetString(rec, 1);
6557 assembly->component = get_loaded_component(list->package, component);
6558 if (!assembly->component)
6559 return ERROR_SUCCESS;
6561 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6562 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6564 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6565 assembly->component->Action = assembly->component->Installed;
6566 return ERROR_SUCCESS;
6568 assembly->component->Action = assembly->component->ActionRequest;
6570 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6571 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6573 if (!assembly->file)
6575 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6576 return ERROR_FUNCTION_FAILED;
6579 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6580 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6581 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6583 if (assembly->application)
6585 WCHAR version[24];
6586 DWORD size = sizeof(version)/sizeof(WCHAR);
6588 /* FIXME: we should probably check the manifest file here */
6590 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6591 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6593 assembly->installed = TRUE;
6596 else
6597 assembly->installed = check_assembly_installed(list->package->db,
6598 list->cache,
6599 assembly->component);
6601 list_add_head(list->assemblies, &assembly->entry);
6602 return ERROR_SUCCESS;
6605 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6607 IAssemblyCache *cache = NULL;
6608 ASSEMBLY_LIST list;
6609 MSIQUERY *view;
6610 HRESULT hr;
6611 UINT r;
6613 static const WCHAR query[] =
6614 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6615 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6617 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6618 if (r != ERROR_SUCCESS)
6619 return ERROR_SUCCESS;
6621 hr = pCreateAssemblyCache(&cache, 0);
6622 if (FAILED(hr))
6623 return ERROR_FUNCTION_FAILED;
6625 list.package = package;
6626 list.cache = cache;
6627 list.assemblies = assemblies;
6629 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6630 msiobj_release(&view->hdr);
6632 IAssemblyCache_Release(cache);
6634 return r;
6637 static void free_assemblies(struct list *assemblies)
6639 struct list *item, *cursor;
6641 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6643 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6645 list_remove(&assembly->entry);
6646 msi_free(assembly->application);
6647 msi_free(assembly->manifest);
6648 msi_free(assembly->display_name);
6649 msi_free(assembly);
6653 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6655 MSIASSEMBLY *assembly;
6657 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6659 if (!lstrcmpW(assembly->file->File, file))
6661 *out = assembly;
6662 return TRUE;
6666 return FALSE;
6669 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6670 LPWSTR *path, DWORD *attrs, PVOID user)
6672 MSIASSEMBLY *assembly;
6673 WCHAR temppath[MAX_PATH];
6674 struct list *assemblies = user;
6675 UINT r;
6677 if (!find_assembly(assemblies, file, &assembly))
6678 return FALSE;
6680 GetTempPathW(MAX_PATH, temppath);
6681 PathAddBackslashW(temppath);
6682 lstrcatW(temppath, assembly->file->FileName);
6684 if (action == MSICABEXTRACT_BEGINEXTRACT)
6686 if (assembly->installed)
6687 return FALSE;
6689 *path = strdupW(temppath);
6690 *attrs = assembly->file->Attributes;
6692 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6694 assembly->installed = TRUE;
6696 r = install_assembly(package, assembly, temppath);
6697 if (r != ERROR_SUCCESS)
6698 ERR("Failed to install assembly\n");
6701 return TRUE;
6704 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6706 UINT r;
6707 struct list assemblies = LIST_INIT(assemblies);
6708 MSIASSEMBLY *assembly;
6709 MSIMEDIAINFO *mi;
6711 if (!init_functionpointers() || !pCreateAssemblyCache)
6712 return ERROR_FUNCTION_FAILED;
6714 r = load_assemblies(package, &assemblies);
6715 if (r != ERROR_SUCCESS)
6716 goto done;
6718 if (list_empty(&assemblies))
6719 goto done;
6721 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6722 if (!mi)
6724 r = ERROR_OUTOFMEMORY;
6725 goto done;
6728 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6730 if (assembly->installed && !mi->is_continuous)
6731 continue;
6733 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6734 (assembly->file->IsCompressed && !mi->is_extracted))
6736 MSICABDATA data;
6738 r = ready_media(package, assembly->file, mi);
6739 if (r != ERROR_SUCCESS)
6741 ERR("Failed to ready media\n");
6742 break;
6745 data.mi = mi;
6746 data.package = package;
6747 data.cb = installassembly_cb;
6748 data.user = &assemblies;
6750 if (assembly->file->IsCompressed &&
6751 !msi_cabextract(package, mi, &data))
6753 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6754 r = ERROR_FUNCTION_FAILED;
6755 break;
6759 if (!assembly->file->IsCompressed)
6761 LPWSTR source = resolve_file_source(package, assembly->file);
6763 r = install_assembly(package, assembly, source);
6764 if (r != ERROR_SUCCESS)
6765 ERR("Failed to install assembly\n");
6767 msi_free(source);
6770 /* FIXME: write Installer assembly reg values */
6773 done:
6774 free_assemblies(&assemblies);
6775 return r;
6778 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6780 LPWSTR key, template, id;
6781 UINT r = ERROR_SUCCESS;
6783 id = msi_dup_property( package, szProductID );
6784 if (id)
6786 msi_free( id );
6787 return ERROR_SUCCESS;
6789 template = msi_dup_property( package, szPIDTemplate );
6790 key = msi_dup_property( package, szPIDKEY );
6792 if (key && template)
6794 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6795 r = MSI_SetPropertyW( package, szProductID, key );
6797 msi_free( template );
6798 msi_free( key );
6799 return r;
6802 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6804 TRACE("\n");
6805 package->need_reboot = 1;
6806 return ERROR_SUCCESS;
6809 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6811 static const WCHAR szAvailableFreeReg[] =
6812 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6813 MSIRECORD *uirow;
6814 int space = msi_get_property_int( package, szAvailableFreeReg, 0 );
6816 TRACE("%p %d kilobytes\n", package, space);
6818 uirow = MSI_CreateRecord( 1 );
6819 MSI_RecordSetInteger( uirow, 1, space );
6820 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6821 msiobj_release( &uirow->hdr );
6823 return ERROR_SUCCESS;
6826 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6828 FIXME("%p\n", package);
6829 return ERROR_SUCCESS;
6832 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6834 FIXME("%p\n", package);
6835 return ERROR_SUCCESS;
6838 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6840 UINT r, count;
6841 MSIQUERY *view;
6843 static const WCHAR driver_query[] = {
6844 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6845 'O','D','B','C','D','r','i','v','e','r',0 };
6847 static const WCHAR translator_query[] = {
6848 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6849 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6851 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6852 if (r == ERROR_SUCCESS)
6854 count = 0;
6855 r = MSI_IterateRecords( view, &count, NULL, package );
6856 msiobj_release( &view->hdr );
6857 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6860 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6861 if (r == ERROR_SUCCESS)
6863 count = 0;
6864 r = MSI_IterateRecords( view, &count, NULL, package );
6865 msiobj_release( &view->hdr );
6866 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6869 return ERROR_SUCCESS;
6872 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6873 LPCSTR action, LPCWSTR table )
6875 static const WCHAR query[] = {
6876 'S','E','L','E','C','T',' ','*',' ',
6877 'F','R','O','M',' ','`','%','s','`',0 };
6878 MSIQUERY *view = NULL;
6879 DWORD count = 0;
6880 UINT r;
6882 r = MSI_OpenQuery( package->db, &view, query, table );
6883 if (r == ERROR_SUCCESS)
6885 r = MSI_IterateRecords(view, &count, NULL, package);
6886 msiobj_release(&view->hdr);
6889 if (count)
6890 FIXME("%s -> %u ignored %s table values\n",
6891 action, count, debugstr_w(table));
6893 return ERROR_SUCCESS;
6896 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6898 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6899 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6902 static UINT ACTION_BindImage( MSIPACKAGE *package )
6904 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6905 return msi_unimplemented_action_stub( package, "BindImage", table );
6908 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6910 static const WCHAR table[] = {
6911 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6912 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6915 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6917 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6918 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6921 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6923 static const WCHAR table[] = {
6924 'M','s','i','A','s','s','e','m','b','l','y',0 };
6925 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6928 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6930 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6931 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6934 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6936 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6937 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6940 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6942 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6943 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6946 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6948 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6949 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6952 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6954 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6955 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6958 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6960 static const struct
6962 const WCHAR *action;
6963 UINT (*handler)(MSIPACKAGE *);
6965 StandardActions[] =
6967 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6968 { szAppSearch, ACTION_AppSearch },
6969 { szBindImage, ACTION_BindImage },
6970 { szCCPSearch, ACTION_CCPSearch },
6971 { szCostFinalize, ACTION_CostFinalize },
6972 { szCostInitialize, ACTION_CostInitialize },
6973 { szCreateFolders, ACTION_CreateFolders },
6974 { szCreateShortcuts, ACTION_CreateShortcuts },
6975 { szDeleteServices, ACTION_DeleteServices },
6976 { szDisableRollback, ACTION_DisableRollback },
6977 { szDuplicateFiles, ACTION_DuplicateFiles },
6978 { szExecuteAction, ACTION_ExecuteAction },
6979 { szFileCost, ACTION_FileCost },
6980 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6981 { szForceReboot, ACTION_ForceReboot },
6982 { szInstallAdminPackage, ACTION_InstallAdminPackage },
6983 { szInstallExecute, ACTION_InstallExecute },
6984 { szInstallExecuteAgain, ACTION_InstallExecute },
6985 { szInstallFiles, ACTION_InstallFiles},
6986 { szInstallFinalize, ACTION_InstallFinalize },
6987 { szInstallInitialize, ACTION_InstallInitialize },
6988 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6989 { szInstallValidate, ACTION_InstallValidate },
6990 { szIsolateComponents, ACTION_IsolateComponents },
6991 { szLaunchConditions, ACTION_LaunchConditions },
6992 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6993 { szMoveFiles, ACTION_MoveFiles },
6994 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6995 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6996 { szInstallODBC, ACTION_InstallODBC },
6997 { szInstallServices, ACTION_InstallServices },
6998 { szPatchFiles, ACTION_PatchFiles },
6999 { szProcessComponents, ACTION_ProcessComponents },
7000 { szPublishComponents, ACTION_PublishComponents },
7001 { szPublishFeatures, ACTION_PublishFeatures },
7002 { szPublishProduct, ACTION_PublishProduct },
7003 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7004 { szRegisterComPlus, ACTION_RegisterComPlus},
7005 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7006 { szRegisterFonts, ACTION_RegisterFonts },
7007 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7008 { szRegisterProduct, ACTION_RegisterProduct },
7009 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7010 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7011 { szRegisterUser, ACTION_RegisterUser },
7012 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7013 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7014 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7015 { szRemoveFiles, ACTION_RemoveFiles },
7016 { szRemoveFolders, ACTION_RemoveFolders },
7017 { szRemoveIniValues, ACTION_RemoveIniValues },
7018 { szRemoveODBC, ACTION_RemoveODBC },
7019 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7020 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7021 { szResolveSource, ACTION_ResolveSource },
7022 { szRMCCPSearch, ACTION_RMCCPSearch },
7023 { szScheduleReboot, ACTION_ScheduleReboot },
7024 { szSelfRegModules, ACTION_SelfRegModules },
7025 { szSelfUnregModules, ACTION_SelfUnregModules },
7026 { szSetODBCFolders, ACTION_SetODBCFolders },
7027 { szStartServices, ACTION_StartServices },
7028 { szStopServices, ACTION_StopServices },
7029 { szUnpublishComponents, ACTION_UnpublishComponents },
7030 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7031 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7032 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7033 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7034 { szUnregisterFonts, ACTION_UnregisterFonts },
7035 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7036 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7037 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7038 { szValidateProductID, ACTION_ValidateProductID },
7039 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7040 { szWriteIniValues, ACTION_WriteIniValues },
7041 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7042 { NULL, NULL },
7045 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7046 UINT* rc, BOOL force )
7048 BOOL ret = FALSE;
7049 BOOL run = force;
7050 int i;
7052 if (!run && !package->script->CurrentlyScripting)
7053 run = TRUE;
7055 if (!run)
7057 if (strcmpW(action,szInstallFinalize) == 0 ||
7058 strcmpW(action,szInstallExecute) == 0 ||
7059 strcmpW(action,szInstallExecuteAgain) == 0)
7060 run = TRUE;
7063 i = 0;
7064 while (StandardActions[i].action != NULL)
7066 if (strcmpW(StandardActions[i].action, action)==0)
7068 if (!run)
7070 ui_actioninfo(package, action, TRUE, 0);
7071 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7072 ui_actioninfo(package, action, FALSE, *rc);
7074 else
7076 ui_actionstart(package, action);
7077 if (StandardActions[i].handler)
7079 *rc = StandardActions[i].handler(package);
7081 else
7083 FIXME("unhandled standard action %s\n",debugstr_w(action));
7084 *rc = ERROR_SUCCESS;
7087 ret = TRUE;
7088 break;
7090 i++;
7092 return ret;
7095 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7097 UINT rc = ERROR_SUCCESS;
7098 BOOL handled;
7100 TRACE("Performing action (%s)\n", debugstr_w(action));
7102 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7104 if (!handled)
7105 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7107 if (!handled)
7109 WARN("unhandled msi action %s\n", debugstr_w(action));
7110 rc = ERROR_FUNCTION_NOT_CALLED;
7113 return rc;
7116 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7118 UINT rc = ERROR_SUCCESS;
7119 BOOL handled = FALSE;
7121 TRACE("Performing action (%s)\n", debugstr_w(action));
7123 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7125 if (!handled)
7126 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7128 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7129 handled = TRUE;
7131 if (!handled)
7133 WARN("unhandled msi action %s\n", debugstr_w(action));
7134 rc = ERROR_FUNCTION_NOT_CALLED;
7137 return rc;
7140 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7142 UINT rc = ERROR_SUCCESS;
7143 MSIRECORD *row;
7145 static const WCHAR ExecSeqQuery[] =
7146 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7147 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7148 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7149 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7150 static const WCHAR UISeqQuery[] =
7151 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7152 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7153 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7154 ' ', '=',' ','%','i',0};
7156 if (needs_ui_sequence(package))
7157 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7158 else
7159 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7161 if (row)
7163 LPCWSTR action, cond;
7165 TRACE("Running the actions\n");
7167 /* check conditions */
7168 cond = MSI_RecordGetString(row, 2);
7170 /* this is a hack to skip errors in the condition code */
7171 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7173 msiobj_release(&row->hdr);
7174 return ERROR_SUCCESS;
7177 action = MSI_RecordGetString(row, 1);
7178 if (!action)
7180 ERR("failed to fetch action\n");
7181 msiobj_release(&row->hdr);
7182 return ERROR_FUNCTION_FAILED;
7185 if (needs_ui_sequence(package))
7186 rc = ACTION_PerformUIAction(package, action, -1);
7187 else
7188 rc = ACTION_PerformAction(package, action, -1, FALSE);
7190 msiobj_release(&row->hdr);
7193 return rc;
7196 /****************************************************
7197 * TOP level entry points
7198 *****************************************************/
7200 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7201 LPCWSTR szCommandLine )
7203 UINT rc;
7204 BOOL ui_exists;
7206 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7207 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7209 MSI_SetPropertyW(package, szAction, szInstall);
7211 package->script->InWhatSequence = SEQUENCE_INSTALL;
7213 if (szPackagePath)
7215 LPWSTR p, dir;
7216 LPCWSTR file;
7218 dir = strdupW(szPackagePath);
7219 p = strrchrW(dir, '\\');
7220 if (p)
7222 *(++p) = 0;
7223 file = szPackagePath + (p - dir);
7225 else
7227 msi_free(dir);
7228 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7229 GetCurrentDirectoryW(MAX_PATH, dir);
7230 lstrcatW(dir, szBackSlash);
7231 file = szPackagePath;
7234 msi_free( package->PackagePath );
7235 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7236 if (!package->PackagePath)
7238 msi_free(dir);
7239 return ERROR_OUTOFMEMORY;
7242 lstrcpyW(package->PackagePath, dir);
7243 lstrcatW(package->PackagePath, file);
7244 msi_free(dir);
7246 msi_set_sourcedir_props(package, FALSE);
7249 msi_parse_command_line( package, szCommandLine, FALSE );
7251 msi_apply_transforms( package );
7252 msi_apply_patches( package );
7254 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
7256 TRACE("setting reinstall property\n");
7257 MSI_SetPropertyW( package, szReinstall, szAll );
7260 /* properties may have been added by a transform */
7261 msi_clone_properties( package );
7262 msi_set_context( package );
7264 if (needs_ui_sequence( package))
7266 package->script->InWhatSequence |= SEQUENCE_UI;
7267 rc = ACTION_ProcessUISequence(package);
7268 ui_exists = ui_sequence_exists(package);
7269 if (rc == ERROR_SUCCESS || !ui_exists)
7271 package->script->InWhatSequence |= SEQUENCE_EXEC;
7272 rc = ACTION_ProcessExecSequence(package, ui_exists);
7275 else
7276 rc = ACTION_ProcessExecSequence(package, FALSE);
7278 package->script->CurrentlyScripting = FALSE;
7280 /* process the ending type action */
7281 if (rc == ERROR_SUCCESS)
7282 ACTION_PerformActionSequence(package, -1);
7283 else if (rc == ERROR_INSTALL_USEREXIT)
7284 ACTION_PerformActionSequence(package, -2);
7285 else if (rc == ERROR_INSTALL_SUSPEND)
7286 ACTION_PerformActionSequence(package, -4);
7287 else /* failed */
7288 ACTION_PerformActionSequence(package, -3);
7290 /* finish up running custom actions */
7291 ACTION_FinishCustomActions(package);
7293 if (rc == ERROR_SUCCESS && package->need_reboot)
7294 return ERROR_SUCCESS_REBOOT_REQUIRED;
7296 return rc;