msi: Implement the UnregisterExtensionInfo standard action.
[wine/multimedia.git] / dlls / msi / action.c
blob25cd4fc1558672a3668c0569b3c9201d3c4c498d
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 szUnregisterMIMEInfo[] =
162 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
163 static const WCHAR szUnregisterTypeLibraries[] =
164 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
165 static const WCHAR szValidateProductID[] =
166 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
167 static const WCHAR szWriteEnvironmentStrings[] =
168 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
170 /********************************************************
171 * helper functions
172 ********************************************************/
174 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
176 static const WCHAR Query_t[] =
177 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
178 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
179 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
180 ' ','\'','%','s','\'',0};
181 MSIRECORD * row;
183 row = MSI_QueryGetRecord( package->db, Query_t, action );
184 if (!row)
185 return;
186 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
187 msiobj_release(&row->hdr);
190 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
191 UINT rc)
193 MSIRECORD * row;
194 static const WCHAR template_s[]=
195 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
196 '%','s', '.',0};
197 static const WCHAR template_e[]=
198 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
199 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
200 '%','i','.',0};
201 static const WCHAR format[] =
202 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
203 WCHAR message[1024];
204 WCHAR timet[0x100];
206 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
207 if (start)
208 sprintfW(message,template_s,timet,action);
209 else
210 sprintfW(message,template_e,timet,action,rc);
212 row = MSI_CreateRecord(1);
213 MSI_RecordSetStringW(row,1,message);
215 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
216 msiobj_release(&row->hdr);
219 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
220 BOOL preserve_case )
222 LPCWSTR ptr,ptr2;
223 BOOL quote;
224 DWORD len;
225 LPWSTR prop = NULL, val = NULL;
227 if (!szCommandLine)
228 return ERROR_SUCCESS;
230 ptr = szCommandLine;
232 while (*ptr)
234 if (*ptr==' ')
236 ptr++;
237 continue;
240 TRACE("Looking at %s\n",debugstr_w(ptr));
242 ptr2 = strchrW(ptr,'=');
243 if (!ptr2)
245 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
246 break;
249 quote = FALSE;
251 len = ptr2-ptr;
252 prop = msi_alloc((len+1)*sizeof(WCHAR));
253 memcpy(prop,ptr,len*sizeof(WCHAR));
254 prop[len]=0;
256 if (!preserve_case)
257 struprW(prop);
259 ptr2++;
261 len = 0;
262 ptr = ptr2;
263 while (*ptr && (quote || (!quote && *ptr!=' ')))
265 if (*ptr == '"')
266 quote = !quote;
267 ptr++;
268 len++;
271 if (*ptr2=='"')
273 ptr2++;
274 len -= 2;
276 val = msi_alloc((len+1)*sizeof(WCHAR));
277 memcpy(val,ptr2,len*sizeof(WCHAR));
278 val[len] = 0;
280 if (lstrlenW(prop) > 0)
282 TRACE("Found commandline property (%s) = (%s)\n",
283 debugstr_w(prop), debugstr_w(val));
284 MSI_SetPropertyW(package,prop,val);
286 msi_free(val);
287 msi_free(prop);
290 return ERROR_SUCCESS;
294 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
296 LPCWSTR pc;
297 LPWSTR p, *ret = NULL;
298 UINT count = 0;
300 if (!str)
301 return ret;
303 /* count the number of substrings */
304 for ( pc = str, count = 0; pc; count++ )
306 pc = strchrW( pc, sep );
307 if (pc)
308 pc++;
311 /* allocate space for an array of substring pointers and the substrings */
312 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
313 (lstrlenW(str)+1) * sizeof(WCHAR) );
314 if (!ret)
315 return ret;
317 /* copy the string and set the pointers */
318 p = (LPWSTR) &ret[count+1];
319 lstrcpyW( p, str );
320 for( count = 0; (ret[count] = p); count++ )
322 p = strchrW( p, sep );
323 if (p)
324 *p++ = 0;
327 return ret;
330 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
332 static const WCHAR szSystemLanguageID[] =
333 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
335 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
336 UINT ret = ERROR_FUNCTION_FAILED;
338 prod_code = msi_dup_property( package, szProductCode );
339 patch_product = msi_get_suminfo_product( patch );
341 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
343 if ( strstrW( patch_product, prod_code ) )
345 MSISUMMARYINFO *si;
346 const WCHAR *p;
348 si = MSI_GetSummaryInformationW( patch, 0 );
349 if (!si)
351 ERR("no summary information!\n");
352 goto end;
355 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
356 if (!template)
358 ERR("no template property!\n");
359 msiobj_release( &si->hdr );
360 goto end;
363 if (!template[0])
365 ret = ERROR_SUCCESS;
366 msiobj_release( &si->hdr );
367 goto end;
370 langid = msi_dup_property( package, szSystemLanguageID );
371 if (!langid)
373 msiobj_release( &si->hdr );
374 goto end;
377 p = strchrW( template, ';' );
378 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
380 TRACE("applicable transform\n");
381 ret = ERROR_SUCCESS;
384 /* FIXME: check platform */
386 msiobj_release( &si->hdr );
389 end:
390 msi_free( patch_product );
391 msi_free( prod_code );
392 msi_free( template );
393 msi_free( langid );
395 return ret;
398 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
399 MSIDATABASE *patch_db, LPCWSTR name )
401 UINT ret = ERROR_FUNCTION_FAILED;
402 IStorage *stg = NULL;
403 HRESULT r;
405 TRACE("%p %s\n", package, debugstr_w(name) );
407 if (*name++ != ':')
409 ERR("expected a colon in %s\n", debugstr_w(name));
410 return ERROR_FUNCTION_FAILED;
413 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
414 if (SUCCEEDED(r))
416 ret = msi_check_transform_applicable( package, stg );
417 if (ret == ERROR_SUCCESS)
418 msi_table_apply_transform( package->db, stg );
419 else
420 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
421 IStorage_Release( stg );
423 else
424 ERR("failed to open substorage %s\n", debugstr_w(name));
426 return ERROR_SUCCESS;
429 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
431 LPWSTR guid_list, *guids, product_code;
432 UINT i, ret = ERROR_FUNCTION_FAILED;
434 product_code = msi_dup_property( package, szProductCode );
435 if (!product_code)
437 /* FIXME: the property ProductCode should be written into the DB somewhere */
438 ERR("no product code to check\n");
439 return ERROR_SUCCESS;
442 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
443 guids = msi_split_string( guid_list, ';' );
444 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
446 if (!lstrcmpW( guids[i], product_code ))
447 ret = ERROR_SUCCESS;
449 msi_free( guids );
450 msi_free( guid_list );
451 msi_free( product_code );
453 return ret;
456 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
458 MSIQUERY *view;
459 MSIRECORD *rec = NULL;
460 LPWSTR patch;
461 LPCWSTR prop;
462 UINT r;
464 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
465 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
466 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
467 '`','S','o','u','r','c','e','`',' ','I','S',' ',
468 'N','O','T',' ','N','U','L','L',0};
470 r = MSI_DatabaseOpenViewW(package->db, query, &view);
471 if (r != ERROR_SUCCESS)
472 return r;
474 r = MSI_ViewExecute(view, 0);
475 if (r != ERROR_SUCCESS)
476 goto done;
478 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
480 prop = MSI_RecordGetString(rec, 1);
481 patch = msi_dup_property(package, szPatch);
482 MSI_SetPropertyW(package, prop, patch);
483 msi_free(patch);
486 done:
487 if (rec) msiobj_release(&rec->hdr);
488 msiobj_release(&view->hdr);
490 return r;
493 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
495 MSISUMMARYINFO *si;
496 LPWSTR str, *substorage;
497 UINT i, r = ERROR_SUCCESS;
499 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
500 if (!si)
501 return ERROR_FUNCTION_FAILED;
503 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
505 TRACE("Patch not applicable\n");
506 return ERROR_SUCCESS;
509 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
510 if (!package->patch)
511 return ERROR_OUTOFMEMORY;
513 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
514 if (!package->patch->patchcode)
515 return ERROR_OUTOFMEMORY;
517 /* enumerate the substorage */
518 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
519 package->patch->transforms = str;
521 substorage = msi_split_string( str, ';' );
522 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
523 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
525 msi_free( substorage );
526 msiobj_release( &si->hdr );
528 msi_set_media_source_prop(package);
530 return r;
533 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
535 MSIDATABASE *patch_db = NULL;
536 UINT 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 );
555 * There might be a CAB file in the patch package,
556 * so append it to the list of storage to search for streams.
558 append_storage_to_db( package->db, patch_db->storage );
560 msiobj_release( &patch_db->hdr );
562 return ERROR_SUCCESS;
565 /* get the PATCH property, and apply all the patches it specifies */
566 static UINT msi_apply_patches( MSIPACKAGE *package )
568 LPWSTR patch_list, *patches;
569 UINT i, r = ERROR_SUCCESS;
571 patch_list = msi_dup_property( package, szPatch );
573 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
575 patches = msi_split_string( patch_list, ';' );
576 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
577 r = msi_apply_patch_package( package, patches[i] );
579 msi_free( patches );
580 msi_free( patch_list );
582 return r;
585 static UINT msi_apply_transforms( MSIPACKAGE *package )
587 static const WCHAR szTransforms[] = {
588 'T','R','A','N','S','F','O','R','M','S',0 };
589 LPWSTR xform_list, *xforms;
590 UINT i, r = ERROR_SUCCESS;
592 xform_list = msi_dup_property( package, szTransforms );
593 xforms = msi_split_string( xform_list, ';' );
595 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
597 if (xforms[i][0] == ':')
598 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
599 else
600 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
603 msi_free( xforms );
604 msi_free( xform_list );
606 return r;
609 static BOOL ui_sequence_exists( MSIPACKAGE *package )
611 MSIQUERY *view;
612 UINT rc;
614 static const WCHAR ExecSeqQuery [] =
615 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
616 '`','I','n','s','t','a','l','l',
617 'U','I','S','e','q','u','e','n','c','e','`',
618 ' ','W','H','E','R','E',' ',
619 '`','S','e','q','u','e','n','c','e','`',' ',
620 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
621 '`','S','e','q','u','e','n','c','e','`',0};
623 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
624 if (rc == ERROR_SUCCESS)
626 msiobj_release(&view->hdr);
627 return TRUE;
630 return FALSE;
633 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
635 LPWSTR p, db;
636 LPWSTR source, check;
637 DWORD len;
639 static const WCHAR szOriginalDatabase[] =
640 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
642 db = msi_dup_property( package, szOriginalDatabase );
643 if (!db)
644 return ERROR_OUTOFMEMORY;
646 p = strrchrW( db, '\\' );
647 if (!p)
649 p = strrchrW( db, '/' );
650 if (!p)
652 msi_free(db);
653 return ERROR_SUCCESS;
657 len = p - db + 2;
658 source = msi_alloc( len * sizeof(WCHAR) );
659 lstrcpynW( source, db, len );
661 check = msi_dup_property( package, cszSourceDir );
662 if (!check || replace)
663 MSI_SetPropertyW( package, cszSourceDir, source );
665 msi_free( check );
667 check = msi_dup_property( package, cszSOURCEDIR );
668 if (!check || replace)
669 MSI_SetPropertyW( package, cszSOURCEDIR, source );
671 msi_free( check );
672 msi_free( source );
673 msi_free( db );
675 return ERROR_SUCCESS;
678 static BOOL needs_ui_sequence(MSIPACKAGE *package)
680 INT level = msi_get_property_int(package, szUILevel, 0);
681 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
684 static UINT msi_set_context(MSIPACKAGE *package)
686 WCHAR val[10];
687 DWORD sz = 10;
688 DWORD num;
689 UINT r;
691 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
693 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
694 if (r == ERROR_SUCCESS)
696 num = atolW(val);
697 if (num == 1 || num == 2)
698 package->Context = MSIINSTALLCONTEXT_MACHINE;
701 return ERROR_SUCCESS;
704 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
706 UINT rc;
707 LPCWSTR cond, action;
708 MSIPACKAGE *package = param;
710 action = MSI_RecordGetString(row,1);
711 if (!action)
713 ERR("Error is retrieving action name\n");
714 return ERROR_FUNCTION_FAILED;
717 /* check conditions */
718 cond = MSI_RecordGetString(row,2);
720 /* this is a hack to skip errors in the condition code */
721 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
723 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
724 return ERROR_SUCCESS;
727 if (needs_ui_sequence(package))
728 rc = ACTION_PerformUIAction(package, action, -1);
729 else
730 rc = ACTION_PerformAction(package, action, -1, FALSE);
732 msi_dialog_check_messages( NULL );
734 if (package->CurrentInstallState != ERROR_SUCCESS)
735 rc = package->CurrentInstallState;
737 if (rc == ERROR_FUNCTION_NOT_CALLED)
738 rc = ERROR_SUCCESS;
740 if (rc != ERROR_SUCCESS)
741 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
743 return rc;
746 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
748 MSIQUERY * view;
749 UINT r;
750 static const WCHAR query[] =
751 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
752 '`','%','s','`',
753 ' ','W','H','E','R','E',' ',
754 '`','S','e','q','u','e','n','c','e','`',' ',
755 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
756 '`','S','e','q','u','e','n','c','e','`',0};
758 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
760 r = MSI_OpenQuery( package->db, &view, query, szTable );
761 if (r == ERROR_SUCCESS)
763 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
764 msiobj_release(&view->hdr);
767 return r;
770 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
772 MSIQUERY * view;
773 UINT rc;
774 static const WCHAR ExecSeqQuery[] =
775 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
776 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
777 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
778 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
779 'O','R','D','E','R',' ', 'B','Y',' ',
780 '`','S','e','q','u','e','n','c','e','`',0 };
781 static const WCHAR IVQuery[] =
782 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
783 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
784 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
785 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
786 ' ','\'', 'I','n','s','t','a','l','l',
787 'V','a','l','i','d','a','t','e','\'', 0};
788 INT seq = 0;
790 if (package->script->ExecuteSequenceRun)
792 TRACE("Execute Sequence already Run\n");
793 return ERROR_SUCCESS;
796 package->script->ExecuteSequenceRun = TRUE;
798 /* get the sequence number */
799 if (UIran)
801 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
802 if( !row )
803 return ERROR_FUNCTION_FAILED;
804 seq = MSI_RecordGetInteger(row,1);
805 msiobj_release(&row->hdr);
808 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
809 if (rc == ERROR_SUCCESS)
811 TRACE("Running the actions\n");
813 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
814 msiobj_release(&view->hdr);
817 return rc;
820 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
822 MSIQUERY * view;
823 UINT rc;
824 static const WCHAR ExecSeqQuery [] =
825 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
826 '`','I','n','s','t','a','l','l',
827 'U','I','S','e','q','u','e','n','c','e','`',
828 ' ','W','H','E','R','E',' ',
829 '`','S','e','q','u','e','n','c','e','`',' ',
830 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
831 '`','S','e','q','u','e','n','c','e','`',0};
833 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
834 if (rc == ERROR_SUCCESS)
836 TRACE("Running the actions\n");
838 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
839 msiobj_release(&view->hdr);
842 return rc;
845 /********************************************************
846 * ACTION helper functions and functions that perform the actions
847 *******************************************************/
848 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
849 UINT* rc, UINT script, BOOL force )
851 BOOL ret=FALSE;
852 UINT arc;
854 arc = ACTION_CustomAction(package, action, script, force);
856 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
858 *rc = arc;
859 ret = TRUE;
861 return ret;
865 * Actual Action Handlers
868 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
870 MSIPACKAGE *package = param;
871 LPCWSTR dir, component;
872 LPWSTR full_path;
873 MSIRECORD *uirow;
874 MSIFOLDER *folder;
875 MSICOMPONENT *comp;
877 component = MSI_RecordGetString(row, 2);
878 comp = get_loaded_component(package, component);
879 if (!comp)
880 return ERROR_SUCCESS;
882 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
884 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
885 comp->Action = comp->Installed;
886 return ERROR_SUCCESS;
888 comp->Action = INSTALLSTATE_LOCAL;
890 dir = MSI_RecordGetString(row,1);
891 if (!dir)
893 ERR("Unable to get folder id\n");
894 return ERROR_SUCCESS;
897 uirow = MSI_CreateRecord(1);
898 MSI_RecordSetStringW(uirow, 1, dir);
899 ui_actiondata(package, szCreateFolders, uirow);
900 msiobj_release(&uirow->hdr);
902 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
903 if (!full_path)
905 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
906 return ERROR_SUCCESS;
909 TRACE("Folder is %s\n",debugstr_w(full_path));
911 if (folder->State == 0)
912 create_full_pathW(full_path);
914 folder->State = 3;
916 msi_free(full_path);
917 return ERROR_SUCCESS;
920 /* FIXME: probably should merge this with the above function */
921 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
923 UINT rc = ERROR_SUCCESS;
924 MSIFOLDER *folder;
925 LPWSTR install_path;
927 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
928 if (!install_path)
929 return ERROR_FUNCTION_FAILED;
931 /* create the path */
932 if (folder->State == 0)
934 create_full_pathW(install_path);
935 folder->State = 2;
937 msi_free(install_path);
939 return rc;
942 UINT msi_create_component_directories( MSIPACKAGE *package )
944 MSICOMPONENT *comp;
946 /* create all the folders required by the components are going to install */
947 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
949 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
950 continue;
951 msi_create_directory( package, comp->Directory );
954 return ERROR_SUCCESS;
957 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
959 static const WCHAR ExecSeqQuery[] =
960 {'S','E','L','E','C','T',' ',
961 '`','D','i','r','e','c','t','o','r','y','_','`',
962 ' ','F','R','O','M',' ',
963 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
964 UINT rc;
965 MSIQUERY *view;
967 /* create all the empty folders specified in the CreateFolder table */
968 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
969 if (rc != ERROR_SUCCESS)
970 return ERROR_SUCCESS;
972 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
973 msiobj_release(&view->hdr);
975 return rc;
978 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
980 MSIPACKAGE *package = param;
981 LPCWSTR dir, component;
982 LPWSTR full_path;
983 MSIRECORD *uirow;
984 MSIFOLDER *folder;
985 MSICOMPONENT *comp;
987 component = MSI_RecordGetString(row, 2);
988 comp = get_loaded_component(package, component);
989 if (!comp)
990 return ERROR_SUCCESS;
992 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
994 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
995 comp->Action = comp->Installed;
996 return ERROR_SUCCESS;
998 comp->Action = INSTALLSTATE_ABSENT;
1000 dir = MSI_RecordGetString( row, 1 );
1001 if (!dir)
1003 ERR("Unable to get folder id\n");
1004 return ERROR_SUCCESS;
1007 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1008 if (!full_path)
1010 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1011 return ERROR_SUCCESS;
1014 TRACE("folder is %s\n", debugstr_w(full_path));
1016 uirow = MSI_CreateRecord( 1 );
1017 MSI_RecordSetStringW( uirow, 1, full_path );
1018 ui_actiondata( package, szRemoveFolders, uirow );
1019 msiobj_release( &uirow->hdr );
1021 RemoveDirectoryW( full_path );
1022 folder->State = 0;
1024 msi_free( full_path );
1025 return ERROR_SUCCESS;
1028 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1030 static const WCHAR query[] =
1031 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1032 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1034 MSIQUERY *view;
1035 UINT rc;
1037 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1038 if (rc != ERROR_SUCCESS)
1039 return ERROR_SUCCESS;
1041 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1042 msiobj_release( &view->hdr );
1044 return rc;
1047 static UINT load_component( MSIRECORD *row, LPVOID param )
1049 MSIPACKAGE *package = param;
1050 MSICOMPONENT *comp;
1052 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1053 if (!comp)
1054 return ERROR_FUNCTION_FAILED;
1056 list_add_tail( &package->components, &comp->entry );
1058 /* fill in the data */
1059 comp->Component = msi_dup_record_field( row, 1 );
1061 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1063 comp->ComponentId = msi_dup_record_field( row, 2 );
1064 comp->Directory = msi_dup_record_field( row, 3 );
1065 comp->Attributes = MSI_RecordGetInteger(row,4);
1066 comp->Condition = msi_dup_record_field( row, 5 );
1067 comp->KeyPath = msi_dup_record_field( row, 6 );
1069 comp->Installed = INSTALLSTATE_UNKNOWN;
1070 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1072 return ERROR_SUCCESS;
1075 static UINT load_all_components( MSIPACKAGE *package )
1077 static const WCHAR query[] = {
1078 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1079 '`','C','o','m','p','o','n','e','n','t','`',0 };
1080 MSIQUERY *view;
1081 UINT r;
1083 if (!list_empty(&package->components))
1084 return ERROR_SUCCESS;
1086 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1087 if (r != ERROR_SUCCESS)
1088 return r;
1090 r = MSI_IterateRecords(view, NULL, load_component, package);
1091 msiobj_release(&view->hdr);
1092 return r;
1095 typedef struct {
1096 MSIPACKAGE *package;
1097 MSIFEATURE *feature;
1098 } _ilfs;
1100 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1102 ComponentList *cl;
1104 cl = msi_alloc( sizeof (*cl) );
1105 if ( !cl )
1106 return ERROR_NOT_ENOUGH_MEMORY;
1107 cl->component = comp;
1108 list_add_tail( &feature->Components, &cl->entry );
1110 return ERROR_SUCCESS;
1113 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1115 FeatureList *fl;
1117 fl = msi_alloc( sizeof(*fl) );
1118 if ( !fl )
1119 return ERROR_NOT_ENOUGH_MEMORY;
1120 fl->feature = child;
1121 list_add_tail( &parent->Children, &fl->entry );
1123 return ERROR_SUCCESS;
1126 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1128 _ilfs* ilfs = param;
1129 LPCWSTR component;
1130 MSICOMPONENT *comp;
1132 component = MSI_RecordGetString(row,1);
1134 /* check to see if the component is already loaded */
1135 comp = get_loaded_component( ilfs->package, component );
1136 if (!comp)
1138 ERR("unknown component %s\n", debugstr_w(component));
1139 return ERROR_FUNCTION_FAILED;
1142 add_feature_component( ilfs->feature, comp );
1143 comp->Enabled = TRUE;
1145 return ERROR_SUCCESS;
1148 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1150 MSIFEATURE *feature;
1152 if ( !name )
1153 return NULL;
1155 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1157 if ( !lstrcmpW( feature->Feature, name ) )
1158 return feature;
1161 return NULL;
1164 static UINT load_feature(MSIRECORD * row, LPVOID param)
1166 MSIPACKAGE* package = param;
1167 MSIFEATURE* feature;
1168 static const WCHAR Query1[] =
1169 {'S','E','L','E','C','T',' ',
1170 '`','C','o','m','p','o','n','e','n','t','_','`',
1171 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1172 'C','o','m','p','o','n','e','n','t','s','`',' ',
1173 'W','H','E','R','E',' ',
1174 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1175 MSIQUERY * view;
1176 UINT rc;
1177 _ilfs ilfs;
1179 /* fill in the data */
1181 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1182 if (!feature)
1183 return ERROR_NOT_ENOUGH_MEMORY;
1185 list_init( &feature->Children );
1186 list_init( &feature->Components );
1188 feature->Feature = msi_dup_record_field( row, 1 );
1190 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1192 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1193 feature->Title = msi_dup_record_field( row, 3 );
1194 feature->Description = msi_dup_record_field( row, 4 );
1196 if (!MSI_RecordIsNull(row,5))
1197 feature->Display = MSI_RecordGetInteger(row,5);
1199 feature->Level= MSI_RecordGetInteger(row,6);
1200 feature->Directory = msi_dup_record_field( row, 7 );
1201 feature->Attributes = MSI_RecordGetInteger(row,8);
1203 feature->Installed = INSTALLSTATE_UNKNOWN;
1204 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1206 list_add_tail( &package->features, &feature->entry );
1208 /* load feature components */
1210 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1211 if (rc != ERROR_SUCCESS)
1212 return ERROR_SUCCESS;
1214 ilfs.package = package;
1215 ilfs.feature = feature;
1217 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1218 msiobj_release(&view->hdr);
1220 return ERROR_SUCCESS;
1223 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1225 MSIPACKAGE* package = param;
1226 MSIFEATURE *parent, *child;
1228 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1229 if (!child)
1230 return ERROR_FUNCTION_FAILED;
1232 if (!child->Feature_Parent)
1233 return ERROR_SUCCESS;
1235 parent = find_feature_by_name( package, child->Feature_Parent );
1236 if (!parent)
1237 return ERROR_FUNCTION_FAILED;
1239 add_feature_child( parent, child );
1240 return ERROR_SUCCESS;
1243 static UINT load_all_features( MSIPACKAGE *package )
1245 static const WCHAR query[] = {
1246 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1247 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1248 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1249 MSIQUERY *view;
1250 UINT r;
1252 if (!list_empty(&package->features))
1253 return ERROR_SUCCESS;
1255 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1256 if (r != ERROR_SUCCESS)
1257 return r;
1259 r = MSI_IterateRecords( view, NULL, load_feature, package );
1260 if (r != ERROR_SUCCESS)
1261 return r;
1263 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1264 msiobj_release( &view->hdr );
1266 return r;
1269 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1271 if (!p)
1272 return p;
1273 p = strchrW(p, ch);
1274 if (!p)
1275 return p;
1276 *p = 0;
1277 return p+1;
1280 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1282 static const WCHAR query[] = {
1283 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1284 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1285 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1286 MSIQUERY *view = NULL;
1287 MSIRECORD *row = NULL;
1288 UINT r;
1290 TRACE("%s\n", debugstr_w(file->File));
1292 r = MSI_OpenQuery(package->db, &view, query, file->File);
1293 if (r != ERROR_SUCCESS)
1294 goto done;
1296 r = MSI_ViewExecute(view, NULL);
1297 if (r != ERROR_SUCCESS)
1298 goto done;
1300 r = MSI_ViewFetch(view, &row);
1301 if (r != ERROR_SUCCESS)
1302 goto done;
1304 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1305 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1306 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1307 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1308 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1310 done:
1311 if (view) msiobj_release(&view->hdr);
1312 if (row) msiobj_release(&row->hdr);
1313 return r;
1316 static UINT load_file(MSIRECORD *row, LPVOID param)
1318 MSIPACKAGE* package = param;
1319 LPCWSTR component;
1320 MSIFILE *file;
1322 /* fill in the data */
1324 file = msi_alloc_zero( sizeof (MSIFILE) );
1325 if (!file)
1326 return ERROR_NOT_ENOUGH_MEMORY;
1328 file->File = msi_dup_record_field( row, 1 );
1330 component = MSI_RecordGetString( row, 2 );
1331 file->Component = get_loaded_component( package, component );
1333 if (!file->Component)
1335 WARN("Component not found: %s\n", debugstr_w(component));
1336 msi_free(file->File);
1337 msi_free(file);
1338 return ERROR_SUCCESS;
1341 file->FileName = msi_dup_record_field( row, 3 );
1342 reduce_to_longfilename( file->FileName );
1344 file->ShortName = msi_dup_record_field( row, 3 );
1345 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1347 file->FileSize = MSI_RecordGetInteger( row, 4 );
1348 file->Version = msi_dup_record_field( row, 5 );
1349 file->Language = msi_dup_record_field( row, 6 );
1350 file->Attributes = MSI_RecordGetInteger( row, 7 );
1351 file->Sequence = MSI_RecordGetInteger( row, 8 );
1353 file->state = msifs_invalid;
1355 /* if the compressed bits are not set in the file attributes,
1356 * then read the information from the package word count property
1358 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1360 file->IsCompressed = FALSE;
1362 else if (file->Attributes &
1363 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1365 file->IsCompressed = TRUE;
1367 else if (file->Attributes & msidbFileAttributesNoncompressed)
1369 file->IsCompressed = FALSE;
1371 else
1373 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1376 load_file_hash(package, file);
1378 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1380 list_add_tail( &package->files, &file->entry );
1382 return ERROR_SUCCESS;
1385 static UINT load_all_files(MSIPACKAGE *package)
1387 MSIQUERY * view;
1388 UINT rc;
1389 static const WCHAR Query[] =
1390 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1391 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1392 '`','S','e','q','u','e','n','c','e','`', 0};
1394 if (!list_empty(&package->files))
1395 return ERROR_SUCCESS;
1397 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1398 if (rc != ERROR_SUCCESS)
1399 return ERROR_SUCCESS;
1401 rc = MSI_IterateRecords(view, NULL, load_file, package);
1402 msiobj_release(&view->hdr);
1404 return ERROR_SUCCESS;
1407 static UINT load_folder( MSIRECORD *row, LPVOID param )
1409 MSIPACKAGE *package = param;
1410 static WCHAR szEmpty[] = { 0 };
1411 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1412 MSIFOLDER *folder;
1414 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1415 if (!folder)
1416 return ERROR_NOT_ENOUGH_MEMORY;
1418 folder->Directory = msi_dup_record_field( row, 1 );
1420 TRACE("%s\n", debugstr_w(folder->Directory));
1422 p = msi_dup_record_field(row, 3);
1424 /* split src and target dir */
1425 tgt_short = p;
1426 src_short = folder_split_path( p, ':' );
1428 /* split the long and short paths */
1429 tgt_long = folder_split_path( tgt_short, '|' );
1430 src_long = folder_split_path( src_short, '|' );
1432 /* check for no-op dirs */
1433 if (!lstrcmpW(szDot, tgt_short))
1434 tgt_short = szEmpty;
1435 if (!lstrcmpW(szDot, src_short))
1436 src_short = szEmpty;
1438 if (!tgt_long)
1439 tgt_long = tgt_short;
1441 if (!src_short) {
1442 src_short = tgt_short;
1443 src_long = tgt_long;
1446 if (!src_long)
1447 src_long = src_short;
1449 /* FIXME: use the target short path too */
1450 folder->TargetDefault = strdupW(tgt_long);
1451 folder->SourceShortPath = strdupW(src_short);
1452 folder->SourceLongPath = strdupW(src_long);
1453 msi_free(p);
1455 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1456 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1457 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1459 folder->Parent = msi_dup_record_field( row, 2 );
1461 folder->Property = msi_dup_property( package, folder->Directory );
1463 list_add_tail( &package->folders, &folder->entry );
1465 TRACE("returning %p\n", folder);
1467 return ERROR_SUCCESS;
1470 static UINT load_all_folders( MSIPACKAGE *package )
1472 static const WCHAR query[] = {
1473 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1474 '`','D','i','r','e','c','t','o','r','y','`',0 };
1475 MSIQUERY *view;
1476 UINT r;
1478 if (!list_empty(&package->folders))
1479 return ERROR_SUCCESS;
1481 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1482 if (r != ERROR_SUCCESS)
1483 return r;
1485 r = MSI_IterateRecords(view, NULL, load_folder, package);
1486 msiobj_release(&view->hdr);
1487 return r;
1491 * I am not doing any of the costing functionality yet.
1492 * Mostly looking at doing the Component and Feature loading
1494 * The native MSI does A LOT of modification to tables here. Mostly adding
1495 * a lot of temporary columns to the Feature and Component tables.
1497 * note: Native msi also tracks the short filename. But I am only going to
1498 * track the long ones. Also looking at this directory table
1499 * it appears that the directory table does not get the parents
1500 * resolved base on property only based on their entries in the
1501 * directory table.
1503 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1505 static const WCHAR szCosting[] =
1506 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1508 MSI_SetPropertyW(package, szCosting, szZero);
1509 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1511 load_all_folders( package );
1512 load_all_components( package );
1513 load_all_features( package );
1514 load_all_files( package );
1516 return ERROR_SUCCESS;
1519 static UINT execute_script(MSIPACKAGE *package, UINT script )
1521 UINT i;
1522 UINT rc = ERROR_SUCCESS;
1524 TRACE("Executing Script %i\n",script);
1526 if (!package->script)
1528 ERR("no script!\n");
1529 return ERROR_FUNCTION_FAILED;
1532 for (i = 0; i < package->script->ActionCount[script]; i++)
1534 LPWSTR action;
1535 action = package->script->Actions[script][i];
1536 ui_actionstart(package, action);
1537 TRACE("Executing Action (%s)\n",debugstr_w(action));
1538 rc = ACTION_PerformAction(package, action, script, TRUE);
1539 if (rc != ERROR_SUCCESS)
1540 break;
1542 msi_free_action_script(package, script);
1543 return rc;
1546 static UINT ACTION_FileCost(MSIPACKAGE *package)
1548 return ERROR_SUCCESS;
1551 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1553 MSICOMPONENT *comp;
1554 INSTALLSTATE state;
1555 UINT r;
1557 state = MsiQueryProductStateW(package->ProductCode);
1559 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1561 if (!comp->ComponentId)
1562 continue;
1564 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1565 comp->Installed = INSTALLSTATE_ABSENT;
1566 else
1568 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1569 package->Context, comp->ComponentId,
1570 &comp->Installed);
1571 if (r != ERROR_SUCCESS)
1572 comp->Installed = INSTALLSTATE_ABSENT;
1577 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1579 MSIFEATURE *feature;
1580 INSTALLSTATE state;
1582 state = MsiQueryProductStateW(package->ProductCode);
1584 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1586 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1587 feature->Installed = INSTALLSTATE_ABSENT;
1588 else
1590 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1591 feature->Feature);
1596 static BOOL process_state_property(MSIPACKAGE* package, int level,
1597 LPCWSTR property, INSTALLSTATE state)
1599 LPWSTR override;
1600 MSIFEATURE *feature;
1602 override = msi_dup_property( package, property );
1603 if (!override)
1604 return FALSE;
1606 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1608 if (lstrcmpW(property, szRemove) &&
1609 (feature->Level <= 0 || feature->Level > level))
1610 continue;
1612 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1614 if (strcmpiW(override, szAll)==0)
1615 msi_feature_set_state(package, feature, state);
1616 else
1618 LPWSTR ptr = override;
1619 LPWSTR ptr2 = strchrW(override,',');
1621 while (ptr)
1623 int len = ptr2 - ptr;
1625 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1626 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1628 msi_feature_set_state(package, feature, state);
1629 break;
1631 if (ptr2)
1633 ptr=ptr2+1;
1634 ptr2 = strchrW(ptr,',');
1636 else
1637 break;
1641 msi_free(override);
1643 return TRUE;
1646 static BOOL process_overrides( MSIPACKAGE *package, int level )
1648 static const WCHAR szAddLocal[] =
1649 {'A','D','D','L','O','C','A','L',0};
1650 static const WCHAR szAddSource[] =
1651 {'A','D','D','S','O','U','R','C','E',0};
1652 static const WCHAR szAdvertise[] =
1653 {'A','D','V','E','R','T','I','S','E',0};
1654 BOOL ret = FALSE;
1656 /* all these activation/deactivation things happen in order and things
1657 * later on the list override things earlier on the list.
1659 * 0 INSTALLLEVEL processing
1660 * 1 ADDLOCAL
1661 * 2 REMOVE
1662 * 3 ADDSOURCE
1663 * 4 ADDDEFAULT
1664 * 5 REINSTALL
1665 * 6 ADVERTISE
1666 * 7 COMPADDLOCAL
1667 * 8 COMPADDSOURCE
1668 * 9 FILEADDLOCAL
1669 * 10 FILEADDSOURCE
1670 * 11 FILEADDDEFAULT
1672 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1673 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1674 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1675 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1676 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1678 if (ret)
1679 MSI_SetPropertyW( package, szPreselected, szOne );
1681 return ret;
1684 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1686 int level;
1687 static const WCHAR szlevel[] =
1688 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1689 MSICOMPONENT* component;
1690 MSIFEATURE *feature;
1692 TRACE("Checking Install Level\n");
1694 level = msi_get_property_int(package, szlevel, 1);
1696 if (!msi_get_property_int( package, szPreselected, 0 ))
1698 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1700 BOOL feature_state = ((feature->Level > 0) &&
1701 (feature->Level <= level));
1703 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1705 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1706 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1707 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1708 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1709 else
1710 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1714 /* disable child features of unselected parent features */
1715 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1717 FeatureList *fl;
1719 if (feature->Level > 0 && feature->Level <= level)
1720 continue;
1722 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1723 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1728 * now we want to enable or disable components base on feature
1731 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1733 ComponentList *cl;
1735 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1736 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1738 if (!feature->Level)
1739 continue;
1741 /* features with components that have compressed files are made local */
1742 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1744 if (cl->component->Enabled &&
1745 cl->component->ForceLocalState &&
1746 feature->Action == INSTALLSTATE_SOURCE)
1748 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1749 break;
1753 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1755 component = cl->component;
1757 if (!component->Enabled)
1758 continue;
1760 switch (feature->Action)
1762 case INSTALLSTATE_ABSENT:
1763 component->anyAbsent = 1;
1764 break;
1765 case INSTALLSTATE_ADVERTISED:
1766 component->hasAdvertiseFeature = 1;
1767 break;
1768 case INSTALLSTATE_SOURCE:
1769 component->hasSourceFeature = 1;
1770 break;
1771 case INSTALLSTATE_LOCAL:
1772 component->hasLocalFeature = 1;
1773 break;
1774 case INSTALLSTATE_DEFAULT:
1775 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1776 component->hasAdvertiseFeature = 1;
1777 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1778 component->hasSourceFeature = 1;
1779 else
1780 component->hasLocalFeature = 1;
1781 break;
1782 default:
1783 break;
1788 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1790 /* if the component isn't enabled, leave it alone */
1791 if (!component->Enabled)
1792 continue;
1794 /* check if it's local or source */
1795 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1796 (component->hasLocalFeature || component->hasSourceFeature))
1798 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1799 !component->ForceLocalState)
1800 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1801 else
1802 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1803 continue;
1806 /* if any feature is local, the component must be local too */
1807 if (component->hasLocalFeature)
1809 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1810 continue;
1813 if (component->hasSourceFeature)
1815 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1816 continue;
1819 if (component->hasAdvertiseFeature)
1821 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1822 continue;
1825 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1826 if (component->anyAbsent)
1827 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1830 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1832 if (component->Action == INSTALLSTATE_DEFAULT)
1834 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1835 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1838 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1839 debugstr_w(component->Component), component->Installed, component->Action);
1843 return ERROR_SUCCESS;
1846 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1848 MSIPACKAGE *package = param;
1849 LPCWSTR name;
1850 LPWSTR path;
1851 MSIFOLDER *f;
1853 name = MSI_RecordGetString(row,1);
1855 f = get_loaded_folder(package, name);
1856 if (!f) return ERROR_SUCCESS;
1858 /* reset the ResolvedTarget */
1859 msi_free(f->ResolvedTarget);
1860 f->ResolvedTarget = NULL;
1862 /* This helper function now does ALL the work */
1863 TRACE("Dir %s ...\n",debugstr_w(name));
1864 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1865 TRACE("resolves to %s\n",debugstr_w(path));
1866 msi_free(path);
1868 return ERROR_SUCCESS;
1871 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1873 MSIPACKAGE *package = param;
1874 LPCWSTR name;
1875 MSIFEATURE *feature;
1877 name = MSI_RecordGetString( row, 1 );
1879 feature = get_loaded_feature( package, name );
1880 if (!feature)
1881 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1882 else
1884 LPCWSTR Condition;
1885 Condition = MSI_RecordGetString(row,3);
1887 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1889 int level = MSI_RecordGetInteger(row,2);
1890 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1891 feature->Level = level;
1894 return ERROR_SUCCESS;
1897 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1899 static const WCHAR name_fmt[] =
1900 {'%','u','.','%','u','.','%','u','.','%','u',0};
1901 static const WCHAR name[] = {'\\',0};
1902 VS_FIXEDFILEINFO *lpVer;
1903 WCHAR filever[0x100];
1904 LPVOID version;
1905 DWORD versize;
1906 DWORD handle;
1907 UINT sz;
1909 TRACE("%s\n", debugstr_w(filename));
1911 versize = GetFileVersionInfoSizeW( filename, &handle );
1912 if (!versize)
1913 return NULL;
1915 version = msi_alloc( versize );
1916 GetFileVersionInfoW( filename, 0, versize, version );
1918 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1920 msi_free( version );
1921 return NULL;
1924 sprintfW( filever, name_fmt,
1925 HIWORD(lpVer->dwFileVersionMS),
1926 LOWORD(lpVer->dwFileVersionMS),
1927 HIWORD(lpVer->dwFileVersionLS),
1928 LOWORD(lpVer->dwFileVersionLS));
1930 msi_free( version );
1932 return strdupW( filever );
1935 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1937 LPWSTR file_version;
1938 MSIFILE *file;
1940 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1942 MSICOMPONENT* comp = file->Component;
1943 LPWSTR p;
1945 if (!comp)
1946 continue;
1948 if (file->IsCompressed)
1949 comp->ForceLocalState = TRUE;
1951 /* calculate target */
1952 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1954 msi_free(file->TargetPath);
1956 TRACE("file %s is named %s\n",
1957 debugstr_w(file->File), debugstr_w(file->FileName));
1959 file->TargetPath = build_directory_name(2, p, file->FileName);
1961 msi_free(p);
1963 TRACE("file %s resolves to %s\n",
1964 debugstr_w(file->File), debugstr_w(file->TargetPath));
1966 /* don't check files of components that aren't installed */
1967 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1968 comp->Installed == INSTALLSTATE_ABSENT)
1970 file->state = msifs_missing; /* assume files are missing */
1971 continue;
1974 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1976 file->state = msifs_missing;
1977 comp->Cost += file->FileSize;
1978 continue;
1981 if (file->Version &&
1982 (file_version = msi_get_disk_file_version( file->TargetPath )))
1984 TRACE("new %s old %s\n", debugstr_w(file->Version),
1985 debugstr_w(file_version));
1986 /* FIXME: seems like a bad way to compare version numbers */
1987 if (lstrcmpiW(file_version, file->Version)<0)
1989 file->state = msifs_overwrite;
1990 comp->Cost += file->FileSize;
1992 else
1993 file->state = msifs_present;
1994 msi_free( file_version );
1996 else
1997 file->state = msifs_present;
2000 return ERROR_SUCCESS;
2004 * A lot is done in this function aside from just the costing.
2005 * The costing needs to be implemented at some point but for now I am going
2006 * to focus on the directory building
2009 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2011 static const WCHAR ExecSeqQuery[] =
2012 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2013 '`','D','i','r','e','c','t','o','r','y','`',0};
2014 static const WCHAR ConditionQuery[] =
2015 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2016 '`','C','o','n','d','i','t','i','o','n','`',0};
2017 static const WCHAR szCosting[] =
2018 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2019 static const WCHAR szlevel[] =
2020 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2021 static const WCHAR szOutOfDiskSpace[] =
2022 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2023 MSICOMPONENT *comp;
2024 UINT rc = ERROR_SUCCESS;
2025 MSIQUERY * view;
2026 LPWSTR level;
2028 TRACE("Building Directory properties\n");
2030 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2031 if (rc == ERROR_SUCCESS)
2033 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2034 package);
2035 msiobj_release(&view->hdr);
2038 /* read components states from the registry */
2039 ACTION_GetComponentInstallStates(package);
2040 ACTION_GetFeatureInstallStates(package);
2042 TRACE("File calculations\n");
2043 msi_check_file_install_states( package );
2045 if (!process_overrides( package, msi_get_property_int( package, szlevel, 1 ) ))
2047 TRACE("Evaluating Condition Table\n");
2049 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2050 if (rc == ERROR_SUCCESS)
2052 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2053 msiobj_release( &view->hdr );
2056 TRACE("Enabling or Disabling Components\n");
2057 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2059 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2061 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2062 comp->Enabled = FALSE;
2064 else
2065 comp->Enabled = TRUE;
2069 MSI_SetPropertyW(package,szCosting,szOne);
2070 /* set default run level if not set */
2071 level = msi_dup_property( package, szlevel );
2072 if (!level)
2073 MSI_SetPropertyW(package,szlevel, szOne);
2074 msi_free(level);
2076 /* FIXME: check volume disk space */
2077 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2079 return MSI_SetFeatureStates(package);
2082 /* OK this value is "interpreted" and then formatted based on the
2083 first few characters */
2084 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2085 DWORD *size)
2087 LPSTR data = NULL;
2089 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2091 if (value[1]=='x')
2093 LPWSTR ptr;
2094 CHAR byte[5];
2095 LPWSTR deformated = NULL;
2096 int count;
2098 deformat_string(package, &value[2], &deformated);
2100 /* binary value type */
2101 ptr = deformated;
2102 *type = REG_BINARY;
2103 if (strlenW(ptr)%2)
2104 *size = (strlenW(ptr)/2)+1;
2105 else
2106 *size = strlenW(ptr)/2;
2108 data = msi_alloc(*size);
2110 byte[0] = '0';
2111 byte[1] = 'x';
2112 byte[4] = 0;
2113 count = 0;
2114 /* if uneven pad with a zero in front */
2115 if (strlenW(ptr)%2)
2117 byte[2]= '0';
2118 byte[3]= *ptr;
2119 ptr++;
2120 data[count] = (BYTE)strtol(byte,NULL,0);
2121 count ++;
2122 TRACE("Uneven byte count\n");
2124 while (*ptr)
2126 byte[2]= *ptr;
2127 ptr++;
2128 byte[3]= *ptr;
2129 ptr++;
2130 data[count] = (BYTE)strtol(byte,NULL,0);
2131 count ++;
2133 msi_free(deformated);
2135 TRACE("Data %i bytes(%i)\n",*size,count);
2137 else
2139 LPWSTR deformated;
2140 LPWSTR p;
2141 DWORD d = 0;
2142 deformat_string(package, &value[1], &deformated);
2144 *type=REG_DWORD;
2145 *size = sizeof(DWORD);
2146 data = msi_alloc(*size);
2147 p = deformated;
2148 if (*p == '-')
2149 p++;
2150 while (*p)
2152 if ( (*p < '0') || (*p > '9') )
2153 break;
2154 d *= 10;
2155 d += (*p - '0');
2156 p++;
2158 if (deformated[0] == '-')
2159 d = -d;
2160 *(LPDWORD)data = d;
2161 TRACE("DWORD %i\n",*(LPDWORD)data);
2163 msi_free(deformated);
2166 else
2168 static const WCHAR szMulti[] = {'[','~',']',0};
2169 LPCWSTR ptr;
2170 *type=REG_SZ;
2172 if (value[0]=='#')
2174 if (value[1]=='%')
2176 ptr = &value[2];
2177 *type=REG_EXPAND_SZ;
2179 else
2180 ptr = &value[1];
2182 else
2183 ptr=value;
2185 if (strstrW(value,szMulti))
2186 *type = REG_MULTI_SZ;
2188 /* remove initial delimiter */
2189 if (!strncmpW(value, szMulti, 3))
2190 ptr = value + 3;
2192 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2194 /* add double NULL terminator */
2195 if (*type == REG_MULTI_SZ)
2197 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2198 data = msi_realloc_zero(data, *size);
2201 return data;
2204 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2206 const WCHAR *ret;
2208 switch (root)
2210 case -1:
2211 if (msi_get_property_int( package, szAllUsers, 0 ))
2213 *root_key = HKEY_LOCAL_MACHINE;
2214 ret = szHLM;
2216 else
2218 *root_key = HKEY_CURRENT_USER;
2219 ret = szHCU;
2221 break;
2222 case 0:
2223 *root_key = HKEY_CLASSES_ROOT;
2224 ret = szHCR;
2225 break;
2226 case 1:
2227 *root_key = HKEY_CURRENT_USER;
2228 ret = szHCU;
2229 break;
2230 case 2:
2231 *root_key = HKEY_LOCAL_MACHINE;
2232 ret = szHLM;
2233 break;
2234 case 3:
2235 *root_key = HKEY_USERS;
2236 ret = szHU;
2237 break;
2238 default:
2239 ERR("Unknown root %i\n", root);
2240 return NULL;
2243 return ret;
2246 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2248 MSIPACKAGE *package = param;
2249 LPSTR value_data = NULL;
2250 HKEY root_key, hkey;
2251 DWORD type,size;
2252 LPWSTR deformated;
2253 LPCWSTR szRoot, component, name, key, value;
2254 MSICOMPONENT *comp;
2255 MSIRECORD * uirow;
2256 LPWSTR uikey;
2257 INT root;
2258 BOOL check_first = FALSE;
2259 UINT rc;
2261 ui_progress(package,2,0,0,0);
2263 value = NULL;
2264 key = NULL;
2265 uikey = NULL;
2266 name = NULL;
2268 component = MSI_RecordGetString(row, 6);
2269 comp = get_loaded_component(package,component);
2270 if (!comp)
2271 return ERROR_SUCCESS;
2273 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2275 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2276 comp->Action = comp->Installed;
2277 return ERROR_SUCCESS;
2279 comp->Action = INSTALLSTATE_LOCAL;
2281 name = MSI_RecordGetString(row, 4);
2282 if( MSI_RecordIsNull(row,5) && name )
2284 /* null values can have special meanings */
2285 if (name[0]=='-' && name[1] == 0)
2286 return ERROR_SUCCESS;
2287 else if ((name[0]=='+' && name[1] == 0) ||
2288 (name[0] == '*' && name[1] == 0))
2289 name = NULL;
2290 check_first = TRUE;
2293 root = MSI_RecordGetInteger(row,2);
2294 key = MSI_RecordGetString(row, 3);
2296 szRoot = get_root_key( package, root, &root_key );
2297 if (!szRoot)
2298 return ERROR_SUCCESS;
2300 deformat_string(package, key , &deformated);
2301 size = strlenW(deformated) + strlenW(szRoot) + 1;
2302 uikey = msi_alloc(size*sizeof(WCHAR));
2303 strcpyW(uikey,szRoot);
2304 strcatW(uikey,deformated);
2306 if (RegCreateKeyW( root_key, deformated, &hkey))
2308 ERR("Could not create key %s\n",debugstr_w(deformated));
2309 msi_free(deformated);
2310 msi_free(uikey);
2311 return ERROR_SUCCESS;
2313 msi_free(deformated);
2315 value = MSI_RecordGetString(row,5);
2316 if (value)
2317 value_data = parse_value(package, value, &type, &size);
2318 else
2320 value_data = (LPSTR)strdupW(szEmpty);
2321 size = sizeof(szEmpty);
2322 type = REG_SZ;
2325 deformat_string(package, name, &deformated);
2327 if (!check_first)
2329 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2330 debugstr_w(uikey));
2331 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2333 else
2335 DWORD sz = 0;
2336 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2337 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2339 TRACE("value %s of %s checked already exists\n",
2340 debugstr_w(deformated), debugstr_w(uikey));
2342 else
2344 TRACE("Checked and setting value %s of %s\n",
2345 debugstr_w(deformated), debugstr_w(uikey));
2346 if (deformated || size)
2347 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2350 RegCloseKey(hkey);
2352 uirow = MSI_CreateRecord(3);
2353 MSI_RecordSetStringW(uirow,2,deformated);
2354 MSI_RecordSetStringW(uirow,1,uikey);
2355 if (type == REG_SZ || type == REG_EXPAND_SZ)
2356 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2357 ui_actiondata(package,szWriteRegistryValues,uirow);
2358 msiobj_release( &uirow->hdr );
2360 msi_free(value_data);
2361 msi_free(deformated);
2362 msi_free(uikey);
2364 return ERROR_SUCCESS;
2367 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2369 UINT rc;
2370 MSIQUERY * view;
2371 static const WCHAR ExecSeqQuery[] =
2372 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2373 '`','R','e','g','i','s','t','r','y','`',0 };
2375 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2376 if (rc != ERROR_SUCCESS)
2377 return ERROR_SUCCESS;
2379 /* increment progress bar each time action data is sent */
2380 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2382 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2384 msiobj_release(&view->hdr);
2385 return rc;
2388 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2390 LONG res;
2391 HKEY hkey;
2392 DWORD num_subkeys, num_values;
2394 if (delete_key)
2396 if ((res = RegDeleteTreeW( hkey_root, key )))
2398 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2400 return;
2403 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2405 if ((res = RegDeleteValueW( hkey, value )))
2407 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2409 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2410 NULL, NULL, NULL, NULL );
2411 RegCloseKey( hkey );
2413 if (!res && !num_subkeys && !num_values)
2415 TRACE("Removing empty key %s\n", debugstr_w(key));
2416 RegDeleteKeyW( hkey_root, key );
2418 return;
2420 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2424 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2426 MSIPACKAGE *package = param;
2427 LPCWSTR component, name, key_str, root_key_str;
2428 LPWSTR deformated_key, deformated_name, ui_key_str;
2429 MSICOMPONENT *comp;
2430 MSIRECORD *uirow;
2431 BOOL delete_key = FALSE;
2432 HKEY hkey_root;
2433 UINT size;
2434 INT root;
2436 ui_progress( package, 2, 0, 0, 0 );
2438 component = MSI_RecordGetString( row, 6 );
2439 comp = get_loaded_component( package, component );
2440 if (!comp)
2441 return ERROR_SUCCESS;
2443 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2445 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2446 comp->Action = comp->Installed;
2447 return ERROR_SUCCESS;
2449 comp->Action = INSTALLSTATE_ABSENT;
2451 name = MSI_RecordGetString( row, 4 );
2452 if (MSI_RecordIsNull( row, 5 ) && name )
2454 if (name[0] == '+' && !name[1])
2455 return ERROR_SUCCESS;
2456 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2458 delete_key = TRUE;
2459 name = NULL;
2463 root = MSI_RecordGetInteger( row, 2 );
2464 key_str = MSI_RecordGetString( row, 3 );
2466 root_key_str = get_root_key( package, root, &hkey_root );
2467 if (!root_key_str)
2468 return ERROR_SUCCESS;
2470 deformat_string( package, key_str, &deformated_key );
2471 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2472 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2473 strcpyW( ui_key_str, root_key_str );
2474 strcatW( ui_key_str, deformated_key );
2476 deformat_string( package, name, &deformated_name );
2478 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2479 msi_free( deformated_key );
2481 uirow = MSI_CreateRecord( 2 );
2482 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2483 MSI_RecordSetStringW( uirow, 2, deformated_name );
2485 ui_actiondata( package, szRemoveRegistryValues, uirow );
2486 msiobj_release( &uirow->hdr );
2488 msi_free( ui_key_str );
2489 msi_free( deformated_name );
2490 return ERROR_SUCCESS;
2493 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2495 MSIPACKAGE *package = param;
2496 LPCWSTR component, name, key_str, root_key_str;
2497 LPWSTR deformated_key, deformated_name, ui_key_str;
2498 MSICOMPONENT *comp;
2499 MSIRECORD *uirow;
2500 BOOL delete_key = FALSE;
2501 HKEY hkey_root;
2502 UINT size;
2503 INT root;
2505 ui_progress( package, 2, 0, 0, 0 );
2507 component = MSI_RecordGetString( row, 5 );
2508 comp = get_loaded_component( package, component );
2509 if (!comp)
2510 return ERROR_SUCCESS;
2512 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2514 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2515 comp->Action = comp->Installed;
2516 return ERROR_SUCCESS;
2518 comp->Action = INSTALLSTATE_LOCAL;
2520 if ((name = MSI_RecordGetString( row, 4 )))
2522 if (name[0] == '-' && !name[1])
2524 delete_key = TRUE;
2525 name = NULL;
2529 root = MSI_RecordGetInteger( row, 2 );
2530 key_str = MSI_RecordGetString( row, 3 );
2532 root_key_str = get_root_key( package, root, &hkey_root );
2533 if (!root_key_str)
2534 return ERROR_SUCCESS;
2536 deformat_string( package, key_str, &deformated_key );
2537 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2538 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2539 strcpyW( ui_key_str, root_key_str );
2540 strcatW( ui_key_str, deformated_key );
2542 deformat_string( package, name, &deformated_name );
2544 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2545 msi_free( deformated_key );
2547 uirow = MSI_CreateRecord( 2 );
2548 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2549 MSI_RecordSetStringW( uirow, 2, deformated_name );
2551 ui_actiondata( package, szRemoveRegistryValues, uirow );
2552 msiobj_release( &uirow->hdr );
2554 msi_free( ui_key_str );
2555 msi_free( deformated_name );
2556 return ERROR_SUCCESS;
2559 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2561 UINT rc;
2562 MSIQUERY *view;
2563 static const WCHAR registry_query[] =
2564 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2565 '`','R','e','g','i','s','t','r','y','`',0 };
2566 static const WCHAR remove_registry_query[] =
2567 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2568 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2570 /* increment progress bar each time action data is sent */
2571 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2573 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2574 if (rc == ERROR_SUCCESS)
2576 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2577 msiobj_release( &view->hdr );
2578 if (rc != ERROR_SUCCESS)
2579 return rc;
2582 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2583 if (rc == ERROR_SUCCESS)
2585 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2586 msiobj_release( &view->hdr );
2587 if (rc != ERROR_SUCCESS)
2588 return rc;
2591 return ERROR_SUCCESS;
2594 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2596 package->script->CurrentlyScripting = TRUE;
2598 return ERROR_SUCCESS;
2602 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2604 MSICOMPONENT *comp;
2605 DWORD progress = 0;
2606 DWORD total = 0;
2607 static const WCHAR q1[]=
2608 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2609 '`','R','e','g','i','s','t','r','y','`',0};
2610 UINT rc;
2611 MSIQUERY * view;
2612 MSIFEATURE *feature;
2613 MSIFILE *file;
2615 TRACE("InstallValidate\n");
2617 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2618 if (rc == ERROR_SUCCESS)
2620 MSI_IterateRecords( view, &progress, NULL, package );
2621 msiobj_release( &view->hdr );
2622 total += progress * REG_PROGRESS_VALUE;
2625 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2626 total += COMPONENT_PROGRESS_VALUE;
2628 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2629 total += file->FileSize;
2631 ui_progress(package,0,total,0,0);
2633 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2635 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2636 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2637 feature->ActionRequest);
2640 return ERROR_SUCCESS;
2643 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2645 MSIPACKAGE* package = param;
2646 LPCWSTR cond = NULL;
2647 LPCWSTR message = NULL;
2648 UINT r;
2650 static const WCHAR title[]=
2651 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2653 cond = MSI_RecordGetString(row,1);
2655 r = MSI_EvaluateConditionW(package,cond);
2656 if (r == MSICONDITION_FALSE)
2658 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2660 LPWSTR deformated;
2661 message = MSI_RecordGetString(row,2);
2662 deformat_string(package,message,&deformated);
2663 MessageBoxW(NULL,deformated,title,MB_OK);
2664 msi_free(deformated);
2667 return ERROR_INSTALL_FAILURE;
2670 return ERROR_SUCCESS;
2673 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2675 UINT rc;
2676 MSIQUERY * view = NULL;
2677 static const WCHAR ExecSeqQuery[] =
2678 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2679 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2681 TRACE("Checking launch conditions\n");
2683 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2684 if (rc != ERROR_SUCCESS)
2685 return ERROR_SUCCESS;
2687 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2688 msiobj_release(&view->hdr);
2690 return rc;
2693 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2696 if (!cmp->KeyPath)
2697 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2699 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2701 MSIRECORD * row = 0;
2702 UINT root,len;
2703 LPWSTR deformated,buffer,deformated_name;
2704 LPCWSTR key,name;
2705 static const WCHAR ExecSeqQuery[] =
2706 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2707 '`','R','e','g','i','s','t','r','y','`',' ',
2708 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2709 ' ','=',' ' ,'\'','%','s','\'',0 };
2710 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2711 static const WCHAR fmt2[]=
2712 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2714 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2715 if (!row)
2716 return NULL;
2718 root = MSI_RecordGetInteger(row,2);
2719 key = MSI_RecordGetString(row, 3);
2720 name = MSI_RecordGetString(row, 4);
2721 deformat_string(package, key , &deformated);
2722 deformat_string(package, name, &deformated_name);
2724 len = strlenW(deformated) + 6;
2725 if (deformated_name)
2726 len+=strlenW(deformated_name);
2728 buffer = msi_alloc( len *sizeof(WCHAR));
2730 if (deformated_name)
2731 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2732 else
2733 sprintfW(buffer,fmt,root,deformated);
2735 msi_free(deformated);
2736 msi_free(deformated_name);
2737 msiobj_release(&row->hdr);
2739 return buffer;
2741 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2743 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2744 return NULL;
2746 else
2748 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2750 if (file)
2751 return strdupW( file->TargetPath );
2753 return NULL;
2756 static HKEY openSharedDLLsKey(void)
2758 HKEY hkey=0;
2759 static const WCHAR path[] =
2760 {'S','o','f','t','w','a','r','e','\\',
2761 'M','i','c','r','o','s','o','f','t','\\',
2762 'W','i','n','d','o','w','s','\\',
2763 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2764 'S','h','a','r','e','d','D','L','L','s',0};
2766 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2767 return hkey;
2770 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2772 HKEY hkey;
2773 DWORD count=0;
2774 DWORD type;
2775 DWORD sz = sizeof(count);
2776 DWORD rc;
2778 hkey = openSharedDLLsKey();
2779 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2780 if (rc != ERROR_SUCCESS)
2781 count = 0;
2782 RegCloseKey(hkey);
2783 return count;
2786 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2788 HKEY hkey;
2790 hkey = openSharedDLLsKey();
2791 if (count > 0)
2792 msi_reg_set_val_dword( hkey, path, count );
2793 else
2794 RegDeleteValueW(hkey,path);
2795 RegCloseKey(hkey);
2796 return count;
2800 * Return TRUE if the count should be written out and FALSE if not
2802 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2804 MSIFEATURE *feature;
2805 INT count = 0;
2806 BOOL write = FALSE;
2808 /* only refcount DLLs */
2809 if (comp->KeyPath == NULL ||
2810 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2811 comp->Attributes & msidbComponentAttributesODBCDataSource)
2812 write = FALSE;
2813 else
2815 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2816 write = (count > 0);
2818 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2819 write = TRUE;
2822 /* increment counts */
2823 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2825 ComponentList *cl;
2827 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2828 continue;
2830 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2832 if ( cl->component == comp )
2833 count++;
2837 /* decrement counts */
2838 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2840 ComponentList *cl;
2842 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2843 continue;
2845 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2847 if ( cl->component == comp )
2848 count--;
2852 /* ref count all the files in the component */
2853 if (write)
2855 MSIFILE *file;
2857 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2859 if (file->Component == comp)
2860 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2864 /* add a count for permanent */
2865 if (comp->Attributes & msidbComponentAttributesPermanent)
2866 count ++;
2868 comp->RefCount = count;
2870 if (write)
2871 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2874 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2876 WCHAR squished_pc[GUID_SIZE];
2877 WCHAR squished_cc[GUID_SIZE];
2878 UINT rc;
2879 MSICOMPONENT *comp;
2880 HKEY hkey;
2882 TRACE("\n");
2884 squash_guid(package->ProductCode,squished_pc);
2885 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2887 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2889 MSIRECORD * uirow;
2891 ui_progress(package,2,0,0,0);
2892 if (!comp->ComponentId)
2893 continue;
2895 squash_guid(comp->ComponentId,squished_cc);
2897 msi_free(comp->FullKeypath);
2898 comp->FullKeypath = resolve_keypath( package, comp );
2900 ACTION_RefCountComponent( package, comp );
2902 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2903 debugstr_w(comp->Component),
2904 debugstr_w(squished_cc),
2905 debugstr_w(comp->FullKeypath),
2906 comp->RefCount);
2908 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2909 comp->ActionRequest == INSTALLSTATE_SOURCE)
2911 if (!comp->FullKeypath)
2912 continue;
2914 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2915 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2916 &hkey, TRUE);
2917 else
2918 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2919 &hkey, TRUE);
2921 if (rc != ERROR_SUCCESS)
2922 continue;
2924 if (comp->Attributes & msidbComponentAttributesPermanent)
2926 static const WCHAR szPermKey[] =
2927 { '0','0','0','0','0','0','0','0','0','0','0','0',
2928 '0','0','0','0','0','0','0','0','0','0','0','0',
2929 '0','0','0','0','0','0','0','0',0 };
2931 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2934 if (comp->Action == INSTALLSTATE_LOCAL)
2935 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2936 else
2938 MSIFILE *file;
2939 MSIRECORD *row;
2940 LPWSTR ptr, ptr2;
2941 WCHAR source[MAX_PATH];
2942 WCHAR base[MAX_PATH];
2943 LPWSTR sourcepath;
2945 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2946 static const WCHAR query[] = {
2947 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2948 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2949 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2950 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2951 '`','D','i','s','k','I','d','`',0};
2953 file = get_loaded_file(package, comp->KeyPath);
2954 if (!file)
2955 continue;
2957 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2958 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2959 ptr2 = strrchrW(source, '\\') + 1;
2960 msiobj_release(&row->hdr);
2962 lstrcpyW(base, package->PackagePath);
2963 ptr = strrchrW(base, '\\');
2964 *(ptr + 1) = '\0';
2966 sourcepath = resolve_file_source(package, file);
2967 ptr = sourcepath + lstrlenW(base);
2968 lstrcpyW(ptr2, ptr);
2969 msi_free(sourcepath);
2971 msi_reg_set_val_str(hkey, squished_pc, source);
2973 RegCloseKey(hkey);
2975 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
2977 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2978 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2979 else
2980 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2982 comp->Action = comp->ActionRequest;
2984 /* UI stuff */
2985 uirow = MSI_CreateRecord(3);
2986 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2987 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2988 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2989 ui_actiondata(package,szProcessComponents,uirow);
2990 msiobj_release( &uirow->hdr );
2993 return ERROR_SUCCESS;
2996 typedef struct {
2997 CLSID clsid;
2998 LPWSTR source;
3000 LPWSTR path;
3001 ITypeLib *ptLib;
3002 } typelib_struct;
3004 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3005 LPWSTR lpszName, LONG_PTR lParam)
3007 TLIBATTR *attr;
3008 typelib_struct *tl_struct = (typelib_struct*) lParam;
3009 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3010 int sz;
3011 HRESULT res;
3013 if (!IS_INTRESOURCE(lpszName))
3015 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3016 return TRUE;
3019 sz = strlenW(tl_struct->source)+4;
3020 sz *= sizeof(WCHAR);
3022 if ((INT_PTR)lpszName == 1)
3023 tl_struct->path = strdupW(tl_struct->source);
3024 else
3026 tl_struct->path = msi_alloc(sz);
3027 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3030 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3031 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3032 if (FAILED(res))
3034 msi_free(tl_struct->path);
3035 tl_struct->path = NULL;
3037 return TRUE;
3040 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3041 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3043 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3044 return FALSE;
3047 msi_free(tl_struct->path);
3048 tl_struct->path = NULL;
3050 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3051 ITypeLib_Release(tl_struct->ptLib);
3053 return TRUE;
3056 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3058 MSIPACKAGE* package = param;
3059 LPCWSTR component;
3060 MSICOMPONENT *comp;
3061 MSIFILE *file;
3062 typelib_struct tl_struct;
3063 ITypeLib *tlib;
3064 HMODULE module;
3065 HRESULT hr;
3067 component = MSI_RecordGetString(row,3);
3068 comp = get_loaded_component(package,component);
3069 if (!comp)
3070 return ERROR_SUCCESS;
3072 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3074 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3075 comp->Action = comp->Installed;
3076 return ERROR_SUCCESS;
3078 comp->Action = INSTALLSTATE_LOCAL;
3080 file = get_loaded_file( package, comp->KeyPath );
3081 if (!file)
3082 return ERROR_SUCCESS;
3084 ui_actiondata( package, szRegisterTypeLibraries, row );
3086 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3087 if (module)
3089 LPCWSTR guid;
3090 guid = MSI_RecordGetString(row,1);
3091 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3092 tl_struct.source = strdupW( file->TargetPath );
3093 tl_struct.path = NULL;
3095 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3096 (LONG_PTR)&tl_struct);
3098 if (tl_struct.path)
3100 LPWSTR help = NULL;
3101 LPCWSTR helpid;
3102 HRESULT res;
3104 helpid = MSI_RecordGetString(row,6);
3106 if (helpid)
3107 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3108 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3109 msi_free(help);
3111 if (FAILED(res))
3112 ERR("Failed to register type library %s\n",
3113 debugstr_w(tl_struct.path));
3114 else
3115 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3117 ITypeLib_Release(tl_struct.ptLib);
3118 msi_free(tl_struct.path);
3120 else
3121 ERR("Failed to load type library %s\n",
3122 debugstr_w(tl_struct.source));
3124 FreeLibrary(module);
3125 msi_free(tl_struct.source);
3127 else
3129 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3130 if (FAILED(hr))
3132 ERR("Failed to load type library: %08x\n", hr);
3133 return ERROR_INSTALL_FAILURE;
3136 ITypeLib_Release(tlib);
3139 return ERROR_SUCCESS;
3142 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3145 * OK this is a bit confusing.. I am given a _Component key and I believe
3146 * that the file that is being registered as a type library is the "key file
3147 * of that component" which I interpret to mean "The file in the KeyPath of
3148 * that component".
3150 UINT rc;
3151 MSIQUERY * view;
3152 static const WCHAR Query[] =
3153 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3154 '`','T','y','p','e','L','i','b','`',0};
3156 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3157 if (rc != ERROR_SUCCESS)
3158 return ERROR_SUCCESS;
3160 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3161 msiobj_release(&view->hdr);
3162 return rc;
3165 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3167 MSIPACKAGE *package = param;
3168 LPCWSTR component, guid;
3169 MSICOMPONENT *comp;
3170 GUID libid;
3171 UINT version;
3172 LCID language;
3173 SYSKIND syskind;
3174 HRESULT hr;
3176 component = MSI_RecordGetString( row, 3 );
3177 comp = get_loaded_component( package, component );
3178 if (!comp)
3179 return ERROR_SUCCESS;
3181 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3183 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3184 comp->Action = comp->Installed;
3185 return ERROR_SUCCESS;
3187 comp->Action = INSTALLSTATE_ABSENT;
3189 ui_actiondata( package, szUnregisterTypeLibraries, row );
3191 guid = MSI_RecordGetString( row, 1 );
3192 CLSIDFromString( (LPCWSTR)guid, &libid );
3193 version = MSI_RecordGetInteger( row, 4 );
3194 language = MSI_RecordGetInteger( row, 2 );
3196 #ifdef _WIN64
3197 syskind = SYS_WIN64;
3198 #else
3199 syskind = SYS_WIN32;
3200 #endif
3202 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3203 if (FAILED(hr))
3205 WARN("Failed to unregister typelib: %08x\n", hr);
3208 return ERROR_SUCCESS;
3211 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3213 UINT rc;
3214 MSIQUERY *view;
3215 static const WCHAR query[] =
3216 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3217 '`','T','y','p','e','L','i','b','`',0};
3219 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3220 if (rc != ERROR_SUCCESS)
3221 return ERROR_SUCCESS;
3223 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3224 msiobj_release( &view->hdr );
3225 return rc;
3228 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3230 static const WCHAR szlnk[] = {'.','l','n','k',0};
3231 LPCWSTR directory, extension;
3232 LPWSTR link_folder, link_file, filename;
3234 directory = MSI_RecordGetString( row, 2 );
3235 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3237 /* may be needed because of a bug somewhere else */
3238 create_full_pathW( link_folder );
3240 filename = msi_dup_record_field( row, 3 );
3241 reduce_to_longfilename( filename );
3243 extension = strchrW( filename, '.' );
3244 if (!extension || strcmpiW( extension, szlnk ))
3246 int len = strlenW( filename );
3247 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3248 memcpy( filename + len, szlnk, sizeof(szlnk) );
3250 link_file = build_directory_name( 2, link_folder, filename );
3251 msi_free( link_folder );
3252 msi_free( filename );
3254 return link_file;
3257 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3259 MSIPACKAGE *package = param;
3260 LPWSTR link_file, deformated, path;
3261 LPCWSTR component, target;
3262 MSICOMPONENT *comp;
3263 IShellLinkW *sl = NULL;
3264 IPersistFile *pf = NULL;
3265 HRESULT res;
3267 component = MSI_RecordGetString(row, 4);
3268 comp = get_loaded_component(package, component);
3269 if (!comp)
3270 return ERROR_SUCCESS;
3272 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3274 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3275 comp->Action = comp->Installed;
3276 return ERROR_SUCCESS;
3278 comp->Action = INSTALLSTATE_LOCAL;
3280 ui_actiondata(package,szCreateShortcuts,row);
3282 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3283 &IID_IShellLinkW, (LPVOID *) &sl );
3285 if (FAILED( res ))
3287 ERR("CLSID_ShellLink not available\n");
3288 goto err;
3291 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3292 if (FAILED( res ))
3294 ERR("QueryInterface(IID_IPersistFile) failed\n");
3295 goto err;
3298 target = MSI_RecordGetString(row, 5);
3299 if (strchrW(target, '['))
3301 deformat_string(package, target, &deformated);
3302 IShellLinkW_SetPath(sl,deformated);
3303 msi_free(deformated);
3305 else
3307 FIXME("poorly handled shortcut format, advertised shortcut\n");
3308 IShellLinkW_SetPath(sl,comp->FullKeypath);
3311 if (!MSI_RecordIsNull(row,6))
3313 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3314 deformat_string(package, arguments, &deformated);
3315 IShellLinkW_SetArguments(sl,deformated);
3316 msi_free(deformated);
3319 if (!MSI_RecordIsNull(row,7))
3321 LPCWSTR description = MSI_RecordGetString(row, 7);
3322 IShellLinkW_SetDescription(sl, description);
3325 if (!MSI_RecordIsNull(row,8))
3326 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3328 if (!MSI_RecordIsNull(row,9))
3330 INT index;
3331 LPCWSTR icon = MSI_RecordGetString(row, 9);
3333 path = build_icon_path(package, icon);
3334 index = MSI_RecordGetInteger(row,10);
3336 /* no value means 0 */
3337 if (index == MSI_NULL_INTEGER)
3338 index = 0;
3340 IShellLinkW_SetIconLocation(sl, path, index);
3341 msi_free(path);
3344 if (!MSI_RecordIsNull(row,11))
3345 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3347 if (!MSI_RecordIsNull(row,12))
3349 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3350 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3351 if (path)
3352 IShellLinkW_SetWorkingDirectory(sl, path);
3353 msi_free(path);
3356 link_file = get_link_file(package, row);
3358 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3359 IPersistFile_Save(pf, link_file, FALSE);
3361 msi_free(link_file);
3363 err:
3364 if (pf)
3365 IPersistFile_Release( pf );
3366 if (sl)
3367 IShellLinkW_Release( sl );
3369 return ERROR_SUCCESS;
3372 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3374 UINT rc;
3375 HRESULT res;
3376 MSIQUERY * view;
3377 static const WCHAR Query[] =
3378 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3379 '`','S','h','o','r','t','c','u','t','`',0};
3381 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3382 if (rc != ERROR_SUCCESS)
3383 return ERROR_SUCCESS;
3385 res = CoInitialize( NULL );
3387 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3388 msiobj_release(&view->hdr);
3390 if (SUCCEEDED(res))
3391 CoUninitialize();
3393 return rc;
3396 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3398 MSIPACKAGE *package = param;
3399 LPWSTR link_file;
3400 LPCWSTR component;
3401 MSICOMPONENT *comp;
3403 component = MSI_RecordGetString( row, 4 );
3404 comp = get_loaded_component( package, component );
3405 if (!comp)
3406 return ERROR_SUCCESS;
3408 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3410 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3411 comp->Action = comp->Installed;
3412 return ERROR_SUCCESS;
3414 comp->Action = INSTALLSTATE_ABSENT;
3416 ui_actiondata( package, szRemoveShortcuts, row );
3418 link_file = get_link_file( package, row );
3420 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3421 if (!DeleteFileW( link_file ))
3423 WARN("Failed to remove shortcut file %u\n", GetLastError());
3425 msi_free( link_file );
3427 return ERROR_SUCCESS;
3430 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3432 UINT rc;
3433 MSIQUERY *view;
3434 static const WCHAR query[] =
3435 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3436 '`','S','h','o','r','t','c','u','t','`',0};
3438 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3439 if (rc != ERROR_SUCCESS)
3440 return ERROR_SUCCESS;
3442 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3443 msiobj_release( &view->hdr );
3445 return rc;
3448 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3450 MSIPACKAGE* package = param;
3451 HANDLE the_file;
3452 LPWSTR FilePath;
3453 LPCWSTR FileName;
3454 CHAR buffer[1024];
3455 DWORD sz;
3456 UINT rc;
3458 FileName = MSI_RecordGetString(row,1);
3459 if (!FileName)
3461 ERR("Unable to get FileName\n");
3462 return ERROR_SUCCESS;
3465 FilePath = build_icon_path(package,FileName);
3467 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3469 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3470 FILE_ATTRIBUTE_NORMAL, NULL);
3472 if (the_file == INVALID_HANDLE_VALUE)
3474 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3475 msi_free(FilePath);
3476 return ERROR_SUCCESS;
3481 DWORD write;
3482 sz = 1024;
3483 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3484 if (rc != ERROR_SUCCESS)
3486 ERR("Failed to get stream\n");
3487 CloseHandle(the_file);
3488 DeleteFileW(FilePath);
3489 break;
3491 WriteFile(the_file,buffer,sz,&write,NULL);
3492 } while (sz == 1024);
3494 msi_free(FilePath);
3495 CloseHandle(the_file);
3497 return ERROR_SUCCESS;
3500 static UINT msi_publish_icons(MSIPACKAGE *package)
3502 UINT r;
3503 MSIQUERY *view;
3505 static const WCHAR query[]= {
3506 'S','E','L','E','C','T',' ','*',' ',
3507 'F','R','O','M',' ','`','I','c','o','n','`',0};
3509 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3510 if (r == ERROR_SUCCESS)
3512 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3513 msiobj_release(&view->hdr);
3516 return ERROR_SUCCESS;
3519 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3521 UINT r;
3522 HKEY source;
3523 LPWSTR buffer;
3524 MSIMEDIADISK *disk;
3525 MSISOURCELISTINFO *info;
3527 r = RegCreateKeyW(hkey, szSourceList, &source);
3528 if (r != ERROR_SUCCESS)
3529 return r;
3531 RegCloseKey(source);
3533 buffer = strrchrW(package->PackagePath, '\\') + 1;
3534 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3535 package->Context, MSICODE_PRODUCT,
3536 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3537 if (r != ERROR_SUCCESS)
3538 return r;
3540 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3541 package->Context, MSICODE_PRODUCT,
3542 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3543 if (r != ERROR_SUCCESS)
3544 return r;
3546 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3547 package->Context, MSICODE_PRODUCT,
3548 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3549 if (r != ERROR_SUCCESS)
3550 return r;
3552 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3554 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3555 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3556 info->options, info->value);
3557 else
3558 MsiSourceListSetInfoW(package->ProductCode, NULL,
3559 info->context, info->options,
3560 info->property, info->value);
3563 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3565 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3566 disk->context, disk->options,
3567 disk->disk_id, disk->volume_label, disk->disk_prompt);
3570 return ERROR_SUCCESS;
3573 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3575 MSIHANDLE hdb, suminfo;
3576 WCHAR guids[MAX_PATH];
3577 WCHAR packcode[SQUISH_GUID_SIZE];
3578 LPWSTR buffer;
3579 LPWSTR ptr;
3580 DWORD langid;
3581 DWORD size;
3582 UINT r;
3584 static const WCHAR szProductLanguage[] =
3585 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3586 static const WCHAR szARPProductIcon[] =
3587 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3588 static const WCHAR szProductVersion[] =
3589 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3590 static const WCHAR szAssignment[] =
3591 {'A','s','s','i','g','n','m','e','n','t',0};
3592 static const WCHAR szAdvertiseFlags[] =
3593 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3594 static const WCHAR szClients[] =
3595 {'C','l','i','e','n','t','s',0};
3596 static const WCHAR szColon[] = {':',0};
3598 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3599 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3600 msi_free(buffer);
3602 langid = msi_get_property_int(package, szProductLanguage, 0);
3603 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3605 /* FIXME */
3606 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3608 buffer = msi_dup_property(package, szARPProductIcon);
3609 if (buffer)
3611 LPWSTR path = build_icon_path(package,buffer);
3612 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3613 msi_free(path);
3614 msi_free(buffer);
3617 buffer = msi_dup_property(package, szProductVersion);
3618 if (buffer)
3620 DWORD verdword = msi_version_str_to_dword(buffer);
3621 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3622 msi_free(buffer);
3625 msi_reg_set_val_dword(hkey, szAssignment, 0);
3626 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3627 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3628 msi_reg_set_val_str(hkey, szClients, szColon);
3630 hdb = alloc_msihandle(&package->db->hdr);
3631 if (!hdb)
3632 return ERROR_NOT_ENOUGH_MEMORY;
3634 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3635 MsiCloseHandle(hdb);
3636 if (r != ERROR_SUCCESS)
3637 goto done;
3639 size = MAX_PATH;
3640 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3641 NULL, guids, &size);
3642 if (r != ERROR_SUCCESS)
3643 goto done;
3645 ptr = strchrW(guids, ';');
3646 if (ptr) *ptr = 0;
3647 squash_guid(guids, packcode);
3648 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3650 done:
3651 MsiCloseHandle(suminfo);
3652 return ERROR_SUCCESS;
3655 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3657 UINT r;
3658 HKEY hkey;
3659 LPWSTR upgrade;
3660 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3662 static const WCHAR szUpgradeCode[] =
3663 {'U','p','g','r','a','d','e','C','o','d','e',0};
3665 upgrade = msi_dup_property(package, szUpgradeCode);
3666 if (!upgrade)
3667 return ERROR_SUCCESS;
3669 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3671 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3672 if (r != ERROR_SUCCESS)
3673 goto done;
3675 else
3677 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3678 if (r != ERROR_SUCCESS)
3679 goto done;
3682 squash_guid(package->ProductCode, squashed_pc);
3683 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3685 RegCloseKey(hkey);
3687 done:
3688 msi_free(upgrade);
3689 return r;
3692 static BOOL msi_check_publish(MSIPACKAGE *package)
3694 MSIFEATURE *feature;
3696 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3698 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3699 return TRUE;
3702 return FALSE;
3705 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3707 MSIFEATURE *feature;
3709 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3711 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3712 return FALSE;
3715 return TRUE;
3718 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3720 WCHAR patch_squashed[GUID_SIZE];
3721 HKEY patches;
3722 LONG res;
3723 UINT r = ERROR_FUNCTION_FAILED;
3725 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3726 &patches, NULL);
3727 if (res != ERROR_SUCCESS)
3728 return ERROR_FUNCTION_FAILED;
3730 squash_guid(package->patch->patchcode, patch_squashed);
3732 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3733 (const BYTE *)patch_squashed,
3734 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3735 if (res != ERROR_SUCCESS)
3736 goto done;
3738 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3739 (const BYTE *)package->patch->transforms,
3740 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3741 if (res == ERROR_SUCCESS)
3742 r = ERROR_SUCCESS;
3744 done:
3745 RegCloseKey(patches);
3746 return r;
3750 * 99% of the work done here is only done for
3751 * advertised installs. However this is where the
3752 * Icon table is processed and written out
3753 * so that is what I am going to do here.
3755 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3757 UINT rc;
3758 HKEY hukey = NULL, hudkey = NULL;
3759 MSIRECORD *uirow;
3761 /* FIXME: also need to publish if the product is in advertise mode */
3762 if (!msi_check_publish(package))
3763 return ERROR_SUCCESS;
3765 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3766 &hukey, TRUE);
3767 if (rc != ERROR_SUCCESS)
3768 goto end;
3770 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3771 NULL, &hudkey, TRUE);
3772 if (rc != ERROR_SUCCESS)
3773 goto end;
3775 rc = msi_publish_upgrade_code(package);
3776 if (rc != ERROR_SUCCESS)
3777 goto end;
3779 if (package->patch)
3781 rc = msi_publish_patch(package, hukey, hudkey);
3782 if (rc != ERROR_SUCCESS)
3783 goto end;
3786 rc = msi_publish_product_properties(package, hukey);
3787 if (rc != ERROR_SUCCESS)
3788 goto end;
3790 rc = msi_publish_sourcelist(package, hukey);
3791 if (rc != ERROR_SUCCESS)
3792 goto end;
3794 rc = msi_publish_icons(package);
3796 end:
3797 uirow = MSI_CreateRecord( 1 );
3798 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3799 ui_actiondata( package, szPublishProduct, uirow );
3800 msiobj_release( &uirow->hdr );
3802 RegCloseKey(hukey);
3803 RegCloseKey(hudkey);
3805 return rc;
3808 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3810 WCHAR *filename, *ptr, *folder, *ret;
3811 const WCHAR *dirprop;
3813 filename = msi_dup_record_field( row, 2 );
3814 if (filename && (ptr = strchrW( filename, '|' )))
3815 ptr++;
3816 else
3817 ptr = filename;
3819 dirprop = MSI_RecordGetString( row, 3 );
3820 if (dirprop)
3822 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3823 if (!folder)
3824 folder = msi_dup_property( package, dirprop );
3826 else
3827 folder = msi_dup_property( package, szWindowsFolder );
3829 if (!folder)
3831 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3832 msi_free( filename );
3833 return NULL;
3836 ret = build_directory_name( 2, folder, ptr );
3838 msi_free( filename );
3839 msi_free( folder );
3840 return ret;
3843 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3845 MSIPACKAGE *package = param;
3846 LPCWSTR component, section, key, value, identifier;
3847 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
3848 MSIRECORD * uirow;
3849 INT action;
3850 MSICOMPONENT *comp;
3852 component = MSI_RecordGetString(row, 8);
3853 comp = get_loaded_component(package,component);
3854 if (!comp)
3855 return ERROR_SUCCESS;
3857 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3859 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3860 comp->Action = comp->Installed;
3861 return ERROR_SUCCESS;
3863 comp->Action = INSTALLSTATE_LOCAL;
3865 identifier = MSI_RecordGetString(row,1);
3866 section = MSI_RecordGetString(row,4);
3867 key = MSI_RecordGetString(row,5);
3868 value = MSI_RecordGetString(row,6);
3869 action = MSI_RecordGetInteger(row,7);
3871 deformat_string(package,section,&deformated_section);
3872 deformat_string(package,key,&deformated_key);
3873 deformat_string(package,value,&deformated_value);
3875 fullname = get_ini_file_name(package, row);
3877 if (action == 0)
3879 TRACE("Adding value %s to section %s in %s\n",
3880 debugstr_w(deformated_key), debugstr_w(deformated_section),
3881 debugstr_w(fullname));
3882 WritePrivateProfileStringW(deformated_section, deformated_key,
3883 deformated_value, fullname);
3885 else if (action == 1)
3887 WCHAR returned[10];
3888 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3889 returned, 10, fullname);
3890 if (returned[0] == 0)
3892 TRACE("Adding value %s to section %s in %s\n",
3893 debugstr_w(deformated_key), debugstr_w(deformated_section),
3894 debugstr_w(fullname));
3896 WritePrivateProfileStringW(deformated_section, deformated_key,
3897 deformated_value, fullname);
3900 else if (action == 3)
3901 FIXME("Append to existing section not yet implemented\n");
3903 uirow = MSI_CreateRecord(4);
3904 MSI_RecordSetStringW(uirow,1,identifier);
3905 MSI_RecordSetStringW(uirow,2,deformated_section);
3906 MSI_RecordSetStringW(uirow,3,deformated_key);
3907 MSI_RecordSetStringW(uirow,4,deformated_value);
3908 ui_actiondata(package,szWriteIniValues,uirow);
3909 msiobj_release( &uirow->hdr );
3911 msi_free(fullname);
3912 msi_free(deformated_key);
3913 msi_free(deformated_value);
3914 msi_free(deformated_section);
3915 return ERROR_SUCCESS;
3918 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3920 UINT rc;
3921 MSIQUERY * view;
3922 static const WCHAR ExecSeqQuery[] =
3923 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3924 '`','I','n','i','F','i','l','e','`',0};
3926 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3927 if (rc != ERROR_SUCCESS)
3929 TRACE("no IniFile table\n");
3930 return ERROR_SUCCESS;
3933 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3934 msiobj_release(&view->hdr);
3935 return rc;
3938 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
3940 MSIPACKAGE *package = param;
3941 LPCWSTR component, section, key, value, identifier;
3942 LPWSTR deformated_section, deformated_key, deformated_value, filename;
3943 MSICOMPONENT *comp;
3944 MSIRECORD *uirow;
3945 INT action;
3947 component = MSI_RecordGetString( row, 8 );
3948 comp = get_loaded_component( package, component );
3949 if (!comp)
3950 return ERROR_SUCCESS;
3952 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3954 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3955 comp->Action = comp->Installed;
3956 return ERROR_SUCCESS;
3958 comp->Action = INSTALLSTATE_ABSENT;
3960 identifier = MSI_RecordGetString( row, 1 );
3961 section = MSI_RecordGetString( row, 4 );
3962 key = MSI_RecordGetString( row, 5 );
3963 value = MSI_RecordGetString( row, 6 );
3964 action = MSI_RecordGetInteger( row, 7 );
3966 deformat_string( package, section, &deformated_section );
3967 deformat_string( package, key, &deformated_key );
3968 deformat_string( package, value, &deformated_value );
3970 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
3972 filename = get_ini_file_name( package, row );
3974 TRACE("Removing key %s from section %s in %s\n",
3975 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
3977 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
3979 WARN("Unable to remove key %u\n", GetLastError());
3981 msi_free( filename );
3983 else
3984 FIXME("Unsupported action %d\n", action);
3987 uirow = MSI_CreateRecord( 4 );
3988 MSI_RecordSetStringW( uirow, 1, identifier );
3989 MSI_RecordSetStringW( uirow, 2, deformated_section );
3990 MSI_RecordSetStringW( uirow, 3, deformated_key );
3991 MSI_RecordSetStringW( uirow, 4, deformated_value );
3992 ui_actiondata( package, szRemoveIniValues, uirow );
3993 msiobj_release( &uirow->hdr );
3995 msi_free( deformated_key );
3996 msi_free( deformated_value );
3997 msi_free( deformated_section );
3998 return ERROR_SUCCESS;
4001 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4003 MSIPACKAGE *package = param;
4004 LPCWSTR component, section, key, value, identifier;
4005 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4006 MSICOMPONENT *comp;
4007 MSIRECORD *uirow;
4008 INT action;
4010 component = MSI_RecordGetString( row, 8 );
4011 comp = get_loaded_component( package, component );
4012 if (!comp)
4013 return ERROR_SUCCESS;
4015 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4017 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4018 comp->Action = comp->Installed;
4019 return ERROR_SUCCESS;
4021 comp->Action = INSTALLSTATE_LOCAL;
4023 identifier = MSI_RecordGetString( row, 1 );
4024 section = MSI_RecordGetString( row, 4 );
4025 key = MSI_RecordGetString( row, 5 );
4026 value = MSI_RecordGetString( row, 6 );
4027 action = MSI_RecordGetInteger( row, 7 );
4029 deformat_string( package, section, &deformated_section );
4030 deformat_string( package, key, &deformated_key );
4031 deformat_string( package, value, &deformated_value );
4033 if (action == msidbIniFileActionRemoveLine)
4035 filename = get_ini_file_name( package, row );
4037 TRACE("Removing key %s from section %s in %s\n",
4038 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4040 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4042 WARN("Unable to remove key %u\n", GetLastError());
4044 msi_free( filename );
4046 else
4047 FIXME("Unsupported action %d\n", action);
4049 uirow = MSI_CreateRecord( 4 );
4050 MSI_RecordSetStringW( uirow, 1, identifier );
4051 MSI_RecordSetStringW( uirow, 2, deformated_section );
4052 MSI_RecordSetStringW( uirow, 3, deformated_key );
4053 MSI_RecordSetStringW( uirow, 4, deformated_value );
4054 ui_actiondata( package, szRemoveIniValues, uirow );
4055 msiobj_release( &uirow->hdr );
4057 msi_free( deformated_key );
4058 msi_free( deformated_value );
4059 msi_free( deformated_section );
4060 return ERROR_SUCCESS;
4063 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4065 UINT rc;
4066 MSIQUERY *view;
4067 static const WCHAR query[] =
4068 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4069 '`','I','n','i','F','i','l','e','`',0};
4070 static const WCHAR remove_query[] =
4071 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4072 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4074 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4075 if (rc == ERROR_SUCCESS)
4077 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4078 msiobj_release( &view->hdr );
4079 if (rc != ERROR_SUCCESS)
4080 return rc;
4083 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4084 if (rc == ERROR_SUCCESS)
4086 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4087 msiobj_release( &view->hdr );
4088 if (rc != ERROR_SUCCESS)
4089 return rc;
4092 return ERROR_SUCCESS;
4095 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4097 MSIPACKAGE *package = param;
4098 LPCWSTR filename;
4099 LPWSTR FullName;
4100 MSIFILE *file;
4101 DWORD len;
4102 static const WCHAR ExeStr[] =
4103 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4104 static const WCHAR close[] = {'\"',0};
4105 STARTUPINFOW si;
4106 PROCESS_INFORMATION info;
4107 BOOL brc;
4108 MSIRECORD *uirow;
4109 LPWSTR uipath, p;
4111 memset(&si,0,sizeof(STARTUPINFOW));
4113 filename = MSI_RecordGetString(row,1);
4114 file = get_loaded_file( package, filename );
4116 if (!file)
4118 ERR("Unable to find file id %s\n",debugstr_w(filename));
4119 return ERROR_SUCCESS;
4122 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4124 FullName = msi_alloc(len*sizeof(WCHAR));
4125 strcpyW(FullName,ExeStr);
4126 strcatW( FullName, file->TargetPath );
4127 strcatW(FullName,close);
4129 TRACE("Registering %s\n",debugstr_w(FullName));
4130 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4131 &si, &info);
4133 if (brc)
4135 CloseHandle(info.hThread);
4136 msi_dialog_check_messages(info.hProcess);
4137 CloseHandle(info.hProcess);
4140 uirow = MSI_CreateRecord( 2 );
4141 MSI_RecordSetStringW( uirow, 1, filename );
4142 uipath = strdupW( file->TargetPath );
4143 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4144 MSI_RecordSetStringW( uirow, 2, uipath );
4145 ui_actiondata( package, szSelfRegModules, uirow );
4146 msiobj_release( &uirow->hdr );
4148 msi_free( FullName );
4149 msi_free( uipath );
4150 return ERROR_SUCCESS;
4153 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4155 UINT rc;
4156 MSIQUERY * view;
4157 static const WCHAR ExecSeqQuery[] =
4158 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4159 '`','S','e','l','f','R','e','g','`',0};
4161 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4162 if (rc != ERROR_SUCCESS)
4164 TRACE("no SelfReg table\n");
4165 return ERROR_SUCCESS;
4168 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4169 msiobj_release(&view->hdr);
4171 return ERROR_SUCCESS;
4174 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4176 static const WCHAR regsvr32[] =
4177 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4178 static const WCHAR close[] = {'\"',0};
4179 MSIPACKAGE *package = param;
4180 LPCWSTR filename;
4181 LPWSTR cmdline;
4182 MSIFILE *file;
4183 DWORD len;
4184 STARTUPINFOW si;
4185 PROCESS_INFORMATION pi;
4186 BOOL ret;
4187 MSIRECORD *uirow;
4188 LPWSTR uipath, p;
4190 memset( &si, 0, sizeof(STARTUPINFOW) );
4192 filename = MSI_RecordGetString( row, 1 );
4193 file = get_loaded_file( package, filename );
4195 if (!file)
4197 ERR("Unable to find file id %s\n", debugstr_w(filename));
4198 return ERROR_SUCCESS;
4201 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4203 cmdline = msi_alloc( len * sizeof(WCHAR) );
4204 strcpyW( cmdline, regsvr32 );
4205 strcatW( cmdline, file->TargetPath );
4206 strcatW( cmdline, close );
4208 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4210 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4211 if (ret)
4213 CloseHandle( pi.hThread );
4214 msi_dialog_check_messages( pi.hProcess );
4215 CloseHandle( pi.hProcess );
4218 uirow = MSI_CreateRecord( 2 );
4219 MSI_RecordSetStringW( uirow, 1, filename );
4220 uipath = strdupW( file->TargetPath );
4221 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4222 MSI_RecordSetStringW( uirow, 2, uipath );
4223 ui_actiondata( package, szSelfUnregModules, uirow );
4224 msiobj_release( &uirow->hdr );
4226 msi_free( cmdline );
4227 msi_free( uipath );
4228 return ERROR_SUCCESS;
4231 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4233 UINT rc;
4234 MSIQUERY *view;
4235 static const WCHAR query[] =
4236 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4237 '`','S','e','l','f','R','e','g','`',0};
4239 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4240 if (rc != ERROR_SUCCESS)
4242 TRACE("no SelfReg table\n");
4243 return ERROR_SUCCESS;
4246 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4247 msiobj_release( &view->hdr );
4249 return ERROR_SUCCESS;
4252 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4254 MSIFEATURE *feature;
4255 UINT rc;
4256 HKEY hkey = NULL, userdata = NULL;
4258 if (!msi_check_publish(package))
4259 return ERROR_SUCCESS;
4261 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4262 &hkey, TRUE);
4263 if (rc != ERROR_SUCCESS)
4264 goto end;
4266 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4267 &userdata, TRUE);
4268 if (rc != ERROR_SUCCESS)
4269 goto end;
4271 /* here the guids are base 85 encoded */
4272 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4274 ComponentList *cl;
4275 LPWSTR data = NULL;
4276 GUID clsid;
4277 INT size;
4278 BOOL absent = FALSE;
4279 MSIRECORD *uirow;
4281 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4282 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4283 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4285 size = 1;
4286 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4288 size += 21;
4290 if (feature->Feature_Parent)
4291 size += strlenW( feature->Feature_Parent )+2;
4293 data = msi_alloc(size * sizeof(WCHAR));
4295 data[0] = 0;
4296 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4298 MSICOMPONENT* component = cl->component;
4299 WCHAR buf[21];
4301 buf[0] = 0;
4302 if (component->ComponentId)
4304 TRACE("From %s\n",debugstr_w(component->ComponentId));
4305 CLSIDFromString(component->ComponentId, &clsid);
4306 encode_base85_guid(&clsid,buf);
4307 TRACE("to %s\n",debugstr_w(buf));
4308 strcatW(data,buf);
4312 if (feature->Feature_Parent)
4314 static const WCHAR sep[] = {'\2',0};
4315 strcatW(data,sep);
4316 strcatW(data,feature->Feature_Parent);
4319 msi_reg_set_val_str( userdata, feature->Feature, data );
4320 msi_free(data);
4322 size = 0;
4323 if (feature->Feature_Parent)
4324 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4325 if (!absent)
4327 size += sizeof(WCHAR);
4328 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4329 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4331 else
4333 size += 2*sizeof(WCHAR);
4334 data = msi_alloc(size);
4335 data[0] = 0x6;
4336 data[1] = 0;
4337 if (feature->Feature_Parent)
4338 strcpyW( &data[1], feature->Feature_Parent );
4339 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4340 (LPBYTE)data,size);
4341 msi_free(data);
4344 /* the UI chunk */
4345 uirow = MSI_CreateRecord( 1 );
4346 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4347 ui_actiondata( package, szPublishFeatures, uirow);
4348 msiobj_release( &uirow->hdr );
4349 /* FIXME: call ui_progress? */
4352 end:
4353 RegCloseKey(hkey);
4354 RegCloseKey(userdata);
4355 return rc;
4358 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4360 UINT r;
4361 HKEY hkey;
4362 MSIRECORD *uirow;
4364 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4366 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4367 &hkey, FALSE);
4368 if (r == ERROR_SUCCESS)
4370 RegDeleteValueW(hkey, feature->Feature);
4371 RegCloseKey(hkey);
4374 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4375 &hkey, FALSE);
4376 if (r == ERROR_SUCCESS)
4378 RegDeleteValueW(hkey, feature->Feature);
4379 RegCloseKey(hkey);
4382 uirow = MSI_CreateRecord( 1 );
4383 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4384 ui_actiondata( package, szUnpublishFeatures, uirow );
4385 msiobj_release( &uirow->hdr );
4387 return ERROR_SUCCESS;
4390 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4392 MSIFEATURE *feature;
4394 if (!msi_check_unpublish(package))
4395 return ERROR_SUCCESS;
4397 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4399 msi_unpublish_feature(package, feature);
4402 return ERROR_SUCCESS;
4405 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4407 LPWSTR prop, val, key;
4408 SYSTEMTIME systime;
4409 DWORD size, langid;
4410 WCHAR date[9];
4411 LPWSTR buffer;
4413 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4414 static const WCHAR szWindowsInstaller[] =
4415 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4416 static const WCHAR modpath_fmt[] =
4417 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4418 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4419 static const WCHAR szModifyPath[] =
4420 {'M','o','d','i','f','y','P','a','t','h',0};
4421 static const WCHAR szUninstallString[] =
4422 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4423 static const WCHAR szEstimatedSize[] =
4424 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4425 static const WCHAR szProductLanguage[] =
4426 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4427 static const WCHAR szProductVersion[] =
4428 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4429 static const WCHAR szProductName[] =
4430 {'P','r','o','d','u','c','t','N','a','m','e',0};
4431 static const WCHAR szDisplayName[] =
4432 {'D','i','s','p','l','a','y','N','a','m','e',0};
4433 static const WCHAR szDisplayVersion[] =
4434 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4435 static const WCHAR szManufacturer[] =
4436 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4438 static const LPCSTR propval[] = {
4439 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4440 "ARPCONTACT", "Contact",
4441 "ARPCOMMENTS", "Comments",
4442 "ProductName", "DisplayName",
4443 "ProductVersion", "DisplayVersion",
4444 "ARPHELPLINK", "HelpLink",
4445 "ARPHELPTELEPHONE", "HelpTelephone",
4446 "ARPINSTALLLOCATION", "InstallLocation",
4447 "SourceDir", "InstallSource",
4448 "Manufacturer", "Publisher",
4449 "ARPREADME", "Readme",
4450 "ARPSIZE", "Size",
4451 "ARPURLINFOABOUT", "URLInfoAbout",
4452 "ARPURLUPDATEINFO", "URLUpdateInfo",
4453 NULL,
4455 const LPCSTR *p = propval;
4457 while (*p)
4459 prop = strdupAtoW(*p++);
4460 key = strdupAtoW(*p++);
4461 val = msi_dup_property(package, prop);
4462 msi_reg_set_val_str(hkey, key, val);
4463 msi_free(val);
4464 msi_free(key);
4465 msi_free(prop);
4468 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4470 size = deformat_string(package, modpath_fmt, &buffer);
4471 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4472 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4473 msi_free(buffer);
4475 /* FIXME: Write real Estimated Size when we have it */
4476 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4478 buffer = msi_dup_property(package, szProductName);
4479 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4480 msi_free(buffer);
4482 buffer = msi_dup_property(package, cszSourceDir);
4483 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4484 msi_free(buffer);
4486 buffer = msi_dup_property(package, szManufacturer);
4487 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4488 msi_free(buffer);
4490 GetLocalTime(&systime);
4491 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4492 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4494 langid = msi_get_property_int(package, szProductLanguage, 0);
4495 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4497 buffer = msi_dup_property(package, szProductVersion);
4498 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4499 if (buffer)
4501 DWORD verdword = msi_version_str_to_dword(buffer);
4503 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4504 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4505 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4506 msi_free(buffer);
4509 return ERROR_SUCCESS;
4512 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4514 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4515 MSIRECORD *uirow;
4516 LPWSTR upgrade_code;
4517 HKEY hkey, props;
4518 HKEY upgrade;
4519 UINT rc;
4521 static const WCHAR szUpgradeCode[] = {
4522 'U','p','g','r','a','d','e','C','o','d','e',0};
4524 /* FIXME: also need to publish if the product is in advertise mode */
4525 if (!msi_check_publish(package))
4526 return ERROR_SUCCESS;
4528 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4529 if (rc != ERROR_SUCCESS)
4530 return rc;
4532 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4533 NULL, &props, TRUE);
4534 if (rc != ERROR_SUCCESS)
4535 goto done;
4537 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4538 msi_free( package->db->localfile );
4539 package->db->localfile = NULL;
4541 rc = msi_publish_install_properties(package, hkey);
4542 if (rc != ERROR_SUCCESS)
4543 goto done;
4545 rc = msi_publish_install_properties(package, props);
4546 if (rc != ERROR_SUCCESS)
4547 goto done;
4549 upgrade_code = msi_dup_property(package, szUpgradeCode);
4550 if (upgrade_code)
4552 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4553 squash_guid(package->ProductCode, squashed_pc);
4554 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4555 RegCloseKey(upgrade);
4556 msi_free(upgrade_code);
4559 done:
4560 uirow = MSI_CreateRecord( 1 );
4561 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4562 ui_actiondata( package, szRegisterProduct, uirow );
4563 msiobj_release( &uirow->hdr );
4565 RegCloseKey(hkey);
4566 return ERROR_SUCCESS;
4569 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4571 return execute_script(package,INSTALL_SCRIPT);
4574 static UINT msi_unpublish_product(MSIPACKAGE *package)
4576 LPWSTR upgrade;
4577 LPWSTR remove = NULL;
4578 LPWSTR *features = NULL;
4579 BOOL full_uninstall = TRUE;
4580 MSIFEATURE *feature;
4582 static const WCHAR szUpgradeCode[] =
4583 {'U','p','g','r','a','d','e','C','o','d','e',0};
4585 remove = msi_dup_property(package, szRemove);
4586 if (!remove)
4587 return ERROR_SUCCESS;
4589 features = msi_split_string(remove, ',');
4590 if (!features)
4592 msi_free(remove);
4593 ERR("REMOVE feature list is empty!\n");
4594 return ERROR_FUNCTION_FAILED;
4597 if (!lstrcmpW(features[0], szAll))
4598 full_uninstall = TRUE;
4599 else
4601 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4603 if (feature->Action != INSTALLSTATE_ABSENT)
4604 full_uninstall = FALSE;
4608 if (!full_uninstall)
4609 goto done;
4611 MSIREG_DeleteProductKey(package->ProductCode);
4612 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4613 MSIREG_DeleteUninstallKey(package->ProductCode);
4615 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4617 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4618 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4620 else
4622 MSIREG_DeleteUserProductKey(package->ProductCode);
4623 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4626 upgrade = msi_dup_property(package, szUpgradeCode);
4627 if (upgrade)
4629 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4630 msi_free(upgrade);
4633 done:
4634 msi_free(remove);
4635 msi_free(features);
4636 return ERROR_SUCCESS;
4639 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4641 UINT rc;
4643 rc = msi_unpublish_product(package);
4644 if (rc != ERROR_SUCCESS)
4645 return rc;
4647 /* turn off scheduling */
4648 package->script->CurrentlyScripting= FALSE;
4650 /* first do the same as an InstallExecute */
4651 rc = ACTION_InstallExecute(package);
4652 if (rc != ERROR_SUCCESS)
4653 return rc;
4655 /* then handle Commit Actions */
4656 rc = execute_script(package,COMMIT_SCRIPT);
4658 return rc;
4661 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4663 static const WCHAR RunOnce[] = {
4664 'S','o','f','t','w','a','r','e','\\',
4665 'M','i','c','r','o','s','o','f','t','\\',
4666 'W','i','n','d','o','w','s','\\',
4667 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4668 'R','u','n','O','n','c','e',0};
4669 static const WCHAR InstallRunOnce[] = {
4670 'S','o','f','t','w','a','r','e','\\',
4671 'M','i','c','r','o','s','o','f','t','\\',
4672 'W','i','n','d','o','w','s','\\',
4673 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4674 'I','n','s','t','a','l','l','e','r','\\',
4675 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4677 static const WCHAR msiexec_fmt[] = {
4678 '%','s',
4679 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4680 '\"','%','s','\"',0};
4681 static const WCHAR install_fmt[] = {
4682 '/','I',' ','\"','%','s','\"',' ',
4683 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4684 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4685 WCHAR buffer[256], sysdir[MAX_PATH];
4686 HKEY hkey;
4687 WCHAR squished_pc[100];
4689 squash_guid(package->ProductCode,squished_pc);
4691 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4692 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4693 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4694 squished_pc);
4696 msi_reg_set_val_str( hkey, squished_pc, buffer );
4697 RegCloseKey(hkey);
4699 TRACE("Reboot command %s\n",debugstr_w(buffer));
4701 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4702 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4704 msi_reg_set_val_str( hkey, squished_pc, buffer );
4705 RegCloseKey(hkey);
4707 return ERROR_INSTALL_SUSPEND;
4710 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4712 DWORD attrib;
4713 UINT rc;
4716 * We are currently doing what should be done here in the top level Install
4717 * however for Administrative and uninstalls this step will be needed
4719 if (!package->PackagePath)
4720 return ERROR_SUCCESS;
4722 msi_set_sourcedir_props(package, TRUE);
4724 attrib = GetFileAttributesW(package->db->path);
4725 if (attrib == INVALID_FILE_ATTRIBUTES)
4727 LPWSTR prompt;
4728 LPWSTR msg;
4729 DWORD size = 0;
4731 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4732 package->Context, MSICODE_PRODUCT,
4733 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4734 if (rc == ERROR_MORE_DATA)
4736 prompt = msi_alloc(size * sizeof(WCHAR));
4737 MsiSourceListGetInfoW(package->ProductCode, NULL,
4738 package->Context, MSICODE_PRODUCT,
4739 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4741 else
4742 prompt = strdupW(package->db->path);
4744 msg = generate_error_string(package,1302,1,prompt);
4745 while(attrib == INVALID_FILE_ATTRIBUTES)
4747 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4748 if (rc == IDCANCEL)
4750 rc = ERROR_INSTALL_USEREXIT;
4751 break;
4753 attrib = GetFileAttributesW(package->db->path);
4755 msi_free(prompt);
4756 rc = ERROR_SUCCESS;
4758 else
4759 return ERROR_SUCCESS;
4761 return rc;
4764 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4766 HKEY hkey = 0;
4767 LPWSTR buffer, productid = NULL;
4768 UINT i, rc = ERROR_SUCCESS;
4769 MSIRECORD *uirow;
4771 static const WCHAR szPropKeys[][80] =
4773 {'P','r','o','d','u','c','t','I','D',0},
4774 {'U','S','E','R','N','A','M','E',0},
4775 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4776 {0},
4779 static const WCHAR szRegKeys[][80] =
4781 {'P','r','o','d','u','c','t','I','D',0},
4782 {'R','e','g','O','w','n','e','r',0},
4783 {'R','e','g','C','o','m','p','a','n','y',0},
4784 {0},
4787 if (msi_check_unpublish(package))
4789 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4790 goto end;
4793 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4794 if (!productid)
4795 goto end;
4797 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4798 NULL, &hkey, TRUE);
4799 if (rc != ERROR_SUCCESS)
4800 goto end;
4802 for( i = 0; szPropKeys[i][0]; i++ )
4804 buffer = msi_dup_property( package, szPropKeys[i] );
4805 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4806 msi_free( buffer );
4809 end:
4810 uirow = MSI_CreateRecord( 1 );
4811 MSI_RecordSetStringW( uirow, 1, productid );
4812 ui_actiondata( package, szRegisterUser, uirow );
4813 msiobj_release( &uirow->hdr );
4815 msi_free(productid);
4816 RegCloseKey(hkey);
4817 return rc;
4821 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4823 UINT rc;
4825 package->script->InWhatSequence |= SEQUENCE_EXEC;
4826 rc = ACTION_ProcessExecSequence(package,FALSE);
4827 return rc;
4831 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4833 MSIPACKAGE *package = param;
4834 LPCWSTR compgroupid, component, feature, qualifier, text;
4835 LPWSTR advertise = NULL, output = NULL;
4836 HKEY hkey = NULL;
4837 UINT rc;
4838 MSICOMPONENT *comp;
4839 MSIFEATURE *feat;
4840 DWORD sz;
4841 MSIRECORD *uirow;
4843 feature = MSI_RecordGetString(rec, 5);
4844 feat = get_loaded_feature(package, feature);
4845 if (!feat)
4846 return ERROR_SUCCESS;
4848 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4849 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4850 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
4852 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4853 feat->Action = feat->Installed;
4854 return ERROR_SUCCESS;
4857 component = MSI_RecordGetString(rec, 3);
4858 comp = get_loaded_component(package, component);
4859 if (!comp)
4860 return ERROR_SUCCESS;
4862 compgroupid = MSI_RecordGetString(rec,1);
4863 qualifier = MSI_RecordGetString(rec,2);
4865 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4866 if (rc != ERROR_SUCCESS)
4867 goto end;
4869 text = MSI_RecordGetString(rec,4);
4870 advertise = create_component_advertise_string(package, comp, feature);
4872 sz = strlenW(advertise);
4874 if (text)
4875 sz += lstrlenW(text);
4877 sz+=3;
4878 sz *= sizeof(WCHAR);
4880 output = msi_alloc_zero(sz);
4881 strcpyW(output,advertise);
4882 msi_free(advertise);
4884 if (text)
4885 strcatW(output,text);
4887 msi_reg_set_val_multi_str( hkey, qualifier, output );
4889 end:
4890 RegCloseKey(hkey);
4891 msi_free(output);
4893 /* the UI chunk */
4894 uirow = MSI_CreateRecord( 2 );
4895 MSI_RecordSetStringW( uirow, 1, compgroupid );
4896 MSI_RecordSetStringW( uirow, 2, qualifier);
4897 ui_actiondata( package, szPublishComponents, uirow);
4898 msiobj_release( &uirow->hdr );
4899 /* FIXME: call ui_progress? */
4901 return rc;
4905 * At present I am ignorning the advertised components part of this and only
4906 * focusing on the qualified component sets
4908 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4910 UINT rc;
4911 MSIQUERY * view;
4912 static const WCHAR ExecSeqQuery[] =
4913 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4914 '`','P','u','b','l','i','s','h',
4915 'C','o','m','p','o','n','e','n','t','`',0};
4917 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4918 if (rc != ERROR_SUCCESS)
4919 return ERROR_SUCCESS;
4921 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4922 msiobj_release(&view->hdr);
4924 return rc;
4927 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
4929 static const WCHAR szInstallerComponents[] = {
4930 'S','o','f','t','w','a','r','e','\\',
4931 'M','i','c','r','o','s','o','f','t','\\',
4932 'I','n','s','t','a','l','l','e','r','\\',
4933 'C','o','m','p','o','n','e','n','t','s','\\',0};
4935 MSIPACKAGE *package = param;
4936 LPCWSTR compgroupid, component, feature, qualifier;
4937 MSICOMPONENT *comp;
4938 MSIFEATURE *feat;
4939 MSIRECORD *uirow;
4940 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
4941 LONG res;
4943 feature = MSI_RecordGetString( rec, 5 );
4944 feat = get_loaded_feature( package, feature );
4945 if (!feat)
4946 return ERROR_SUCCESS;
4948 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
4950 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
4951 feat->Action = feat->Installed;
4952 return ERROR_SUCCESS;
4955 component = MSI_RecordGetString( rec, 3 );
4956 comp = get_loaded_component( package, component );
4957 if (!comp)
4958 return ERROR_SUCCESS;
4960 compgroupid = MSI_RecordGetString( rec, 1 );
4961 qualifier = MSI_RecordGetString( rec, 2 );
4963 squash_guid( compgroupid, squashed );
4964 strcpyW( keypath, szInstallerComponents );
4965 strcatW( keypath, squashed );
4967 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
4968 if (res != ERROR_SUCCESS)
4970 WARN("Unable to delete component key %d\n", res);
4973 uirow = MSI_CreateRecord( 2 );
4974 MSI_RecordSetStringW( uirow, 1, compgroupid );
4975 MSI_RecordSetStringW( uirow, 2, qualifier );
4976 ui_actiondata( package, szUnpublishComponents, uirow );
4977 msiobj_release( &uirow->hdr );
4979 return ERROR_SUCCESS;
4982 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
4984 UINT rc;
4985 MSIQUERY *view;
4986 static const WCHAR query[] =
4987 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4988 '`','P','u','b','l','i','s','h',
4989 'C','o','m','p','o','n','e','n','t','`',0};
4991 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4992 if (rc != ERROR_SUCCESS)
4993 return ERROR_SUCCESS;
4995 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
4996 msiobj_release( &view->hdr );
4998 return rc;
5001 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5003 MSIPACKAGE *package = param;
5004 MSIRECORD *row;
5005 MSIFILE *file;
5006 SC_HANDLE hscm, service = NULL;
5007 LPCWSTR comp, depends, pass;
5008 LPWSTR name = NULL, disp = NULL;
5009 LPCWSTR load_order, serv_name, key;
5010 DWORD serv_type, start_type;
5011 DWORD err_control;
5013 static const WCHAR query[] =
5014 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5015 '`','C','o','m','p','o','n','e','n','t','`',' ',
5016 'W','H','E','R','E',' ',
5017 '`','C','o','m','p','o','n','e','n','t','`',' ',
5018 '=','\'','%','s','\'',0};
5020 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5021 if (!hscm)
5023 ERR("Failed to open the SC Manager!\n");
5024 goto done;
5027 start_type = MSI_RecordGetInteger(rec, 5);
5028 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5029 goto done;
5031 depends = MSI_RecordGetString(rec, 8);
5032 if (depends && *depends)
5033 FIXME("Dependency list unhandled!\n");
5035 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5036 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5037 serv_type = MSI_RecordGetInteger(rec, 4);
5038 err_control = MSI_RecordGetInteger(rec, 6);
5039 load_order = MSI_RecordGetString(rec, 7);
5040 serv_name = MSI_RecordGetString(rec, 9);
5041 pass = MSI_RecordGetString(rec, 10);
5042 comp = MSI_RecordGetString(rec, 12);
5044 /* fetch the service path */
5045 row = MSI_QueryGetRecord(package->db, query, comp);
5046 if (!row)
5048 ERR("Control query failed!\n");
5049 goto done;
5052 key = MSI_RecordGetString(row, 6);
5054 file = get_loaded_file(package, key);
5055 msiobj_release(&row->hdr);
5056 if (!file)
5058 ERR("Failed to load the service file\n");
5059 goto done;
5062 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5063 start_type, err_control, file->TargetPath,
5064 load_order, NULL, NULL, serv_name, pass);
5065 if (!service)
5067 if (GetLastError() != ERROR_SERVICE_EXISTS)
5068 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5071 done:
5072 CloseServiceHandle(service);
5073 CloseServiceHandle(hscm);
5074 msi_free(name);
5075 msi_free(disp);
5077 return ERROR_SUCCESS;
5080 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5082 UINT rc;
5083 MSIQUERY * view;
5084 static const WCHAR ExecSeqQuery[] =
5085 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5086 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5088 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5089 if (rc != ERROR_SUCCESS)
5090 return ERROR_SUCCESS;
5092 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5093 msiobj_release(&view->hdr);
5095 return rc;
5098 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5099 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5101 LPCWSTR *vector, *temp_vector;
5102 LPWSTR p, q;
5103 DWORD sep_len;
5105 static const WCHAR separator[] = {'[','~',']',0};
5107 *numargs = 0;
5108 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5110 if (!args)
5111 return NULL;
5113 vector = msi_alloc(sizeof(LPWSTR));
5114 if (!vector)
5115 return NULL;
5117 p = args;
5120 (*numargs)++;
5121 vector[*numargs - 1] = p;
5123 if ((q = strstrW(p, separator)))
5125 *q = '\0';
5127 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5128 if (!temp_vector)
5130 msi_free(vector);
5131 return NULL;
5133 vector = temp_vector;
5135 p = q + sep_len;
5137 } while (q);
5139 return vector;
5142 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5144 MSIPACKAGE *package = param;
5145 MSICOMPONENT *comp;
5146 MSIRECORD *uirow;
5147 SC_HANDLE scm = NULL, service = NULL;
5148 LPCWSTR component, *vector = NULL;
5149 LPWSTR name, args, display_name = NULL;
5150 DWORD event, numargs, len;
5151 UINT r = ERROR_FUNCTION_FAILED;
5153 component = MSI_RecordGetString(rec, 6);
5154 comp = get_loaded_component(package, component);
5155 if (!comp)
5156 return ERROR_SUCCESS;
5158 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5160 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5161 comp->Action = comp->Installed;
5162 return ERROR_SUCCESS;
5164 comp->Action = INSTALLSTATE_LOCAL;
5166 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5167 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5168 event = MSI_RecordGetInteger(rec, 3);
5170 if (!(event & msidbServiceControlEventStart))
5172 r = ERROR_SUCCESS;
5173 goto done;
5176 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5177 if (!scm)
5179 ERR("Failed to open the service control manager\n");
5180 goto done;
5183 len = 0;
5184 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5185 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5187 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5188 GetServiceDisplayNameW( scm, name, display_name, &len );
5191 service = OpenServiceW(scm, name, SERVICE_START);
5192 if (!service)
5194 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5195 goto done;
5198 vector = msi_service_args_to_vector(args, &numargs);
5200 if (!StartServiceW(service, numargs, vector) &&
5201 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5203 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5204 goto done;
5207 r = ERROR_SUCCESS;
5209 done:
5210 uirow = MSI_CreateRecord( 2 );
5211 MSI_RecordSetStringW( uirow, 1, display_name );
5212 MSI_RecordSetStringW( uirow, 2, name );
5213 ui_actiondata( package, szStartServices, uirow );
5214 msiobj_release( &uirow->hdr );
5216 CloseServiceHandle(service);
5217 CloseServiceHandle(scm);
5219 msi_free(name);
5220 msi_free(args);
5221 msi_free(vector);
5222 msi_free(display_name);
5223 return r;
5226 static UINT ACTION_StartServices( MSIPACKAGE *package )
5228 UINT rc;
5229 MSIQUERY *view;
5231 static const WCHAR query[] = {
5232 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5233 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5235 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5236 if (rc != ERROR_SUCCESS)
5237 return ERROR_SUCCESS;
5239 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5240 msiobj_release(&view->hdr);
5242 return rc;
5245 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5247 DWORD i, needed, count;
5248 ENUM_SERVICE_STATUSW *dependencies;
5249 SERVICE_STATUS ss;
5250 SC_HANDLE depserv;
5252 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5253 0, &needed, &count))
5254 return TRUE;
5256 if (GetLastError() != ERROR_MORE_DATA)
5257 return FALSE;
5259 dependencies = msi_alloc(needed);
5260 if (!dependencies)
5261 return FALSE;
5263 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5264 needed, &needed, &count))
5265 goto error;
5267 for (i = 0; i < count; i++)
5269 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5270 SERVICE_STOP | SERVICE_QUERY_STATUS);
5271 if (!depserv)
5272 goto error;
5274 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5275 goto error;
5278 return TRUE;
5280 error:
5281 msi_free(dependencies);
5282 return FALSE;
5285 static UINT stop_service( LPCWSTR name )
5287 SC_HANDLE scm = NULL, service = NULL;
5288 SERVICE_STATUS status;
5289 SERVICE_STATUS_PROCESS ssp;
5290 DWORD needed;
5292 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5293 if (!scm)
5295 WARN("Failed to open the SCM: %d\n", GetLastError());
5296 goto done;
5299 service = OpenServiceW(scm, name,
5300 SERVICE_STOP |
5301 SERVICE_QUERY_STATUS |
5302 SERVICE_ENUMERATE_DEPENDENTS);
5303 if (!service)
5305 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5306 goto done;
5309 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5310 sizeof(SERVICE_STATUS_PROCESS), &needed))
5312 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5313 goto done;
5316 if (ssp.dwCurrentState == SERVICE_STOPPED)
5317 goto done;
5319 stop_service_dependents(scm, service);
5321 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5322 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5324 done:
5325 CloseServiceHandle(service);
5326 CloseServiceHandle(scm);
5328 return ERROR_SUCCESS;
5331 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5333 MSIPACKAGE *package = param;
5334 MSICOMPONENT *comp;
5335 MSIRECORD *uirow;
5336 LPCWSTR component;
5337 LPWSTR name = NULL, display_name = NULL;
5338 DWORD event, len;
5339 SC_HANDLE scm;
5341 event = MSI_RecordGetInteger( rec, 3 );
5342 if (!(event & msidbServiceControlEventStop))
5343 return ERROR_SUCCESS;
5345 component = MSI_RecordGetString( rec, 6 );
5346 comp = get_loaded_component( package, component );
5347 if (!comp)
5348 return ERROR_SUCCESS;
5350 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5352 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5353 comp->Action = comp->Installed;
5354 return ERROR_SUCCESS;
5356 comp->Action = INSTALLSTATE_ABSENT;
5358 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5359 if (!scm)
5361 ERR("Failed to open the service control manager\n");
5362 goto done;
5365 len = 0;
5366 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5367 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5369 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5370 GetServiceDisplayNameW( scm, name, display_name, &len );
5372 CloseServiceHandle( scm );
5374 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5375 stop_service( name );
5377 done:
5378 uirow = MSI_CreateRecord( 2 );
5379 MSI_RecordSetStringW( uirow, 1, display_name );
5380 MSI_RecordSetStringW( uirow, 2, name );
5381 ui_actiondata( package, szStopServices, uirow );
5382 msiobj_release( &uirow->hdr );
5384 msi_free( name );
5385 msi_free( display_name );
5386 return ERROR_SUCCESS;
5389 static UINT ACTION_StopServices( MSIPACKAGE *package )
5391 UINT rc;
5392 MSIQUERY *view;
5394 static const WCHAR query[] = {
5395 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5396 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5398 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5399 if (rc != ERROR_SUCCESS)
5400 return ERROR_SUCCESS;
5402 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5403 msiobj_release(&view->hdr);
5405 return rc;
5408 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5410 MSIPACKAGE *package = param;
5411 MSICOMPONENT *comp;
5412 MSIRECORD *uirow;
5413 LPCWSTR component;
5414 LPWSTR name = NULL, display_name = NULL;
5415 DWORD event, len;
5416 SC_HANDLE scm = NULL, service = NULL;
5418 event = MSI_RecordGetInteger( rec, 3 );
5419 if (!(event & msidbServiceControlEventDelete))
5420 return ERROR_SUCCESS;
5422 component = MSI_RecordGetString(rec, 6);
5423 comp = get_loaded_component(package, component);
5424 if (!comp)
5425 return ERROR_SUCCESS;
5427 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5429 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5430 comp->Action = comp->Installed;
5431 return ERROR_SUCCESS;
5433 comp->Action = INSTALLSTATE_ABSENT;
5435 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5436 stop_service( name );
5438 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5439 if (!scm)
5441 WARN("Failed to open the SCM: %d\n", GetLastError());
5442 goto done;
5445 len = 0;
5446 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5447 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5449 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5450 GetServiceDisplayNameW( scm, name, display_name, &len );
5453 service = OpenServiceW( scm, name, DELETE );
5454 if (!service)
5456 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5457 goto done;
5460 if (!DeleteService( service ))
5461 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5463 done:
5464 uirow = MSI_CreateRecord( 2 );
5465 MSI_RecordSetStringW( uirow, 1, display_name );
5466 MSI_RecordSetStringW( uirow, 2, name );
5467 ui_actiondata( package, szDeleteServices, uirow );
5468 msiobj_release( &uirow->hdr );
5470 CloseServiceHandle( service );
5471 CloseServiceHandle( scm );
5472 msi_free( name );
5473 msi_free( display_name );
5475 return ERROR_SUCCESS;
5478 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5480 UINT rc;
5481 MSIQUERY *view;
5483 static const WCHAR query[] = {
5484 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5485 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5487 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5488 if (rc != ERROR_SUCCESS)
5489 return ERROR_SUCCESS;
5491 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5492 msiobj_release( &view->hdr );
5494 return rc;
5497 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5499 MSIFILE *file;
5501 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5503 if (!lstrcmpW(file->File, filename))
5504 return file;
5507 return NULL;
5510 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5512 MSIPACKAGE *package = param;
5513 LPWSTR driver, driver_path, ptr;
5514 WCHAR outpath[MAX_PATH];
5515 MSIFILE *driver_file, *setup_file;
5516 MSIRECORD *uirow;
5517 LPCWSTR desc;
5518 DWORD len, usage;
5519 UINT r = ERROR_SUCCESS;
5521 static const WCHAR driver_fmt[] = {
5522 'D','r','i','v','e','r','=','%','s',0};
5523 static const WCHAR setup_fmt[] = {
5524 'S','e','t','u','p','=','%','s',0};
5525 static const WCHAR usage_fmt[] = {
5526 'F','i','l','e','U','s','a','g','e','=','1',0};
5528 desc = MSI_RecordGetString(rec, 3);
5530 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5531 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5533 if (!driver_file)
5535 ERR("ODBC Driver entry not found!\n");
5536 return ERROR_FUNCTION_FAILED;
5539 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5540 if (setup_file)
5541 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5542 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5544 driver = msi_alloc(len * sizeof(WCHAR));
5545 if (!driver)
5546 return ERROR_OUTOFMEMORY;
5548 ptr = driver;
5549 lstrcpyW(ptr, desc);
5550 ptr += lstrlenW(ptr) + 1;
5552 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5553 ptr += len + 1;
5555 if (setup_file)
5557 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5558 ptr += len + 1;
5561 lstrcpyW(ptr, usage_fmt);
5562 ptr += lstrlenW(ptr) + 1;
5563 *ptr = '\0';
5565 driver_path = strdupW(driver_file->TargetPath);
5566 ptr = strrchrW(driver_path, '\\');
5567 if (ptr) *ptr = '\0';
5569 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5570 NULL, ODBC_INSTALL_COMPLETE, &usage))
5572 ERR("Failed to install SQL driver!\n");
5573 r = ERROR_FUNCTION_FAILED;
5576 uirow = MSI_CreateRecord( 5 );
5577 MSI_RecordSetStringW( uirow, 1, desc );
5578 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5579 MSI_RecordSetStringW( uirow, 3, driver_path );
5580 ui_actiondata( package, szInstallODBC, uirow );
5581 msiobj_release( &uirow->hdr );
5583 msi_free(driver);
5584 msi_free(driver_path);
5586 return r;
5589 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5591 MSIPACKAGE *package = param;
5592 LPWSTR translator, translator_path, ptr;
5593 WCHAR outpath[MAX_PATH];
5594 MSIFILE *translator_file, *setup_file;
5595 MSIRECORD *uirow;
5596 LPCWSTR desc;
5597 DWORD len, usage;
5598 UINT r = ERROR_SUCCESS;
5600 static const WCHAR translator_fmt[] = {
5601 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5602 static const WCHAR setup_fmt[] = {
5603 'S','e','t','u','p','=','%','s',0};
5605 desc = MSI_RecordGetString(rec, 3);
5607 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5608 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5610 if (!translator_file)
5612 ERR("ODBC Translator entry not found!\n");
5613 return ERROR_FUNCTION_FAILED;
5616 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5617 if (setup_file)
5618 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5620 translator = msi_alloc(len * sizeof(WCHAR));
5621 if (!translator)
5622 return ERROR_OUTOFMEMORY;
5624 ptr = translator;
5625 lstrcpyW(ptr, desc);
5626 ptr += lstrlenW(ptr) + 1;
5628 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5629 ptr += len + 1;
5631 if (setup_file)
5633 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5634 ptr += len + 1;
5636 *ptr = '\0';
5638 translator_path = strdupW(translator_file->TargetPath);
5639 ptr = strrchrW(translator_path, '\\');
5640 if (ptr) *ptr = '\0';
5642 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5643 NULL, ODBC_INSTALL_COMPLETE, &usage))
5645 ERR("Failed to install SQL translator!\n");
5646 r = ERROR_FUNCTION_FAILED;
5649 uirow = MSI_CreateRecord( 5 );
5650 MSI_RecordSetStringW( uirow, 1, desc );
5651 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5652 MSI_RecordSetStringW( uirow, 3, translator_path );
5653 ui_actiondata( package, szInstallODBC, uirow );
5654 msiobj_release( &uirow->hdr );
5656 msi_free(translator);
5657 msi_free(translator_path);
5659 return r;
5662 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5664 MSIPACKAGE *package = param;
5665 LPWSTR attrs;
5666 LPCWSTR desc, driver;
5667 WORD request = ODBC_ADD_SYS_DSN;
5668 INT registration;
5669 DWORD len;
5670 UINT r = ERROR_SUCCESS;
5671 MSIRECORD *uirow;
5673 static const WCHAR attrs_fmt[] = {
5674 'D','S','N','=','%','s',0 };
5676 desc = MSI_RecordGetString(rec, 3);
5677 driver = MSI_RecordGetString(rec, 4);
5678 registration = MSI_RecordGetInteger(rec, 5);
5680 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5681 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5683 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5684 attrs = msi_alloc(len * sizeof(WCHAR));
5685 if (!attrs)
5686 return ERROR_OUTOFMEMORY;
5688 len = sprintfW(attrs, attrs_fmt, desc);
5689 attrs[len + 1] = 0;
5691 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5693 ERR("Failed to install SQL data source!\n");
5694 r = ERROR_FUNCTION_FAILED;
5697 uirow = MSI_CreateRecord( 5 );
5698 MSI_RecordSetStringW( uirow, 1, desc );
5699 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5700 MSI_RecordSetInteger( uirow, 3, request );
5701 ui_actiondata( package, szInstallODBC, uirow );
5702 msiobj_release( &uirow->hdr );
5704 msi_free(attrs);
5706 return r;
5709 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5711 UINT rc;
5712 MSIQUERY *view;
5714 static const WCHAR driver_query[] = {
5715 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5716 'O','D','B','C','D','r','i','v','e','r',0 };
5718 static const WCHAR translator_query[] = {
5719 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5720 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5722 static const WCHAR source_query[] = {
5723 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5724 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5726 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5727 if (rc != ERROR_SUCCESS)
5728 return ERROR_SUCCESS;
5730 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5731 msiobj_release(&view->hdr);
5733 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5734 if (rc != ERROR_SUCCESS)
5735 return ERROR_SUCCESS;
5737 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5738 msiobj_release(&view->hdr);
5740 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5741 if (rc != ERROR_SUCCESS)
5742 return ERROR_SUCCESS;
5744 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5745 msiobj_release(&view->hdr);
5747 return rc;
5750 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5752 MSIPACKAGE *package = param;
5753 MSIRECORD *uirow;
5754 DWORD usage;
5755 LPCWSTR desc;
5757 desc = MSI_RecordGetString( rec, 3 );
5758 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5760 WARN("Failed to remove ODBC driver\n");
5762 else if (!usage)
5764 FIXME("Usage count reached 0\n");
5767 uirow = MSI_CreateRecord( 2 );
5768 MSI_RecordSetStringW( uirow, 1, desc );
5769 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5770 ui_actiondata( package, szRemoveODBC, uirow );
5771 msiobj_release( &uirow->hdr );
5773 return ERROR_SUCCESS;
5776 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5778 MSIPACKAGE *package = param;
5779 MSIRECORD *uirow;
5780 DWORD usage;
5781 LPCWSTR desc;
5783 desc = MSI_RecordGetString( rec, 3 );
5784 if (!SQLRemoveTranslatorW( desc, &usage ))
5786 WARN("Failed to remove ODBC translator\n");
5788 else if (!usage)
5790 FIXME("Usage count reached 0\n");
5793 uirow = MSI_CreateRecord( 2 );
5794 MSI_RecordSetStringW( uirow, 1, desc );
5795 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5796 ui_actiondata( package, szRemoveODBC, uirow );
5797 msiobj_release( &uirow->hdr );
5799 return ERROR_SUCCESS;
5802 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5804 MSIPACKAGE *package = param;
5805 MSIRECORD *uirow;
5806 LPWSTR attrs;
5807 LPCWSTR desc, driver;
5808 WORD request = ODBC_REMOVE_SYS_DSN;
5809 INT registration;
5810 DWORD len;
5812 static const WCHAR attrs_fmt[] = {
5813 'D','S','N','=','%','s',0 };
5815 desc = MSI_RecordGetString( rec, 3 );
5816 driver = MSI_RecordGetString( rec, 4 );
5817 registration = MSI_RecordGetInteger( rec, 5 );
5819 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5820 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5822 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
5823 attrs = msi_alloc( len * sizeof(WCHAR) );
5824 if (!attrs)
5825 return ERROR_OUTOFMEMORY;
5827 FIXME("Use ODBCSourceAttribute table\n");
5829 len = sprintfW( attrs, attrs_fmt, desc );
5830 attrs[len + 1] = 0;
5832 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5834 WARN("Failed to remove ODBC data source\n");
5836 msi_free( attrs );
5838 uirow = MSI_CreateRecord( 3 );
5839 MSI_RecordSetStringW( uirow, 1, desc );
5840 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5841 MSI_RecordSetInteger( uirow, 3, request );
5842 ui_actiondata( package, szRemoveODBC, uirow );
5843 msiobj_release( &uirow->hdr );
5845 return ERROR_SUCCESS;
5848 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5850 UINT rc;
5851 MSIQUERY *view;
5853 static const WCHAR driver_query[] = {
5854 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5855 'O','D','B','C','D','r','i','v','e','r',0 };
5857 static const WCHAR translator_query[] = {
5858 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5859 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5861 static const WCHAR source_query[] = {
5862 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5863 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5865 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5866 if (rc != ERROR_SUCCESS)
5867 return ERROR_SUCCESS;
5869 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5870 msiobj_release( &view->hdr );
5872 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5873 if (rc != ERROR_SUCCESS)
5874 return ERROR_SUCCESS;
5876 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5877 msiobj_release( &view->hdr );
5879 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5880 if (rc != ERROR_SUCCESS)
5881 return ERROR_SUCCESS;
5883 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5884 msiobj_release( &view->hdr );
5886 return rc;
5889 #define ENV_ACT_SETALWAYS 0x1
5890 #define ENV_ACT_SETABSENT 0x2
5891 #define ENV_ACT_REMOVE 0x4
5892 #define ENV_ACT_REMOVEMATCH 0x8
5894 #define ENV_MOD_MACHINE 0x20000000
5895 #define ENV_MOD_APPEND 0x40000000
5896 #define ENV_MOD_PREFIX 0x80000000
5897 #define ENV_MOD_MASK 0xC0000000
5899 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5901 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5903 LPCWSTR cptr = *name;
5905 static const WCHAR prefix[] = {'[','~',']',0};
5906 static const int prefix_len = 3;
5908 *flags = 0;
5909 while (*cptr)
5911 if (*cptr == '=')
5912 *flags |= ENV_ACT_SETALWAYS;
5913 else if (*cptr == '+')
5914 *flags |= ENV_ACT_SETABSENT;
5915 else if (*cptr == '-')
5916 *flags |= ENV_ACT_REMOVE;
5917 else if (*cptr == '!')
5918 *flags |= ENV_ACT_REMOVEMATCH;
5919 else if (*cptr == '*')
5920 *flags |= ENV_MOD_MACHINE;
5921 else
5922 break;
5924 cptr++;
5925 (*name)++;
5928 if (!*cptr)
5930 ERR("Missing environment variable\n");
5931 return ERROR_FUNCTION_FAILED;
5934 if (*value)
5936 LPCWSTR ptr = *value;
5937 if (!strncmpW(ptr, prefix, prefix_len))
5939 if (ptr[prefix_len] == szSemiColon[0])
5941 *flags |= ENV_MOD_APPEND;
5942 *value += lstrlenW(prefix);
5944 else
5946 *value = NULL;
5949 else if (lstrlenW(*value) >= prefix_len)
5951 ptr += lstrlenW(ptr) - prefix_len;
5952 if (!lstrcmpW(ptr, prefix))
5954 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5956 *flags |= ENV_MOD_PREFIX;
5957 /* the "[~]" will be removed by deformat_string */;
5959 else
5961 *value = NULL;
5967 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5968 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5969 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5970 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5972 ERR("Invalid flags: %08x\n", *flags);
5973 return ERROR_FUNCTION_FAILED;
5976 if (!*flags)
5977 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5979 return ERROR_SUCCESS;
5982 static UINT open_env_key( DWORD flags, HKEY *key )
5984 static const WCHAR user_env[] =
5985 {'E','n','v','i','r','o','n','m','e','n','t',0};
5986 static const WCHAR machine_env[] =
5987 {'S','y','s','t','e','m','\\',
5988 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5989 'C','o','n','t','r','o','l','\\',
5990 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5991 'E','n','v','i','r','o','n','m','e','n','t',0};
5992 const WCHAR *env;
5993 HKEY root;
5994 LONG res;
5996 if (flags & ENV_MOD_MACHINE)
5998 env = machine_env;
5999 root = HKEY_LOCAL_MACHINE;
6001 else
6003 env = user_env;
6004 root = HKEY_CURRENT_USER;
6007 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6008 if (res != ERROR_SUCCESS)
6010 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6011 return ERROR_FUNCTION_FAILED;
6014 return ERROR_SUCCESS;
6017 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6019 MSIPACKAGE *package = param;
6020 LPCWSTR name, value, component;
6021 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6022 DWORD flags, type, size;
6023 UINT res;
6024 HKEY env = NULL;
6025 MSICOMPONENT *comp;
6026 MSIRECORD *uirow;
6027 int action = 0;
6029 component = MSI_RecordGetString(rec, 4);
6030 comp = get_loaded_component(package, component);
6031 if (!comp)
6032 return ERROR_SUCCESS;
6034 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6036 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6037 comp->Action = comp->Installed;
6038 return ERROR_SUCCESS;
6040 comp->Action = INSTALLSTATE_LOCAL;
6042 name = MSI_RecordGetString(rec, 2);
6043 value = MSI_RecordGetString(rec, 3);
6045 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6047 res = env_parse_flags(&name, &value, &flags);
6048 if (res != ERROR_SUCCESS || !value)
6049 goto done;
6051 if (value && !deformat_string(package, value, &deformatted))
6053 res = ERROR_OUTOFMEMORY;
6054 goto done;
6057 value = deformatted;
6059 res = open_env_key( flags, &env );
6060 if (res != ERROR_SUCCESS)
6061 goto done;
6063 if (flags & ENV_MOD_MACHINE)
6064 action |= 0x20000000;
6066 size = 0;
6067 type = REG_SZ;
6068 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6069 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6070 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6071 goto done;
6073 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6075 action = 0x2;
6077 /* Nothing to do. */
6078 if (!value)
6080 res = ERROR_SUCCESS;
6081 goto done;
6084 /* If we are appending but the string was empty, strip ; */
6085 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6087 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6088 newval = strdupW(value);
6089 if (!newval)
6091 res = ERROR_OUTOFMEMORY;
6092 goto done;
6095 else
6097 action = 0x1;
6099 /* Contrary to MSDN, +-variable to [~];path works */
6100 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6102 res = ERROR_SUCCESS;
6103 goto done;
6106 data = msi_alloc(size);
6107 if (!data)
6109 RegCloseKey(env);
6110 return ERROR_OUTOFMEMORY;
6113 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6114 if (res != ERROR_SUCCESS)
6115 goto done;
6117 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6119 action = 0x4;
6120 res = RegDeleteValueW(env, name);
6121 if (res != ERROR_SUCCESS)
6122 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6123 goto done;
6126 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6127 if (flags & ENV_MOD_MASK)
6129 DWORD mod_size;
6130 int multiplier = 0;
6131 if (flags & ENV_MOD_APPEND) multiplier++;
6132 if (flags & ENV_MOD_PREFIX) multiplier++;
6133 mod_size = lstrlenW(value) * multiplier;
6134 size += mod_size * sizeof(WCHAR);
6137 newval = msi_alloc(size);
6138 ptr = newval;
6139 if (!newval)
6141 res = ERROR_OUTOFMEMORY;
6142 goto done;
6145 if (flags & ENV_MOD_PREFIX)
6147 lstrcpyW(newval, value);
6148 ptr = newval + lstrlenW(value);
6149 action |= 0x80000000;
6152 lstrcpyW(ptr, data);
6154 if (flags & ENV_MOD_APPEND)
6156 lstrcatW(newval, value);
6157 action |= 0x40000000;
6160 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6161 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6162 if (res)
6164 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6167 done:
6168 uirow = MSI_CreateRecord( 3 );
6169 MSI_RecordSetStringW( uirow, 1, name );
6170 MSI_RecordSetStringW( uirow, 2, newval );
6171 MSI_RecordSetInteger( uirow, 3, action );
6172 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6173 msiobj_release( &uirow->hdr );
6175 if (env) RegCloseKey(env);
6176 msi_free(deformatted);
6177 msi_free(data);
6178 msi_free(newval);
6179 return res;
6182 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6184 UINT rc;
6185 MSIQUERY * view;
6186 static const WCHAR ExecSeqQuery[] =
6187 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6188 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6189 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6190 if (rc != ERROR_SUCCESS)
6191 return ERROR_SUCCESS;
6193 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6194 msiobj_release(&view->hdr);
6196 return rc;
6199 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6201 MSIPACKAGE *package = param;
6202 LPCWSTR name, value, component;
6203 LPWSTR deformatted = NULL;
6204 DWORD flags;
6205 HKEY env;
6206 MSICOMPONENT *comp;
6207 MSIRECORD *uirow;
6208 int action = 0;
6209 LONG res;
6210 UINT r;
6212 component = MSI_RecordGetString( rec, 4 );
6213 comp = get_loaded_component( package, component );
6214 if (!comp)
6215 return ERROR_SUCCESS;
6217 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6219 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6220 comp->Action = comp->Installed;
6221 return ERROR_SUCCESS;
6223 comp->Action = INSTALLSTATE_ABSENT;
6225 name = MSI_RecordGetString( rec, 2 );
6226 value = MSI_RecordGetString( rec, 3 );
6228 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6230 r = env_parse_flags( &name, &value, &flags );
6231 if (r != ERROR_SUCCESS)
6232 return r;
6234 if (!(flags & ENV_ACT_REMOVE))
6236 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6237 return ERROR_SUCCESS;
6240 if (value && !deformat_string( package, value, &deformatted ))
6241 return ERROR_OUTOFMEMORY;
6243 value = deformatted;
6245 r = open_env_key( flags, &env );
6246 if (r != ERROR_SUCCESS)
6248 r = ERROR_SUCCESS;
6249 goto done;
6252 if (flags & ENV_MOD_MACHINE)
6253 action |= 0x20000000;
6255 TRACE("Removing %s\n", debugstr_w(name));
6257 res = RegDeleteValueW( env, name );
6258 if (res != ERROR_SUCCESS)
6260 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6261 r = ERROR_SUCCESS;
6264 done:
6265 uirow = MSI_CreateRecord( 3 );
6266 MSI_RecordSetStringW( uirow, 1, name );
6267 MSI_RecordSetStringW( uirow, 2, value );
6268 MSI_RecordSetInteger( uirow, 3, action );
6269 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6270 msiobj_release( &uirow->hdr );
6272 if (env) RegCloseKey( env );
6273 msi_free( deformatted );
6274 return r;
6277 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6279 UINT rc;
6280 MSIQUERY *view;
6281 static const WCHAR query[] =
6282 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6283 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6285 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6286 if (rc != ERROR_SUCCESS)
6287 return ERROR_SUCCESS;
6289 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6290 msiobj_release( &view->hdr );
6292 return rc;
6295 typedef struct tagMSIASSEMBLY
6297 struct list entry;
6298 MSICOMPONENT *component;
6299 MSIFEATURE *feature;
6300 MSIFILE *file;
6301 LPWSTR manifest;
6302 LPWSTR application;
6303 LPWSTR display_name;
6304 DWORD attributes;
6305 BOOL installed;
6306 } MSIASSEMBLY;
6308 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6309 DWORD dwReserved);
6310 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6311 LPVOID pvReserved, HMODULE *phModDll);
6313 static BOOL init_functionpointers(void)
6315 HRESULT hr;
6316 HMODULE hfusion;
6317 HMODULE hmscoree;
6319 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6321 hmscoree = LoadLibraryA("mscoree.dll");
6322 if (!hmscoree)
6324 WARN("mscoree.dll not available\n");
6325 return FALSE;
6328 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6329 if (!pLoadLibraryShim)
6331 WARN("LoadLibraryShim not available\n");
6332 FreeLibrary(hmscoree);
6333 return FALSE;
6336 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6337 if (FAILED(hr))
6339 WARN("fusion.dll not available\n");
6340 FreeLibrary(hmscoree);
6341 return FALSE;
6344 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6346 FreeLibrary(hmscoree);
6347 return TRUE;
6350 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6351 LPWSTR path)
6353 IAssemblyCache *cache;
6354 MSIRECORD *uirow;
6355 HRESULT hr;
6356 UINT r = ERROR_FUNCTION_FAILED;
6358 TRACE("installing assembly: %s\n", debugstr_w(path));
6360 uirow = MSI_CreateRecord( 2 );
6361 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6362 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6363 msiobj_release( &uirow->hdr );
6365 if (assembly->feature)
6366 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6368 if (assembly->manifest)
6369 FIXME("Manifest unhandled\n");
6371 if (assembly->application)
6373 FIXME("Assembly should be privately installed\n");
6374 return ERROR_SUCCESS;
6377 if (assembly->attributes == msidbAssemblyAttributesWin32)
6379 FIXME("Win32 assemblies not handled\n");
6380 return ERROR_SUCCESS;
6383 hr = pCreateAssemblyCache(&cache, 0);
6384 if (FAILED(hr))
6385 goto done;
6387 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6388 if (FAILED(hr))
6389 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6391 r = ERROR_SUCCESS;
6393 done:
6394 IAssemblyCache_Release(cache);
6395 return r;
6398 typedef struct tagASSEMBLY_LIST
6400 MSIPACKAGE *package;
6401 IAssemblyCache *cache;
6402 struct list *assemblies;
6403 } ASSEMBLY_LIST;
6405 typedef struct tagASSEMBLY_NAME
6407 LPWSTR name;
6408 LPWSTR version;
6409 LPWSTR culture;
6410 LPWSTR pubkeytoken;
6411 } ASSEMBLY_NAME;
6413 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6415 ASSEMBLY_NAME *asmname = param;
6416 LPCWSTR name = MSI_RecordGetString(rec, 2);
6417 LPWSTR val = msi_dup_record_field(rec, 3);
6419 static const WCHAR Name[] = {'N','a','m','e',0};
6420 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6421 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6422 static const WCHAR PublicKeyToken[] = {
6423 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6425 if (!strcmpiW(name, Name))
6426 asmname->name = val;
6427 else if (!strcmpiW(name, Version))
6428 asmname->version = val;
6429 else if (!strcmpiW(name, Culture))
6430 asmname->culture = val;
6431 else if (!strcmpiW(name, PublicKeyToken))
6432 asmname->pubkeytoken = val;
6433 else
6434 msi_free(val);
6436 return ERROR_SUCCESS;
6439 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6441 if (!*str)
6443 *size = lstrlenW(append) + 1;
6444 *str = msi_alloc((*size) * sizeof(WCHAR));
6445 lstrcpyW(*str, append);
6446 return;
6449 (*size) += lstrlenW(append);
6450 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6451 lstrcatW(*str, append);
6454 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6456 static const WCHAR separator[] = {',',' ',0};
6457 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6458 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6459 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6460 static const WCHAR query[] = {
6461 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6462 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6463 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6464 '=','\'','%','s','\'',0};
6465 ASSEMBLY_NAME name;
6466 MSIQUERY *view;
6467 LPWSTR display_name;
6468 DWORD size;
6469 UINT r;
6471 display_name = NULL;
6472 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6474 r = MSI_OpenQuery( db, &view, query, comp->Component );
6475 if (r != ERROR_SUCCESS)
6476 return NULL;
6478 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6479 msiobj_release( &view->hdr );
6481 if (!name.name)
6483 ERR("No assembly name specified!\n");
6484 return NULL;
6487 append_str( &display_name, &size, name.name );
6489 if (name.version)
6491 append_str( &display_name, &size, separator );
6492 append_str( &display_name, &size, Version );
6493 append_str( &display_name, &size, name.version );
6495 if (name.culture)
6497 append_str( &display_name, &size, separator );
6498 append_str( &display_name, &size, Culture );
6499 append_str( &display_name, &size, name.culture );
6501 if (name.pubkeytoken)
6503 append_str( &display_name, &size, separator );
6504 append_str( &display_name, &size, PublicKeyToken );
6505 append_str( &display_name, &size, name.pubkeytoken );
6508 msi_free( name.name );
6509 msi_free( name.version );
6510 msi_free( name.culture );
6511 msi_free( name.pubkeytoken );
6513 return display_name;
6516 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6518 ASSEMBLY_INFO asminfo;
6519 LPWSTR disp;
6520 BOOL found = FALSE;
6521 HRESULT hr;
6523 disp = get_assembly_display_name( db, comp );
6524 if (!disp)
6525 return FALSE;
6527 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6528 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6530 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6531 if (SUCCEEDED(hr))
6532 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6534 msi_free( disp );
6535 return found;
6538 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6540 ASSEMBLY_LIST *list = param;
6541 MSIASSEMBLY *assembly;
6542 LPCWSTR component;
6544 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6545 if (!assembly)
6546 return ERROR_OUTOFMEMORY;
6548 component = MSI_RecordGetString(rec, 1);
6549 assembly->component = get_loaded_component(list->package, component);
6550 if (!assembly->component)
6551 return ERROR_SUCCESS;
6553 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6554 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6556 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6557 assembly->component->Action = assembly->component->Installed;
6558 return ERROR_SUCCESS;
6560 assembly->component->Action = assembly->component->ActionRequest;
6562 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6563 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6565 if (!assembly->file)
6567 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6568 return ERROR_FUNCTION_FAILED;
6571 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6572 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6573 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6575 if (assembly->application)
6577 WCHAR version[24];
6578 DWORD size = sizeof(version)/sizeof(WCHAR);
6580 /* FIXME: we should probably check the manifest file here */
6582 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6583 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6585 assembly->installed = TRUE;
6588 else
6589 assembly->installed = check_assembly_installed(list->package->db,
6590 list->cache,
6591 assembly->component);
6593 list_add_head(list->assemblies, &assembly->entry);
6594 return ERROR_SUCCESS;
6597 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6599 IAssemblyCache *cache = NULL;
6600 ASSEMBLY_LIST list;
6601 MSIQUERY *view;
6602 HRESULT hr;
6603 UINT r;
6605 static const WCHAR query[] =
6606 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6607 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6609 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6610 if (r != ERROR_SUCCESS)
6611 return ERROR_SUCCESS;
6613 hr = pCreateAssemblyCache(&cache, 0);
6614 if (FAILED(hr))
6615 return ERROR_FUNCTION_FAILED;
6617 list.package = package;
6618 list.cache = cache;
6619 list.assemblies = assemblies;
6621 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6622 msiobj_release(&view->hdr);
6624 IAssemblyCache_Release(cache);
6626 return r;
6629 static void free_assemblies(struct list *assemblies)
6631 struct list *item, *cursor;
6633 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6635 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6637 list_remove(&assembly->entry);
6638 msi_free(assembly->application);
6639 msi_free(assembly->manifest);
6640 msi_free(assembly->display_name);
6641 msi_free(assembly);
6645 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6647 MSIASSEMBLY *assembly;
6649 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6651 if (!lstrcmpW(assembly->file->File, file))
6653 *out = assembly;
6654 return TRUE;
6658 return FALSE;
6661 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6662 LPWSTR *path, DWORD *attrs, PVOID user)
6664 MSIASSEMBLY *assembly;
6665 WCHAR temppath[MAX_PATH];
6666 struct list *assemblies = user;
6667 UINT r;
6669 if (!find_assembly(assemblies, file, &assembly))
6670 return FALSE;
6672 GetTempPathW(MAX_PATH, temppath);
6673 PathAddBackslashW(temppath);
6674 lstrcatW(temppath, assembly->file->FileName);
6676 if (action == MSICABEXTRACT_BEGINEXTRACT)
6678 if (assembly->installed)
6679 return FALSE;
6681 *path = strdupW(temppath);
6682 *attrs = assembly->file->Attributes;
6684 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6686 assembly->installed = TRUE;
6688 r = install_assembly(package, assembly, temppath);
6689 if (r != ERROR_SUCCESS)
6690 ERR("Failed to install assembly\n");
6693 return TRUE;
6696 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6698 UINT r;
6699 struct list assemblies = LIST_INIT(assemblies);
6700 MSIASSEMBLY *assembly;
6701 MSIMEDIAINFO *mi;
6703 if (!init_functionpointers() || !pCreateAssemblyCache)
6704 return ERROR_FUNCTION_FAILED;
6706 r = load_assemblies(package, &assemblies);
6707 if (r != ERROR_SUCCESS)
6708 goto done;
6710 if (list_empty(&assemblies))
6711 goto done;
6713 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6714 if (!mi)
6716 r = ERROR_OUTOFMEMORY;
6717 goto done;
6720 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6722 if (assembly->installed && !mi->is_continuous)
6723 continue;
6725 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6726 (assembly->file->IsCompressed && !mi->is_extracted))
6728 MSICABDATA data;
6730 r = ready_media(package, assembly->file, mi);
6731 if (r != ERROR_SUCCESS)
6733 ERR("Failed to ready media\n");
6734 break;
6737 data.mi = mi;
6738 data.package = package;
6739 data.cb = installassembly_cb;
6740 data.user = &assemblies;
6742 if (assembly->file->IsCompressed &&
6743 !msi_cabextract(package, mi, &data))
6745 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6746 r = ERROR_FUNCTION_FAILED;
6747 break;
6751 if (!assembly->file->IsCompressed)
6753 LPWSTR source = resolve_file_source(package, assembly->file);
6755 r = install_assembly(package, assembly, source);
6756 if (r != ERROR_SUCCESS)
6757 ERR("Failed to install assembly\n");
6759 msi_free(source);
6762 /* FIXME: write Installer assembly reg values */
6765 done:
6766 free_assemblies(&assemblies);
6767 return r;
6770 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6772 LPWSTR key, template, id;
6773 UINT r = ERROR_SUCCESS;
6775 id = msi_dup_property( package, szProductID );
6776 if (id)
6778 msi_free( id );
6779 return ERROR_SUCCESS;
6781 template = msi_dup_property( package, szPIDTemplate );
6782 key = msi_dup_property( package, szPIDKEY );
6784 if (key && template)
6786 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6787 r = MSI_SetPropertyW( package, szProductID, key );
6789 msi_free( template );
6790 msi_free( key );
6791 return r;
6794 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6796 TRACE("\n");
6797 package->need_reboot = 1;
6798 return ERROR_SUCCESS;
6801 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6803 static const WCHAR szAvailableFreeReg[] =
6804 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6805 MSIRECORD *uirow;
6806 int space = msi_get_property_int( package, szAvailableFreeReg, 0 );
6808 TRACE("%p %d kilobytes\n", package, space);
6810 uirow = MSI_CreateRecord( 1 );
6811 MSI_RecordSetInteger( uirow, 1, space );
6812 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6813 msiobj_release( &uirow->hdr );
6815 return ERROR_SUCCESS;
6818 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6820 FIXME("%p\n", package);
6821 return ERROR_SUCCESS;
6824 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6826 FIXME("%p\n", package);
6827 return ERROR_SUCCESS;
6830 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6832 UINT r, count;
6833 MSIQUERY *view;
6835 static const WCHAR driver_query[] = {
6836 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6837 'O','D','B','C','D','r','i','v','e','r',0 };
6839 static const WCHAR translator_query[] = {
6840 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6841 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6843 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6844 if (r == ERROR_SUCCESS)
6846 count = 0;
6847 r = MSI_IterateRecords( view, &count, NULL, package );
6848 msiobj_release( &view->hdr );
6849 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6852 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6853 if (r == ERROR_SUCCESS)
6855 count = 0;
6856 r = MSI_IterateRecords( view, &count, NULL, package );
6857 msiobj_release( &view->hdr );
6858 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6861 return ERROR_SUCCESS;
6864 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6865 LPCSTR action, LPCWSTR table )
6867 static const WCHAR query[] = {
6868 'S','E','L','E','C','T',' ','*',' ',
6869 'F','R','O','M',' ','`','%','s','`',0 };
6870 MSIQUERY *view = NULL;
6871 DWORD count = 0;
6872 UINT r;
6874 r = MSI_OpenQuery( package->db, &view, query, table );
6875 if (r == ERROR_SUCCESS)
6877 r = MSI_IterateRecords(view, &count, NULL, package);
6878 msiobj_release(&view->hdr);
6881 if (count)
6882 FIXME("%s -> %u ignored %s table values\n",
6883 action, count, debugstr_w(table));
6885 return ERROR_SUCCESS;
6888 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6890 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6891 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6894 static UINT ACTION_BindImage( MSIPACKAGE *package )
6896 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6897 return msi_unimplemented_action_stub( package, "BindImage", table );
6900 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6902 static const WCHAR table[] = {
6903 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6904 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6907 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6909 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6910 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6913 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6915 static const WCHAR table[] = {
6916 'M','s','i','A','s','s','e','m','b','l','y',0 };
6917 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6920 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6922 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6923 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6926 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6928 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6929 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6932 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6934 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6935 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6938 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6940 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6941 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6944 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6946 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6947 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6950 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6952 static const WCHAR table[] = { 'M','I','M','E',0 };
6953 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6956 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6958 static const struct
6960 const WCHAR *action;
6961 UINT (*handler)(MSIPACKAGE *);
6963 StandardActions[] =
6965 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6966 { szAppSearch, ACTION_AppSearch },
6967 { szBindImage, ACTION_BindImage },
6968 { szCCPSearch, ACTION_CCPSearch },
6969 { szCostFinalize, ACTION_CostFinalize },
6970 { szCostInitialize, ACTION_CostInitialize },
6971 { szCreateFolders, ACTION_CreateFolders },
6972 { szCreateShortcuts, ACTION_CreateShortcuts },
6973 { szDeleteServices, ACTION_DeleteServices },
6974 { szDisableRollback, ACTION_DisableRollback },
6975 { szDuplicateFiles, ACTION_DuplicateFiles },
6976 { szExecuteAction, ACTION_ExecuteAction },
6977 { szFileCost, ACTION_FileCost },
6978 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6979 { szForceReboot, ACTION_ForceReboot },
6980 { szInstallAdminPackage, ACTION_InstallAdminPackage },
6981 { szInstallExecute, ACTION_InstallExecute },
6982 { szInstallExecuteAgain, ACTION_InstallExecute },
6983 { szInstallFiles, ACTION_InstallFiles},
6984 { szInstallFinalize, ACTION_InstallFinalize },
6985 { szInstallInitialize, ACTION_InstallInitialize },
6986 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6987 { szInstallValidate, ACTION_InstallValidate },
6988 { szIsolateComponents, ACTION_IsolateComponents },
6989 { szLaunchConditions, ACTION_LaunchConditions },
6990 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6991 { szMoveFiles, ACTION_MoveFiles },
6992 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6993 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6994 { szInstallODBC, ACTION_InstallODBC },
6995 { szInstallServices, ACTION_InstallServices },
6996 { szPatchFiles, ACTION_PatchFiles },
6997 { szProcessComponents, ACTION_ProcessComponents },
6998 { szPublishComponents, ACTION_PublishComponents },
6999 { szPublishFeatures, ACTION_PublishFeatures },
7000 { szPublishProduct, ACTION_PublishProduct },
7001 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7002 { szRegisterComPlus, ACTION_RegisterComPlus},
7003 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7004 { szRegisterFonts, ACTION_RegisterFonts },
7005 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7006 { szRegisterProduct, ACTION_RegisterProduct },
7007 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7008 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7009 { szRegisterUser, ACTION_RegisterUser },
7010 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7011 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7012 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7013 { szRemoveFiles, ACTION_RemoveFiles },
7014 { szRemoveFolders, ACTION_RemoveFolders },
7015 { szRemoveIniValues, ACTION_RemoveIniValues },
7016 { szRemoveODBC, ACTION_RemoveODBC },
7017 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7018 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7019 { szResolveSource, ACTION_ResolveSource },
7020 { szRMCCPSearch, ACTION_RMCCPSearch },
7021 { szScheduleReboot, ACTION_ScheduleReboot },
7022 { szSelfRegModules, ACTION_SelfRegModules },
7023 { szSelfUnregModules, ACTION_SelfUnregModules },
7024 { szSetODBCFolders, ACTION_SetODBCFolders },
7025 { szStartServices, ACTION_StartServices },
7026 { szStopServices, ACTION_StopServices },
7027 { szUnpublishComponents, ACTION_UnpublishComponents },
7028 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7029 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7030 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7031 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7032 { szUnregisterFonts, ACTION_UnregisterFonts },
7033 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7034 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7035 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7036 { szValidateProductID, ACTION_ValidateProductID },
7037 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7038 { szWriteIniValues, ACTION_WriteIniValues },
7039 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7040 { NULL, NULL },
7043 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7044 UINT* rc, BOOL force )
7046 BOOL ret = FALSE;
7047 BOOL run = force;
7048 int i;
7050 if (!run && !package->script->CurrentlyScripting)
7051 run = TRUE;
7053 if (!run)
7055 if (strcmpW(action,szInstallFinalize) == 0 ||
7056 strcmpW(action,szInstallExecute) == 0 ||
7057 strcmpW(action,szInstallExecuteAgain) == 0)
7058 run = TRUE;
7061 i = 0;
7062 while (StandardActions[i].action != NULL)
7064 if (strcmpW(StandardActions[i].action, action)==0)
7066 if (!run)
7068 ui_actioninfo(package, action, TRUE, 0);
7069 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7070 ui_actioninfo(package, action, FALSE, *rc);
7072 else
7074 ui_actionstart(package, action);
7075 if (StandardActions[i].handler)
7077 *rc = StandardActions[i].handler(package);
7079 else
7081 FIXME("unhandled standard action %s\n",debugstr_w(action));
7082 *rc = ERROR_SUCCESS;
7085 ret = TRUE;
7086 break;
7088 i++;
7090 return ret;
7093 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7095 UINT rc = ERROR_SUCCESS;
7096 BOOL handled;
7098 TRACE("Performing action (%s)\n", debugstr_w(action));
7100 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7102 if (!handled)
7103 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7105 if (!handled)
7107 WARN("unhandled msi action %s\n", debugstr_w(action));
7108 rc = ERROR_FUNCTION_NOT_CALLED;
7111 return rc;
7114 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7116 UINT rc = ERROR_SUCCESS;
7117 BOOL handled = FALSE;
7119 TRACE("Performing action (%s)\n", debugstr_w(action));
7121 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7123 if (!handled)
7124 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7126 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7127 handled = TRUE;
7129 if (!handled)
7131 WARN("unhandled msi action %s\n", debugstr_w(action));
7132 rc = ERROR_FUNCTION_NOT_CALLED;
7135 return rc;
7138 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7140 UINT rc = ERROR_SUCCESS;
7141 MSIRECORD *row;
7143 static const WCHAR ExecSeqQuery[] =
7144 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7145 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7146 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7147 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7148 static const WCHAR UISeqQuery[] =
7149 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7150 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7151 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7152 ' ', '=',' ','%','i',0};
7154 if (needs_ui_sequence(package))
7155 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7156 else
7157 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7159 if (row)
7161 LPCWSTR action, cond;
7163 TRACE("Running the actions\n");
7165 /* check conditions */
7166 cond = MSI_RecordGetString(row, 2);
7168 /* this is a hack to skip errors in the condition code */
7169 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7171 msiobj_release(&row->hdr);
7172 return ERROR_SUCCESS;
7175 action = MSI_RecordGetString(row, 1);
7176 if (!action)
7178 ERR("failed to fetch action\n");
7179 msiobj_release(&row->hdr);
7180 return ERROR_FUNCTION_FAILED;
7183 if (needs_ui_sequence(package))
7184 rc = ACTION_PerformUIAction(package, action, -1);
7185 else
7186 rc = ACTION_PerformAction(package, action, -1, FALSE);
7188 msiobj_release(&row->hdr);
7191 return rc;
7194 /****************************************************
7195 * TOP level entry points
7196 *****************************************************/
7198 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7199 LPCWSTR szCommandLine )
7201 UINT rc;
7202 BOOL ui_exists;
7204 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7205 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7207 MSI_SetPropertyW(package, szAction, szInstall);
7209 package->script->InWhatSequence = SEQUENCE_INSTALL;
7211 if (szPackagePath)
7213 LPWSTR p, dir;
7214 LPCWSTR file;
7216 dir = strdupW(szPackagePath);
7217 p = strrchrW(dir, '\\');
7218 if (p)
7220 *(++p) = 0;
7221 file = szPackagePath + (p - dir);
7223 else
7225 msi_free(dir);
7226 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7227 GetCurrentDirectoryW(MAX_PATH, dir);
7228 lstrcatW(dir, szBackSlash);
7229 file = szPackagePath;
7232 msi_free( package->PackagePath );
7233 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7234 if (!package->PackagePath)
7236 msi_free(dir);
7237 return ERROR_OUTOFMEMORY;
7240 lstrcpyW(package->PackagePath, dir);
7241 lstrcatW(package->PackagePath, file);
7242 msi_free(dir);
7244 msi_set_sourcedir_props(package, FALSE);
7247 msi_parse_command_line( package, szCommandLine, FALSE );
7249 msi_apply_transforms( package );
7250 msi_apply_patches( package );
7252 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
7254 TRACE("setting reinstall property\n");
7255 MSI_SetPropertyW( package, szReinstall, szAll );
7258 /* properties may have been added by a transform */
7259 msi_clone_properties( package );
7260 msi_set_context( package );
7262 if (needs_ui_sequence( package))
7264 package->script->InWhatSequence |= SEQUENCE_UI;
7265 rc = ACTION_ProcessUISequence(package);
7266 ui_exists = ui_sequence_exists(package);
7267 if (rc == ERROR_SUCCESS || !ui_exists)
7269 package->script->InWhatSequence |= SEQUENCE_EXEC;
7270 rc = ACTION_ProcessExecSequence(package, ui_exists);
7273 else
7274 rc = ACTION_ProcessExecSequence(package, FALSE);
7276 package->script->CurrentlyScripting = FALSE;
7278 /* process the ending type action */
7279 if (rc == ERROR_SUCCESS)
7280 ACTION_PerformActionSequence(package, -1);
7281 else if (rc == ERROR_INSTALL_USEREXIT)
7282 ACTION_PerformActionSequence(package, -2);
7283 else if (rc == ERROR_INSTALL_SUSPEND)
7284 ACTION_PerformActionSequence(package, -4);
7285 else /* failed */
7286 ACTION_PerformActionSequence(package, -3);
7288 /* finish up running custom actions */
7289 ACTION_FinishCustomActions(package);
7291 if (rc == ERROR_SUCCESS && package->need_reboot)
7292 return ERROR_SUCCESS_REBOOT_REQUIRED;
7294 return rc;