msi: Implement the UnregisterProgIdInfo standard action.
[wine.git] / dlls / msi / action.c
blob4f1be9aaa3472c0afa02d3eae901292926200b74
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 szUnregisterExtensionInfo[] =
162 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
163 static const WCHAR szUnregisterMIMEInfo[] =
164 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
165 static const WCHAR szUnregisterTypeLibraries[] =
166 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
167 static const WCHAR szValidateProductID[] =
168 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
169 static const WCHAR szWriteEnvironmentStrings[] =
170 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
172 /********************************************************
173 * helper functions
174 ********************************************************/
176 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
178 static const WCHAR Query_t[] =
179 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
180 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
181 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
182 ' ','\'','%','s','\'',0};
183 MSIRECORD * row;
185 row = MSI_QueryGetRecord( package->db, Query_t, action );
186 if (!row)
187 return;
188 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
189 msiobj_release(&row->hdr);
192 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
193 UINT rc)
195 MSIRECORD * row;
196 static const WCHAR template_s[]=
197 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
198 '%','s', '.',0};
199 static const WCHAR template_e[]=
200 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
201 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
202 '%','i','.',0};
203 static const WCHAR format[] =
204 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
205 WCHAR message[1024];
206 WCHAR timet[0x100];
208 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
209 if (start)
210 sprintfW(message,template_s,timet,action);
211 else
212 sprintfW(message,template_e,timet,action,rc);
214 row = MSI_CreateRecord(1);
215 MSI_RecordSetStringW(row,1,message);
217 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
218 msiobj_release(&row->hdr);
221 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
222 BOOL preserve_case )
224 LPCWSTR ptr,ptr2;
225 BOOL quote;
226 DWORD len;
227 LPWSTR prop = NULL, val = NULL;
229 if (!szCommandLine)
230 return ERROR_SUCCESS;
232 ptr = szCommandLine;
234 while (*ptr)
236 if (*ptr==' ')
238 ptr++;
239 continue;
242 TRACE("Looking at %s\n",debugstr_w(ptr));
244 ptr2 = strchrW(ptr,'=');
245 if (!ptr2)
247 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
248 break;
251 quote = FALSE;
253 len = ptr2-ptr;
254 prop = msi_alloc((len+1)*sizeof(WCHAR));
255 memcpy(prop,ptr,len*sizeof(WCHAR));
256 prop[len]=0;
258 if (!preserve_case)
259 struprW(prop);
261 ptr2++;
263 len = 0;
264 ptr = ptr2;
265 while (*ptr && (quote || (!quote && *ptr!=' ')))
267 if (*ptr == '"')
268 quote = !quote;
269 ptr++;
270 len++;
273 if (*ptr2=='"')
275 ptr2++;
276 len -= 2;
278 val = msi_alloc((len+1)*sizeof(WCHAR));
279 memcpy(val,ptr2,len*sizeof(WCHAR));
280 val[len] = 0;
282 if (lstrlenW(prop) > 0)
284 TRACE("Found commandline property (%s) = (%s)\n",
285 debugstr_w(prop), debugstr_w(val));
286 MSI_SetPropertyW(package,prop,val);
288 msi_free(val);
289 msi_free(prop);
292 return ERROR_SUCCESS;
296 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
298 LPCWSTR pc;
299 LPWSTR p, *ret = NULL;
300 UINT count = 0;
302 if (!str)
303 return ret;
305 /* count the number of substrings */
306 for ( pc = str, count = 0; pc; count++ )
308 pc = strchrW( pc, sep );
309 if (pc)
310 pc++;
313 /* allocate space for an array of substring pointers and the substrings */
314 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
315 (lstrlenW(str)+1) * sizeof(WCHAR) );
316 if (!ret)
317 return ret;
319 /* copy the string and set the pointers */
320 p = (LPWSTR) &ret[count+1];
321 lstrcpyW( p, str );
322 for( count = 0; (ret[count] = p); count++ )
324 p = strchrW( p, sep );
325 if (p)
326 *p++ = 0;
329 return ret;
332 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
334 static const WCHAR szSystemLanguageID[] =
335 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
337 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
338 UINT ret = ERROR_FUNCTION_FAILED;
340 prod_code = msi_dup_property( package, szProductCode );
341 patch_product = msi_get_suminfo_product( patch );
343 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
345 if ( strstrW( patch_product, prod_code ) )
347 MSISUMMARYINFO *si;
348 const WCHAR *p;
350 si = MSI_GetSummaryInformationW( patch, 0 );
351 if (!si)
353 ERR("no summary information!\n");
354 goto end;
357 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
358 if (!template)
360 ERR("no template property!\n");
361 msiobj_release( &si->hdr );
362 goto end;
365 if (!template[0])
367 ret = ERROR_SUCCESS;
368 msiobj_release( &si->hdr );
369 goto end;
372 langid = msi_dup_property( package, szSystemLanguageID );
373 if (!langid)
375 msiobj_release( &si->hdr );
376 goto end;
379 p = strchrW( template, ';' );
380 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
382 TRACE("applicable transform\n");
383 ret = ERROR_SUCCESS;
386 /* FIXME: check platform */
388 msiobj_release( &si->hdr );
391 end:
392 msi_free( patch_product );
393 msi_free( prod_code );
394 msi_free( template );
395 msi_free( langid );
397 return ret;
400 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
401 MSIDATABASE *patch_db, LPCWSTR name )
403 UINT ret = ERROR_FUNCTION_FAILED;
404 IStorage *stg = NULL;
405 HRESULT r;
407 TRACE("%p %s\n", package, debugstr_w(name) );
409 if (*name++ != ':')
411 ERR("expected a colon in %s\n", debugstr_w(name));
412 return ERROR_FUNCTION_FAILED;
415 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
416 if (SUCCEEDED(r))
418 ret = msi_check_transform_applicable( package, stg );
419 if (ret == ERROR_SUCCESS)
420 msi_table_apply_transform( package->db, stg );
421 else
422 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
423 IStorage_Release( stg );
425 else
426 ERR("failed to open substorage %s\n", debugstr_w(name));
428 return ERROR_SUCCESS;
431 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
433 LPWSTR guid_list, *guids, product_code;
434 UINT i, ret = ERROR_FUNCTION_FAILED;
436 product_code = msi_dup_property( package, szProductCode );
437 if (!product_code)
439 /* FIXME: the property ProductCode should be written into the DB somewhere */
440 ERR("no product code to check\n");
441 return ERROR_SUCCESS;
444 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
445 guids = msi_split_string( guid_list, ';' );
446 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
448 if (!lstrcmpW( guids[i], product_code ))
449 ret = ERROR_SUCCESS;
451 msi_free( guids );
452 msi_free( guid_list );
453 msi_free( product_code );
455 return ret;
458 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
460 MSIQUERY *view;
461 MSIRECORD *rec = NULL;
462 LPWSTR patch;
463 LPCWSTR prop;
464 UINT r;
466 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
467 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
468 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
469 '`','S','o','u','r','c','e','`',' ','I','S',' ',
470 'N','O','T',' ','N','U','L','L',0};
472 r = MSI_DatabaseOpenViewW(package->db, query, &view);
473 if (r != ERROR_SUCCESS)
474 return r;
476 r = MSI_ViewExecute(view, 0);
477 if (r != ERROR_SUCCESS)
478 goto done;
480 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
482 prop = MSI_RecordGetString(rec, 1);
483 patch = msi_dup_property(package, szPatch);
484 MSI_SetPropertyW(package, prop, patch);
485 msi_free(patch);
488 done:
489 if (rec) msiobj_release(&rec->hdr);
490 msiobj_release(&view->hdr);
492 return r;
495 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
497 MSISUMMARYINFO *si;
498 LPWSTR str, *substorage;
499 UINT i, r = ERROR_SUCCESS;
501 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
502 if (!si)
503 return ERROR_FUNCTION_FAILED;
505 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
507 TRACE("Patch not applicable\n");
508 return ERROR_SUCCESS;
511 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
512 if (!package->patch)
513 return ERROR_OUTOFMEMORY;
515 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
516 if (!package->patch->patchcode)
517 return ERROR_OUTOFMEMORY;
519 /* enumerate the substorage */
520 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
521 package->patch->transforms = str;
523 substorage = msi_split_string( str, ';' );
524 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
525 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
527 msi_free( substorage );
528 msiobj_release( &si->hdr );
530 msi_set_media_source_prop(package);
532 return r;
535 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
537 MSIDATABASE *patch_db = NULL;
538 UINT r;
540 TRACE("%p %s\n", package, debugstr_w( file ) );
542 /* FIXME:
543 * We probably want to make sure we only open a patch collection here.
544 * Patch collections (.msp) and databases (.msi) have different GUIDs
545 * but currently MSI_OpenDatabaseW will accept both.
547 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
548 if ( r != ERROR_SUCCESS )
550 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
551 return r;
554 msi_parse_patch_summary( package, patch_db );
557 * There might be a CAB file in the patch package,
558 * so append it to the list of storage to search for streams.
560 append_storage_to_db( package->db, patch_db->storage );
562 msiobj_release( &patch_db->hdr );
564 return ERROR_SUCCESS;
567 /* get the PATCH property, and apply all the patches it specifies */
568 static UINT msi_apply_patches( MSIPACKAGE *package )
570 LPWSTR patch_list, *patches;
571 UINT i, r = ERROR_SUCCESS;
573 patch_list = msi_dup_property( package, szPatch );
575 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
577 patches = msi_split_string( patch_list, ';' );
578 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
579 r = msi_apply_patch_package( package, patches[i] );
581 msi_free( patches );
582 msi_free( patch_list );
584 return r;
587 static UINT msi_apply_transforms( MSIPACKAGE *package )
589 static const WCHAR szTransforms[] = {
590 'T','R','A','N','S','F','O','R','M','S',0 };
591 LPWSTR xform_list, *xforms;
592 UINT i, r = ERROR_SUCCESS;
594 xform_list = msi_dup_property( package, szTransforms );
595 xforms = msi_split_string( xform_list, ';' );
597 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
599 if (xforms[i][0] == ':')
600 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
601 else
602 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
605 msi_free( xforms );
606 msi_free( xform_list );
608 return r;
611 static BOOL ui_sequence_exists( MSIPACKAGE *package )
613 MSIQUERY *view;
614 UINT rc;
616 static const WCHAR ExecSeqQuery [] =
617 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
618 '`','I','n','s','t','a','l','l',
619 'U','I','S','e','q','u','e','n','c','e','`',
620 ' ','W','H','E','R','E',' ',
621 '`','S','e','q','u','e','n','c','e','`',' ',
622 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
623 '`','S','e','q','u','e','n','c','e','`',0};
625 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
626 if (rc == ERROR_SUCCESS)
628 msiobj_release(&view->hdr);
629 return TRUE;
632 return FALSE;
635 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
637 LPWSTR p, db;
638 LPWSTR source, check;
639 DWORD len;
641 static const WCHAR szOriginalDatabase[] =
642 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
644 db = msi_dup_property( package, szOriginalDatabase );
645 if (!db)
646 return ERROR_OUTOFMEMORY;
648 p = strrchrW( db, '\\' );
649 if (!p)
651 p = strrchrW( db, '/' );
652 if (!p)
654 msi_free(db);
655 return ERROR_SUCCESS;
659 len = p - db + 2;
660 source = msi_alloc( len * sizeof(WCHAR) );
661 lstrcpynW( source, db, len );
663 check = msi_dup_property( package, cszSourceDir );
664 if (!check || replace)
665 MSI_SetPropertyW( package, cszSourceDir, source );
667 msi_free( check );
669 check = msi_dup_property( package, cszSOURCEDIR );
670 if (!check || replace)
671 MSI_SetPropertyW( package, cszSOURCEDIR, source );
673 msi_free( check );
674 msi_free( source );
675 msi_free( db );
677 return ERROR_SUCCESS;
680 static BOOL needs_ui_sequence(MSIPACKAGE *package)
682 INT level = msi_get_property_int(package, szUILevel, 0);
683 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
686 static UINT msi_set_context(MSIPACKAGE *package)
688 WCHAR val[10];
689 DWORD sz = 10;
690 DWORD num;
691 UINT r;
693 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
695 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
696 if (r == ERROR_SUCCESS)
698 num = atolW(val);
699 if (num == 1 || num == 2)
700 package->Context = MSIINSTALLCONTEXT_MACHINE;
703 return ERROR_SUCCESS;
706 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
708 UINT rc;
709 LPCWSTR cond, action;
710 MSIPACKAGE *package = param;
712 action = MSI_RecordGetString(row,1);
713 if (!action)
715 ERR("Error is retrieving action name\n");
716 return ERROR_FUNCTION_FAILED;
719 /* check conditions */
720 cond = MSI_RecordGetString(row,2);
722 /* this is a hack to skip errors in the condition code */
723 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
725 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
726 return ERROR_SUCCESS;
729 if (needs_ui_sequence(package))
730 rc = ACTION_PerformUIAction(package, action, -1);
731 else
732 rc = ACTION_PerformAction(package, action, -1, FALSE);
734 msi_dialog_check_messages( NULL );
736 if (package->CurrentInstallState != ERROR_SUCCESS)
737 rc = package->CurrentInstallState;
739 if (rc == ERROR_FUNCTION_NOT_CALLED)
740 rc = ERROR_SUCCESS;
742 if (rc != ERROR_SUCCESS)
743 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
745 return rc;
748 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
750 MSIQUERY * view;
751 UINT r;
752 static const WCHAR query[] =
753 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
754 '`','%','s','`',
755 ' ','W','H','E','R','E',' ',
756 '`','S','e','q','u','e','n','c','e','`',' ',
757 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
758 '`','S','e','q','u','e','n','c','e','`',0};
760 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
762 r = MSI_OpenQuery( package->db, &view, query, szTable );
763 if (r == ERROR_SUCCESS)
765 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
766 msiobj_release(&view->hdr);
769 return r;
772 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
774 MSIQUERY * view;
775 UINT rc;
776 static const WCHAR ExecSeqQuery[] =
777 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
778 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
779 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
780 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
781 'O','R','D','E','R',' ', 'B','Y',' ',
782 '`','S','e','q','u','e','n','c','e','`',0 };
783 static const WCHAR IVQuery[] =
784 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
785 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
786 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
787 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
788 ' ','\'', 'I','n','s','t','a','l','l',
789 'V','a','l','i','d','a','t','e','\'', 0};
790 INT seq = 0;
792 if (package->script->ExecuteSequenceRun)
794 TRACE("Execute Sequence already Run\n");
795 return ERROR_SUCCESS;
798 package->script->ExecuteSequenceRun = TRUE;
800 /* get the sequence number */
801 if (UIran)
803 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
804 if( !row )
805 return ERROR_FUNCTION_FAILED;
806 seq = MSI_RecordGetInteger(row,1);
807 msiobj_release(&row->hdr);
810 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
811 if (rc == ERROR_SUCCESS)
813 TRACE("Running the actions\n");
815 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
816 msiobj_release(&view->hdr);
819 return rc;
822 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
824 MSIQUERY * view;
825 UINT rc;
826 static const WCHAR ExecSeqQuery [] =
827 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
828 '`','I','n','s','t','a','l','l',
829 'U','I','S','e','q','u','e','n','c','e','`',
830 ' ','W','H','E','R','E',' ',
831 '`','S','e','q','u','e','n','c','e','`',' ',
832 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
833 '`','S','e','q','u','e','n','c','e','`',0};
835 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
836 if (rc == ERROR_SUCCESS)
838 TRACE("Running the actions\n");
840 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
841 msiobj_release(&view->hdr);
844 return rc;
847 /********************************************************
848 * ACTION helper functions and functions that perform the actions
849 *******************************************************/
850 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
851 UINT* rc, UINT script, BOOL force )
853 BOOL ret=FALSE;
854 UINT arc;
856 arc = ACTION_CustomAction(package, action, script, force);
858 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
860 *rc = arc;
861 ret = TRUE;
863 return ret;
867 * Actual Action Handlers
870 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
872 MSIPACKAGE *package = param;
873 LPCWSTR dir, component;
874 LPWSTR full_path;
875 MSIRECORD *uirow;
876 MSIFOLDER *folder;
877 MSICOMPONENT *comp;
879 component = MSI_RecordGetString(row, 2);
880 comp = get_loaded_component(package, component);
881 if (!comp)
882 return ERROR_SUCCESS;
884 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
886 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
887 comp->Action = comp->Installed;
888 return ERROR_SUCCESS;
890 comp->Action = INSTALLSTATE_LOCAL;
892 dir = MSI_RecordGetString(row,1);
893 if (!dir)
895 ERR("Unable to get folder id\n");
896 return ERROR_SUCCESS;
899 uirow = MSI_CreateRecord(1);
900 MSI_RecordSetStringW(uirow, 1, dir);
901 ui_actiondata(package, szCreateFolders, uirow);
902 msiobj_release(&uirow->hdr);
904 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
905 if (!full_path)
907 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
908 return ERROR_SUCCESS;
911 TRACE("Folder is %s\n",debugstr_w(full_path));
913 if (folder->State == 0)
914 create_full_pathW(full_path);
916 folder->State = 3;
918 msi_free(full_path);
919 return ERROR_SUCCESS;
922 /* FIXME: probably should merge this with the above function */
923 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
925 UINT rc = ERROR_SUCCESS;
926 MSIFOLDER *folder;
927 LPWSTR install_path;
929 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
930 if (!install_path)
931 return ERROR_FUNCTION_FAILED;
933 /* create the path */
934 if (folder->State == 0)
936 create_full_pathW(install_path);
937 folder->State = 2;
939 msi_free(install_path);
941 return rc;
944 UINT msi_create_component_directories( MSIPACKAGE *package )
946 MSICOMPONENT *comp;
948 /* create all the folders required by the components are going to install */
949 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
951 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
952 continue;
953 msi_create_directory( package, comp->Directory );
956 return ERROR_SUCCESS;
959 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
961 static const WCHAR ExecSeqQuery[] =
962 {'S','E','L','E','C','T',' ',
963 '`','D','i','r','e','c','t','o','r','y','_','`',
964 ' ','F','R','O','M',' ',
965 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
966 UINT rc;
967 MSIQUERY *view;
969 /* create all the empty folders specified in the CreateFolder table */
970 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
971 if (rc != ERROR_SUCCESS)
972 return ERROR_SUCCESS;
974 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
975 msiobj_release(&view->hdr);
977 return rc;
980 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
982 MSIPACKAGE *package = param;
983 LPCWSTR dir, component;
984 LPWSTR full_path;
985 MSIRECORD *uirow;
986 MSIFOLDER *folder;
987 MSICOMPONENT *comp;
989 component = MSI_RecordGetString(row, 2);
990 comp = get_loaded_component(package, component);
991 if (!comp)
992 return ERROR_SUCCESS;
994 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
996 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
997 comp->Action = comp->Installed;
998 return ERROR_SUCCESS;
1000 comp->Action = INSTALLSTATE_ABSENT;
1002 dir = MSI_RecordGetString( row, 1 );
1003 if (!dir)
1005 ERR("Unable to get folder id\n");
1006 return ERROR_SUCCESS;
1009 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1010 if (!full_path)
1012 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1013 return ERROR_SUCCESS;
1016 TRACE("folder is %s\n", debugstr_w(full_path));
1018 uirow = MSI_CreateRecord( 1 );
1019 MSI_RecordSetStringW( uirow, 1, full_path );
1020 ui_actiondata( package, szRemoveFolders, uirow );
1021 msiobj_release( &uirow->hdr );
1023 RemoveDirectoryW( full_path );
1024 folder->State = 0;
1026 msi_free( full_path );
1027 return ERROR_SUCCESS;
1030 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1032 static const WCHAR query[] =
1033 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1034 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1036 MSIQUERY *view;
1037 UINT rc;
1039 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1040 if (rc != ERROR_SUCCESS)
1041 return ERROR_SUCCESS;
1043 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1044 msiobj_release( &view->hdr );
1046 return rc;
1049 static UINT load_component( MSIRECORD *row, LPVOID param )
1051 MSIPACKAGE *package = param;
1052 MSICOMPONENT *comp;
1054 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1055 if (!comp)
1056 return ERROR_FUNCTION_FAILED;
1058 list_add_tail( &package->components, &comp->entry );
1060 /* fill in the data */
1061 comp->Component = msi_dup_record_field( row, 1 );
1063 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1065 comp->ComponentId = msi_dup_record_field( row, 2 );
1066 comp->Directory = msi_dup_record_field( row, 3 );
1067 comp->Attributes = MSI_RecordGetInteger(row,4);
1068 comp->Condition = msi_dup_record_field( row, 5 );
1069 comp->KeyPath = msi_dup_record_field( row, 6 );
1071 comp->Installed = INSTALLSTATE_UNKNOWN;
1072 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1074 return ERROR_SUCCESS;
1077 static UINT load_all_components( MSIPACKAGE *package )
1079 static const WCHAR query[] = {
1080 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1081 '`','C','o','m','p','o','n','e','n','t','`',0 };
1082 MSIQUERY *view;
1083 UINT r;
1085 if (!list_empty(&package->components))
1086 return ERROR_SUCCESS;
1088 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1089 if (r != ERROR_SUCCESS)
1090 return r;
1092 r = MSI_IterateRecords(view, NULL, load_component, package);
1093 msiobj_release(&view->hdr);
1094 return r;
1097 typedef struct {
1098 MSIPACKAGE *package;
1099 MSIFEATURE *feature;
1100 } _ilfs;
1102 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1104 ComponentList *cl;
1106 cl = msi_alloc( sizeof (*cl) );
1107 if ( !cl )
1108 return ERROR_NOT_ENOUGH_MEMORY;
1109 cl->component = comp;
1110 list_add_tail( &feature->Components, &cl->entry );
1112 return ERROR_SUCCESS;
1115 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1117 FeatureList *fl;
1119 fl = msi_alloc( sizeof(*fl) );
1120 if ( !fl )
1121 return ERROR_NOT_ENOUGH_MEMORY;
1122 fl->feature = child;
1123 list_add_tail( &parent->Children, &fl->entry );
1125 return ERROR_SUCCESS;
1128 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1130 _ilfs* ilfs = param;
1131 LPCWSTR component;
1132 MSICOMPONENT *comp;
1134 component = MSI_RecordGetString(row,1);
1136 /* check to see if the component is already loaded */
1137 comp = get_loaded_component( ilfs->package, component );
1138 if (!comp)
1140 ERR("unknown component %s\n", debugstr_w(component));
1141 return ERROR_FUNCTION_FAILED;
1144 add_feature_component( ilfs->feature, comp );
1145 comp->Enabled = TRUE;
1147 return ERROR_SUCCESS;
1150 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1152 MSIFEATURE *feature;
1154 if ( !name )
1155 return NULL;
1157 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1159 if ( !lstrcmpW( feature->Feature, name ) )
1160 return feature;
1163 return NULL;
1166 static UINT load_feature(MSIRECORD * row, LPVOID param)
1168 MSIPACKAGE* package = param;
1169 MSIFEATURE* feature;
1170 static const WCHAR Query1[] =
1171 {'S','E','L','E','C','T',' ',
1172 '`','C','o','m','p','o','n','e','n','t','_','`',
1173 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1174 'C','o','m','p','o','n','e','n','t','s','`',' ',
1175 'W','H','E','R','E',' ',
1176 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1177 MSIQUERY * view;
1178 UINT rc;
1179 _ilfs ilfs;
1181 /* fill in the data */
1183 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1184 if (!feature)
1185 return ERROR_NOT_ENOUGH_MEMORY;
1187 list_init( &feature->Children );
1188 list_init( &feature->Components );
1190 feature->Feature = msi_dup_record_field( row, 1 );
1192 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1194 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1195 feature->Title = msi_dup_record_field( row, 3 );
1196 feature->Description = msi_dup_record_field( row, 4 );
1198 if (!MSI_RecordIsNull(row,5))
1199 feature->Display = MSI_RecordGetInteger(row,5);
1201 feature->Level= MSI_RecordGetInteger(row,6);
1202 feature->Directory = msi_dup_record_field( row, 7 );
1203 feature->Attributes = MSI_RecordGetInteger(row,8);
1205 feature->Installed = INSTALLSTATE_UNKNOWN;
1206 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1208 list_add_tail( &package->features, &feature->entry );
1210 /* load feature components */
1212 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1213 if (rc != ERROR_SUCCESS)
1214 return ERROR_SUCCESS;
1216 ilfs.package = package;
1217 ilfs.feature = feature;
1219 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1220 msiobj_release(&view->hdr);
1222 return ERROR_SUCCESS;
1225 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1227 MSIPACKAGE* package = param;
1228 MSIFEATURE *parent, *child;
1230 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1231 if (!child)
1232 return ERROR_FUNCTION_FAILED;
1234 if (!child->Feature_Parent)
1235 return ERROR_SUCCESS;
1237 parent = find_feature_by_name( package, child->Feature_Parent );
1238 if (!parent)
1239 return ERROR_FUNCTION_FAILED;
1241 add_feature_child( parent, child );
1242 return ERROR_SUCCESS;
1245 static UINT load_all_features( MSIPACKAGE *package )
1247 static const WCHAR query[] = {
1248 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1249 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1250 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1251 MSIQUERY *view;
1252 UINT r;
1254 if (!list_empty(&package->features))
1255 return ERROR_SUCCESS;
1257 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1258 if (r != ERROR_SUCCESS)
1259 return r;
1261 r = MSI_IterateRecords( view, NULL, load_feature, package );
1262 if (r != ERROR_SUCCESS)
1263 return r;
1265 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1266 msiobj_release( &view->hdr );
1268 return r;
1271 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1273 if (!p)
1274 return p;
1275 p = strchrW(p, ch);
1276 if (!p)
1277 return p;
1278 *p = 0;
1279 return p+1;
1282 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1284 static const WCHAR query[] = {
1285 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1286 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1287 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1288 MSIQUERY *view = NULL;
1289 MSIRECORD *row = NULL;
1290 UINT r;
1292 TRACE("%s\n", debugstr_w(file->File));
1294 r = MSI_OpenQuery(package->db, &view, query, file->File);
1295 if (r != ERROR_SUCCESS)
1296 goto done;
1298 r = MSI_ViewExecute(view, NULL);
1299 if (r != ERROR_SUCCESS)
1300 goto done;
1302 r = MSI_ViewFetch(view, &row);
1303 if (r != ERROR_SUCCESS)
1304 goto done;
1306 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1307 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1308 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1309 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1310 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1312 done:
1313 if (view) msiobj_release(&view->hdr);
1314 if (row) msiobj_release(&row->hdr);
1315 return r;
1318 static UINT load_file(MSIRECORD *row, LPVOID param)
1320 MSIPACKAGE* package = param;
1321 LPCWSTR component;
1322 MSIFILE *file;
1324 /* fill in the data */
1326 file = msi_alloc_zero( sizeof (MSIFILE) );
1327 if (!file)
1328 return ERROR_NOT_ENOUGH_MEMORY;
1330 file->File = msi_dup_record_field( row, 1 );
1332 component = MSI_RecordGetString( row, 2 );
1333 file->Component = get_loaded_component( package, component );
1335 if (!file->Component)
1337 WARN("Component not found: %s\n", debugstr_w(component));
1338 msi_free(file->File);
1339 msi_free(file);
1340 return ERROR_SUCCESS;
1343 file->FileName = msi_dup_record_field( row, 3 );
1344 reduce_to_longfilename( file->FileName );
1346 file->ShortName = msi_dup_record_field( row, 3 );
1347 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1349 file->FileSize = MSI_RecordGetInteger( row, 4 );
1350 file->Version = msi_dup_record_field( row, 5 );
1351 file->Language = msi_dup_record_field( row, 6 );
1352 file->Attributes = MSI_RecordGetInteger( row, 7 );
1353 file->Sequence = MSI_RecordGetInteger( row, 8 );
1355 file->state = msifs_invalid;
1357 /* if the compressed bits are not set in the file attributes,
1358 * then read the information from the package word count property
1360 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1362 file->IsCompressed = FALSE;
1364 else if (file->Attributes &
1365 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1367 file->IsCompressed = TRUE;
1369 else if (file->Attributes & msidbFileAttributesNoncompressed)
1371 file->IsCompressed = FALSE;
1373 else
1375 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1378 load_file_hash(package, file);
1380 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1382 list_add_tail( &package->files, &file->entry );
1384 return ERROR_SUCCESS;
1387 static UINT load_all_files(MSIPACKAGE *package)
1389 MSIQUERY * view;
1390 UINT rc;
1391 static const WCHAR Query[] =
1392 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1393 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1394 '`','S','e','q','u','e','n','c','e','`', 0};
1396 if (!list_empty(&package->files))
1397 return ERROR_SUCCESS;
1399 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1400 if (rc != ERROR_SUCCESS)
1401 return ERROR_SUCCESS;
1403 rc = MSI_IterateRecords(view, NULL, load_file, package);
1404 msiobj_release(&view->hdr);
1406 return ERROR_SUCCESS;
1409 static UINT load_folder( MSIRECORD *row, LPVOID param )
1411 MSIPACKAGE *package = param;
1412 static WCHAR szEmpty[] = { 0 };
1413 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1414 MSIFOLDER *folder;
1416 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1417 if (!folder)
1418 return ERROR_NOT_ENOUGH_MEMORY;
1420 folder->Directory = msi_dup_record_field( row, 1 );
1422 TRACE("%s\n", debugstr_w(folder->Directory));
1424 p = msi_dup_record_field(row, 3);
1426 /* split src and target dir */
1427 tgt_short = p;
1428 src_short = folder_split_path( p, ':' );
1430 /* split the long and short paths */
1431 tgt_long = folder_split_path( tgt_short, '|' );
1432 src_long = folder_split_path( src_short, '|' );
1434 /* check for no-op dirs */
1435 if (!lstrcmpW(szDot, tgt_short))
1436 tgt_short = szEmpty;
1437 if (!lstrcmpW(szDot, src_short))
1438 src_short = szEmpty;
1440 if (!tgt_long)
1441 tgt_long = tgt_short;
1443 if (!src_short) {
1444 src_short = tgt_short;
1445 src_long = tgt_long;
1448 if (!src_long)
1449 src_long = src_short;
1451 /* FIXME: use the target short path too */
1452 folder->TargetDefault = strdupW(tgt_long);
1453 folder->SourceShortPath = strdupW(src_short);
1454 folder->SourceLongPath = strdupW(src_long);
1455 msi_free(p);
1457 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1458 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1459 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1461 folder->Parent = msi_dup_record_field( row, 2 );
1463 folder->Property = msi_dup_property( package, folder->Directory );
1465 list_add_tail( &package->folders, &folder->entry );
1467 TRACE("returning %p\n", folder);
1469 return ERROR_SUCCESS;
1472 static UINT load_all_folders( MSIPACKAGE *package )
1474 static const WCHAR query[] = {
1475 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1476 '`','D','i','r','e','c','t','o','r','y','`',0 };
1477 MSIQUERY *view;
1478 UINT r;
1480 if (!list_empty(&package->folders))
1481 return ERROR_SUCCESS;
1483 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1484 if (r != ERROR_SUCCESS)
1485 return r;
1487 r = MSI_IterateRecords(view, NULL, load_folder, package);
1488 msiobj_release(&view->hdr);
1489 return r;
1493 * I am not doing any of the costing functionality yet.
1494 * Mostly looking at doing the Component and Feature loading
1496 * The native MSI does A LOT of modification to tables here. Mostly adding
1497 * a lot of temporary columns to the Feature and Component tables.
1499 * note: Native msi also tracks the short filename. But I am only going to
1500 * track the long ones. Also looking at this directory table
1501 * it appears that the directory table does not get the parents
1502 * resolved base on property only based on their entries in the
1503 * directory table.
1505 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1507 static const WCHAR szCosting[] =
1508 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1510 MSI_SetPropertyW(package, szCosting, szZero);
1511 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1513 load_all_folders( package );
1514 load_all_components( package );
1515 load_all_features( package );
1516 load_all_files( package );
1518 return ERROR_SUCCESS;
1521 static UINT execute_script(MSIPACKAGE *package, UINT script )
1523 UINT i;
1524 UINT rc = ERROR_SUCCESS;
1526 TRACE("Executing Script %i\n",script);
1528 if (!package->script)
1530 ERR("no script!\n");
1531 return ERROR_FUNCTION_FAILED;
1534 for (i = 0; i < package->script->ActionCount[script]; i++)
1536 LPWSTR action;
1537 action = package->script->Actions[script][i];
1538 ui_actionstart(package, action);
1539 TRACE("Executing Action (%s)\n",debugstr_w(action));
1540 rc = ACTION_PerformAction(package, action, script, TRUE);
1541 if (rc != ERROR_SUCCESS)
1542 break;
1544 msi_free_action_script(package, script);
1545 return rc;
1548 static UINT ACTION_FileCost(MSIPACKAGE *package)
1550 return ERROR_SUCCESS;
1553 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1555 MSICOMPONENT *comp;
1556 INSTALLSTATE state;
1557 UINT r;
1559 state = MsiQueryProductStateW(package->ProductCode);
1561 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1563 if (!comp->ComponentId)
1564 continue;
1566 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1567 comp->Installed = INSTALLSTATE_ABSENT;
1568 else
1570 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1571 package->Context, comp->ComponentId,
1572 &comp->Installed);
1573 if (r != ERROR_SUCCESS)
1574 comp->Installed = INSTALLSTATE_ABSENT;
1579 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1581 MSIFEATURE *feature;
1582 INSTALLSTATE state;
1584 state = MsiQueryProductStateW(package->ProductCode);
1586 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1588 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1589 feature->Installed = INSTALLSTATE_ABSENT;
1590 else
1592 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1593 feature->Feature);
1598 static BOOL process_state_property(MSIPACKAGE* package, int level,
1599 LPCWSTR property, INSTALLSTATE state)
1601 LPWSTR override;
1602 MSIFEATURE *feature;
1604 override = msi_dup_property( package, property );
1605 if (!override)
1606 return FALSE;
1608 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1610 if (lstrcmpW(property, szRemove) &&
1611 (feature->Level <= 0 || feature->Level > level))
1612 continue;
1614 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1616 if (strcmpiW(override, szAll)==0)
1617 msi_feature_set_state(package, feature, state);
1618 else
1620 LPWSTR ptr = override;
1621 LPWSTR ptr2 = strchrW(override,',');
1623 while (ptr)
1625 int len = ptr2 - ptr;
1627 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1628 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1630 msi_feature_set_state(package, feature, state);
1631 break;
1633 if (ptr2)
1635 ptr=ptr2+1;
1636 ptr2 = strchrW(ptr,',');
1638 else
1639 break;
1643 msi_free(override);
1645 return TRUE;
1648 static BOOL process_overrides( MSIPACKAGE *package, int level )
1650 static const WCHAR szAddLocal[] =
1651 {'A','D','D','L','O','C','A','L',0};
1652 static const WCHAR szAddSource[] =
1653 {'A','D','D','S','O','U','R','C','E',0};
1654 static const WCHAR szAdvertise[] =
1655 {'A','D','V','E','R','T','I','S','E',0};
1656 BOOL ret = FALSE;
1658 /* all these activation/deactivation things happen in order and things
1659 * later on the list override things earlier on the list.
1661 * 0 INSTALLLEVEL processing
1662 * 1 ADDLOCAL
1663 * 2 REMOVE
1664 * 3 ADDSOURCE
1665 * 4 ADDDEFAULT
1666 * 5 REINSTALL
1667 * 6 ADVERTISE
1668 * 7 COMPADDLOCAL
1669 * 8 COMPADDSOURCE
1670 * 9 FILEADDLOCAL
1671 * 10 FILEADDSOURCE
1672 * 11 FILEADDDEFAULT
1674 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1675 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1676 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1677 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1678 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1680 if (ret)
1681 MSI_SetPropertyW( package, szPreselected, szOne );
1683 return ret;
1686 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1688 int level;
1689 static const WCHAR szlevel[] =
1690 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1691 MSICOMPONENT* component;
1692 MSIFEATURE *feature;
1694 TRACE("Checking Install Level\n");
1696 level = msi_get_property_int(package, szlevel, 1);
1698 if (!msi_get_property_int( package, szPreselected, 0 ))
1700 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1702 BOOL feature_state = ((feature->Level > 0) &&
1703 (feature->Level <= level));
1705 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1707 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1708 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1709 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1710 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1711 else
1712 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1716 /* disable child features of unselected parent features */
1717 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1719 FeatureList *fl;
1721 if (feature->Level > 0 && feature->Level <= level)
1722 continue;
1724 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1725 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1730 * now we want to enable or disable components base on feature
1733 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1735 ComponentList *cl;
1737 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1738 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1740 if (!feature->Level)
1741 continue;
1743 /* features with components that have compressed files are made local */
1744 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1746 if (cl->component->Enabled &&
1747 cl->component->ForceLocalState &&
1748 feature->Action == INSTALLSTATE_SOURCE)
1750 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1751 break;
1755 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1757 component = cl->component;
1759 if (!component->Enabled)
1760 continue;
1762 switch (feature->Action)
1764 case INSTALLSTATE_ABSENT:
1765 component->anyAbsent = 1;
1766 break;
1767 case INSTALLSTATE_ADVERTISED:
1768 component->hasAdvertiseFeature = 1;
1769 break;
1770 case INSTALLSTATE_SOURCE:
1771 component->hasSourceFeature = 1;
1772 break;
1773 case INSTALLSTATE_LOCAL:
1774 component->hasLocalFeature = 1;
1775 break;
1776 case INSTALLSTATE_DEFAULT:
1777 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1778 component->hasAdvertiseFeature = 1;
1779 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1780 component->hasSourceFeature = 1;
1781 else
1782 component->hasLocalFeature = 1;
1783 break;
1784 default:
1785 break;
1790 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1792 /* if the component isn't enabled, leave it alone */
1793 if (!component->Enabled)
1794 continue;
1796 /* check if it's local or source */
1797 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1798 (component->hasLocalFeature || component->hasSourceFeature))
1800 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1801 !component->ForceLocalState)
1802 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1803 else
1804 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1805 continue;
1808 /* if any feature is local, the component must be local too */
1809 if (component->hasLocalFeature)
1811 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1812 continue;
1815 if (component->hasSourceFeature)
1817 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1818 continue;
1821 if (component->hasAdvertiseFeature)
1823 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1824 continue;
1827 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1828 if (component->anyAbsent)
1829 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1832 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1834 if (component->Action == INSTALLSTATE_DEFAULT)
1836 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1837 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1840 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1841 debugstr_w(component->Component), component->Installed, component->Action);
1845 return ERROR_SUCCESS;
1848 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1850 MSIPACKAGE *package = param;
1851 LPCWSTR name;
1852 LPWSTR path;
1853 MSIFOLDER *f;
1855 name = MSI_RecordGetString(row,1);
1857 f = get_loaded_folder(package, name);
1858 if (!f) return ERROR_SUCCESS;
1860 /* reset the ResolvedTarget */
1861 msi_free(f->ResolvedTarget);
1862 f->ResolvedTarget = NULL;
1864 /* This helper function now does ALL the work */
1865 TRACE("Dir %s ...\n",debugstr_w(name));
1866 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1867 TRACE("resolves to %s\n",debugstr_w(path));
1868 msi_free(path);
1870 return ERROR_SUCCESS;
1873 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1875 MSIPACKAGE *package = param;
1876 LPCWSTR name;
1877 MSIFEATURE *feature;
1879 name = MSI_RecordGetString( row, 1 );
1881 feature = get_loaded_feature( package, name );
1882 if (!feature)
1883 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1884 else
1886 LPCWSTR Condition;
1887 Condition = MSI_RecordGetString(row,3);
1889 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1891 int level = MSI_RecordGetInteger(row,2);
1892 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1893 feature->Level = level;
1896 return ERROR_SUCCESS;
1899 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1901 static const WCHAR name_fmt[] =
1902 {'%','u','.','%','u','.','%','u','.','%','u',0};
1903 static const WCHAR name[] = {'\\',0};
1904 VS_FIXEDFILEINFO *lpVer;
1905 WCHAR filever[0x100];
1906 LPVOID version;
1907 DWORD versize;
1908 DWORD handle;
1909 UINT sz;
1911 TRACE("%s\n", debugstr_w(filename));
1913 versize = GetFileVersionInfoSizeW( filename, &handle );
1914 if (!versize)
1915 return NULL;
1917 version = msi_alloc( versize );
1918 GetFileVersionInfoW( filename, 0, versize, version );
1920 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1922 msi_free( version );
1923 return NULL;
1926 sprintfW( filever, name_fmt,
1927 HIWORD(lpVer->dwFileVersionMS),
1928 LOWORD(lpVer->dwFileVersionMS),
1929 HIWORD(lpVer->dwFileVersionLS),
1930 LOWORD(lpVer->dwFileVersionLS));
1932 msi_free( version );
1934 return strdupW( filever );
1937 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1939 LPWSTR file_version;
1940 MSIFILE *file;
1942 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1944 MSICOMPONENT* comp = file->Component;
1945 LPWSTR p;
1947 if (!comp)
1948 continue;
1950 if (file->IsCompressed)
1951 comp->ForceLocalState = TRUE;
1953 /* calculate target */
1954 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1956 msi_free(file->TargetPath);
1958 TRACE("file %s is named %s\n",
1959 debugstr_w(file->File), debugstr_w(file->FileName));
1961 file->TargetPath = build_directory_name(2, p, file->FileName);
1963 msi_free(p);
1965 TRACE("file %s resolves to %s\n",
1966 debugstr_w(file->File), debugstr_w(file->TargetPath));
1968 /* don't check files of components that aren't installed */
1969 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1970 comp->Installed == INSTALLSTATE_ABSENT)
1972 file->state = msifs_missing; /* assume files are missing */
1973 continue;
1976 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1978 file->state = msifs_missing;
1979 comp->Cost += file->FileSize;
1980 continue;
1983 if (file->Version &&
1984 (file_version = msi_get_disk_file_version( file->TargetPath )))
1986 TRACE("new %s old %s\n", debugstr_w(file->Version),
1987 debugstr_w(file_version));
1988 /* FIXME: seems like a bad way to compare version numbers */
1989 if (lstrcmpiW(file_version, file->Version)<0)
1991 file->state = msifs_overwrite;
1992 comp->Cost += file->FileSize;
1994 else
1995 file->state = msifs_present;
1996 msi_free( file_version );
1998 else
1999 file->state = msifs_present;
2002 return ERROR_SUCCESS;
2006 * A lot is done in this function aside from just the costing.
2007 * The costing needs to be implemented at some point but for now I am going
2008 * to focus on the directory building
2011 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2013 static const WCHAR ExecSeqQuery[] =
2014 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2015 '`','D','i','r','e','c','t','o','r','y','`',0};
2016 static const WCHAR ConditionQuery[] =
2017 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2018 '`','C','o','n','d','i','t','i','o','n','`',0};
2019 static const WCHAR szCosting[] =
2020 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2021 static const WCHAR szlevel[] =
2022 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2023 static const WCHAR szOutOfDiskSpace[] =
2024 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2025 MSICOMPONENT *comp;
2026 UINT rc = ERROR_SUCCESS;
2027 MSIQUERY * view;
2028 LPWSTR level;
2030 TRACE("Building Directory properties\n");
2032 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2033 if (rc == ERROR_SUCCESS)
2035 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2036 package);
2037 msiobj_release(&view->hdr);
2040 /* read components states from the registry */
2041 ACTION_GetComponentInstallStates(package);
2042 ACTION_GetFeatureInstallStates(package);
2044 TRACE("File calculations\n");
2045 msi_check_file_install_states( package );
2047 if (!process_overrides( package, msi_get_property_int( package, szlevel, 1 ) ))
2049 TRACE("Evaluating Condition Table\n");
2051 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2052 if (rc == ERROR_SUCCESS)
2054 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2055 msiobj_release( &view->hdr );
2058 TRACE("Enabling or Disabling Components\n");
2059 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2061 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2063 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2064 comp->Enabled = FALSE;
2066 else
2067 comp->Enabled = TRUE;
2071 MSI_SetPropertyW(package,szCosting,szOne);
2072 /* set default run level if not set */
2073 level = msi_dup_property( package, szlevel );
2074 if (!level)
2075 MSI_SetPropertyW(package,szlevel, szOne);
2076 msi_free(level);
2078 /* FIXME: check volume disk space */
2079 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2081 return MSI_SetFeatureStates(package);
2084 /* OK this value is "interpreted" and then formatted based on the
2085 first few characters */
2086 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2087 DWORD *size)
2089 LPSTR data = NULL;
2091 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2093 if (value[1]=='x')
2095 LPWSTR ptr;
2096 CHAR byte[5];
2097 LPWSTR deformated = NULL;
2098 int count;
2100 deformat_string(package, &value[2], &deformated);
2102 /* binary value type */
2103 ptr = deformated;
2104 *type = REG_BINARY;
2105 if (strlenW(ptr)%2)
2106 *size = (strlenW(ptr)/2)+1;
2107 else
2108 *size = strlenW(ptr)/2;
2110 data = msi_alloc(*size);
2112 byte[0] = '0';
2113 byte[1] = 'x';
2114 byte[4] = 0;
2115 count = 0;
2116 /* if uneven pad with a zero in front */
2117 if (strlenW(ptr)%2)
2119 byte[2]= '0';
2120 byte[3]= *ptr;
2121 ptr++;
2122 data[count] = (BYTE)strtol(byte,NULL,0);
2123 count ++;
2124 TRACE("Uneven byte count\n");
2126 while (*ptr)
2128 byte[2]= *ptr;
2129 ptr++;
2130 byte[3]= *ptr;
2131 ptr++;
2132 data[count] = (BYTE)strtol(byte,NULL,0);
2133 count ++;
2135 msi_free(deformated);
2137 TRACE("Data %i bytes(%i)\n",*size,count);
2139 else
2141 LPWSTR deformated;
2142 LPWSTR p;
2143 DWORD d = 0;
2144 deformat_string(package, &value[1], &deformated);
2146 *type=REG_DWORD;
2147 *size = sizeof(DWORD);
2148 data = msi_alloc(*size);
2149 p = deformated;
2150 if (*p == '-')
2151 p++;
2152 while (*p)
2154 if ( (*p < '0') || (*p > '9') )
2155 break;
2156 d *= 10;
2157 d += (*p - '0');
2158 p++;
2160 if (deformated[0] == '-')
2161 d = -d;
2162 *(LPDWORD)data = d;
2163 TRACE("DWORD %i\n",*(LPDWORD)data);
2165 msi_free(deformated);
2168 else
2170 static const WCHAR szMulti[] = {'[','~',']',0};
2171 LPCWSTR ptr;
2172 *type=REG_SZ;
2174 if (value[0]=='#')
2176 if (value[1]=='%')
2178 ptr = &value[2];
2179 *type=REG_EXPAND_SZ;
2181 else
2182 ptr = &value[1];
2184 else
2185 ptr=value;
2187 if (strstrW(value,szMulti))
2188 *type = REG_MULTI_SZ;
2190 /* remove initial delimiter */
2191 if (!strncmpW(value, szMulti, 3))
2192 ptr = value + 3;
2194 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2196 /* add double NULL terminator */
2197 if (*type == REG_MULTI_SZ)
2199 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2200 data = msi_realloc_zero(data, *size);
2203 return data;
2206 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2208 const WCHAR *ret;
2210 switch (root)
2212 case -1:
2213 if (msi_get_property_int( package, szAllUsers, 0 ))
2215 *root_key = HKEY_LOCAL_MACHINE;
2216 ret = szHLM;
2218 else
2220 *root_key = HKEY_CURRENT_USER;
2221 ret = szHCU;
2223 break;
2224 case 0:
2225 *root_key = HKEY_CLASSES_ROOT;
2226 ret = szHCR;
2227 break;
2228 case 1:
2229 *root_key = HKEY_CURRENT_USER;
2230 ret = szHCU;
2231 break;
2232 case 2:
2233 *root_key = HKEY_LOCAL_MACHINE;
2234 ret = szHLM;
2235 break;
2236 case 3:
2237 *root_key = HKEY_USERS;
2238 ret = szHU;
2239 break;
2240 default:
2241 ERR("Unknown root %i\n", root);
2242 return NULL;
2245 return ret;
2248 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2250 MSIPACKAGE *package = param;
2251 LPSTR value_data = NULL;
2252 HKEY root_key, hkey;
2253 DWORD type,size;
2254 LPWSTR deformated;
2255 LPCWSTR szRoot, component, name, key, value;
2256 MSICOMPONENT *comp;
2257 MSIRECORD * uirow;
2258 LPWSTR uikey;
2259 INT root;
2260 BOOL check_first = FALSE;
2261 UINT rc;
2263 ui_progress(package,2,0,0,0);
2265 value = NULL;
2266 key = NULL;
2267 uikey = NULL;
2268 name = NULL;
2270 component = MSI_RecordGetString(row, 6);
2271 comp = get_loaded_component(package,component);
2272 if (!comp)
2273 return ERROR_SUCCESS;
2275 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2277 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2278 comp->Action = comp->Installed;
2279 return ERROR_SUCCESS;
2281 comp->Action = INSTALLSTATE_LOCAL;
2283 name = MSI_RecordGetString(row, 4);
2284 if( MSI_RecordIsNull(row,5) && name )
2286 /* null values can have special meanings */
2287 if (name[0]=='-' && name[1] == 0)
2288 return ERROR_SUCCESS;
2289 else if ((name[0]=='+' && name[1] == 0) ||
2290 (name[0] == '*' && name[1] == 0))
2291 name = NULL;
2292 check_first = TRUE;
2295 root = MSI_RecordGetInteger(row,2);
2296 key = MSI_RecordGetString(row, 3);
2298 szRoot = get_root_key( package, root, &root_key );
2299 if (!szRoot)
2300 return ERROR_SUCCESS;
2302 deformat_string(package, key , &deformated);
2303 size = strlenW(deformated) + strlenW(szRoot) + 1;
2304 uikey = msi_alloc(size*sizeof(WCHAR));
2305 strcpyW(uikey,szRoot);
2306 strcatW(uikey,deformated);
2308 if (RegCreateKeyW( root_key, deformated, &hkey))
2310 ERR("Could not create key %s\n",debugstr_w(deformated));
2311 msi_free(deformated);
2312 msi_free(uikey);
2313 return ERROR_SUCCESS;
2315 msi_free(deformated);
2317 value = MSI_RecordGetString(row,5);
2318 if (value)
2319 value_data = parse_value(package, value, &type, &size);
2320 else
2322 value_data = (LPSTR)strdupW(szEmpty);
2323 size = sizeof(szEmpty);
2324 type = REG_SZ;
2327 deformat_string(package, name, &deformated);
2329 if (!check_first)
2331 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2332 debugstr_w(uikey));
2333 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2335 else
2337 DWORD sz = 0;
2338 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2339 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2341 TRACE("value %s of %s checked already exists\n",
2342 debugstr_w(deformated), debugstr_w(uikey));
2344 else
2346 TRACE("Checked and setting value %s of %s\n",
2347 debugstr_w(deformated), debugstr_w(uikey));
2348 if (deformated || size)
2349 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2352 RegCloseKey(hkey);
2354 uirow = MSI_CreateRecord(3);
2355 MSI_RecordSetStringW(uirow,2,deformated);
2356 MSI_RecordSetStringW(uirow,1,uikey);
2357 if (type == REG_SZ || type == REG_EXPAND_SZ)
2358 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2359 ui_actiondata(package,szWriteRegistryValues,uirow);
2360 msiobj_release( &uirow->hdr );
2362 msi_free(value_data);
2363 msi_free(deformated);
2364 msi_free(uikey);
2366 return ERROR_SUCCESS;
2369 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2371 UINT rc;
2372 MSIQUERY * view;
2373 static const WCHAR ExecSeqQuery[] =
2374 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2375 '`','R','e','g','i','s','t','r','y','`',0 };
2377 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2378 if (rc != ERROR_SUCCESS)
2379 return ERROR_SUCCESS;
2381 /* increment progress bar each time action data is sent */
2382 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2384 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2386 msiobj_release(&view->hdr);
2387 return rc;
2390 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2392 LONG res;
2393 HKEY hkey;
2394 DWORD num_subkeys, num_values;
2396 if (delete_key)
2398 if ((res = RegDeleteTreeW( hkey_root, key )))
2400 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2402 return;
2405 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2407 if ((res = RegDeleteValueW( hkey, value )))
2409 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2411 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2412 NULL, NULL, NULL, NULL );
2413 RegCloseKey( hkey );
2415 if (!res && !num_subkeys && !num_values)
2417 TRACE("Removing empty key %s\n", debugstr_w(key));
2418 RegDeleteKeyW( hkey_root, key );
2420 return;
2422 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2426 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2428 MSIPACKAGE *package = param;
2429 LPCWSTR component, name, key_str, root_key_str;
2430 LPWSTR deformated_key, deformated_name, ui_key_str;
2431 MSICOMPONENT *comp;
2432 MSIRECORD *uirow;
2433 BOOL delete_key = FALSE;
2434 HKEY hkey_root;
2435 UINT size;
2436 INT root;
2438 ui_progress( package, 2, 0, 0, 0 );
2440 component = MSI_RecordGetString( row, 6 );
2441 comp = get_loaded_component( package, component );
2442 if (!comp)
2443 return ERROR_SUCCESS;
2445 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2447 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2448 comp->Action = comp->Installed;
2449 return ERROR_SUCCESS;
2451 comp->Action = INSTALLSTATE_ABSENT;
2453 name = MSI_RecordGetString( row, 4 );
2454 if (MSI_RecordIsNull( row, 5 ) && name )
2456 if (name[0] == '+' && !name[1])
2457 return ERROR_SUCCESS;
2458 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2460 delete_key = TRUE;
2461 name = NULL;
2465 root = MSI_RecordGetInteger( row, 2 );
2466 key_str = MSI_RecordGetString( row, 3 );
2468 root_key_str = get_root_key( package, root, &hkey_root );
2469 if (!root_key_str)
2470 return ERROR_SUCCESS;
2472 deformat_string( package, key_str, &deformated_key );
2473 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2474 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2475 strcpyW( ui_key_str, root_key_str );
2476 strcatW( ui_key_str, deformated_key );
2478 deformat_string( package, name, &deformated_name );
2480 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2481 msi_free( deformated_key );
2483 uirow = MSI_CreateRecord( 2 );
2484 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2485 MSI_RecordSetStringW( uirow, 2, deformated_name );
2487 ui_actiondata( package, szRemoveRegistryValues, uirow );
2488 msiobj_release( &uirow->hdr );
2490 msi_free( ui_key_str );
2491 msi_free( deformated_name );
2492 return ERROR_SUCCESS;
2495 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2497 MSIPACKAGE *package = param;
2498 LPCWSTR component, name, key_str, root_key_str;
2499 LPWSTR deformated_key, deformated_name, ui_key_str;
2500 MSICOMPONENT *comp;
2501 MSIRECORD *uirow;
2502 BOOL delete_key = FALSE;
2503 HKEY hkey_root;
2504 UINT size;
2505 INT root;
2507 ui_progress( package, 2, 0, 0, 0 );
2509 component = MSI_RecordGetString( row, 5 );
2510 comp = get_loaded_component( package, component );
2511 if (!comp)
2512 return ERROR_SUCCESS;
2514 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2516 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2517 comp->Action = comp->Installed;
2518 return ERROR_SUCCESS;
2520 comp->Action = INSTALLSTATE_LOCAL;
2522 if ((name = MSI_RecordGetString( row, 4 )))
2524 if (name[0] == '-' && !name[1])
2526 delete_key = TRUE;
2527 name = NULL;
2531 root = MSI_RecordGetInteger( row, 2 );
2532 key_str = MSI_RecordGetString( row, 3 );
2534 root_key_str = get_root_key( package, root, &hkey_root );
2535 if (!root_key_str)
2536 return ERROR_SUCCESS;
2538 deformat_string( package, key_str, &deformated_key );
2539 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2540 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2541 strcpyW( ui_key_str, root_key_str );
2542 strcatW( ui_key_str, deformated_key );
2544 deformat_string( package, name, &deformated_name );
2546 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2547 msi_free( deformated_key );
2549 uirow = MSI_CreateRecord( 2 );
2550 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2551 MSI_RecordSetStringW( uirow, 2, deformated_name );
2553 ui_actiondata( package, szRemoveRegistryValues, uirow );
2554 msiobj_release( &uirow->hdr );
2556 msi_free( ui_key_str );
2557 msi_free( deformated_name );
2558 return ERROR_SUCCESS;
2561 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2563 UINT rc;
2564 MSIQUERY *view;
2565 static const WCHAR registry_query[] =
2566 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2567 '`','R','e','g','i','s','t','r','y','`',0 };
2568 static const WCHAR remove_registry_query[] =
2569 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2570 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2572 /* increment progress bar each time action data is sent */
2573 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2575 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2576 if (rc == ERROR_SUCCESS)
2578 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2579 msiobj_release( &view->hdr );
2580 if (rc != ERROR_SUCCESS)
2581 return rc;
2584 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2585 if (rc == ERROR_SUCCESS)
2587 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2588 msiobj_release( &view->hdr );
2589 if (rc != ERROR_SUCCESS)
2590 return rc;
2593 return ERROR_SUCCESS;
2596 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2598 package->script->CurrentlyScripting = TRUE;
2600 return ERROR_SUCCESS;
2604 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2606 MSICOMPONENT *comp;
2607 DWORD progress = 0;
2608 DWORD total = 0;
2609 static const WCHAR q1[]=
2610 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2611 '`','R','e','g','i','s','t','r','y','`',0};
2612 UINT rc;
2613 MSIQUERY * view;
2614 MSIFEATURE *feature;
2615 MSIFILE *file;
2617 TRACE("InstallValidate\n");
2619 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2620 if (rc == ERROR_SUCCESS)
2622 MSI_IterateRecords( view, &progress, NULL, package );
2623 msiobj_release( &view->hdr );
2624 total += progress * REG_PROGRESS_VALUE;
2627 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2628 total += COMPONENT_PROGRESS_VALUE;
2630 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2631 total += file->FileSize;
2633 ui_progress(package,0,total,0,0);
2635 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2637 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2638 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2639 feature->ActionRequest);
2642 return ERROR_SUCCESS;
2645 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2647 MSIPACKAGE* package = param;
2648 LPCWSTR cond = NULL;
2649 LPCWSTR message = NULL;
2650 UINT r;
2652 static const WCHAR title[]=
2653 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2655 cond = MSI_RecordGetString(row,1);
2657 r = MSI_EvaluateConditionW(package,cond);
2658 if (r == MSICONDITION_FALSE)
2660 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2662 LPWSTR deformated;
2663 message = MSI_RecordGetString(row,2);
2664 deformat_string(package,message,&deformated);
2665 MessageBoxW(NULL,deformated,title,MB_OK);
2666 msi_free(deformated);
2669 return ERROR_INSTALL_FAILURE;
2672 return ERROR_SUCCESS;
2675 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2677 UINT rc;
2678 MSIQUERY * view = NULL;
2679 static const WCHAR ExecSeqQuery[] =
2680 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2681 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2683 TRACE("Checking launch conditions\n");
2685 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2686 if (rc != ERROR_SUCCESS)
2687 return ERROR_SUCCESS;
2689 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2690 msiobj_release(&view->hdr);
2692 return rc;
2695 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2698 if (!cmp->KeyPath)
2699 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2701 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2703 MSIRECORD * row = 0;
2704 UINT root,len;
2705 LPWSTR deformated,buffer,deformated_name;
2706 LPCWSTR key,name;
2707 static const WCHAR ExecSeqQuery[] =
2708 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2709 '`','R','e','g','i','s','t','r','y','`',' ',
2710 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2711 ' ','=',' ' ,'\'','%','s','\'',0 };
2712 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2713 static const WCHAR fmt2[]=
2714 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2716 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2717 if (!row)
2718 return NULL;
2720 root = MSI_RecordGetInteger(row,2);
2721 key = MSI_RecordGetString(row, 3);
2722 name = MSI_RecordGetString(row, 4);
2723 deformat_string(package, key , &deformated);
2724 deformat_string(package, name, &deformated_name);
2726 len = strlenW(deformated) + 6;
2727 if (deformated_name)
2728 len+=strlenW(deformated_name);
2730 buffer = msi_alloc( len *sizeof(WCHAR));
2732 if (deformated_name)
2733 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2734 else
2735 sprintfW(buffer,fmt,root,deformated);
2737 msi_free(deformated);
2738 msi_free(deformated_name);
2739 msiobj_release(&row->hdr);
2741 return buffer;
2743 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2745 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2746 return NULL;
2748 else
2750 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2752 if (file)
2753 return strdupW( file->TargetPath );
2755 return NULL;
2758 static HKEY openSharedDLLsKey(void)
2760 HKEY hkey=0;
2761 static const WCHAR path[] =
2762 {'S','o','f','t','w','a','r','e','\\',
2763 'M','i','c','r','o','s','o','f','t','\\',
2764 'W','i','n','d','o','w','s','\\',
2765 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2766 'S','h','a','r','e','d','D','L','L','s',0};
2768 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2769 return hkey;
2772 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2774 HKEY hkey;
2775 DWORD count=0;
2776 DWORD type;
2777 DWORD sz = sizeof(count);
2778 DWORD rc;
2780 hkey = openSharedDLLsKey();
2781 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2782 if (rc != ERROR_SUCCESS)
2783 count = 0;
2784 RegCloseKey(hkey);
2785 return count;
2788 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2790 HKEY hkey;
2792 hkey = openSharedDLLsKey();
2793 if (count > 0)
2794 msi_reg_set_val_dword( hkey, path, count );
2795 else
2796 RegDeleteValueW(hkey,path);
2797 RegCloseKey(hkey);
2798 return count;
2802 * Return TRUE if the count should be written out and FALSE if not
2804 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2806 MSIFEATURE *feature;
2807 INT count = 0;
2808 BOOL write = FALSE;
2810 /* only refcount DLLs */
2811 if (comp->KeyPath == NULL ||
2812 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2813 comp->Attributes & msidbComponentAttributesODBCDataSource)
2814 write = FALSE;
2815 else
2817 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2818 write = (count > 0);
2820 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2821 write = TRUE;
2824 /* increment counts */
2825 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2827 ComponentList *cl;
2829 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2830 continue;
2832 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2834 if ( cl->component == comp )
2835 count++;
2839 /* decrement counts */
2840 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2842 ComponentList *cl;
2844 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2845 continue;
2847 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2849 if ( cl->component == comp )
2850 count--;
2854 /* ref count all the files in the component */
2855 if (write)
2857 MSIFILE *file;
2859 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2861 if (file->Component == comp)
2862 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2866 /* add a count for permanent */
2867 if (comp->Attributes & msidbComponentAttributesPermanent)
2868 count ++;
2870 comp->RefCount = count;
2872 if (write)
2873 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2876 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2878 WCHAR squished_pc[GUID_SIZE];
2879 WCHAR squished_cc[GUID_SIZE];
2880 UINT rc;
2881 MSICOMPONENT *comp;
2882 HKEY hkey;
2884 TRACE("\n");
2886 squash_guid(package->ProductCode,squished_pc);
2887 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2889 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2891 MSIRECORD * uirow;
2893 ui_progress(package,2,0,0,0);
2894 if (!comp->ComponentId)
2895 continue;
2897 squash_guid(comp->ComponentId,squished_cc);
2899 msi_free(comp->FullKeypath);
2900 comp->FullKeypath = resolve_keypath( package, comp );
2902 ACTION_RefCountComponent( package, comp );
2904 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2905 debugstr_w(comp->Component),
2906 debugstr_w(squished_cc),
2907 debugstr_w(comp->FullKeypath),
2908 comp->RefCount);
2910 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2911 comp->ActionRequest == INSTALLSTATE_SOURCE)
2913 if (!comp->FullKeypath)
2914 continue;
2916 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2917 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2918 &hkey, TRUE);
2919 else
2920 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2921 &hkey, TRUE);
2923 if (rc != ERROR_SUCCESS)
2924 continue;
2926 if (comp->Attributes & msidbComponentAttributesPermanent)
2928 static const WCHAR szPermKey[] =
2929 { '0','0','0','0','0','0','0','0','0','0','0','0',
2930 '0','0','0','0','0','0','0','0','0','0','0','0',
2931 '0','0','0','0','0','0','0','0',0 };
2933 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2936 if (comp->Action == INSTALLSTATE_LOCAL)
2937 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2938 else
2940 MSIFILE *file;
2941 MSIRECORD *row;
2942 LPWSTR ptr, ptr2;
2943 WCHAR source[MAX_PATH];
2944 WCHAR base[MAX_PATH];
2945 LPWSTR sourcepath;
2947 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2948 static const WCHAR query[] = {
2949 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2950 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2951 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2952 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2953 '`','D','i','s','k','I','d','`',0};
2955 file = get_loaded_file(package, comp->KeyPath);
2956 if (!file)
2957 continue;
2959 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2960 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2961 ptr2 = strrchrW(source, '\\') + 1;
2962 msiobj_release(&row->hdr);
2964 lstrcpyW(base, package->PackagePath);
2965 ptr = strrchrW(base, '\\');
2966 *(ptr + 1) = '\0';
2968 sourcepath = resolve_file_source(package, file);
2969 ptr = sourcepath + lstrlenW(base);
2970 lstrcpyW(ptr2, ptr);
2971 msi_free(sourcepath);
2973 msi_reg_set_val_str(hkey, squished_pc, source);
2975 RegCloseKey(hkey);
2977 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
2979 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2980 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2981 else
2982 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2984 comp->Action = comp->ActionRequest;
2986 /* UI stuff */
2987 uirow = MSI_CreateRecord(3);
2988 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2989 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2990 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2991 ui_actiondata(package,szProcessComponents,uirow);
2992 msiobj_release( &uirow->hdr );
2995 return ERROR_SUCCESS;
2998 typedef struct {
2999 CLSID clsid;
3000 LPWSTR source;
3002 LPWSTR path;
3003 ITypeLib *ptLib;
3004 } typelib_struct;
3006 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3007 LPWSTR lpszName, LONG_PTR lParam)
3009 TLIBATTR *attr;
3010 typelib_struct *tl_struct = (typelib_struct*) lParam;
3011 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3012 int sz;
3013 HRESULT res;
3015 if (!IS_INTRESOURCE(lpszName))
3017 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3018 return TRUE;
3021 sz = strlenW(tl_struct->source)+4;
3022 sz *= sizeof(WCHAR);
3024 if ((INT_PTR)lpszName == 1)
3025 tl_struct->path = strdupW(tl_struct->source);
3026 else
3028 tl_struct->path = msi_alloc(sz);
3029 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3032 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3033 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3034 if (FAILED(res))
3036 msi_free(tl_struct->path);
3037 tl_struct->path = NULL;
3039 return TRUE;
3042 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3043 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3045 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3046 return FALSE;
3049 msi_free(tl_struct->path);
3050 tl_struct->path = NULL;
3052 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3053 ITypeLib_Release(tl_struct->ptLib);
3055 return TRUE;
3058 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3060 MSIPACKAGE* package = param;
3061 LPCWSTR component;
3062 MSICOMPONENT *comp;
3063 MSIFILE *file;
3064 typelib_struct tl_struct;
3065 ITypeLib *tlib;
3066 HMODULE module;
3067 HRESULT hr;
3069 component = MSI_RecordGetString(row,3);
3070 comp = get_loaded_component(package,component);
3071 if (!comp)
3072 return ERROR_SUCCESS;
3074 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3076 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3077 comp->Action = comp->Installed;
3078 return ERROR_SUCCESS;
3080 comp->Action = INSTALLSTATE_LOCAL;
3082 file = get_loaded_file( package, comp->KeyPath );
3083 if (!file)
3084 return ERROR_SUCCESS;
3086 ui_actiondata( package, szRegisterTypeLibraries, row );
3088 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3089 if (module)
3091 LPCWSTR guid;
3092 guid = MSI_RecordGetString(row,1);
3093 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3094 tl_struct.source = strdupW( file->TargetPath );
3095 tl_struct.path = NULL;
3097 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3098 (LONG_PTR)&tl_struct);
3100 if (tl_struct.path)
3102 LPWSTR help = NULL;
3103 LPCWSTR helpid;
3104 HRESULT res;
3106 helpid = MSI_RecordGetString(row,6);
3108 if (helpid)
3109 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3110 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3111 msi_free(help);
3113 if (FAILED(res))
3114 ERR("Failed to register type library %s\n",
3115 debugstr_w(tl_struct.path));
3116 else
3117 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3119 ITypeLib_Release(tl_struct.ptLib);
3120 msi_free(tl_struct.path);
3122 else
3123 ERR("Failed to load type library %s\n",
3124 debugstr_w(tl_struct.source));
3126 FreeLibrary(module);
3127 msi_free(tl_struct.source);
3129 else
3131 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3132 if (FAILED(hr))
3134 ERR("Failed to load type library: %08x\n", hr);
3135 return ERROR_INSTALL_FAILURE;
3138 ITypeLib_Release(tlib);
3141 return ERROR_SUCCESS;
3144 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3147 * OK this is a bit confusing.. I am given a _Component key and I believe
3148 * that the file that is being registered as a type library is the "key file
3149 * of that component" which I interpret to mean "The file in the KeyPath of
3150 * that component".
3152 UINT rc;
3153 MSIQUERY * view;
3154 static const WCHAR Query[] =
3155 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3156 '`','T','y','p','e','L','i','b','`',0};
3158 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3159 if (rc != ERROR_SUCCESS)
3160 return ERROR_SUCCESS;
3162 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3163 msiobj_release(&view->hdr);
3164 return rc;
3167 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3169 MSIPACKAGE *package = param;
3170 LPCWSTR component, guid;
3171 MSICOMPONENT *comp;
3172 GUID libid;
3173 UINT version;
3174 LCID language;
3175 SYSKIND syskind;
3176 HRESULT hr;
3178 component = MSI_RecordGetString( row, 3 );
3179 comp = get_loaded_component( package, component );
3180 if (!comp)
3181 return ERROR_SUCCESS;
3183 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3185 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3186 comp->Action = comp->Installed;
3187 return ERROR_SUCCESS;
3189 comp->Action = INSTALLSTATE_ABSENT;
3191 ui_actiondata( package, szUnregisterTypeLibraries, row );
3193 guid = MSI_RecordGetString( row, 1 );
3194 CLSIDFromString( (LPCWSTR)guid, &libid );
3195 version = MSI_RecordGetInteger( row, 4 );
3196 language = MSI_RecordGetInteger( row, 2 );
3198 #ifdef _WIN64
3199 syskind = SYS_WIN64;
3200 #else
3201 syskind = SYS_WIN32;
3202 #endif
3204 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3205 if (FAILED(hr))
3207 WARN("Failed to unregister typelib: %08x\n", hr);
3210 return ERROR_SUCCESS;
3213 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3215 UINT rc;
3216 MSIQUERY *view;
3217 static const WCHAR query[] =
3218 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3219 '`','T','y','p','e','L','i','b','`',0};
3221 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3222 if (rc != ERROR_SUCCESS)
3223 return ERROR_SUCCESS;
3225 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3226 msiobj_release( &view->hdr );
3227 return rc;
3230 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3232 static const WCHAR szlnk[] = {'.','l','n','k',0};
3233 LPCWSTR directory, extension;
3234 LPWSTR link_folder, link_file, filename;
3236 directory = MSI_RecordGetString( row, 2 );
3237 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3239 /* may be needed because of a bug somewhere else */
3240 create_full_pathW( link_folder );
3242 filename = msi_dup_record_field( row, 3 );
3243 reduce_to_longfilename( filename );
3245 extension = strchrW( filename, '.' );
3246 if (!extension || strcmpiW( extension, szlnk ))
3248 int len = strlenW( filename );
3249 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3250 memcpy( filename + len, szlnk, sizeof(szlnk) );
3252 link_file = build_directory_name( 2, link_folder, filename );
3253 msi_free( link_folder );
3254 msi_free( filename );
3256 return link_file;
3259 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3261 MSIPACKAGE *package = param;
3262 LPWSTR link_file, deformated, path;
3263 LPCWSTR component, target;
3264 MSICOMPONENT *comp;
3265 IShellLinkW *sl = NULL;
3266 IPersistFile *pf = NULL;
3267 HRESULT res;
3269 component = MSI_RecordGetString(row, 4);
3270 comp = get_loaded_component(package, component);
3271 if (!comp)
3272 return ERROR_SUCCESS;
3274 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3276 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3277 comp->Action = comp->Installed;
3278 return ERROR_SUCCESS;
3280 comp->Action = INSTALLSTATE_LOCAL;
3282 ui_actiondata(package,szCreateShortcuts,row);
3284 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3285 &IID_IShellLinkW, (LPVOID *) &sl );
3287 if (FAILED( res ))
3289 ERR("CLSID_ShellLink not available\n");
3290 goto err;
3293 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3294 if (FAILED( res ))
3296 ERR("QueryInterface(IID_IPersistFile) failed\n");
3297 goto err;
3300 target = MSI_RecordGetString(row, 5);
3301 if (strchrW(target, '['))
3303 deformat_string(package, target, &deformated);
3304 IShellLinkW_SetPath(sl,deformated);
3305 msi_free(deformated);
3307 else
3309 FIXME("poorly handled shortcut format, advertised shortcut\n");
3310 IShellLinkW_SetPath(sl,comp->FullKeypath);
3313 if (!MSI_RecordIsNull(row,6))
3315 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3316 deformat_string(package, arguments, &deformated);
3317 IShellLinkW_SetArguments(sl,deformated);
3318 msi_free(deformated);
3321 if (!MSI_RecordIsNull(row,7))
3323 LPCWSTR description = MSI_RecordGetString(row, 7);
3324 IShellLinkW_SetDescription(sl, description);
3327 if (!MSI_RecordIsNull(row,8))
3328 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3330 if (!MSI_RecordIsNull(row,9))
3332 INT index;
3333 LPCWSTR icon = MSI_RecordGetString(row, 9);
3335 path = build_icon_path(package, icon);
3336 index = MSI_RecordGetInteger(row,10);
3338 /* no value means 0 */
3339 if (index == MSI_NULL_INTEGER)
3340 index = 0;
3342 IShellLinkW_SetIconLocation(sl, path, index);
3343 msi_free(path);
3346 if (!MSI_RecordIsNull(row,11))
3347 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3349 if (!MSI_RecordIsNull(row,12))
3351 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3352 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3353 if (path)
3354 IShellLinkW_SetWorkingDirectory(sl, path);
3355 msi_free(path);
3358 link_file = get_link_file(package, row);
3360 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3361 IPersistFile_Save(pf, link_file, FALSE);
3363 msi_free(link_file);
3365 err:
3366 if (pf)
3367 IPersistFile_Release( pf );
3368 if (sl)
3369 IShellLinkW_Release( sl );
3371 return ERROR_SUCCESS;
3374 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3376 UINT rc;
3377 HRESULT res;
3378 MSIQUERY * view;
3379 static const WCHAR Query[] =
3380 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3381 '`','S','h','o','r','t','c','u','t','`',0};
3383 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3384 if (rc != ERROR_SUCCESS)
3385 return ERROR_SUCCESS;
3387 res = CoInitialize( NULL );
3389 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3390 msiobj_release(&view->hdr);
3392 if (SUCCEEDED(res))
3393 CoUninitialize();
3395 return rc;
3398 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3400 MSIPACKAGE *package = param;
3401 LPWSTR link_file;
3402 LPCWSTR component;
3403 MSICOMPONENT *comp;
3405 component = MSI_RecordGetString( row, 4 );
3406 comp = get_loaded_component( package, component );
3407 if (!comp)
3408 return ERROR_SUCCESS;
3410 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3412 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3413 comp->Action = comp->Installed;
3414 return ERROR_SUCCESS;
3416 comp->Action = INSTALLSTATE_ABSENT;
3418 ui_actiondata( package, szRemoveShortcuts, row );
3420 link_file = get_link_file( package, row );
3422 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3423 if (!DeleteFileW( link_file ))
3425 WARN("Failed to remove shortcut file %u\n", GetLastError());
3427 msi_free( link_file );
3429 return ERROR_SUCCESS;
3432 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3434 UINT rc;
3435 MSIQUERY *view;
3436 static const WCHAR query[] =
3437 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3438 '`','S','h','o','r','t','c','u','t','`',0};
3440 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3441 if (rc != ERROR_SUCCESS)
3442 return ERROR_SUCCESS;
3444 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3445 msiobj_release( &view->hdr );
3447 return rc;
3450 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3452 MSIPACKAGE* package = param;
3453 HANDLE the_file;
3454 LPWSTR FilePath;
3455 LPCWSTR FileName;
3456 CHAR buffer[1024];
3457 DWORD sz;
3458 UINT rc;
3460 FileName = MSI_RecordGetString(row,1);
3461 if (!FileName)
3463 ERR("Unable to get FileName\n");
3464 return ERROR_SUCCESS;
3467 FilePath = build_icon_path(package,FileName);
3469 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3471 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3472 FILE_ATTRIBUTE_NORMAL, NULL);
3474 if (the_file == INVALID_HANDLE_VALUE)
3476 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3477 msi_free(FilePath);
3478 return ERROR_SUCCESS;
3483 DWORD write;
3484 sz = 1024;
3485 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3486 if (rc != ERROR_SUCCESS)
3488 ERR("Failed to get stream\n");
3489 CloseHandle(the_file);
3490 DeleteFileW(FilePath);
3491 break;
3493 WriteFile(the_file,buffer,sz,&write,NULL);
3494 } while (sz == 1024);
3496 msi_free(FilePath);
3497 CloseHandle(the_file);
3499 return ERROR_SUCCESS;
3502 static UINT msi_publish_icons(MSIPACKAGE *package)
3504 UINT r;
3505 MSIQUERY *view;
3507 static const WCHAR query[]= {
3508 'S','E','L','E','C','T',' ','*',' ',
3509 'F','R','O','M',' ','`','I','c','o','n','`',0};
3511 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3512 if (r == ERROR_SUCCESS)
3514 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3515 msiobj_release(&view->hdr);
3518 return ERROR_SUCCESS;
3521 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3523 UINT r;
3524 HKEY source;
3525 LPWSTR buffer;
3526 MSIMEDIADISK *disk;
3527 MSISOURCELISTINFO *info;
3529 r = RegCreateKeyW(hkey, szSourceList, &source);
3530 if (r != ERROR_SUCCESS)
3531 return r;
3533 RegCloseKey(source);
3535 buffer = strrchrW(package->PackagePath, '\\') + 1;
3536 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3537 package->Context, MSICODE_PRODUCT,
3538 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3539 if (r != ERROR_SUCCESS)
3540 return r;
3542 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3543 package->Context, MSICODE_PRODUCT,
3544 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3545 if (r != ERROR_SUCCESS)
3546 return r;
3548 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3549 package->Context, MSICODE_PRODUCT,
3550 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3551 if (r != ERROR_SUCCESS)
3552 return r;
3554 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3556 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3557 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3558 info->options, info->value);
3559 else
3560 MsiSourceListSetInfoW(package->ProductCode, NULL,
3561 info->context, info->options,
3562 info->property, info->value);
3565 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3567 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3568 disk->context, disk->options,
3569 disk->disk_id, disk->volume_label, disk->disk_prompt);
3572 return ERROR_SUCCESS;
3575 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3577 MSIHANDLE hdb, suminfo;
3578 WCHAR guids[MAX_PATH];
3579 WCHAR packcode[SQUISH_GUID_SIZE];
3580 LPWSTR buffer;
3581 LPWSTR ptr;
3582 DWORD langid;
3583 DWORD size;
3584 UINT r;
3586 static const WCHAR szProductLanguage[] =
3587 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3588 static const WCHAR szARPProductIcon[] =
3589 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3590 static const WCHAR szProductVersion[] =
3591 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3592 static const WCHAR szAssignment[] =
3593 {'A','s','s','i','g','n','m','e','n','t',0};
3594 static const WCHAR szAdvertiseFlags[] =
3595 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3596 static const WCHAR szClients[] =
3597 {'C','l','i','e','n','t','s',0};
3598 static const WCHAR szColon[] = {':',0};
3600 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3601 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3602 msi_free(buffer);
3604 langid = msi_get_property_int(package, szProductLanguage, 0);
3605 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3607 /* FIXME */
3608 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3610 buffer = msi_dup_property(package, szARPProductIcon);
3611 if (buffer)
3613 LPWSTR path = build_icon_path(package,buffer);
3614 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3615 msi_free(path);
3616 msi_free(buffer);
3619 buffer = msi_dup_property(package, szProductVersion);
3620 if (buffer)
3622 DWORD verdword = msi_version_str_to_dword(buffer);
3623 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3624 msi_free(buffer);
3627 msi_reg_set_val_dword(hkey, szAssignment, 0);
3628 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3629 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3630 msi_reg_set_val_str(hkey, szClients, szColon);
3632 hdb = alloc_msihandle(&package->db->hdr);
3633 if (!hdb)
3634 return ERROR_NOT_ENOUGH_MEMORY;
3636 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3637 MsiCloseHandle(hdb);
3638 if (r != ERROR_SUCCESS)
3639 goto done;
3641 size = MAX_PATH;
3642 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3643 NULL, guids, &size);
3644 if (r != ERROR_SUCCESS)
3645 goto done;
3647 ptr = strchrW(guids, ';');
3648 if (ptr) *ptr = 0;
3649 squash_guid(guids, packcode);
3650 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3652 done:
3653 MsiCloseHandle(suminfo);
3654 return ERROR_SUCCESS;
3657 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3659 UINT r;
3660 HKEY hkey;
3661 LPWSTR upgrade;
3662 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3664 static const WCHAR szUpgradeCode[] =
3665 {'U','p','g','r','a','d','e','C','o','d','e',0};
3667 upgrade = msi_dup_property(package, szUpgradeCode);
3668 if (!upgrade)
3669 return ERROR_SUCCESS;
3671 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3673 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3674 if (r != ERROR_SUCCESS)
3675 goto done;
3677 else
3679 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3680 if (r != ERROR_SUCCESS)
3681 goto done;
3684 squash_guid(package->ProductCode, squashed_pc);
3685 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3687 RegCloseKey(hkey);
3689 done:
3690 msi_free(upgrade);
3691 return r;
3694 static BOOL msi_check_publish(MSIPACKAGE *package)
3696 MSIFEATURE *feature;
3698 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3700 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3701 return TRUE;
3704 return FALSE;
3707 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3709 MSIFEATURE *feature;
3711 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3713 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3714 return FALSE;
3717 return TRUE;
3720 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3722 WCHAR patch_squashed[GUID_SIZE];
3723 HKEY patches;
3724 LONG res;
3725 UINT r = ERROR_FUNCTION_FAILED;
3727 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3728 &patches, NULL);
3729 if (res != ERROR_SUCCESS)
3730 return ERROR_FUNCTION_FAILED;
3732 squash_guid(package->patch->patchcode, patch_squashed);
3734 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3735 (const BYTE *)patch_squashed,
3736 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3737 if (res != ERROR_SUCCESS)
3738 goto done;
3740 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3741 (const BYTE *)package->patch->transforms,
3742 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3743 if (res == ERROR_SUCCESS)
3744 r = ERROR_SUCCESS;
3746 done:
3747 RegCloseKey(patches);
3748 return r;
3752 * 99% of the work done here is only done for
3753 * advertised installs. However this is where the
3754 * Icon table is processed and written out
3755 * so that is what I am going to do here.
3757 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3759 UINT rc;
3760 HKEY hukey = NULL, hudkey = NULL;
3761 MSIRECORD *uirow;
3763 /* FIXME: also need to publish if the product is in advertise mode */
3764 if (!msi_check_publish(package))
3765 return ERROR_SUCCESS;
3767 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3768 &hukey, TRUE);
3769 if (rc != ERROR_SUCCESS)
3770 goto end;
3772 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3773 NULL, &hudkey, TRUE);
3774 if (rc != ERROR_SUCCESS)
3775 goto end;
3777 rc = msi_publish_upgrade_code(package);
3778 if (rc != ERROR_SUCCESS)
3779 goto end;
3781 if (package->patch)
3783 rc = msi_publish_patch(package, hukey, hudkey);
3784 if (rc != ERROR_SUCCESS)
3785 goto end;
3788 rc = msi_publish_product_properties(package, hukey);
3789 if (rc != ERROR_SUCCESS)
3790 goto end;
3792 rc = msi_publish_sourcelist(package, hukey);
3793 if (rc != ERROR_SUCCESS)
3794 goto end;
3796 rc = msi_publish_icons(package);
3798 end:
3799 uirow = MSI_CreateRecord( 1 );
3800 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3801 ui_actiondata( package, szPublishProduct, uirow );
3802 msiobj_release( &uirow->hdr );
3804 RegCloseKey(hukey);
3805 RegCloseKey(hudkey);
3807 return rc;
3810 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3812 WCHAR *filename, *ptr, *folder, *ret;
3813 const WCHAR *dirprop;
3815 filename = msi_dup_record_field( row, 2 );
3816 if (filename && (ptr = strchrW( filename, '|' )))
3817 ptr++;
3818 else
3819 ptr = filename;
3821 dirprop = MSI_RecordGetString( row, 3 );
3822 if (dirprop)
3824 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3825 if (!folder)
3826 folder = msi_dup_property( package, dirprop );
3828 else
3829 folder = msi_dup_property( package, szWindowsFolder );
3831 if (!folder)
3833 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3834 msi_free( filename );
3835 return NULL;
3838 ret = build_directory_name( 2, folder, ptr );
3840 msi_free( filename );
3841 msi_free( folder );
3842 return ret;
3845 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3847 MSIPACKAGE *package = param;
3848 LPCWSTR component, section, key, value, identifier;
3849 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
3850 MSIRECORD * uirow;
3851 INT action;
3852 MSICOMPONENT *comp;
3854 component = MSI_RecordGetString(row, 8);
3855 comp = get_loaded_component(package,component);
3856 if (!comp)
3857 return ERROR_SUCCESS;
3859 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3861 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3862 comp->Action = comp->Installed;
3863 return ERROR_SUCCESS;
3865 comp->Action = INSTALLSTATE_LOCAL;
3867 identifier = MSI_RecordGetString(row,1);
3868 section = MSI_RecordGetString(row,4);
3869 key = MSI_RecordGetString(row,5);
3870 value = MSI_RecordGetString(row,6);
3871 action = MSI_RecordGetInteger(row,7);
3873 deformat_string(package,section,&deformated_section);
3874 deformat_string(package,key,&deformated_key);
3875 deformat_string(package,value,&deformated_value);
3877 fullname = get_ini_file_name(package, row);
3879 if (action == 0)
3881 TRACE("Adding value %s to section %s in %s\n",
3882 debugstr_w(deformated_key), debugstr_w(deformated_section),
3883 debugstr_w(fullname));
3884 WritePrivateProfileStringW(deformated_section, deformated_key,
3885 deformated_value, fullname);
3887 else if (action == 1)
3889 WCHAR returned[10];
3890 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3891 returned, 10, fullname);
3892 if (returned[0] == 0)
3894 TRACE("Adding value %s to section %s in %s\n",
3895 debugstr_w(deformated_key), debugstr_w(deformated_section),
3896 debugstr_w(fullname));
3898 WritePrivateProfileStringW(deformated_section, deformated_key,
3899 deformated_value, fullname);
3902 else if (action == 3)
3903 FIXME("Append to existing section not yet implemented\n");
3905 uirow = MSI_CreateRecord(4);
3906 MSI_RecordSetStringW(uirow,1,identifier);
3907 MSI_RecordSetStringW(uirow,2,deformated_section);
3908 MSI_RecordSetStringW(uirow,3,deformated_key);
3909 MSI_RecordSetStringW(uirow,4,deformated_value);
3910 ui_actiondata(package,szWriteIniValues,uirow);
3911 msiobj_release( &uirow->hdr );
3913 msi_free(fullname);
3914 msi_free(deformated_key);
3915 msi_free(deformated_value);
3916 msi_free(deformated_section);
3917 return ERROR_SUCCESS;
3920 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3922 UINT rc;
3923 MSIQUERY * view;
3924 static const WCHAR ExecSeqQuery[] =
3925 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3926 '`','I','n','i','F','i','l','e','`',0};
3928 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3929 if (rc != ERROR_SUCCESS)
3931 TRACE("no IniFile table\n");
3932 return ERROR_SUCCESS;
3935 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3936 msiobj_release(&view->hdr);
3937 return rc;
3940 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
3942 MSIPACKAGE *package = param;
3943 LPCWSTR component, section, key, value, identifier;
3944 LPWSTR deformated_section, deformated_key, deformated_value, filename;
3945 MSICOMPONENT *comp;
3946 MSIRECORD *uirow;
3947 INT action;
3949 component = MSI_RecordGetString( row, 8 );
3950 comp = get_loaded_component( package, component );
3951 if (!comp)
3952 return ERROR_SUCCESS;
3954 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3956 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3957 comp->Action = comp->Installed;
3958 return ERROR_SUCCESS;
3960 comp->Action = INSTALLSTATE_ABSENT;
3962 identifier = MSI_RecordGetString( row, 1 );
3963 section = MSI_RecordGetString( row, 4 );
3964 key = MSI_RecordGetString( row, 5 );
3965 value = MSI_RecordGetString( row, 6 );
3966 action = MSI_RecordGetInteger( row, 7 );
3968 deformat_string( package, section, &deformated_section );
3969 deformat_string( package, key, &deformated_key );
3970 deformat_string( package, value, &deformated_value );
3972 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
3974 filename = get_ini_file_name( package, row );
3976 TRACE("Removing key %s from section %s in %s\n",
3977 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
3979 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
3981 WARN("Unable to remove key %u\n", GetLastError());
3983 msi_free( filename );
3985 else
3986 FIXME("Unsupported action %d\n", action);
3989 uirow = MSI_CreateRecord( 4 );
3990 MSI_RecordSetStringW( uirow, 1, identifier );
3991 MSI_RecordSetStringW( uirow, 2, deformated_section );
3992 MSI_RecordSetStringW( uirow, 3, deformated_key );
3993 MSI_RecordSetStringW( uirow, 4, deformated_value );
3994 ui_actiondata( package, szRemoveIniValues, uirow );
3995 msiobj_release( &uirow->hdr );
3997 msi_free( deformated_key );
3998 msi_free( deformated_value );
3999 msi_free( deformated_section );
4000 return ERROR_SUCCESS;
4003 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4005 MSIPACKAGE *package = param;
4006 LPCWSTR component, section, key, value, identifier;
4007 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4008 MSICOMPONENT *comp;
4009 MSIRECORD *uirow;
4010 INT action;
4012 component = MSI_RecordGetString( row, 8 );
4013 comp = get_loaded_component( package, component );
4014 if (!comp)
4015 return ERROR_SUCCESS;
4017 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4019 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4020 comp->Action = comp->Installed;
4021 return ERROR_SUCCESS;
4023 comp->Action = INSTALLSTATE_LOCAL;
4025 identifier = MSI_RecordGetString( row, 1 );
4026 section = MSI_RecordGetString( row, 4 );
4027 key = MSI_RecordGetString( row, 5 );
4028 value = MSI_RecordGetString( row, 6 );
4029 action = MSI_RecordGetInteger( row, 7 );
4031 deformat_string( package, section, &deformated_section );
4032 deformat_string( package, key, &deformated_key );
4033 deformat_string( package, value, &deformated_value );
4035 if (action == msidbIniFileActionRemoveLine)
4037 filename = get_ini_file_name( package, row );
4039 TRACE("Removing key %s from section %s in %s\n",
4040 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4042 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4044 WARN("Unable to remove key %u\n", GetLastError());
4046 msi_free( filename );
4048 else
4049 FIXME("Unsupported action %d\n", action);
4051 uirow = MSI_CreateRecord( 4 );
4052 MSI_RecordSetStringW( uirow, 1, identifier );
4053 MSI_RecordSetStringW( uirow, 2, deformated_section );
4054 MSI_RecordSetStringW( uirow, 3, deformated_key );
4055 MSI_RecordSetStringW( uirow, 4, deformated_value );
4056 ui_actiondata( package, szRemoveIniValues, uirow );
4057 msiobj_release( &uirow->hdr );
4059 msi_free( deformated_key );
4060 msi_free( deformated_value );
4061 msi_free( deformated_section );
4062 return ERROR_SUCCESS;
4065 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4067 UINT rc;
4068 MSIQUERY *view;
4069 static const WCHAR query[] =
4070 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4071 '`','I','n','i','F','i','l','e','`',0};
4072 static const WCHAR remove_query[] =
4073 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4074 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4076 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4077 if (rc == ERROR_SUCCESS)
4079 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4080 msiobj_release( &view->hdr );
4081 if (rc != ERROR_SUCCESS)
4082 return rc;
4085 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4086 if (rc == ERROR_SUCCESS)
4088 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4089 msiobj_release( &view->hdr );
4090 if (rc != ERROR_SUCCESS)
4091 return rc;
4094 return ERROR_SUCCESS;
4097 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4099 MSIPACKAGE *package = param;
4100 LPCWSTR filename;
4101 LPWSTR FullName;
4102 MSIFILE *file;
4103 DWORD len;
4104 static const WCHAR ExeStr[] =
4105 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4106 static const WCHAR close[] = {'\"',0};
4107 STARTUPINFOW si;
4108 PROCESS_INFORMATION info;
4109 BOOL brc;
4110 MSIRECORD *uirow;
4111 LPWSTR uipath, p;
4113 memset(&si,0,sizeof(STARTUPINFOW));
4115 filename = MSI_RecordGetString(row,1);
4116 file = get_loaded_file( package, filename );
4118 if (!file)
4120 ERR("Unable to find file id %s\n",debugstr_w(filename));
4121 return ERROR_SUCCESS;
4124 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4126 FullName = msi_alloc(len*sizeof(WCHAR));
4127 strcpyW(FullName,ExeStr);
4128 strcatW( FullName, file->TargetPath );
4129 strcatW(FullName,close);
4131 TRACE("Registering %s\n",debugstr_w(FullName));
4132 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4133 &si, &info);
4135 if (brc)
4137 CloseHandle(info.hThread);
4138 msi_dialog_check_messages(info.hProcess);
4139 CloseHandle(info.hProcess);
4142 uirow = MSI_CreateRecord( 2 );
4143 MSI_RecordSetStringW( uirow, 1, filename );
4144 uipath = strdupW( file->TargetPath );
4145 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4146 MSI_RecordSetStringW( uirow, 2, uipath );
4147 ui_actiondata( package, szSelfRegModules, uirow );
4148 msiobj_release( &uirow->hdr );
4150 msi_free( FullName );
4151 msi_free( uipath );
4152 return ERROR_SUCCESS;
4155 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4157 UINT rc;
4158 MSIQUERY * view;
4159 static const WCHAR ExecSeqQuery[] =
4160 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4161 '`','S','e','l','f','R','e','g','`',0};
4163 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4164 if (rc != ERROR_SUCCESS)
4166 TRACE("no SelfReg table\n");
4167 return ERROR_SUCCESS;
4170 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4171 msiobj_release(&view->hdr);
4173 return ERROR_SUCCESS;
4176 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4178 static const WCHAR regsvr32[] =
4179 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4180 static const WCHAR close[] = {'\"',0};
4181 MSIPACKAGE *package = param;
4182 LPCWSTR filename;
4183 LPWSTR cmdline;
4184 MSIFILE *file;
4185 DWORD len;
4186 STARTUPINFOW si;
4187 PROCESS_INFORMATION pi;
4188 BOOL ret;
4189 MSIRECORD *uirow;
4190 LPWSTR uipath, p;
4192 memset( &si, 0, sizeof(STARTUPINFOW) );
4194 filename = MSI_RecordGetString( row, 1 );
4195 file = get_loaded_file( package, filename );
4197 if (!file)
4199 ERR("Unable to find file id %s\n", debugstr_w(filename));
4200 return ERROR_SUCCESS;
4203 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4205 cmdline = msi_alloc( len * sizeof(WCHAR) );
4206 strcpyW( cmdline, regsvr32 );
4207 strcatW( cmdline, file->TargetPath );
4208 strcatW( cmdline, close );
4210 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4212 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4213 if (ret)
4215 CloseHandle( pi.hThread );
4216 msi_dialog_check_messages( pi.hProcess );
4217 CloseHandle( pi.hProcess );
4220 uirow = MSI_CreateRecord( 2 );
4221 MSI_RecordSetStringW( uirow, 1, filename );
4222 uipath = strdupW( file->TargetPath );
4223 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4224 MSI_RecordSetStringW( uirow, 2, uipath );
4225 ui_actiondata( package, szSelfUnregModules, uirow );
4226 msiobj_release( &uirow->hdr );
4228 msi_free( cmdline );
4229 msi_free( uipath );
4230 return ERROR_SUCCESS;
4233 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4235 UINT rc;
4236 MSIQUERY *view;
4237 static const WCHAR query[] =
4238 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4239 '`','S','e','l','f','R','e','g','`',0};
4241 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4242 if (rc != ERROR_SUCCESS)
4244 TRACE("no SelfReg table\n");
4245 return ERROR_SUCCESS;
4248 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4249 msiobj_release( &view->hdr );
4251 return ERROR_SUCCESS;
4254 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4256 MSIFEATURE *feature;
4257 UINT rc;
4258 HKEY hkey = NULL, userdata = NULL;
4260 if (!msi_check_publish(package))
4261 return ERROR_SUCCESS;
4263 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4264 &hkey, TRUE);
4265 if (rc != ERROR_SUCCESS)
4266 goto end;
4268 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4269 &userdata, TRUE);
4270 if (rc != ERROR_SUCCESS)
4271 goto end;
4273 /* here the guids are base 85 encoded */
4274 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4276 ComponentList *cl;
4277 LPWSTR data = NULL;
4278 GUID clsid;
4279 INT size;
4280 BOOL absent = FALSE;
4281 MSIRECORD *uirow;
4283 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4284 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4285 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4287 size = 1;
4288 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4290 size += 21;
4292 if (feature->Feature_Parent)
4293 size += strlenW( feature->Feature_Parent )+2;
4295 data = msi_alloc(size * sizeof(WCHAR));
4297 data[0] = 0;
4298 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4300 MSICOMPONENT* component = cl->component;
4301 WCHAR buf[21];
4303 buf[0] = 0;
4304 if (component->ComponentId)
4306 TRACE("From %s\n",debugstr_w(component->ComponentId));
4307 CLSIDFromString(component->ComponentId, &clsid);
4308 encode_base85_guid(&clsid,buf);
4309 TRACE("to %s\n",debugstr_w(buf));
4310 strcatW(data,buf);
4314 if (feature->Feature_Parent)
4316 static const WCHAR sep[] = {'\2',0};
4317 strcatW(data,sep);
4318 strcatW(data,feature->Feature_Parent);
4321 msi_reg_set_val_str( userdata, feature->Feature, data );
4322 msi_free(data);
4324 size = 0;
4325 if (feature->Feature_Parent)
4326 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4327 if (!absent)
4329 size += sizeof(WCHAR);
4330 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4331 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4333 else
4335 size += 2*sizeof(WCHAR);
4336 data = msi_alloc(size);
4337 data[0] = 0x6;
4338 data[1] = 0;
4339 if (feature->Feature_Parent)
4340 strcpyW( &data[1], feature->Feature_Parent );
4341 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4342 (LPBYTE)data,size);
4343 msi_free(data);
4346 /* the UI chunk */
4347 uirow = MSI_CreateRecord( 1 );
4348 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4349 ui_actiondata( package, szPublishFeatures, uirow);
4350 msiobj_release( &uirow->hdr );
4351 /* FIXME: call ui_progress? */
4354 end:
4355 RegCloseKey(hkey);
4356 RegCloseKey(userdata);
4357 return rc;
4360 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4362 UINT r;
4363 HKEY hkey;
4364 MSIRECORD *uirow;
4366 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4368 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4369 &hkey, FALSE);
4370 if (r == ERROR_SUCCESS)
4372 RegDeleteValueW(hkey, feature->Feature);
4373 RegCloseKey(hkey);
4376 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4377 &hkey, FALSE);
4378 if (r == ERROR_SUCCESS)
4380 RegDeleteValueW(hkey, feature->Feature);
4381 RegCloseKey(hkey);
4384 uirow = MSI_CreateRecord( 1 );
4385 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4386 ui_actiondata( package, szUnpublishFeatures, uirow );
4387 msiobj_release( &uirow->hdr );
4389 return ERROR_SUCCESS;
4392 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4394 MSIFEATURE *feature;
4396 if (!msi_check_unpublish(package))
4397 return ERROR_SUCCESS;
4399 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4401 msi_unpublish_feature(package, feature);
4404 return ERROR_SUCCESS;
4407 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4409 LPWSTR prop, val, key;
4410 SYSTEMTIME systime;
4411 DWORD size, langid;
4412 WCHAR date[9];
4413 LPWSTR buffer;
4415 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4416 static const WCHAR szWindowsInstaller[] =
4417 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4418 static const WCHAR modpath_fmt[] =
4419 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4420 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4421 static const WCHAR szModifyPath[] =
4422 {'M','o','d','i','f','y','P','a','t','h',0};
4423 static const WCHAR szUninstallString[] =
4424 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4425 static const WCHAR szEstimatedSize[] =
4426 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4427 static const WCHAR szProductLanguage[] =
4428 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4429 static const WCHAR szProductVersion[] =
4430 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4431 static const WCHAR szProductName[] =
4432 {'P','r','o','d','u','c','t','N','a','m','e',0};
4433 static const WCHAR szDisplayName[] =
4434 {'D','i','s','p','l','a','y','N','a','m','e',0};
4435 static const WCHAR szDisplayVersion[] =
4436 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4437 static const WCHAR szManufacturer[] =
4438 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4440 static const LPCSTR propval[] = {
4441 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4442 "ARPCONTACT", "Contact",
4443 "ARPCOMMENTS", "Comments",
4444 "ProductName", "DisplayName",
4445 "ProductVersion", "DisplayVersion",
4446 "ARPHELPLINK", "HelpLink",
4447 "ARPHELPTELEPHONE", "HelpTelephone",
4448 "ARPINSTALLLOCATION", "InstallLocation",
4449 "SourceDir", "InstallSource",
4450 "Manufacturer", "Publisher",
4451 "ARPREADME", "Readme",
4452 "ARPSIZE", "Size",
4453 "ARPURLINFOABOUT", "URLInfoAbout",
4454 "ARPURLUPDATEINFO", "URLUpdateInfo",
4455 NULL,
4457 const LPCSTR *p = propval;
4459 while (*p)
4461 prop = strdupAtoW(*p++);
4462 key = strdupAtoW(*p++);
4463 val = msi_dup_property(package, prop);
4464 msi_reg_set_val_str(hkey, key, val);
4465 msi_free(val);
4466 msi_free(key);
4467 msi_free(prop);
4470 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4472 size = deformat_string(package, modpath_fmt, &buffer);
4473 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4474 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4475 msi_free(buffer);
4477 /* FIXME: Write real Estimated Size when we have it */
4478 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4480 buffer = msi_dup_property(package, szProductName);
4481 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4482 msi_free(buffer);
4484 buffer = msi_dup_property(package, cszSourceDir);
4485 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4486 msi_free(buffer);
4488 buffer = msi_dup_property(package, szManufacturer);
4489 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4490 msi_free(buffer);
4492 GetLocalTime(&systime);
4493 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4494 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4496 langid = msi_get_property_int(package, szProductLanguage, 0);
4497 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4499 buffer = msi_dup_property(package, szProductVersion);
4500 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4501 if (buffer)
4503 DWORD verdword = msi_version_str_to_dword(buffer);
4505 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4506 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4507 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4508 msi_free(buffer);
4511 return ERROR_SUCCESS;
4514 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4516 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4517 MSIRECORD *uirow;
4518 LPWSTR upgrade_code;
4519 HKEY hkey, props;
4520 HKEY upgrade;
4521 UINT rc;
4523 static const WCHAR szUpgradeCode[] = {
4524 'U','p','g','r','a','d','e','C','o','d','e',0};
4526 /* FIXME: also need to publish if the product is in advertise mode */
4527 if (!msi_check_publish(package))
4528 return ERROR_SUCCESS;
4530 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4531 if (rc != ERROR_SUCCESS)
4532 return rc;
4534 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4535 NULL, &props, TRUE);
4536 if (rc != ERROR_SUCCESS)
4537 goto done;
4539 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4540 msi_free( package->db->localfile );
4541 package->db->localfile = NULL;
4543 rc = msi_publish_install_properties(package, hkey);
4544 if (rc != ERROR_SUCCESS)
4545 goto done;
4547 rc = msi_publish_install_properties(package, props);
4548 if (rc != ERROR_SUCCESS)
4549 goto done;
4551 upgrade_code = msi_dup_property(package, szUpgradeCode);
4552 if (upgrade_code)
4554 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4555 squash_guid(package->ProductCode, squashed_pc);
4556 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4557 RegCloseKey(upgrade);
4558 msi_free(upgrade_code);
4561 done:
4562 uirow = MSI_CreateRecord( 1 );
4563 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4564 ui_actiondata( package, szRegisterProduct, uirow );
4565 msiobj_release( &uirow->hdr );
4567 RegCloseKey(hkey);
4568 return ERROR_SUCCESS;
4571 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4573 return execute_script(package,INSTALL_SCRIPT);
4576 static UINT msi_unpublish_product(MSIPACKAGE *package)
4578 LPWSTR upgrade;
4579 LPWSTR remove = NULL;
4580 LPWSTR *features = NULL;
4581 BOOL full_uninstall = TRUE;
4582 MSIFEATURE *feature;
4584 static const WCHAR szUpgradeCode[] =
4585 {'U','p','g','r','a','d','e','C','o','d','e',0};
4587 remove = msi_dup_property(package, szRemove);
4588 if (!remove)
4589 return ERROR_SUCCESS;
4591 features = msi_split_string(remove, ',');
4592 if (!features)
4594 msi_free(remove);
4595 ERR("REMOVE feature list is empty!\n");
4596 return ERROR_FUNCTION_FAILED;
4599 if (!lstrcmpW(features[0], szAll))
4600 full_uninstall = TRUE;
4601 else
4603 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4605 if (feature->Action != INSTALLSTATE_ABSENT)
4606 full_uninstall = FALSE;
4610 if (!full_uninstall)
4611 goto done;
4613 MSIREG_DeleteProductKey(package->ProductCode);
4614 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4615 MSIREG_DeleteUninstallKey(package->ProductCode);
4617 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4619 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4620 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4622 else
4624 MSIREG_DeleteUserProductKey(package->ProductCode);
4625 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4628 upgrade = msi_dup_property(package, szUpgradeCode);
4629 if (upgrade)
4631 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4632 msi_free(upgrade);
4635 done:
4636 msi_free(remove);
4637 msi_free(features);
4638 return ERROR_SUCCESS;
4641 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4643 UINT rc;
4645 rc = msi_unpublish_product(package);
4646 if (rc != ERROR_SUCCESS)
4647 return rc;
4649 /* turn off scheduling */
4650 package->script->CurrentlyScripting= FALSE;
4652 /* first do the same as an InstallExecute */
4653 rc = ACTION_InstallExecute(package);
4654 if (rc != ERROR_SUCCESS)
4655 return rc;
4657 /* then handle Commit Actions */
4658 rc = execute_script(package,COMMIT_SCRIPT);
4660 return rc;
4663 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4665 static const WCHAR RunOnce[] = {
4666 'S','o','f','t','w','a','r','e','\\',
4667 'M','i','c','r','o','s','o','f','t','\\',
4668 'W','i','n','d','o','w','s','\\',
4669 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4670 'R','u','n','O','n','c','e',0};
4671 static const WCHAR InstallRunOnce[] = {
4672 'S','o','f','t','w','a','r','e','\\',
4673 'M','i','c','r','o','s','o','f','t','\\',
4674 'W','i','n','d','o','w','s','\\',
4675 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4676 'I','n','s','t','a','l','l','e','r','\\',
4677 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4679 static const WCHAR msiexec_fmt[] = {
4680 '%','s',
4681 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4682 '\"','%','s','\"',0};
4683 static const WCHAR install_fmt[] = {
4684 '/','I',' ','\"','%','s','\"',' ',
4685 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4686 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4687 WCHAR buffer[256], sysdir[MAX_PATH];
4688 HKEY hkey;
4689 WCHAR squished_pc[100];
4691 squash_guid(package->ProductCode,squished_pc);
4693 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4694 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4695 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4696 squished_pc);
4698 msi_reg_set_val_str( hkey, squished_pc, buffer );
4699 RegCloseKey(hkey);
4701 TRACE("Reboot command %s\n",debugstr_w(buffer));
4703 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4704 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4706 msi_reg_set_val_str( hkey, squished_pc, buffer );
4707 RegCloseKey(hkey);
4709 return ERROR_INSTALL_SUSPEND;
4712 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4714 DWORD attrib;
4715 UINT rc;
4718 * We are currently doing what should be done here in the top level Install
4719 * however for Administrative and uninstalls this step will be needed
4721 if (!package->PackagePath)
4722 return ERROR_SUCCESS;
4724 msi_set_sourcedir_props(package, TRUE);
4726 attrib = GetFileAttributesW(package->db->path);
4727 if (attrib == INVALID_FILE_ATTRIBUTES)
4729 LPWSTR prompt;
4730 LPWSTR msg;
4731 DWORD size = 0;
4733 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4734 package->Context, MSICODE_PRODUCT,
4735 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4736 if (rc == ERROR_MORE_DATA)
4738 prompt = msi_alloc(size * sizeof(WCHAR));
4739 MsiSourceListGetInfoW(package->ProductCode, NULL,
4740 package->Context, MSICODE_PRODUCT,
4741 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4743 else
4744 prompt = strdupW(package->db->path);
4746 msg = generate_error_string(package,1302,1,prompt);
4747 while(attrib == INVALID_FILE_ATTRIBUTES)
4749 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4750 if (rc == IDCANCEL)
4752 rc = ERROR_INSTALL_USEREXIT;
4753 break;
4755 attrib = GetFileAttributesW(package->db->path);
4757 msi_free(prompt);
4758 rc = ERROR_SUCCESS;
4760 else
4761 return ERROR_SUCCESS;
4763 return rc;
4766 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4768 HKEY hkey = 0;
4769 LPWSTR buffer, productid = NULL;
4770 UINT i, rc = ERROR_SUCCESS;
4771 MSIRECORD *uirow;
4773 static const WCHAR szPropKeys[][80] =
4775 {'P','r','o','d','u','c','t','I','D',0},
4776 {'U','S','E','R','N','A','M','E',0},
4777 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4778 {0},
4781 static const WCHAR szRegKeys[][80] =
4783 {'P','r','o','d','u','c','t','I','D',0},
4784 {'R','e','g','O','w','n','e','r',0},
4785 {'R','e','g','C','o','m','p','a','n','y',0},
4786 {0},
4789 if (msi_check_unpublish(package))
4791 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4792 goto end;
4795 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4796 if (!productid)
4797 goto end;
4799 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4800 NULL, &hkey, TRUE);
4801 if (rc != ERROR_SUCCESS)
4802 goto end;
4804 for( i = 0; szPropKeys[i][0]; i++ )
4806 buffer = msi_dup_property( package, szPropKeys[i] );
4807 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4808 msi_free( buffer );
4811 end:
4812 uirow = MSI_CreateRecord( 1 );
4813 MSI_RecordSetStringW( uirow, 1, productid );
4814 ui_actiondata( package, szRegisterUser, uirow );
4815 msiobj_release( &uirow->hdr );
4817 msi_free(productid);
4818 RegCloseKey(hkey);
4819 return rc;
4823 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4825 UINT rc;
4827 package->script->InWhatSequence |= SEQUENCE_EXEC;
4828 rc = ACTION_ProcessExecSequence(package,FALSE);
4829 return rc;
4833 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4835 MSIPACKAGE *package = param;
4836 LPCWSTR compgroupid, component, feature, qualifier, text;
4837 LPWSTR advertise = NULL, output = NULL;
4838 HKEY hkey = NULL;
4839 UINT rc;
4840 MSICOMPONENT *comp;
4841 MSIFEATURE *feat;
4842 DWORD sz;
4843 MSIRECORD *uirow;
4845 feature = MSI_RecordGetString(rec, 5);
4846 feat = get_loaded_feature(package, feature);
4847 if (!feat)
4848 return ERROR_SUCCESS;
4850 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4851 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4852 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
4854 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4855 feat->Action = feat->Installed;
4856 return ERROR_SUCCESS;
4859 component = MSI_RecordGetString(rec, 3);
4860 comp = get_loaded_component(package, component);
4861 if (!comp)
4862 return ERROR_SUCCESS;
4864 compgroupid = MSI_RecordGetString(rec,1);
4865 qualifier = MSI_RecordGetString(rec,2);
4867 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4868 if (rc != ERROR_SUCCESS)
4869 goto end;
4871 text = MSI_RecordGetString(rec,4);
4872 advertise = create_component_advertise_string(package, comp, feature);
4874 sz = strlenW(advertise);
4876 if (text)
4877 sz += lstrlenW(text);
4879 sz+=3;
4880 sz *= sizeof(WCHAR);
4882 output = msi_alloc_zero(sz);
4883 strcpyW(output,advertise);
4884 msi_free(advertise);
4886 if (text)
4887 strcatW(output,text);
4889 msi_reg_set_val_multi_str( hkey, qualifier, output );
4891 end:
4892 RegCloseKey(hkey);
4893 msi_free(output);
4895 /* the UI chunk */
4896 uirow = MSI_CreateRecord( 2 );
4897 MSI_RecordSetStringW( uirow, 1, compgroupid );
4898 MSI_RecordSetStringW( uirow, 2, qualifier);
4899 ui_actiondata( package, szPublishComponents, uirow);
4900 msiobj_release( &uirow->hdr );
4901 /* FIXME: call ui_progress? */
4903 return rc;
4907 * At present I am ignorning the advertised components part of this and only
4908 * focusing on the qualified component sets
4910 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4912 UINT rc;
4913 MSIQUERY * view;
4914 static const WCHAR ExecSeqQuery[] =
4915 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4916 '`','P','u','b','l','i','s','h',
4917 'C','o','m','p','o','n','e','n','t','`',0};
4919 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4920 if (rc != ERROR_SUCCESS)
4921 return ERROR_SUCCESS;
4923 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4924 msiobj_release(&view->hdr);
4926 return rc;
4929 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
4931 static const WCHAR szInstallerComponents[] = {
4932 'S','o','f','t','w','a','r','e','\\',
4933 'M','i','c','r','o','s','o','f','t','\\',
4934 'I','n','s','t','a','l','l','e','r','\\',
4935 'C','o','m','p','o','n','e','n','t','s','\\',0};
4937 MSIPACKAGE *package = param;
4938 LPCWSTR compgroupid, component, feature, qualifier;
4939 MSICOMPONENT *comp;
4940 MSIFEATURE *feat;
4941 MSIRECORD *uirow;
4942 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
4943 LONG res;
4945 feature = MSI_RecordGetString( rec, 5 );
4946 feat = get_loaded_feature( package, feature );
4947 if (!feat)
4948 return ERROR_SUCCESS;
4950 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
4952 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
4953 feat->Action = feat->Installed;
4954 return ERROR_SUCCESS;
4957 component = MSI_RecordGetString( rec, 3 );
4958 comp = get_loaded_component( package, component );
4959 if (!comp)
4960 return ERROR_SUCCESS;
4962 compgroupid = MSI_RecordGetString( rec, 1 );
4963 qualifier = MSI_RecordGetString( rec, 2 );
4965 squash_guid( compgroupid, squashed );
4966 strcpyW( keypath, szInstallerComponents );
4967 strcatW( keypath, squashed );
4969 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
4970 if (res != ERROR_SUCCESS)
4972 WARN("Unable to delete component key %d\n", res);
4975 uirow = MSI_CreateRecord( 2 );
4976 MSI_RecordSetStringW( uirow, 1, compgroupid );
4977 MSI_RecordSetStringW( uirow, 2, qualifier );
4978 ui_actiondata( package, szUnpublishComponents, uirow );
4979 msiobj_release( &uirow->hdr );
4981 return ERROR_SUCCESS;
4984 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
4986 UINT rc;
4987 MSIQUERY *view;
4988 static const WCHAR query[] =
4989 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4990 '`','P','u','b','l','i','s','h',
4991 'C','o','m','p','o','n','e','n','t','`',0};
4993 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4994 if (rc != ERROR_SUCCESS)
4995 return ERROR_SUCCESS;
4997 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
4998 msiobj_release( &view->hdr );
5000 return rc;
5003 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5005 MSIPACKAGE *package = param;
5006 MSIRECORD *row;
5007 MSIFILE *file;
5008 SC_HANDLE hscm, service = NULL;
5009 LPCWSTR comp, depends, pass;
5010 LPWSTR name = NULL, disp = NULL;
5011 LPCWSTR load_order, serv_name, key;
5012 DWORD serv_type, start_type;
5013 DWORD err_control;
5015 static const WCHAR query[] =
5016 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5017 '`','C','o','m','p','o','n','e','n','t','`',' ',
5018 'W','H','E','R','E',' ',
5019 '`','C','o','m','p','o','n','e','n','t','`',' ',
5020 '=','\'','%','s','\'',0};
5022 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5023 if (!hscm)
5025 ERR("Failed to open the SC Manager!\n");
5026 goto done;
5029 start_type = MSI_RecordGetInteger(rec, 5);
5030 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5031 goto done;
5033 depends = MSI_RecordGetString(rec, 8);
5034 if (depends && *depends)
5035 FIXME("Dependency list unhandled!\n");
5037 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5038 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5039 serv_type = MSI_RecordGetInteger(rec, 4);
5040 err_control = MSI_RecordGetInteger(rec, 6);
5041 load_order = MSI_RecordGetString(rec, 7);
5042 serv_name = MSI_RecordGetString(rec, 9);
5043 pass = MSI_RecordGetString(rec, 10);
5044 comp = MSI_RecordGetString(rec, 12);
5046 /* fetch the service path */
5047 row = MSI_QueryGetRecord(package->db, query, comp);
5048 if (!row)
5050 ERR("Control query failed!\n");
5051 goto done;
5054 key = MSI_RecordGetString(row, 6);
5056 file = get_loaded_file(package, key);
5057 msiobj_release(&row->hdr);
5058 if (!file)
5060 ERR("Failed to load the service file\n");
5061 goto done;
5064 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5065 start_type, err_control, file->TargetPath,
5066 load_order, NULL, NULL, serv_name, pass);
5067 if (!service)
5069 if (GetLastError() != ERROR_SERVICE_EXISTS)
5070 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5073 done:
5074 CloseServiceHandle(service);
5075 CloseServiceHandle(hscm);
5076 msi_free(name);
5077 msi_free(disp);
5079 return ERROR_SUCCESS;
5082 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5084 UINT rc;
5085 MSIQUERY * view;
5086 static const WCHAR ExecSeqQuery[] =
5087 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5088 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5090 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5091 if (rc != ERROR_SUCCESS)
5092 return ERROR_SUCCESS;
5094 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5095 msiobj_release(&view->hdr);
5097 return rc;
5100 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5101 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5103 LPCWSTR *vector, *temp_vector;
5104 LPWSTR p, q;
5105 DWORD sep_len;
5107 static const WCHAR separator[] = {'[','~',']',0};
5109 *numargs = 0;
5110 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5112 if (!args)
5113 return NULL;
5115 vector = msi_alloc(sizeof(LPWSTR));
5116 if (!vector)
5117 return NULL;
5119 p = args;
5122 (*numargs)++;
5123 vector[*numargs - 1] = p;
5125 if ((q = strstrW(p, separator)))
5127 *q = '\0';
5129 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5130 if (!temp_vector)
5132 msi_free(vector);
5133 return NULL;
5135 vector = temp_vector;
5137 p = q + sep_len;
5139 } while (q);
5141 return vector;
5144 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5146 MSIPACKAGE *package = param;
5147 MSICOMPONENT *comp;
5148 MSIRECORD *uirow;
5149 SC_HANDLE scm = NULL, service = NULL;
5150 LPCWSTR component, *vector = NULL;
5151 LPWSTR name, args, display_name = NULL;
5152 DWORD event, numargs, len;
5153 UINT r = ERROR_FUNCTION_FAILED;
5155 component = MSI_RecordGetString(rec, 6);
5156 comp = get_loaded_component(package, component);
5157 if (!comp)
5158 return ERROR_SUCCESS;
5160 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5162 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5163 comp->Action = comp->Installed;
5164 return ERROR_SUCCESS;
5166 comp->Action = INSTALLSTATE_LOCAL;
5168 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5169 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5170 event = MSI_RecordGetInteger(rec, 3);
5172 if (!(event & msidbServiceControlEventStart))
5174 r = ERROR_SUCCESS;
5175 goto done;
5178 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5179 if (!scm)
5181 ERR("Failed to open the service control manager\n");
5182 goto done;
5185 len = 0;
5186 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5187 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5189 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5190 GetServiceDisplayNameW( scm, name, display_name, &len );
5193 service = OpenServiceW(scm, name, SERVICE_START);
5194 if (!service)
5196 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5197 goto done;
5200 vector = msi_service_args_to_vector(args, &numargs);
5202 if (!StartServiceW(service, numargs, vector) &&
5203 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5205 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5206 goto done;
5209 r = ERROR_SUCCESS;
5211 done:
5212 uirow = MSI_CreateRecord( 2 );
5213 MSI_RecordSetStringW( uirow, 1, display_name );
5214 MSI_RecordSetStringW( uirow, 2, name );
5215 ui_actiondata( package, szStartServices, uirow );
5216 msiobj_release( &uirow->hdr );
5218 CloseServiceHandle(service);
5219 CloseServiceHandle(scm);
5221 msi_free(name);
5222 msi_free(args);
5223 msi_free(vector);
5224 msi_free(display_name);
5225 return r;
5228 static UINT ACTION_StartServices( MSIPACKAGE *package )
5230 UINT rc;
5231 MSIQUERY *view;
5233 static const WCHAR query[] = {
5234 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5235 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5237 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5238 if (rc != ERROR_SUCCESS)
5239 return ERROR_SUCCESS;
5241 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5242 msiobj_release(&view->hdr);
5244 return rc;
5247 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5249 DWORD i, needed, count;
5250 ENUM_SERVICE_STATUSW *dependencies;
5251 SERVICE_STATUS ss;
5252 SC_HANDLE depserv;
5254 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5255 0, &needed, &count))
5256 return TRUE;
5258 if (GetLastError() != ERROR_MORE_DATA)
5259 return FALSE;
5261 dependencies = msi_alloc(needed);
5262 if (!dependencies)
5263 return FALSE;
5265 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5266 needed, &needed, &count))
5267 goto error;
5269 for (i = 0; i < count; i++)
5271 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5272 SERVICE_STOP | SERVICE_QUERY_STATUS);
5273 if (!depserv)
5274 goto error;
5276 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5277 goto error;
5280 return TRUE;
5282 error:
5283 msi_free(dependencies);
5284 return FALSE;
5287 static UINT stop_service( LPCWSTR name )
5289 SC_HANDLE scm = NULL, service = NULL;
5290 SERVICE_STATUS status;
5291 SERVICE_STATUS_PROCESS ssp;
5292 DWORD needed;
5294 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5295 if (!scm)
5297 WARN("Failed to open the SCM: %d\n", GetLastError());
5298 goto done;
5301 service = OpenServiceW(scm, name,
5302 SERVICE_STOP |
5303 SERVICE_QUERY_STATUS |
5304 SERVICE_ENUMERATE_DEPENDENTS);
5305 if (!service)
5307 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5308 goto done;
5311 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5312 sizeof(SERVICE_STATUS_PROCESS), &needed))
5314 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5315 goto done;
5318 if (ssp.dwCurrentState == SERVICE_STOPPED)
5319 goto done;
5321 stop_service_dependents(scm, service);
5323 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5324 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5326 done:
5327 CloseServiceHandle(service);
5328 CloseServiceHandle(scm);
5330 return ERROR_SUCCESS;
5333 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5335 MSIPACKAGE *package = param;
5336 MSICOMPONENT *comp;
5337 MSIRECORD *uirow;
5338 LPCWSTR component;
5339 LPWSTR name = NULL, display_name = NULL;
5340 DWORD event, len;
5341 SC_HANDLE scm;
5343 event = MSI_RecordGetInteger( rec, 3 );
5344 if (!(event & msidbServiceControlEventStop))
5345 return ERROR_SUCCESS;
5347 component = MSI_RecordGetString( rec, 6 );
5348 comp = get_loaded_component( package, component );
5349 if (!comp)
5350 return ERROR_SUCCESS;
5352 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5354 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5355 comp->Action = comp->Installed;
5356 return ERROR_SUCCESS;
5358 comp->Action = INSTALLSTATE_ABSENT;
5360 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5361 if (!scm)
5363 ERR("Failed to open the service control manager\n");
5364 goto done;
5367 len = 0;
5368 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5369 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5371 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5372 GetServiceDisplayNameW( scm, name, display_name, &len );
5374 CloseServiceHandle( scm );
5376 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5377 stop_service( name );
5379 done:
5380 uirow = MSI_CreateRecord( 2 );
5381 MSI_RecordSetStringW( uirow, 1, display_name );
5382 MSI_RecordSetStringW( uirow, 2, name );
5383 ui_actiondata( package, szStopServices, uirow );
5384 msiobj_release( &uirow->hdr );
5386 msi_free( name );
5387 msi_free( display_name );
5388 return ERROR_SUCCESS;
5391 static UINT ACTION_StopServices( MSIPACKAGE *package )
5393 UINT rc;
5394 MSIQUERY *view;
5396 static const WCHAR query[] = {
5397 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5398 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5400 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5401 if (rc != ERROR_SUCCESS)
5402 return ERROR_SUCCESS;
5404 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5405 msiobj_release(&view->hdr);
5407 return rc;
5410 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5412 MSIPACKAGE *package = param;
5413 MSICOMPONENT *comp;
5414 MSIRECORD *uirow;
5415 LPCWSTR component;
5416 LPWSTR name = NULL, display_name = NULL;
5417 DWORD event, len;
5418 SC_HANDLE scm = NULL, service = NULL;
5420 event = MSI_RecordGetInteger( rec, 3 );
5421 if (!(event & msidbServiceControlEventDelete))
5422 return ERROR_SUCCESS;
5424 component = MSI_RecordGetString(rec, 6);
5425 comp = get_loaded_component(package, component);
5426 if (!comp)
5427 return ERROR_SUCCESS;
5429 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5431 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5432 comp->Action = comp->Installed;
5433 return ERROR_SUCCESS;
5435 comp->Action = INSTALLSTATE_ABSENT;
5437 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5438 stop_service( name );
5440 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5441 if (!scm)
5443 WARN("Failed to open the SCM: %d\n", GetLastError());
5444 goto done;
5447 len = 0;
5448 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5449 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5451 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5452 GetServiceDisplayNameW( scm, name, display_name, &len );
5455 service = OpenServiceW( scm, name, DELETE );
5456 if (!service)
5458 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5459 goto done;
5462 if (!DeleteService( service ))
5463 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5465 done:
5466 uirow = MSI_CreateRecord( 2 );
5467 MSI_RecordSetStringW( uirow, 1, display_name );
5468 MSI_RecordSetStringW( uirow, 2, name );
5469 ui_actiondata( package, szDeleteServices, uirow );
5470 msiobj_release( &uirow->hdr );
5472 CloseServiceHandle( service );
5473 CloseServiceHandle( scm );
5474 msi_free( name );
5475 msi_free( display_name );
5477 return ERROR_SUCCESS;
5480 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5482 UINT rc;
5483 MSIQUERY *view;
5485 static const WCHAR query[] = {
5486 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5487 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5489 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5490 if (rc != ERROR_SUCCESS)
5491 return ERROR_SUCCESS;
5493 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5494 msiobj_release( &view->hdr );
5496 return rc;
5499 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5501 MSIFILE *file;
5503 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5505 if (!lstrcmpW(file->File, filename))
5506 return file;
5509 return NULL;
5512 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5514 MSIPACKAGE *package = param;
5515 LPWSTR driver, driver_path, ptr;
5516 WCHAR outpath[MAX_PATH];
5517 MSIFILE *driver_file, *setup_file;
5518 MSIRECORD *uirow;
5519 LPCWSTR desc;
5520 DWORD len, usage;
5521 UINT r = ERROR_SUCCESS;
5523 static const WCHAR driver_fmt[] = {
5524 'D','r','i','v','e','r','=','%','s',0};
5525 static const WCHAR setup_fmt[] = {
5526 'S','e','t','u','p','=','%','s',0};
5527 static const WCHAR usage_fmt[] = {
5528 'F','i','l','e','U','s','a','g','e','=','1',0};
5530 desc = MSI_RecordGetString(rec, 3);
5532 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5533 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5535 if (!driver_file)
5537 ERR("ODBC Driver entry not found!\n");
5538 return ERROR_FUNCTION_FAILED;
5541 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5542 if (setup_file)
5543 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5544 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5546 driver = msi_alloc(len * sizeof(WCHAR));
5547 if (!driver)
5548 return ERROR_OUTOFMEMORY;
5550 ptr = driver;
5551 lstrcpyW(ptr, desc);
5552 ptr += lstrlenW(ptr) + 1;
5554 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5555 ptr += len + 1;
5557 if (setup_file)
5559 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5560 ptr += len + 1;
5563 lstrcpyW(ptr, usage_fmt);
5564 ptr += lstrlenW(ptr) + 1;
5565 *ptr = '\0';
5567 driver_path = strdupW(driver_file->TargetPath);
5568 ptr = strrchrW(driver_path, '\\');
5569 if (ptr) *ptr = '\0';
5571 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5572 NULL, ODBC_INSTALL_COMPLETE, &usage))
5574 ERR("Failed to install SQL driver!\n");
5575 r = ERROR_FUNCTION_FAILED;
5578 uirow = MSI_CreateRecord( 5 );
5579 MSI_RecordSetStringW( uirow, 1, desc );
5580 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5581 MSI_RecordSetStringW( uirow, 3, driver_path );
5582 ui_actiondata( package, szInstallODBC, uirow );
5583 msiobj_release( &uirow->hdr );
5585 msi_free(driver);
5586 msi_free(driver_path);
5588 return r;
5591 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5593 MSIPACKAGE *package = param;
5594 LPWSTR translator, translator_path, ptr;
5595 WCHAR outpath[MAX_PATH];
5596 MSIFILE *translator_file, *setup_file;
5597 MSIRECORD *uirow;
5598 LPCWSTR desc;
5599 DWORD len, usage;
5600 UINT r = ERROR_SUCCESS;
5602 static const WCHAR translator_fmt[] = {
5603 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5604 static const WCHAR setup_fmt[] = {
5605 'S','e','t','u','p','=','%','s',0};
5607 desc = MSI_RecordGetString(rec, 3);
5609 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5610 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5612 if (!translator_file)
5614 ERR("ODBC Translator entry not found!\n");
5615 return ERROR_FUNCTION_FAILED;
5618 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5619 if (setup_file)
5620 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5622 translator = msi_alloc(len * sizeof(WCHAR));
5623 if (!translator)
5624 return ERROR_OUTOFMEMORY;
5626 ptr = translator;
5627 lstrcpyW(ptr, desc);
5628 ptr += lstrlenW(ptr) + 1;
5630 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5631 ptr += len + 1;
5633 if (setup_file)
5635 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5636 ptr += len + 1;
5638 *ptr = '\0';
5640 translator_path = strdupW(translator_file->TargetPath);
5641 ptr = strrchrW(translator_path, '\\');
5642 if (ptr) *ptr = '\0';
5644 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5645 NULL, ODBC_INSTALL_COMPLETE, &usage))
5647 ERR("Failed to install SQL translator!\n");
5648 r = ERROR_FUNCTION_FAILED;
5651 uirow = MSI_CreateRecord( 5 );
5652 MSI_RecordSetStringW( uirow, 1, desc );
5653 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5654 MSI_RecordSetStringW( uirow, 3, translator_path );
5655 ui_actiondata( package, szInstallODBC, uirow );
5656 msiobj_release( &uirow->hdr );
5658 msi_free(translator);
5659 msi_free(translator_path);
5661 return r;
5664 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5666 MSIPACKAGE *package = param;
5667 LPWSTR attrs;
5668 LPCWSTR desc, driver;
5669 WORD request = ODBC_ADD_SYS_DSN;
5670 INT registration;
5671 DWORD len;
5672 UINT r = ERROR_SUCCESS;
5673 MSIRECORD *uirow;
5675 static const WCHAR attrs_fmt[] = {
5676 'D','S','N','=','%','s',0 };
5678 desc = MSI_RecordGetString(rec, 3);
5679 driver = MSI_RecordGetString(rec, 4);
5680 registration = MSI_RecordGetInteger(rec, 5);
5682 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5683 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5685 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5686 attrs = msi_alloc(len * sizeof(WCHAR));
5687 if (!attrs)
5688 return ERROR_OUTOFMEMORY;
5690 len = sprintfW(attrs, attrs_fmt, desc);
5691 attrs[len + 1] = 0;
5693 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5695 ERR("Failed to install SQL data source!\n");
5696 r = ERROR_FUNCTION_FAILED;
5699 uirow = MSI_CreateRecord( 5 );
5700 MSI_RecordSetStringW( uirow, 1, desc );
5701 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5702 MSI_RecordSetInteger( uirow, 3, request );
5703 ui_actiondata( package, szInstallODBC, uirow );
5704 msiobj_release( &uirow->hdr );
5706 msi_free(attrs);
5708 return r;
5711 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5713 UINT rc;
5714 MSIQUERY *view;
5716 static const WCHAR driver_query[] = {
5717 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5718 'O','D','B','C','D','r','i','v','e','r',0 };
5720 static const WCHAR translator_query[] = {
5721 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5722 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5724 static const WCHAR source_query[] = {
5725 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5726 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5728 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5729 if (rc != ERROR_SUCCESS)
5730 return ERROR_SUCCESS;
5732 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5733 msiobj_release(&view->hdr);
5735 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5736 if (rc != ERROR_SUCCESS)
5737 return ERROR_SUCCESS;
5739 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5740 msiobj_release(&view->hdr);
5742 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5743 if (rc != ERROR_SUCCESS)
5744 return ERROR_SUCCESS;
5746 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5747 msiobj_release(&view->hdr);
5749 return rc;
5752 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5754 MSIPACKAGE *package = param;
5755 MSIRECORD *uirow;
5756 DWORD usage;
5757 LPCWSTR desc;
5759 desc = MSI_RecordGetString( rec, 3 );
5760 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5762 WARN("Failed to remove ODBC driver\n");
5764 else if (!usage)
5766 FIXME("Usage count reached 0\n");
5769 uirow = MSI_CreateRecord( 2 );
5770 MSI_RecordSetStringW( uirow, 1, desc );
5771 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5772 ui_actiondata( package, szRemoveODBC, uirow );
5773 msiobj_release( &uirow->hdr );
5775 return ERROR_SUCCESS;
5778 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5780 MSIPACKAGE *package = param;
5781 MSIRECORD *uirow;
5782 DWORD usage;
5783 LPCWSTR desc;
5785 desc = MSI_RecordGetString( rec, 3 );
5786 if (!SQLRemoveTranslatorW( desc, &usage ))
5788 WARN("Failed to remove ODBC translator\n");
5790 else if (!usage)
5792 FIXME("Usage count reached 0\n");
5795 uirow = MSI_CreateRecord( 2 );
5796 MSI_RecordSetStringW( uirow, 1, desc );
5797 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5798 ui_actiondata( package, szRemoveODBC, uirow );
5799 msiobj_release( &uirow->hdr );
5801 return ERROR_SUCCESS;
5804 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5806 MSIPACKAGE *package = param;
5807 MSIRECORD *uirow;
5808 LPWSTR attrs;
5809 LPCWSTR desc, driver;
5810 WORD request = ODBC_REMOVE_SYS_DSN;
5811 INT registration;
5812 DWORD len;
5814 static const WCHAR attrs_fmt[] = {
5815 'D','S','N','=','%','s',0 };
5817 desc = MSI_RecordGetString( rec, 3 );
5818 driver = MSI_RecordGetString( rec, 4 );
5819 registration = MSI_RecordGetInteger( rec, 5 );
5821 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5822 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5824 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
5825 attrs = msi_alloc( len * sizeof(WCHAR) );
5826 if (!attrs)
5827 return ERROR_OUTOFMEMORY;
5829 FIXME("Use ODBCSourceAttribute table\n");
5831 len = sprintfW( attrs, attrs_fmt, desc );
5832 attrs[len + 1] = 0;
5834 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5836 WARN("Failed to remove ODBC data source\n");
5838 msi_free( attrs );
5840 uirow = MSI_CreateRecord( 3 );
5841 MSI_RecordSetStringW( uirow, 1, desc );
5842 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5843 MSI_RecordSetInteger( uirow, 3, request );
5844 ui_actiondata( package, szRemoveODBC, uirow );
5845 msiobj_release( &uirow->hdr );
5847 return ERROR_SUCCESS;
5850 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5852 UINT rc;
5853 MSIQUERY *view;
5855 static const WCHAR driver_query[] = {
5856 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5857 'O','D','B','C','D','r','i','v','e','r',0 };
5859 static const WCHAR translator_query[] = {
5860 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5861 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5863 static const WCHAR source_query[] = {
5864 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5865 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5867 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5868 if (rc != ERROR_SUCCESS)
5869 return ERROR_SUCCESS;
5871 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5872 msiobj_release( &view->hdr );
5874 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5875 if (rc != ERROR_SUCCESS)
5876 return ERROR_SUCCESS;
5878 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5879 msiobj_release( &view->hdr );
5881 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5882 if (rc != ERROR_SUCCESS)
5883 return ERROR_SUCCESS;
5885 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5886 msiobj_release( &view->hdr );
5888 return rc;
5891 #define ENV_ACT_SETALWAYS 0x1
5892 #define ENV_ACT_SETABSENT 0x2
5893 #define ENV_ACT_REMOVE 0x4
5894 #define ENV_ACT_REMOVEMATCH 0x8
5896 #define ENV_MOD_MACHINE 0x20000000
5897 #define ENV_MOD_APPEND 0x40000000
5898 #define ENV_MOD_PREFIX 0x80000000
5899 #define ENV_MOD_MASK 0xC0000000
5901 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5903 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5905 LPCWSTR cptr = *name;
5907 static const WCHAR prefix[] = {'[','~',']',0};
5908 static const int prefix_len = 3;
5910 *flags = 0;
5911 while (*cptr)
5913 if (*cptr == '=')
5914 *flags |= ENV_ACT_SETALWAYS;
5915 else if (*cptr == '+')
5916 *flags |= ENV_ACT_SETABSENT;
5917 else if (*cptr == '-')
5918 *flags |= ENV_ACT_REMOVE;
5919 else if (*cptr == '!')
5920 *flags |= ENV_ACT_REMOVEMATCH;
5921 else if (*cptr == '*')
5922 *flags |= ENV_MOD_MACHINE;
5923 else
5924 break;
5926 cptr++;
5927 (*name)++;
5930 if (!*cptr)
5932 ERR("Missing environment variable\n");
5933 return ERROR_FUNCTION_FAILED;
5936 if (*value)
5938 LPCWSTR ptr = *value;
5939 if (!strncmpW(ptr, prefix, prefix_len))
5941 if (ptr[prefix_len] == szSemiColon[0])
5943 *flags |= ENV_MOD_APPEND;
5944 *value += lstrlenW(prefix);
5946 else
5948 *value = NULL;
5951 else if (lstrlenW(*value) >= prefix_len)
5953 ptr += lstrlenW(ptr) - prefix_len;
5954 if (!lstrcmpW(ptr, prefix))
5956 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5958 *flags |= ENV_MOD_PREFIX;
5959 /* the "[~]" will be removed by deformat_string */;
5961 else
5963 *value = NULL;
5969 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5970 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5971 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5972 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5974 ERR("Invalid flags: %08x\n", *flags);
5975 return ERROR_FUNCTION_FAILED;
5978 if (!*flags)
5979 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5981 return ERROR_SUCCESS;
5984 static UINT open_env_key( DWORD flags, HKEY *key )
5986 static const WCHAR user_env[] =
5987 {'E','n','v','i','r','o','n','m','e','n','t',0};
5988 static const WCHAR machine_env[] =
5989 {'S','y','s','t','e','m','\\',
5990 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5991 'C','o','n','t','r','o','l','\\',
5992 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5993 'E','n','v','i','r','o','n','m','e','n','t',0};
5994 const WCHAR *env;
5995 HKEY root;
5996 LONG res;
5998 if (flags & ENV_MOD_MACHINE)
6000 env = machine_env;
6001 root = HKEY_LOCAL_MACHINE;
6003 else
6005 env = user_env;
6006 root = HKEY_CURRENT_USER;
6009 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6010 if (res != ERROR_SUCCESS)
6012 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6013 return ERROR_FUNCTION_FAILED;
6016 return ERROR_SUCCESS;
6019 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6021 MSIPACKAGE *package = param;
6022 LPCWSTR name, value, component;
6023 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6024 DWORD flags, type, size;
6025 UINT res;
6026 HKEY env = NULL;
6027 MSICOMPONENT *comp;
6028 MSIRECORD *uirow;
6029 int action = 0;
6031 component = MSI_RecordGetString(rec, 4);
6032 comp = get_loaded_component(package, component);
6033 if (!comp)
6034 return ERROR_SUCCESS;
6036 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6038 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6039 comp->Action = comp->Installed;
6040 return ERROR_SUCCESS;
6042 comp->Action = INSTALLSTATE_LOCAL;
6044 name = MSI_RecordGetString(rec, 2);
6045 value = MSI_RecordGetString(rec, 3);
6047 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6049 res = env_parse_flags(&name, &value, &flags);
6050 if (res != ERROR_SUCCESS || !value)
6051 goto done;
6053 if (value && !deformat_string(package, value, &deformatted))
6055 res = ERROR_OUTOFMEMORY;
6056 goto done;
6059 value = deformatted;
6061 res = open_env_key( flags, &env );
6062 if (res != ERROR_SUCCESS)
6063 goto done;
6065 if (flags & ENV_MOD_MACHINE)
6066 action |= 0x20000000;
6068 size = 0;
6069 type = REG_SZ;
6070 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6071 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6072 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6073 goto done;
6075 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6077 action = 0x2;
6079 /* Nothing to do. */
6080 if (!value)
6082 res = ERROR_SUCCESS;
6083 goto done;
6086 /* If we are appending but the string was empty, strip ; */
6087 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6089 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6090 newval = strdupW(value);
6091 if (!newval)
6093 res = ERROR_OUTOFMEMORY;
6094 goto done;
6097 else
6099 action = 0x1;
6101 /* Contrary to MSDN, +-variable to [~];path works */
6102 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6104 res = ERROR_SUCCESS;
6105 goto done;
6108 data = msi_alloc(size);
6109 if (!data)
6111 RegCloseKey(env);
6112 return ERROR_OUTOFMEMORY;
6115 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6116 if (res != ERROR_SUCCESS)
6117 goto done;
6119 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6121 action = 0x4;
6122 res = RegDeleteValueW(env, name);
6123 if (res != ERROR_SUCCESS)
6124 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6125 goto done;
6128 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6129 if (flags & ENV_MOD_MASK)
6131 DWORD mod_size;
6132 int multiplier = 0;
6133 if (flags & ENV_MOD_APPEND) multiplier++;
6134 if (flags & ENV_MOD_PREFIX) multiplier++;
6135 mod_size = lstrlenW(value) * multiplier;
6136 size += mod_size * sizeof(WCHAR);
6139 newval = msi_alloc(size);
6140 ptr = newval;
6141 if (!newval)
6143 res = ERROR_OUTOFMEMORY;
6144 goto done;
6147 if (flags & ENV_MOD_PREFIX)
6149 lstrcpyW(newval, value);
6150 ptr = newval + lstrlenW(value);
6151 action |= 0x80000000;
6154 lstrcpyW(ptr, data);
6156 if (flags & ENV_MOD_APPEND)
6158 lstrcatW(newval, value);
6159 action |= 0x40000000;
6162 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6163 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6164 if (res)
6166 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6169 done:
6170 uirow = MSI_CreateRecord( 3 );
6171 MSI_RecordSetStringW( uirow, 1, name );
6172 MSI_RecordSetStringW( uirow, 2, newval );
6173 MSI_RecordSetInteger( uirow, 3, action );
6174 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6175 msiobj_release( &uirow->hdr );
6177 if (env) RegCloseKey(env);
6178 msi_free(deformatted);
6179 msi_free(data);
6180 msi_free(newval);
6181 return res;
6184 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6186 UINT rc;
6187 MSIQUERY * view;
6188 static const WCHAR ExecSeqQuery[] =
6189 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6190 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6191 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6192 if (rc != ERROR_SUCCESS)
6193 return ERROR_SUCCESS;
6195 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6196 msiobj_release(&view->hdr);
6198 return rc;
6201 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6203 MSIPACKAGE *package = param;
6204 LPCWSTR name, value, component;
6205 LPWSTR deformatted = NULL;
6206 DWORD flags;
6207 HKEY env;
6208 MSICOMPONENT *comp;
6209 MSIRECORD *uirow;
6210 int action = 0;
6211 LONG res;
6212 UINT r;
6214 component = MSI_RecordGetString( rec, 4 );
6215 comp = get_loaded_component( package, component );
6216 if (!comp)
6217 return ERROR_SUCCESS;
6219 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6221 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6222 comp->Action = comp->Installed;
6223 return ERROR_SUCCESS;
6225 comp->Action = INSTALLSTATE_ABSENT;
6227 name = MSI_RecordGetString( rec, 2 );
6228 value = MSI_RecordGetString( rec, 3 );
6230 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6232 r = env_parse_flags( &name, &value, &flags );
6233 if (r != ERROR_SUCCESS)
6234 return r;
6236 if (!(flags & ENV_ACT_REMOVE))
6238 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6239 return ERROR_SUCCESS;
6242 if (value && !deformat_string( package, value, &deformatted ))
6243 return ERROR_OUTOFMEMORY;
6245 value = deformatted;
6247 r = open_env_key( flags, &env );
6248 if (r != ERROR_SUCCESS)
6250 r = ERROR_SUCCESS;
6251 goto done;
6254 if (flags & ENV_MOD_MACHINE)
6255 action |= 0x20000000;
6257 TRACE("Removing %s\n", debugstr_w(name));
6259 res = RegDeleteValueW( env, name );
6260 if (res != ERROR_SUCCESS)
6262 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6263 r = ERROR_SUCCESS;
6266 done:
6267 uirow = MSI_CreateRecord( 3 );
6268 MSI_RecordSetStringW( uirow, 1, name );
6269 MSI_RecordSetStringW( uirow, 2, value );
6270 MSI_RecordSetInteger( uirow, 3, action );
6271 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6272 msiobj_release( &uirow->hdr );
6274 if (env) RegCloseKey( env );
6275 msi_free( deformatted );
6276 return r;
6279 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6281 UINT rc;
6282 MSIQUERY *view;
6283 static const WCHAR query[] =
6284 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6285 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6287 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6288 if (rc != ERROR_SUCCESS)
6289 return ERROR_SUCCESS;
6291 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6292 msiobj_release( &view->hdr );
6294 return rc;
6297 typedef struct tagMSIASSEMBLY
6299 struct list entry;
6300 MSICOMPONENT *component;
6301 MSIFEATURE *feature;
6302 MSIFILE *file;
6303 LPWSTR manifest;
6304 LPWSTR application;
6305 LPWSTR display_name;
6306 DWORD attributes;
6307 BOOL installed;
6308 } MSIASSEMBLY;
6310 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6311 DWORD dwReserved);
6312 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6313 LPVOID pvReserved, HMODULE *phModDll);
6315 static BOOL init_functionpointers(void)
6317 HRESULT hr;
6318 HMODULE hfusion;
6319 HMODULE hmscoree;
6321 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6323 hmscoree = LoadLibraryA("mscoree.dll");
6324 if (!hmscoree)
6326 WARN("mscoree.dll not available\n");
6327 return FALSE;
6330 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6331 if (!pLoadLibraryShim)
6333 WARN("LoadLibraryShim not available\n");
6334 FreeLibrary(hmscoree);
6335 return FALSE;
6338 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6339 if (FAILED(hr))
6341 WARN("fusion.dll not available\n");
6342 FreeLibrary(hmscoree);
6343 return FALSE;
6346 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6348 FreeLibrary(hmscoree);
6349 return TRUE;
6352 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6353 LPWSTR path)
6355 IAssemblyCache *cache;
6356 MSIRECORD *uirow;
6357 HRESULT hr;
6358 UINT r = ERROR_FUNCTION_FAILED;
6360 TRACE("installing assembly: %s\n", debugstr_w(path));
6362 uirow = MSI_CreateRecord( 2 );
6363 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6364 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6365 msiobj_release( &uirow->hdr );
6367 if (assembly->feature)
6368 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6370 if (assembly->manifest)
6371 FIXME("Manifest unhandled\n");
6373 if (assembly->application)
6375 FIXME("Assembly should be privately installed\n");
6376 return ERROR_SUCCESS;
6379 if (assembly->attributes == msidbAssemblyAttributesWin32)
6381 FIXME("Win32 assemblies not handled\n");
6382 return ERROR_SUCCESS;
6385 hr = pCreateAssemblyCache(&cache, 0);
6386 if (FAILED(hr))
6387 goto done;
6389 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6390 if (FAILED(hr))
6391 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6393 r = ERROR_SUCCESS;
6395 done:
6396 IAssemblyCache_Release(cache);
6397 return r;
6400 typedef struct tagASSEMBLY_LIST
6402 MSIPACKAGE *package;
6403 IAssemblyCache *cache;
6404 struct list *assemblies;
6405 } ASSEMBLY_LIST;
6407 typedef struct tagASSEMBLY_NAME
6409 LPWSTR name;
6410 LPWSTR version;
6411 LPWSTR culture;
6412 LPWSTR pubkeytoken;
6413 } ASSEMBLY_NAME;
6415 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6417 ASSEMBLY_NAME *asmname = param;
6418 LPCWSTR name = MSI_RecordGetString(rec, 2);
6419 LPWSTR val = msi_dup_record_field(rec, 3);
6421 static const WCHAR Name[] = {'N','a','m','e',0};
6422 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6423 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6424 static const WCHAR PublicKeyToken[] = {
6425 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6427 if (!strcmpiW(name, Name))
6428 asmname->name = val;
6429 else if (!strcmpiW(name, Version))
6430 asmname->version = val;
6431 else if (!strcmpiW(name, Culture))
6432 asmname->culture = val;
6433 else if (!strcmpiW(name, PublicKeyToken))
6434 asmname->pubkeytoken = val;
6435 else
6436 msi_free(val);
6438 return ERROR_SUCCESS;
6441 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6443 if (!*str)
6445 *size = lstrlenW(append) + 1;
6446 *str = msi_alloc((*size) * sizeof(WCHAR));
6447 lstrcpyW(*str, append);
6448 return;
6451 (*size) += lstrlenW(append);
6452 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6453 lstrcatW(*str, append);
6456 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6458 static const WCHAR separator[] = {',',' ',0};
6459 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6460 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6461 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6462 static const WCHAR query[] = {
6463 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6464 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6465 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6466 '=','\'','%','s','\'',0};
6467 ASSEMBLY_NAME name;
6468 MSIQUERY *view;
6469 LPWSTR display_name;
6470 DWORD size;
6471 UINT r;
6473 display_name = NULL;
6474 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6476 r = MSI_OpenQuery( db, &view, query, comp->Component );
6477 if (r != ERROR_SUCCESS)
6478 return NULL;
6480 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6481 msiobj_release( &view->hdr );
6483 if (!name.name)
6485 ERR("No assembly name specified!\n");
6486 return NULL;
6489 append_str( &display_name, &size, name.name );
6491 if (name.version)
6493 append_str( &display_name, &size, separator );
6494 append_str( &display_name, &size, Version );
6495 append_str( &display_name, &size, name.version );
6497 if (name.culture)
6499 append_str( &display_name, &size, separator );
6500 append_str( &display_name, &size, Culture );
6501 append_str( &display_name, &size, name.culture );
6503 if (name.pubkeytoken)
6505 append_str( &display_name, &size, separator );
6506 append_str( &display_name, &size, PublicKeyToken );
6507 append_str( &display_name, &size, name.pubkeytoken );
6510 msi_free( name.name );
6511 msi_free( name.version );
6512 msi_free( name.culture );
6513 msi_free( name.pubkeytoken );
6515 return display_name;
6518 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6520 ASSEMBLY_INFO asminfo;
6521 LPWSTR disp;
6522 BOOL found = FALSE;
6523 HRESULT hr;
6525 disp = get_assembly_display_name( db, comp );
6526 if (!disp)
6527 return FALSE;
6529 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6530 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6532 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6533 if (SUCCEEDED(hr))
6534 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6536 msi_free( disp );
6537 return found;
6540 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6542 ASSEMBLY_LIST *list = param;
6543 MSIASSEMBLY *assembly;
6544 LPCWSTR component;
6546 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6547 if (!assembly)
6548 return ERROR_OUTOFMEMORY;
6550 component = MSI_RecordGetString(rec, 1);
6551 assembly->component = get_loaded_component(list->package, component);
6552 if (!assembly->component)
6553 return ERROR_SUCCESS;
6555 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6556 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6558 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6559 assembly->component->Action = assembly->component->Installed;
6560 return ERROR_SUCCESS;
6562 assembly->component->Action = assembly->component->ActionRequest;
6564 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6565 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6567 if (!assembly->file)
6569 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6570 return ERROR_FUNCTION_FAILED;
6573 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6574 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6575 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6577 if (assembly->application)
6579 WCHAR version[24];
6580 DWORD size = sizeof(version)/sizeof(WCHAR);
6582 /* FIXME: we should probably check the manifest file here */
6584 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6585 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6587 assembly->installed = TRUE;
6590 else
6591 assembly->installed = check_assembly_installed(list->package->db,
6592 list->cache,
6593 assembly->component);
6595 list_add_head(list->assemblies, &assembly->entry);
6596 return ERROR_SUCCESS;
6599 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6601 IAssemblyCache *cache = NULL;
6602 ASSEMBLY_LIST list;
6603 MSIQUERY *view;
6604 HRESULT hr;
6605 UINT r;
6607 static const WCHAR query[] =
6608 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6609 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6611 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6612 if (r != ERROR_SUCCESS)
6613 return ERROR_SUCCESS;
6615 hr = pCreateAssemblyCache(&cache, 0);
6616 if (FAILED(hr))
6617 return ERROR_FUNCTION_FAILED;
6619 list.package = package;
6620 list.cache = cache;
6621 list.assemblies = assemblies;
6623 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6624 msiobj_release(&view->hdr);
6626 IAssemblyCache_Release(cache);
6628 return r;
6631 static void free_assemblies(struct list *assemblies)
6633 struct list *item, *cursor;
6635 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6637 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6639 list_remove(&assembly->entry);
6640 msi_free(assembly->application);
6641 msi_free(assembly->manifest);
6642 msi_free(assembly->display_name);
6643 msi_free(assembly);
6647 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6649 MSIASSEMBLY *assembly;
6651 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6653 if (!lstrcmpW(assembly->file->File, file))
6655 *out = assembly;
6656 return TRUE;
6660 return FALSE;
6663 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6664 LPWSTR *path, DWORD *attrs, PVOID user)
6666 MSIASSEMBLY *assembly;
6667 WCHAR temppath[MAX_PATH];
6668 struct list *assemblies = user;
6669 UINT r;
6671 if (!find_assembly(assemblies, file, &assembly))
6672 return FALSE;
6674 GetTempPathW(MAX_PATH, temppath);
6675 PathAddBackslashW(temppath);
6676 lstrcatW(temppath, assembly->file->FileName);
6678 if (action == MSICABEXTRACT_BEGINEXTRACT)
6680 if (assembly->installed)
6681 return FALSE;
6683 *path = strdupW(temppath);
6684 *attrs = assembly->file->Attributes;
6686 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6688 assembly->installed = TRUE;
6690 r = install_assembly(package, assembly, temppath);
6691 if (r != ERROR_SUCCESS)
6692 ERR("Failed to install assembly\n");
6695 return TRUE;
6698 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6700 UINT r;
6701 struct list assemblies = LIST_INIT(assemblies);
6702 MSIASSEMBLY *assembly;
6703 MSIMEDIAINFO *mi;
6705 if (!init_functionpointers() || !pCreateAssemblyCache)
6706 return ERROR_FUNCTION_FAILED;
6708 r = load_assemblies(package, &assemblies);
6709 if (r != ERROR_SUCCESS)
6710 goto done;
6712 if (list_empty(&assemblies))
6713 goto done;
6715 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6716 if (!mi)
6718 r = ERROR_OUTOFMEMORY;
6719 goto done;
6722 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6724 if (assembly->installed && !mi->is_continuous)
6725 continue;
6727 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6728 (assembly->file->IsCompressed && !mi->is_extracted))
6730 MSICABDATA data;
6732 r = ready_media(package, assembly->file, mi);
6733 if (r != ERROR_SUCCESS)
6735 ERR("Failed to ready media\n");
6736 break;
6739 data.mi = mi;
6740 data.package = package;
6741 data.cb = installassembly_cb;
6742 data.user = &assemblies;
6744 if (assembly->file->IsCompressed &&
6745 !msi_cabextract(package, mi, &data))
6747 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6748 r = ERROR_FUNCTION_FAILED;
6749 break;
6753 if (!assembly->file->IsCompressed)
6755 LPWSTR source = resolve_file_source(package, assembly->file);
6757 r = install_assembly(package, assembly, source);
6758 if (r != ERROR_SUCCESS)
6759 ERR("Failed to install assembly\n");
6761 msi_free(source);
6764 /* FIXME: write Installer assembly reg values */
6767 done:
6768 free_assemblies(&assemblies);
6769 return r;
6772 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6774 LPWSTR key, template, id;
6775 UINT r = ERROR_SUCCESS;
6777 id = msi_dup_property( package, szProductID );
6778 if (id)
6780 msi_free( id );
6781 return ERROR_SUCCESS;
6783 template = msi_dup_property( package, szPIDTemplate );
6784 key = msi_dup_property( package, szPIDKEY );
6786 if (key && template)
6788 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6789 r = MSI_SetPropertyW( package, szProductID, key );
6791 msi_free( template );
6792 msi_free( key );
6793 return r;
6796 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6798 TRACE("\n");
6799 package->need_reboot = 1;
6800 return ERROR_SUCCESS;
6803 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6805 static const WCHAR szAvailableFreeReg[] =
6806 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6807 MSIRECORD *uirow;
6808 int space = msi_get_property_int( package, szAvailableFreeReg, 0 );
6810 TRACE("%p %d kilobytes\n", package, space);
6812 uirow = MSI_CreateRecord( 1 );
6813 MSI_RecordSetInteger( uirow, 1, space );
6814 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6815 msiobj_release( &uirow->hdr );
6817 return ERROR_SUCCESS;
6820 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6822 FIXME("%p\n", package);
6823 return ERROR_SUCCESS;
6826 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6828 FIXME("%p\n", package);
6829 return ERROR_SUCCESS;
6832 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6834 UINT r, count;
6835 MSIQUERY *view;
6837 static const WCHAR driver_query[] = {
6838 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6839 'O','D','B','C','D','r','i','v','e','r',0 };
6841 static const WCHAR translator_query[] = {
6842 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6843 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6845 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6846 if (r == ERROR_SUCCESS)
6848 count = 0;
6849 r = MSI_IterateRecords( view, &count, NULL, package );
6850 msiobj_release( &view->hdr );
6851 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6854 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6855 if (r == ERROR_SUCCESS)
6857 count = 0;
6858 r = MSI_IterateRecords( view, &count, NULL, package );
6859 msiobj_release( &view->hdr );
6860 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6863 return ERROR_SUCCESS;
6866 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6867 LPCSTR action, LPCWSTR table )
6869 static const WCHAR query[] = {
6870 'S','E','L','E','C','T',' ','*',' ',
6871 'F','R','O','M',' ','`','%','s','`',0 };
6872 MSIQUERY *view = NULL;
6873 DWORD count = 0;
6874 UINT r;
6876 r = MSI_OpenQuery( package->db, &view, query, table );
6877 if (r == ERROR_SUCCESS)
6879 r = MSI_IterateRecords(view, &count, NULL, package);
6880 msiobj_release(&view->hdr);
6883 if (count)
6884 FIXME("%s -> %u ignored %s table values\n",
6885 action, count, debugstr_w(table));
6887 return ERROR_SUCCESS;
6890 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6892 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6893 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6896 static UINT ACTION_BindImage( MSIPACKAGE *package )
6898 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6899 return msi_unimplemented_action_stub( package, "BindImage", table );
6902 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6904 static const WCHAR table[] = {
6905 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6906 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6909 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6911 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6912 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6915 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6917 static const WCHAR table[] = {
6918 'M','s','i','A','s','s','e','m','b','l','y',0 };
6919 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6922 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6924 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6925 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6928 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6930 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6931 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6934 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6936 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6937 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6940 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6942 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6943 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6946 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6948 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6949 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6952 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6954 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6955 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6958 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6960 static const WCHAR table[] = { 'M','I','M','E',0 };
6961 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6964 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6966 static const struct
6968 const WCHAR *action;
6969 UINT (*handler)(MSIPACKAGE *);
6971 StandardActions[] =
6973 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6974 { szAppSearch, ACTION_AppSearch },
6975 { szBindImage, ACTION_BindImage },
6976 { szCCPSearch, ACTION_CCPSearch },
6977 { szCostFinalize, ACTION_CostFinalize },
6978 { szCostInitialize, ACTION_CostInitialize },
6979 { szCreateFolders, ACTION_CreateFolders },
6980 { szCreateShortcuts, ACTION_CreateShortcuts },
6981 { szDeleteServices, ACTION_DeleteServices },
6982 { szDisableRollback, ACTION_DisableRollback },
6983 { szDuplicateFiles, ACTION_DuplicateFiles },
6984 { szExecuteAction, ACTION_ExecuteAction },
6985 { szFileCost, ACTION_FileCost },
6986 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6987 { szForceReboot, ACTION_ForceReboot },
6988 { szInstallAdminPackage, ACTION_InstallAdminPackage },
6989 { szInstallExecute, ACTION_InstallExecute },
6990 { szInstallExecuteAgain, ACTION_InstallExecute },
6991 { szInstallFiles, ACTION_InstallFiles},
6992 { szInstallFinalize, ACTION_InstallFinalize },
6993 { szInstallInitialize, ACTION_InstallInitialize },
6994 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6995 { szInstallValidate, ACTION_InstallValidate },
6996 { szIsolateComponents, ACTION_IsolateComponents },
6997 { szLaunchConditions, ACTION_LaunchConditions },
6998 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6999 { szMoveFiles, ACTION_MoveFiles },
7000 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7001 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7002 { szInstallODBC, ACTION_InstallODBC },
7003 { szInstallServices, ACTION_InstallServices },
7004 { szPatchFiles, ACTION_PatchFiles },
7005 { szProcessComponents, ACTION_ProcessComponents },
7006 { szPublishComponents, ACTION_PublishComponents },
7007 { szPublishFeatures, ACTION_PublishFeatures },
7008 { szPublishProduct, ACTION_PublishProduct },
7009 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7010 { szRegisterComPlus, ACTION_RegisterComPlus},
7011 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7012 { szRegisterFonts, ACTION_RegisterFonts },
7013 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7014 { szRegisterProduct, ACTION_RegisterProduct },
7015 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7016 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7017 { szRegisterUser, ACTION_RegisterUser },
7018 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7019 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7020 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7021 { szRemoveFiles, ACTION_RemoveFiles },
7022 { szRemoveFolders, ACTION_RemoveFolders },
7023 { szRemoveIniValues, ACTION_RemoveIniValues },
7024 { szRemoveODBC, ACTION_RemoveODBC },
7025 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7026 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7027 { szResolveSource, ACTION_ResolveSource },
7028 { szRMCCPSearch, ACTION_RMCCPSearch },
7029 { szScheduleReboot, ACTION_ScheduleReboot },
7030 { szSelfRegModules, ACTION_SelfRegModules },
7031 { szSelfUnregModules, ACTION_SelfUnregModules },
7032 { szSetODBCFolders, ACTION_SetODBCFolders },
7033 { szStartServices, ACTION_StartServices },
7034 { szStopServices, ACTION_StopServices },
7035 { szUnpublishComponents, ACTION_UnpublishComponents },
7036 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7037 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7038 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7039 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7040 { szUnregisterFonts, ACTION_UnregisterFonts },
7041 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7042 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7043 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7044 { szValidateProductID, ACTION_ValidateProductID },
7045 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7046 { szWriteIniValues, ACTION_WriteIniValues },
7047 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7048 { NULL, NULL },
7051 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7052 UINT* rc, BOOL force )
7054 BOOL ret = FALSE;
7055 BOOL run = force;
7056 int i;
7058 if (!run && !package->script->CurrentlyScripting)
7059 run = TRUE;
7061 if (!run)
7063 if (strcmpW(action,szInstallFinalize) == 0 ||
7064 strcmpW(action,szInstallExecute) == 0 ||
7065 strcmpW(action,szInstallExecuteAgain) == 0)
7066 run = TRUE;
7069 i = 0;
7070 while (StandardActions[i].action != NULL)
7072 if (strcmpW(StandardActions[i].action, action)==0)
7074 if (!run)
7076 ui_actioninfo(package, action, TRUE, 0);
7077 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7078 ui_actioninfo(package, action, FALSE, *rc);
7080 else
7082 ui_actionstart(package, action);
7083 if (StandardActions[i].handler)
7085 *rc = StandardActions[i].handler(package);
7087 else
7089 FIXME("unhandled standard action %s\n",debugstr_w(action));
7090 *rc = ERROR_SUCCESS;
7093 ret = TRUE;
7094 break;
7096 i++;
7098 return ret;
7101 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7103 UINT rc = ERROR_SUCCESS;
7104 BOOL handled;
7106 TRACE("Performing action (%s)\n", debugstr_w(action));
7108 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7110 if (!handled)
7111 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7113 if (!handled)
7115 WARN("unhandled msi action %s\n", debugstr_w(action));
7116 rc = ERROR_FUNCTION_NOT_CALLED;
7119 return rc;
7122 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7124 UINT rc = ERROR_SUCCESS;
7125 BOOL handled = FALSE;
7127 TRACE("Performing action (%s)\n", debugstr_w(action));
7129 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7131 if (!handled)
7132 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7134 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7135 handled = TRUE;
7137 if (!handled)
7139 WARN("unhandled msi action %s\n", debugstr_w(action));
7140 rc = ERROR_FUNCTION_NOT_CALLED;
7143 return rc;
7146 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7148 UINT rc = ERROR_SUCCESS;
7149 MSIRECORD *row;
7151 static const WCHAR ExecSeqQuery[] =
7152 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7153 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7154 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7155 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7156 static const WCHAR UISeqQuery[] =
7157 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7158 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7159 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7160 ' ', '=',' ','%','i',0};
7162 if (needs_ui_sequence(package))
7163 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7164 else
7165 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7167 if (row)
7169 LPCWSTR action, cond;
7171 TRACE("Running the actions\n");
7173 /* check conditions */
7174 cond = MSI_RecordGetString(row, 2);
7176 /* this is a hack to skip errors in the condition code */
7177 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7179 msiobj_release(&row->hdr);
7180 return ERROR_SUCCESS;
7183 action = MSI_RecordGetString(row, 1);
7184 if (!action)
7186 ERR("failed to fetch action\n");
7187 msiobj_release(&row->hdr);
7188 return ERROR_FUNCTION_FAILED;
7191 if (needs_ui_sequence(package))
7192 rc = ACTION_PerformUIAction(package, action, -1);
7193 else
7194 rc = ACTION_PerformAction(package, action, -1, FALSE);
7196 msiobj_release(&row->hdr);
7199 return rc;
7202 /****************************************************
7203 * TOP level entry points
7204 *****************************************************/
7206 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7207 LPCWSTR szCommandLine )
7209 UINT rc;
7210 BOOL ui_exists;
7212 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7213 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7215 MSI_SetPropertyW(package, szAction, szInstall);
7217 package->script->InWhatSequence = SEQUENCE_INSTALL;
7219 if (szPackagePath)
7221 LPWSTR p, dir;
7222 LPCWSTR file;
7224 dir = strdupW(szPackagePath);
7225 p = strrchrW(dir, '\\');
7226 if (p)
7228 *(++p) = 0;
7229 file = szPackagePath + (p - dir);
7231 else
7233 msi_free(dir);
7234 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7235 GetCurrentDirectoryW(MAX_PATH, dir);
7236 lstrcatW(dir, szBackSlash);
7237 file = szPackagePath;
7240 msi_free( package->PackagePath );
7241 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7242 if (!package->PackagePath)
7244 msi_free(dir);
7245 return ERROR_OUTOFMEMORY;
7248 lstrcpyW(package->PackagePath, dir);
7249 lstrcatW(package->PackagePath, file);
7250 msi_free(dir);
7252 msi_set_sourcedir_props(package, FALSE);
7255 msi_parse_command_line( package, szCommandLine, FALSE );
7257 msi_apply_transforms( package );
7258 msi_apply_patches( package );
7260 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
7262 TRACE("setting reinstall property\n");
7263 MSI_SetPropertyW( package, szReinstall, szAll );
7266 /* properties may have been added by a transform */
7267 msi_clone_properties( package );
7268 msi_set_context( package );
7270 if (needs_ui_sequence( package))
7272 package->script->InWhatSequence |= SEQUENCE_UI;
7273 rc = ACTION_ProcessUISequence(package);
7274 ui_exists = ui_sequence_exists(package);
7275 if (rc == ERROR_SUCCESS || !ui_exists)
7277 package->script->InWhatSequence |= SEQUENCE_EXEC;
7278 rc = ACTION_ProcessExecSequence(package, ui_exists);
7281 else
7282 rc = ACTION_ProcessExecSequence(package, FALSE);
7284 package->script->CurrentlyScripting = FALSE;
7286 /* process the ending type action */
7287 if (rc == ERROR_SUCCESS)
7288 ACTION_PerformActionSequence(package, -1);
7289 else if (rc == ERROR_INSTALL_USEREXIT)
7290 ACTION_PerformActionSequence(package, -2);
7291 else if (rc == ERROR_INSTALL_SUSPEND)
7292 ACTION_PerformActionSequence(package, -4);
7293 else /* failed */
7294 ACTION_PerformActionSequence(package, -3);
7296 /* finish up running custom actions */
7297 ACTION_FinishCustomActions(package);
7299 if (rc == ERROR_SUCCESS && package->need_reboot)
7300 return ERROR_SUCCESS_REBOOT_REQUIRED;
7302 return rc;