msi: The AppSearch and CCPSearch actions must be run only once.
[wine/multimedia.git] / dlls / msi / action.c
blob0d0e33367b3fd0043ff10b7509cf8511551fd714
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 szRegisterFonts[] =
128 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
129 static const WCHAR szRegisterUser[] =
130 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
131 static const WCHAR szRemoveEnvironmentStrings[] =
132 {'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};
133 static const WCHAR szRemoveExistingProducts[] =
134 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
135 static const WCHAR szRemoveFolders[] =
136 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
137 static const WCHAR szRemoveIniValues[] =
138 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
139 static const WCHAR szRemoveODBC[] =
140 {'R','e','m','o','v','e','O','D','B','C',0};
141 static const WCHAR szRemoveRegistryValues[] =
142 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
143 static const WCHAR szRemoveShortcuts[] =
144 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
145 static const WCHAR szRMCCPSearch[] =
146 {'R','M','C','C','P','S','e','a','r','c','h',0};
147 static const WCHAR szScheduleReboot[] =
148 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
149 static const WCHAR szSelfUnregModules[] =
150 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
151 static const WCHAR szSetODBCFolders[] =
152 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
153 static const WCHAR szStartServices[] =
154 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
155 static const WCHAR szStopServices[] =
156 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
157 static const WCHAR szUnpublishComponents[] =
158 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
159 static const WCHAR szUnpublishFeatures[] =
160 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
161 static const WCHAR szUnregisterClassInfo[] =
162 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
163 static const WCHAR szUnregisterComPlus[] =
164 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
165 static const WCHAR szUnregisterExtensionInfo[] =
166 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
167 static const WCHAR szUnregisterFonts[] =
168 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
169 static const WCHAR szUnregisterMIMEInfo[] =
170 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
171 static const WCHAR szUnregisterProgIdInfo[] =
172 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
173 static const WCHAR szUnregisterTypeLibraries[] =
174 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
175 static const WCHAR szValidateProductID[] =
176 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
177 static const WCHAR szWriteEnvironmentStrings[] =
178 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
180 /********************************************************
181 * helper functions
182 ********************************************************/
184 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
186 static const WCHAR Query_t[] =
187 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
188 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
189 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
190 ' ','\'','%','s','\'',0};
191 MSIRECORD * row;
193 row = MSI_QueryGetRecord( package->db, Query_t, action );
194 if (!row)
195 return;
196 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
197 msiobj_release(&row->hdr);
200 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
201 UINT rc)
203 MSIRECORD * row;
204 static const WCHAR template_s[]=
205 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
206 '%','s', '.',0};
207 static const WCHAR template_e[]=
208 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
209 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
210 '%','i','.',0};
211 static const WCHAR format[] =
212 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
213 WCHAR message[1024];
214 WCHAR timet[0x100];
216 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
217 if (start)
218 sprintfW(message,template_s,timet,action);
219 else
220 sprintfW(message,template_e,timet,action,rc);
222 row = MSI_CreateRecord(1);
223 MSI_RecordSetStringW(row,1,message);
225 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
226 msiobj_release(&row->hdr);
229 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
230 BOOL preserve_case )
232 LPCWSTR ptr,ptr2;
233 BOOL quote;
234 DWORD len;
235 LPWSTR prop = NULL, val = NULL;
237 if (!szCommandLine)
238 return ERROR_SUCCESS;
240 ptr = szCommandLine;
242 while (*ptr)
244 if (*ptr==' ')
246 ptr++;
247 continue;
250 TRACE("Looking at %s\n",debugstr_w(ptr));
252 ptr2 = strchrW(ptr,'=');
253 if (!ptr2)
255 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
256 break;
259 quote = FALSE;
261 len = ptr2-ptr;
262 prop = msi_alloc((len+1)*sizeof(WCHAR));
263 memcpy(prop,ptr,len*sizeof(WCHAR));
264 prop[len]=0;
266 if (!preserve_case)
267 struprW(prop);
269 ptr2++;
271 len = 0;
272 ptr = ptr2;
273 while (*ptr && (quote || (!quote && *ptr!=' ')))
275 if (*ptr == '"')
276 quote = !quote;
277 ptr++;
278 len++;
281 if (*ptr2=='"')
283 ptr2++;
284 len -= 2;
286 val = msi_alloc((len+1)*sizeof(WCHAR));
287 memcpy(val,ptr2,len*sizeof(WCHAR));
288 val[len] = 0;
290 if (lstrlenW(prop) > 0)
292 TRACE("Found commandline property (%s) = (%s)\n",
293 debugstr_w(prop), debugstr_w(val));
294 MSI_SetPropertyW(package,prop,val);
296 msi_free(val);
297 msi_free(prop);
300 return ERROR_SUCCESS;
304 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
306 LPCWSTR pc;
307 LPWSTR p, *ret = NULL;
308 UINT count = 0;
310 if (!str)
311 return ret;
313 /* count the number of substrings */
314 for ( pc = str, count = 0; pc; count++ )
316 pc = strchrW( pc, sep );
317 if (pc)
318 pc++;
321 /* allocate space for an array of substring pointers and the substrings */
322 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
323 (lstrlenW(str)+1) * sizeof(WCHAR) );
324 if (!ret)
325 return ret;
327 /* copy the string and set the pointers */
328 p = (LPWSTR) &ret[count+1];
329 lstrcpyW( p, str );
330 for( count = 0; (ret[count] = p); count++ )
332 p = strchrW( p, sep );
333 if (p)
334 *p++ = 0;
337 return ret;
340 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
342 static const WCHAR szSystemLanguageID[] =
343 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
345 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
346 UINT ret = ERROR_FUNCTION_FAILED;
348 prod_code = msi_dup_property( package, szProductCode );
349 patch_product = msi_get_suminfo_product( patch );
351 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
353 if ( strstrW( patch_product, prod_code ) )
355 MSISUMMARYINFO *si;
356 const WCHAR *p;
358 si = MSI_GetSummaryInformationW( patch, 0 );
359 if (!si)
361 ERR("no summary information!\n");
362 goto end;
365 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
366 if (!template)
368 ERR("no template property!\n");
369 msiobj_release( &si->hdr );
370 goto end;
373 if (!template[0])
375 ret = ERROR_SUCCESS;
376 msiobj_release( &si->hdr );
377 goto end;
380 langid = msi_dup_property( package, szSystemLanguageID );
381 if (!langid)
383 msiobj_release( &si->hdr );
384 goto end;
387 p = strchrW( template, ';' );
388 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
390 TRACE("applicable transform\n");
391 ret = ERROR_SUCCESS;
394 /* FIXME: check platform */
396 msiobj_release( &si->hdr );
399 end:
400 msi_free( patch_product );
401 msi_free( prod_code );
402 msi_free( template );
403 msi_free( langid );
405 return ret;
408 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
409 MSIDATABASE *patch_db, LPCWSTR name )
411 UINT ret = ERROR_FUNCTION_FAILED;
412 IStorage *stg = NULL;
413 HRESULT r;
415 TRACE("%p %s\n", package, debugstr_w(name) );
417 if (*name++ != ':')
419 ERR("expected a colon in %s\n", debugstr_w(name));
420 return ERROR_FUNCTION_FAILED;
423 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
424 if (SUCCEEDED(r))
426 ret = msi_check_transform_applicable( package, stg );
427 if (ret == ERROR_SUCCESS)
428 msi_table_apply_transform( package->db, stg );
429 else
430 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
431 IStorage_Release( stg );
433 else
434 ERR("failed to open substorage %s\n", debugstr_w(name));
436 return ERROR_SUCCESS;
439 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
441 LPWSTR guid_list, *guids, product_code;
442 UINT i, ret = ERROR_FUNCTION_FAILED;
444 product_code = msi_dup_property( package, szProductCode );
445 if (!product_code)
447 /* FIXME: the property ProductCode should be written into the DB somewhere */
448 ERR("no product code to check\n");
449 return ERROR_SUCCESS;
452 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
453 guids = msi_split_string( guid_list, ';' );
454 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
456 if (!lstrcmpW( guids[i], product_code ))
457 ret = ERROR_SUCCESS;
459 msi_free( guids );
460 msi_free( guid_list );
461 msi_free( product_code );
463 return ret;
466 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
468 MSIQUERY *view;
469 MSIRECORD *rec = NULL;
470 LPWSTR patch;
471 LPCWSTR prop;
472 UINT r;
474 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
475 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
476 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
477 '`','S','o','u','r','c','e','`',' ','I','S',' ',
478 'N','O','T',' ','N','U','L','L',0};
480 r = MSI_DatabaseOpenViewW(package->db, query, &view);
481 if (r != ERROR_SUCCESS)
482 return r;
484 r = MSI_ViewExecute(view, 0);
485 if (r != ERROR_SUCCESS)
486 goto done;
488 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
490 prop = MSI_RecordGetString(rec, 1);
491 patch = msi_dup_property(package, szPatch);
492 MSI_SetPropertyW(package, prop, patch);
493 msi_free(patch);
496 done:
497 if (rec) msiobj_release(&rec->hdr);
498 msiobj_release(&view->hdr);
500 return r;
503 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
505 MSISUMMARYINFO *si;
506 LPWSTR str, *substorage;
507 UINT i, r = ERROR_SUCCESS;
509 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
510 if (!si)
511 return ERROR_FUNCTION_FAILED;
513 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
515 TRACE("Patch not applicable\n");
516 return ERROR_SUCCESS;
519 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
520 if (!package->patch)
521 return ERROR_OUTOFMEMORY;
523 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
524 if (!package->patch->patchcode)
525 return ERROR_OUTOFMEMORY;
527 /* enumerate the substorage */
528 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
529 package->patch->transforms = str;
531 substorage = msi_split_string( str, ';' );
532 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
533 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
535 msi_free( substorage );
536 msiobj_release( &si->hdr );
538 msi_set_media_source_prop(package);
540 return r;
543 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
545 MSIDATABASE *patch_db = NULL;
546 UINT r;
548 TRACE("%p %s\n", package, debugstr_w( file ) );
550 /* FIXME:
551 * We probably want to make sure we only open a patch collection here.
552 * Patch collections (.msp) and databases (.msi) have different GUIDs
553 * but currently MSI_OpenDatabaseW will accept both.
555 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
556 if ( r != ERROR_SUCCESS )
558 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
559 return r;
562 msi_parse_patch_summary( package, patch_db );
565 * There might be a CAB file in the patch package,
566 * so append it to the list of storage to search for streams.
568 append_storage_to_db( package->db, patch_db->storage );
570 msiobj_release( &patch_db->hdr );
572 return ERROR_SUCCESS;
575 /* get the PATCH property, and apply all the patches it specifies */
576 static UINT msi_apply_patches( MSIPACKAGE *package )
578 LPWSTR patch_list, *patches;
579 UINT i, r = ERROR_SUCCESS;
581 patch_list = msi_dup_property( package, szPatch );
583 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
585 patches = msi_split_string( patch_list, ';' );
586 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
587 r = msi_apply_patch_package( package, patches[i] );
589 msi_free( patches );
590 msi_free( patch_list );
592 return r;
595 static UINT msi_apply_transforms( MSIPACKAGE *package )
597 static const WCHAR szTransforms[] = {
598 'T','R','A','N','S','F','O','R','M','S',0 };
599 LPWSTR xform_list, *xforms;
600 UINT i, r = ERROR_SUCCESS;
602 xform_list = msi_dup_property( package, szTransforms );
603 xforms = msi_split_string( xform_list, ';' );
605 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
607 if (xforms[i][0] == ':')
608 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
609 else
610 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
613 msi_free( xforms );
614 msi_free( xform_list );
616 return r;
619 static BOOL ui_sequence_exists( MSIPACKAGE *package )
621 MSIQUERY *view;
622 UINT rc;
624 static const WCHAR ExecSeqQuery [] =
625 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
626 '`','I','n','s','t','a','l','l',
627 'U','I','S','e','q','u','e','n','c','e','`',
628 ' ','W','H','E','R','E',' ',
629 '`','S','e','q','u','e','n','c','e','`',' ',
630 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
631 '`','S','e','q','u','e','n','c','e','`',0};
633 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
634 if (rc == ERROR_SUCCESS)
636 msiobj_release(&view->hdr);
637 return TRUE;
640 return FALSE;
643 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
645 LPWSTR p, db;
646 LPWSTR source, check;
647 DWORD len;
649 static const WCHAR szOriginalDatabase[] =
650 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
652 db = msi_dup_property( package, szOriginalDatabase );
653 if (!db)
654 return ERROR_OUTOFMEMORY;
656 p = strrchrW( db, '\\' );
657 if (!p)
659 p = strrchrW( db, '/' );
660 if (!p)
662 msi_free(db);
663 return ERROR_SUCCESS;
667 len = p - db + 2;
668 source = msi_alloc( len * sizeof(WCHAR) );
669 lstrcpynW( source, db, len );
671 check = msi_dup_property( package, cszSourceDir );
672 if (!check || replace)
673 MSI_SetPropertyW( package, cszSourceDir, source );
675 msi_free( check );
677 check = msi_dup_property( package, cszSOURCEDIR );
678 if (!check || replace)
679 MSI_SetPropertyW( package, cszSOURCEDIR, source );
681 msi_free( check );
682 msi_free( source );
683 msi_free( db );
685 return ERROR_SUCCESS;
688 static BOOL needs_ui_sequence(MSIPACKAGE *package)
690 INT level = msi_get_property_int(package, szUILevel, 0);
691 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
694 static UINT msi_set_context(MSIPACKAGE *package)
696 WCHAR val[10];
697 DWORD sz = 10;
698 DWORD num;
699 UINT r;
701 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
703 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
704 if (r == ERROR_SUCCESS)
706 num = atolW(val);
707 if (num == 1 || num == 2)
708 package->Context = MSIINSTALLCONTEXT_MACHINE;
711 return ERROR_SUCCESS;
714 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
716 UINT rc;
717 LPCWSTR cond, action;
718 MSIPACKAGE *package = param;
720 action = MSI_RecordGetString(row,1);
721 if (!action)
723 ERR("Error is retrieving action name\n");
724 return ERROR_FUNCTION_FAILED;
727 /* check conditions */
728 cond = MSI_RecordGetString(row,2);
730 /* this is a hack to skip errors in the condition code */
731 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
733 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
734 return ERROR_SUCCESS;
737 if (needs_ui_sequence(package))
738 rc = ACTION_PerformUIAction(package, action, -1);
739 else
740 rc = ACTION_PerformAction(package, action, -1, FALSE);
742 msi_dialog_check_messages( NULL );
744 if (package->CurrentInstallState != ERROR_SUCCESS)
745 rc = package->CurrentInstallState;
747 if (rc == ERROR_FUNCTION_NOT_CALLED)
748 rc = ERROR_SUCCESS;
750 if (rc != ERROR_SUCCESS)
751 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
753 return rc;
756 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
758 MSIQUERY * view;
759 UINT r;
760 static const WCHAR query[] =
761 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
762 '`','%','s','`',
763 ' ','W','H','E','R','E',' ',
764 '`','S','e','q','u','e','n','c','e','`',' ',
765 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
766 '`','S','e','q','u','e','n','c','e','`',0};
768 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
770 r = MSI_OpenQuery( package->db, &view, query, szTable );
771 if (r == ERROR_SUCCESS)
773 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
774 msiobj_release(&view->hdr);
777 return r;
780 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
782 MSIQUERY * view;
783 UINT rc;
784 static const WCHAR ExecSeqQuery[] =
785 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
786 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
787 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
788 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
789 'O','R','D','E','R',' ', 'B','Y',' ',
790 '`','S','e','q','u','e','n','c','e','`',0 };
791 static const WCHAR IVQuery[] =
792 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
793 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
794 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
795 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
796 ' ','\'', 'I','n','s','t','a','l','l',
797 'V','a','l','i','d','a','t','e','\'', 0};
798 INT seq = 0;
800 if (package->script->ExecuteSequenceRun)
802 TRACE("Execute Sequence already Run\n");
803 return ERROR_SUCCESS;
806 package->script->ExecuteSequenceRun = TRUE;
808 /* get the sequence number */
809 if (UIran)
811 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
812 if( !row )
813 return ERROR_FUNCTION_FAILED;
814 seq = MSI_RecordGetInteger(row,1);
815 msiobj_release(&row->hdr);
818 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
819 if (rc == ERROR_SUCCESS)
821 TRACE("Running the actions\n");
823 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
824 msiobj_release(&view->hdr);
827 return rc;
830 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
832 MSIQUERY * view;
833 UINT rc;
834 static const WCHAR ExecSeqQuery [] =
835 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
836 '`','I','n','s','t','a','l','l',
837 'U','I','S','e','q','u','e','n','c','e','`',
838 ' ','W','H','E','R','E',' ',
839 '`','S','e','q','u','e','n','c','e','`',' ',
840 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
841 '`','S','e','q','u','e','n','c','e','`',0};
843 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
844 if (rc == ERROR_SUCCESS)
846 TRACE("Running the actions\n");
848 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
849 msiobj_release(&view->hdr);
852 return rc;
855 /********************************************************
856 * ACTION helper functions and functions that perform the actions
857 *******************************************************/
858 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
859 UINT* rc, UINT script, BOOL force )
861 BOOL ret=FALSE;
862 UINT arc;
864 arc = ACTION_CustomAction(package, action, script, force);
866 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
868 *rc = arc;
869 ret = TRUE;
871 return ret;
875 * Actual Action Handlers
878 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
880 MSIPACKAGE *package = param;
881 LPCWSTR dir, component;
882 LPWSTR full_path;
883 MSIRECORD *uirow;
884 MSIFOLDER *folder;
885 MSICOMPONENT *comp;
887 component = MSI_RecordGetString(row, 2);
888 comp = get_loaded_component(package, component);
889 if (!comp)
890 return ERROR_SUCCESS;
892 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
894 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
895 comp->Action = comp->Installed;
896 return ERROR_SUCCESS;
898 comp->Action = INSTALLSTATE_LOCAL;
900 dir = MSI_RecordGetString(row,1);
901 if (!dir)
903 ERR("Unable to get folder id\n");
904 return ERROR_SUCCESS;
907 uirow = MSI_CreateRecord(1);
908 MSI_RecordSetStringW(uirow, 1, dir);
909 ui_actiondata(package, szCreateFolders, uirow);
910 msiobj_release(&uirow->hdr);
912 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
913 if (!full_path)
915 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
916 return ERROR_SUCCESS;
919 TRACE("Folder is %s\n",debugstr_w(full_path));
921 if (folder->State == 0)
922 create_full_pathW(full_path);
924 folder->State = 3;
926 msi_free(full_path);
927 return ERROR_SUCCESS;
930 /* FIXME: probably should merge this with the above function */
931 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
933 UINT rc = ERROR_SUCCESS;
934 MSIFOLDER *folder;
935 LPWSTR install_path;
937 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
938 if (!install_path)
939 return ERROR_FUNCTION_FAILED;
941 /* create the path */
942 if (folder->State == 0)
944 create_full_pathW(install_path);
945 folder->State = 2;
947 msi_free(install_path);
949 return rc;
952 UINT msi_create_component_directories( MSIPACKAGE *package )
954 MSICOMPONENT *comp;
956 /* create all the folders required by the components are going to install */
957 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
959 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
960 continue;
961 msi_create_directory( package, comp->Directory );
964 return ERROR_SUCCESS;
967 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
969 static const WCHAR ExecSeqQuery[] =
970 {'S','E','L','E','C','T',' ',
971 '`','D','i','r','e','c','t','o','r','y','_','`',
972 ' ','F','R','O','M',' ',
973 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
974 UINT rc;
975 MSIQUERY *view;
977 /* create all the empty folders specified in the CreateFolder table */
978 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
979 if (rc != ERROR_SUCCESS)
980 return ERROR_SUCCESS;
982 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
983 msiobj_release(&view->hdr);
985 return rc;
988 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
990 MSIPACKAGE *package = param;
991 LPCWSTR dir, component;
992 LPWSTR full_path;
993 MSIRECORD *uirow;
994 MSIFOLDER *folder;
995 MSICOMPONENT *comp;
997 component = MSI_RecordGetString(row, 2);
998 comp = get_loaded_component(package, component);
999 if (!comp)
1000 return ERROR_SUCCESS;
1002 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1004 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1005 comp->Action = comp->Installed;
1006 return ERROR_SUCCESS;
1008 comp->Action = INSTALLSTATE_ABSENT;
1010 dir = MSI_RecordGetString( row, 1 );
1011 if (!dir)
1013 ERR("Unable to get folder id\n");
1014 return ERROR_SUCCESS;
1017 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1018 if (!full_path)
1020 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1021 return ERROR_SUCCESS;
1024 TRACE("folder is %s\n", debugstr_w(full_path));
1026 uirow = MSI_CreateRecord( 1 );
1027 MSI_RecordSetStringW( uirow, 1, full_path );
1028 ui_actiondata( package, szRemoveFolders, uirow );
1029 msiobj_release( &uirow->hdr );
1031 RemoveDirectoryW( full_path );
1032 folder->State = 0;
1034 msi_free( full_path );
1035 return ERROR_SUCCESS;
1038 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1040 static const WCHAR query[] =
1041 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1042 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1044 MSIQUERY *view;
1045 UINT rc;
1047 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1048 if (rc != ERROR_SUCCESS)
1049 return ERROR_SUCCESS;
1051 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1052 msiobj_release( &view->hdr );
1054 return rc;
1057 static UINT load_component( MSIRECORD *row, LPVOID param )
1059 MSIPACKAGE *package = param;
1060 MSICOMPONENT *comp;
1062 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1063 if (!comp)
1064 return ERROR_FUNCTION_FAILED;
1066 list_add_tail( &package->components, &comp->entry );
1068 /* fill in the data */
1069 comp->Component = msi_dup_record_field( row, 1 );
1071 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1073 comp->ComponentId = msi_dup_record_field( row, 2 );
1074 comp->Directory = msi_dup_record_field( row, 3 );
1075 comp->Attributes = MSI_RecordGetInteger(row,4);
1076 comp->Condition = msi_dup_record_field( row, 5 );
1077 comp->KeyPath = msi_dup_record_field( row, 6 );
1079 comp->Installed = INSTALLSTATE_UNKNOWN;
1080 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1082 return ERROR_SUCCESS;
1085 static UINT load_all_components( MSIPACKAGE *package )
1087 static const WCHAR query[] = {
1088 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1089 '`','C','o','m','p','o','n','e','n','t','`',0 };
1090 MSIQUERY *view;
1091 UINT r;
1093 if (!list_empty(&package->components))
1094 return ERROR_SUCCESS;
1096 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1097 if (r != ERROR_SUCCESS)
1098 return r;
1100 r = MSI_IterateRecords(view, NULL, load_component, package);
1101 msiobj_release(&view->hdr);
1102 return r;
1105 typedef struct {
1106 MSIPACKAGE *package;
1107 MSIFEATURE *feature;
1108 } _ilfs;
1110 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1112 ComponentList *cl;
1114 cl = msi_alloc( sizeof (*cl) );
1115 if ( !cl )
1116 return ERROR_NOT_ENOUGH_MEMORY;
1117 cl->component = comp;
1118 list_add_tail( &feature->Components, &cl->entry );
1120 return ERROR_SUCCESS;
1123 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1125 FeatureList *fl;
1127 fl = msi_alloc( sizeof(*fl) );
1128 if ( !fl )
1129 return ERROR_NOT_ENOUGH_MEMORY;
1130 fl->feature = child;
1131 list_add_tail( &parent->Children, &fl->entry );
1133 return ERROR_SUCCESS;
1136 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1138 _ilfs* ilfs = param;
1139 LPCWSTR component;
1140 MSICOMPONENT *comp;
1142 component = MSI_RecordGetString(row,1);
1144 /* check to see if the component is already loaded */
1145 comp = get_loaded_component( ilfs->package, component );
1146 if (!comp)
1148 ERR("unknown component %s\n", debugstr_w(component));
1149 return ERROR_FUNCTION_FAILED;
1152 add_feature_component( ilfs->feature, comp );
1153 comp->Enabled = TRUE;
1155 return ERROR_SUCCESS;
1158 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1160 MSIFEATURE *feature;
1162 if ( !name )
1163 return NULL;
1165 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1167 if ( !lstrcmpW( feature->Feature, name ) )
1168 return feature;
1171 return NULL;
1174 static UINT load_feature(MSIRECORD * row, LPVOID param)
1176 MSIPACKAGE* package = param;
1177 MSIFEATURE* feature;
1178 static const WCHAR Query1[] =
1179 {'S','E','L','E','C','T',' ',
1180 '`','C','o','m','p','o','n','e','n','t','_','`',
1181 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1182 'C','o','m','p','o','n','e','n','t','s','`',' ',
1183 'W','H','E','R','E',' ',
1184 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1185 MSIQUERY * view;
1186 UINT rc;
1187 _ilfs ilfs;
1189 /* fill in the data */
1191 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1192 if (!feature)
1193 return ERROR_NOT_ENOUGH_MEMORY;
1195 list_init( &feature->Children );
1196 list_init( &feature->Components );
1198 feature->Feature = msi_dup_record_field( row, 1 );
1200 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1202 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1203 feature->Title = msi_dup_record_field( row, 3 );
1204 feature->Description = msi_dup_record_field( row, 4 );
1206 if (!MSI_RecordIsNull(row,5))
1207 feature->Display = MSI_RecordGetInteger(row,5);
1209 feature->Level= MSI_RecordGetInteger(row,6);
1210 feature->Directory = msi_dup_record_field( row, 7 );
1211 feature->Attributes = MSI_RecordGetInteger(row,8);
1213 feature->Installed = INSTALLSTATE_UNKNOWN;
1214 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1216 list_add_tail( &package->features, &feature->entry );
1218 /* load feature components */
1220 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1221 if (rc != ERROR_SUCCESS)
1222 return ERROR_SUCCESS;
1224 ilfs.package = package;
1225 ilfs.feature = feature;
1227 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1228 msiobj_release(&view->hdr);
1230 return ERROR_SUCCESS;
1233 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1235 MSIPACKAGE* package = param;
1236 MSIFEATURE *parent, *child;
1238 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1239 if (!child)
1240 return ERROR_FUNCTION_FAILED;
1242 if (!child->Feature_Parent)
1243 return ERROR_SUCCESS;
1245 parent = find_feature_by_name( package, child->Feature_Parent );
1246 if (!parent)
1247 return ERROR_FUNCTION_FAILED;
1249 add_feature_child( parent, child );
1250 return ERROR_SUCCESS;
1253 static UINT load_all_features( MSIPACKAGE *package )
1255 static const WCHAR query[] = {
1256 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1257 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1258 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1259 MSIQUERY *view;
1260 UINT r;
1262 if (!list_empty(&package->features))
1263 return ERROR_SUCCESS;
1265 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1266 if (r != ERROR_SUCCESS)
1267 return r;
1269 r = MSI_IterateRecords( view, NULL, load_feature, package );
1270 if (r != ERROR_SUCCESS)
1271 return r;
1273 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1274 msiobj_release( &view->hdr );
1276 return r;
1279 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1281 if (!p)
1282 return p;
1283 p = strchrW(p, ch);
1284 if (!p)
1285 return p;
1286 *p = 0;
1287 return p+1;
1290 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1292 static const WCHAR query[] = {
1293 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1294 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1295 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1296 MSIQUERY *view = NULL;
1297 MSIRECORD *row = NULL;
1298 UINT r;
1300 TRACE("%s\n", debugstr_w(file->File));
1302 r = MSI_OpenQuery(package->db, &view, query, file->File);
1303 if (r != ERROR_SUCCESS)
1304 goto done;
1306 r = MSI_ViewExecute(view, NULL);
1307 if (r != ERROR_SUCCESS)
1308 goto done;
1310 r = MSI_ViewFetch(view, &row);
1311 if (r != ERROR_SUCCESS)
1312 goto done;
1314 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1315 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1316 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1317 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1318 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1320 done:
1321 if (view) msiobj_release(&view->hdr);
1322 if (row) msiobj_release(&row->hdr);
1323 return r;
1326 static UINT load_file(MSIRECORD *row, LPVOID param)
1328 MSIPACKAGE* package = param;
1329 LPCWSTR component;
1330 MSIFILE *file;
1332 /* fill in the data */
1334 file = msi_alloc_zero( sizeof (MSIFILE) );
1335 if (!file)
1336 return ERROR_NOT_ENOUGH_MEMORY;
1338 file->File = msi_dup_record_field( row, 1 );
1340 component = MSI_RecordGetString( row, 2 );
1341 file->Component = get_loaded_component( package, component );
1343 if (!file->Component)
1345 WARN("Component not found: %s\n", debugstr_w(component));
1346 msi_free(file->File);
1347 msi_free(file);
1348 return ERROR_SUCCESS;
1351 file->FileName = msi_dup_record_field( row, 3 );
1352 reduce_to_longfilename( file->FileName );
1354 file->ShortName = msi_dup_record_field( row, 3 );
1355 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1357 file->FileSize = MSI_RecordGetInteger( row, 4 );
1358 file->Version = msi_dup_record_field( row, 5 );
1359 file->Language = msi_dup_record_field( row, 6 );
1360 file->Attributes = MSI_RecordGetInteger( row, 7 );
1361 file->Sequence = MSI_RecordGetInteger( row, 8 );
1363 file->state = msifs_invalid;
1365 /* if the compressed bits are not set in the file attributes,
1366 * then read the information from the package word count property
1368 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1370 file->IsCompressed = FALSE;
1372 else if (file->Attributes &
1373 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1375 file->IsCompressed = TRUE;
1377 else if (file->Attributes & msidbFileAttributesNoncompressed)
1379 file->IsCompressed = FALSE;
1381 else
1383 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1386 load_file_hash(package, file);
1388 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1390 list_add_tail( &package->files, &file->entry );
1392 return ERROR_SUCCESS;
1395 static UINT load_all_files(MSIPACKAGE *package)
1397 MSIQUERY * view;
1398 UINT rc;
1399 static const WCHAR Query[] =
1400 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1401 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1402 '`','S','e','q','u','e','n','c','e','`', 0};
1404 if (!list_empty(&package->files))
1405 return ERROR_SUCCESS;
1407 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1408 if (rc != ERROR_SUCCESS)
1409 return ERROR_SUCCESS;
1411 rc = MSI_IterateRecords(view, NULL, load_file, package);
1412 msiobj_release(&view->hdr);
1414 return ERROR_SUCCESS;
1417 static UINT load_folder( MSIRECORD *row, LPVOID param )
1419 MSIPACKAGE *package = param;
1420 static WCHAR szEmpty[] = { 0 };
1421 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1422 MSIFOLDER *folder;
1424 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1425 if (!folder)
1426 return ERROR_NOT_ENOUGH_MEMORY;
1428 folder->Directory = msi_dup_record_field( row, 1 );
1430 TRACE("%s\n", debugstr_w(folder->Directory));
1432 p = msi_dup_record_field(row, 3);
1434 /* split src and target dir */
1435 tgt_short = p;
1436 src_short = folder_split_path( p, ':' );
1438 /* split the long and short paths */
1439 tgt_long = folder_split_path( tgt_short, '|' );
1440 src_long = folder_split_path( src_short, '|' );
1442 /* check for no-op dirs */
1443 if (!lstrcmpW(szDot, tgt_short))
1444 tgt_short = szEmpty;
1445 if (!lstrcmpW(szDot, src_short))
1446 src_short = szEmpty;
1448 if (!tgt_long)
1449 tgt_long = tgt_short;
1451 if (!src_short) {
1452 src_short = tgt_short;
1453 src_long = tgt_long;
1456 if (!src_long)
1457 src_long = src_short;
1459 /* FIXME: use the target short path too */
1460 folder->TargetDefault = strdupW(tgt_long);
1461 folder->SourceShortPath = strdupW(src_short);
1462 folder->SourceLongPath = strdupW(src_long);
1463 msi_free(p);
1465 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1466 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1467 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1469 folder->Parent = msi_dup_record_field( row, 2 );
1471 folder->Property = msi_dup_property( package, folder->Directory );
1473 list_add_tail( &package->folders, &folder->entry );
1475 TRACE("returning %p\n", folder);
1477 return ERROR_SUCCESS;
1480 static UINT load_all_folders( MSIPACKAGE *package )
1482 static const WCHAR query[] = {
1483 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1484 '`','D','i','r','e','c','t','o','r','y','`',0 };
1485 MSIQUERY *view;
1486 UINT r;
1488 if (!list_empty(&package->folders))
1489 return ERROR_SUCCESS;
1491 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1492 if (r != ERROR_SUCCESS)
1493 return r;
1495 r = MSI_IterateRecords(view, NULL, load_folder, package);
1496 msiobj_release(&view->hdr);
1497 return r;
1501 * I am not doing any of the costing functionality yet.
1502 * Mostly looking at doing the Component and Feature loading
1504 * The native MSI does A LOT of modification to tables here. Mostly adding
1505 * a lot of temporary columns to the Feature and Component tables.
1507 * note: Native msi also tracks the short filename. But I am only going to
1508 * track the long ones. Also looking at this directory table
1509 * it appears that the directory table does not get the parents
1510 * resolved base on property only based on their entries in the
1511 * directory table.
1513 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1515 static const WCHAR szCosting[] =
1516 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1518 MSI_SetPropertyW(package, szCosting, szZero);
1519 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1521 load_all_folders( package );
1522 load_all_components( package );
1523 load_all_features( package );
1524 load_all_files( package );
1526 return ERROR_SUCCESS;
1529 static UINT execute_script(MSIPACKAGE *package, UINT script )
1531 UINT i;
1532 UINT rc = ERROR_SUCCESS;
1534 TRACE("Executing Script %i\n",script);
1536 if (!package->script)
1538 ERR("no script!\n");
1539 return ERROR_FUNCTION_FAILED;
1542 for (i = 0; i < package->script->ActionCount[script]; i++)
1544 LPWSTR action;
1545 action = package->script->Actions[script][i];
1546 ui_actionstart(package, action);
1547 TRACE("Executing Action (%s)\n",debugstr_w(action));
1548 rc = ACTION_PerformAction(package, action, script, TRUE);
1549 if (rc != ERROR_SUCCESS)
1550 break;
1552 msi_free_action_script(package, script);
1553 return rc;
1556 static UINT ACTION_FileCost(MSIPACKAGE *package)
1558 return ERROR_SUCCESS;
1561 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1563 MSICOMPONENT *comp;
1564 INSTALLSTATE state;
1565 UINT r;
1567 state = MsiQueryProductStateW(package->ProductCode);
1569 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1571 if (!comp->ComponentId)
1572 continue;
1574 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1575 comp->Installed = INSTALLSTATE_ABSENT;
1576 else
1578 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1579 package->Context, comp->ComponentId,
1580 &comp->Installed);
1581 if (r != ERROR_SUCCESS)
1582 comp->Installed = INSTALLSTATE_ABSENT;
1587 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1589 MSIFEATURE *feature;
1590 INSTALLSTATE state;
1592 state = MsiQueryProductStateW(package->ProductCode);
1594 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1596 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1597 feature->Installed = INSTALLSTATE_ABSENT;
1598 else
1600 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1601 feature->Feature);
1606 static BOOL process_state_property(MSIPACKAGE* package, int level,
1607 LPCWSTR property, INSTALLSTATE state)
1609 LPWSTR override;
1610 MSIFEATURE *feature;
1612 override = msi_dup_property( package, property );
1613 if (!override)
1614 return FALSE;
1616 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1618 if (lstrcmpW(property, szRemove) &&
1619 (feature->Level <= 0 || feature->Level > level))
1620 continue;
1622 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1624 if (strcmpiW(override, szAll)==0)
1625 msi_feature_set_state(package, feature, state);
1626 else
1628 LPWSTR ptr = override;
1629 LPWSTR ptr2 = strchrW(override,',');
1631 while (ptr)
1633 int len = ptr2 - ptr;
1635 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1636 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1638 msi_feature_set_state(package, feature, state);
1639 break;
1641 if (ptr2)
1643 ptr=ptr2+1;
1644 ptr2 = strchrW(ptr,',');
1646 else
1647 break;
1651 msi_free(override);
1653 return TRUE;
1656 static BOOL process_overrides( MSIPACKAGE *package, int level )
1658 static const WCHAR szAddLocal[] =
1659 {'A','D','D','L','O','C','A','L',0};
1660 static const WCHAR szAddSource[] =
1661 {'A','D','D','S','O','U','R','C','E',0};
1662 static const WCHAR szAdvertise[] =
1663 {'A','D','V','E','R','T','I','S','E',0};
1664 BOOL ret = FALSE;
1666 /* all these activation/deactivation things happen in order and things
1667 * later on the list override things earlier on the list.
1669 * 0 INSTALLLEVEL processing
1670 * 1 ADDLOCAL
1671 * 2 REMOVE
1672 * 3 ADDSOURCE
1673 * 4 ADDDEFAULT
1674 * 5 REINSTALL
1675 * 6 ADVERTISE
1676 * 7 COMPADDLOCAL
1677 * 8 COMPADDSOURCE
1678 * 9 FILEADDLOCAL
1679 * 10 FILEADDSOURCE
1680 * 11 FILEADDDEFAULT
1682 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1683 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1684 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1685 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1686 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1688 if (ret)
1689 MSI_SetPropertyW( package, szPreselected, szOne );
1691 return ret;
1694 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1696 int level;
1697 static const WCHAR szlevel[] =
1698 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1699 MSICOMPONENT* component;
1700 MSIFEATURE *feature;
1702 TRACE("Checking Install Level\n");
1704 level = msi_get_property_int(package, szlevel, 1);
1706 if (!msi_get_property_int( package, szPreselected, 0 ))
1708 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1710 BOOL feature_state = ((feature->Level > 0) &&
1711 (feature->Level <= level));
1713 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1715 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1716 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1717 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1718 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1719 else
1720 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1724 /* disable child features of unselected parent features */
1725 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1727 FeatureList *fl;
1729 if (feature->Level > 0 && feature->Level <= level)
1730 continue;
1732 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1733 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1738 * now we want to enable or disable components base on feature
1741 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1743 ComponentList *cl;
1745 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1746 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1748 if (!feature->Level)
1749 continue;
1751 /* features with components that have compressed files are made local */
1752 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1754 if (cl->component->Enabled &&
1755 cl->component->ForceLocalState &&
1756 feature->Action == INSTALLSTATE_SOURCE)
1758 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1759 break;
1763 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1765 component = cl->component;
1767 if (!component->Enabled)
1768 continue;
1770 switch (feature->Action)
1772 case INSTALLSTATE_ABSENT:
1773 component->anyAbsent = 1;
1774 break;
1775 case INSTALLSTATE_ADVERTISED:
1776 component->hasAdvertiseFeature = 1;
1777 break;
1778 case INSTALLSTATE_SOURCE:
1779 component->hasSourceFeature = 1;
1780 break;
1781 case INSTALLSTATE_LOCAL:
1782 component->hasLocalFeature = 1;
1783 break;
1784 case INSTALLSTATE_DEFAULT:
1785 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1786 component->hasAdvertiseFeature = 1;
1787 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1788 component->hasSourceFeature = 1;
1789 else
1790 component->hasLocalFeature = 1;
1791 break;
1792 default:
1793 break;
1798 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1800 /* if the component isn't enabled, leave it alone */
1801 if (!component->Enabled)
1802 continue;
1804 /* check if it's local or source */
1805 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1806 (component->hasLocalFeature || component->hasSourceFeature))
1808 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1809 !component->ForceLocalState)
1810 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1811 else
1812 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1813 continue;
1816 /* if any feature is local, the component must be local too */
1817 if (component->hasLocalFeature)
1819 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1820 continue;
1823 if (component->hasSourceFeature)
1825 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1826 continue;
1829 if (component->hasAdvertiseFeature)
1831 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1832 continue;
1835 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1836 if (component->anyAbsent)
1837 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1840 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1842 if (component->Action == INSTALLSTATE_DEFAULT)
1844 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1845 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1848 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1849 debugstr_w(component->Component), component->Installed, component->Action);
1853 return ERROR_SUCCESS;
1856 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1858 MSIPACKAGE *package = param;
1859 LPCWSTR name;
1860 LPWSTR path;
1861 MSIFOLDER *f;
1863 name = MSI_RecordGetString(row,1);
1865 f = get_loaded_folder(package, name);
1866 if (!f) return ERROR_SUCCESS;
1868 /* reset the ResolvedTarget */
1869 msi_free(f->ResolvedTarget);
1870 f->ResolvedTarget = NULL;
1872 /* This helper function now does ALL the work */
1873 TRACE("Dir %s ...\n",debugstr_w(name));
1874 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1875 TRACE("resolves to %s\n",debugstr_w(path));
1876 msi_free(path);
1878 return ERROR_SUCCESS;
1881 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1883 MSIPACKAGE *package = param;
1884 LPCWSTR name;
1885 MSIFEATURE *feature;
1887 name = MSI_RecordGetString( row, 1 );
1889 feature = get_loaded_feature( package, name );
1890 if (!feature)
1891 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1892 else
1894 LPCWSTR Condition;
1895 Condition = MSI_RecordGetString(row,3);
1897 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1899 int level = MSI_RecordGetInteger(row,2);
1900 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1901 feature->Level = level;
1904 return ERROR_SUCCESS;
1907 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1909 static const WCHAR name_fmt[] =
1910 {'%','u','.','%','u','.','%','u','.','%','u',0};
1911 static const WCHAR name[] = {'\\',0};
1912 VS_FIXEDFILEINFO *lpVer;
1913 WCHAR filever[0x100];
1914 LPVOID version;
1915 DWORD versize;
1916 DWORD handle;
1917 UINT sz;
1919 TRACE("%s\n", debugstr_w(filename));
1921 versize = GetFileVersionInfoSizeW( filename, &handle );
1922 if (!versize)
1923 return NULL;
1925 version = msi_alloc( versize );
1926 GetFileVersionInfoW( filename, 0, versize, version );
1928 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1930 msi_free( version );
1931 return NULL;
1934 sprintfW( filever, name_fmt,
1935 HIWORD(lpVer->dwFileVersionMS),
1936 LOWORD(lpVer->dwFileVersionMS),
1937 HIWORD(lpVer->dwFileVersionLS),
1938 LOWORD(lpVer->dwFileVersionLS));
1940 msi_free( version );
1942 return strdupW( filever );
1945 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1947 LPWSTR file_version;
1948 MSIFILE *file;
1950 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1952 MSICOMPONENT* comp = file->Component;
1953 LPWSTR p;
1955 if (!comp)
1956 continue;
1958 if (file->IsCompressed)
1959 comp->ForceLocalState = TRUE;
1961 /* calculate target */
1962 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1964 msi_free(file->TargetPath);
1966 TRACE("file %s is named %s\n",
1967 debugstr_w(file->File), debugstr_w(file->FileName));
1969 file->TargetPath = build_directory_name(2, p, file->FileName);
1971 msi_free(p);
1973 TRACE("file %s resolves to %s\n",
1974 debugstr_w(file->File), debugstr_w(file->TargetPath));
1976 /* don't check files of components that aren't installed */
1977 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1978 comp->Installed == INSTALLSTATE_ABSENT)
1980 file->state = msifs_missing; /* assume files are missing */
1981 continue;
1984 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1986 file->state = msifs_missing;
1987 comp->Cost += file->FileSize;
1988 continue;
1991 if (file->Version &&
1992 (file_version = msi_get_disk_file_version( file->TargetPath )))
1994 TRACE("new %s old %s\n", debugstr_w(file->Version),
1995 debugstr_w(file_version));
1996 /* FIXME: seems like a bad way to compare version numbers */
1997 if (lstrcmpiW(file_version, file->Version)<0)
1999 file->state = msifs_overwrite;
2000 comp->Cost += file->FileSize;
2002 else
2003 file->state = msifs_present;
2004 msi_free( file_version );
2006 else
2007 file->state = msifs_present;
2010 return ERROR_SUCCESS;
2014 * A lot is done in this function aside from just the costing.
2015 * The costing needs to be implemented at some point but for now I am going
2016 * to focus on the directory building
2019 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2021 static const WCHAR ExecSeqQuery[] =
2022 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2023 '`','D','i','r','e','c','t','o','r','y','`',0};
2024 static const WCHAR ConditionQuery[] =
2025 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2026 '`','C','o','n','d','i','t','i','o','n','`',0};
2027 static const WCHAR szCosting[] =
2028 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2029 static const WCHAR szlevel[] =
2030 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2031 static const WCHAR szOutOfDiskSpace[] =
2032 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2033 MSICOMPONENT *comp;
2034 UINT rc = ERROR_SUCCESS;
2035 MSIQUERY * view;
2036 LPWSTR level;
2038 TRACE("Building Directory properties\n");
2040 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2041 if (rc == ERROR_SUCCESS)
2043 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2044 package);
2045 msiobj_release(&view->hdr);
2048 /* read components states from the registry */
2049 ACTION_GetComponentInstallStates(package);
2050 ACTION_GetFeatureInstallStates(package);
2052 TRACE("File calculations\n");
2053 msi_check_file_install_states( package );
2055 if (!process_overrides( package, msi_get_property_int( package, szlevel, 1 ) ))
2057 TRACE("Evaluating Condition Table\n");
2059 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2060 if (rc == ERROR_SUCCESS)
2062 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2063 msiobj_release( &view->hdr );
2066 TRACE("Enabling or Disabling Components\n");
2067 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2069 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2071 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2072 comp->Enabled = FALSE;
2074 else
2075 comp->Enabled = TRUE;
2079 MSI_SetPropertyW(package,szCosting,szOne);
2080 /* set default run level if not set */
2081 level = msi_dup_property( package, szlevel );
2082 if (!level)
2083 MSI_SetPropertyW(package,szlevel, szOne);
2084 msi_free(level);
2086 /* FIXME: check volume disk space */
2087 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2089 return MSI_SetFeatureStates(package);
2092 /* OK this value is "interpreted" and then formatted based on the
2093 first few characters */
2094 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2095 DWORD *size)
2097 LPSTR data = NULL;
2099 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2101 if (value[1]=='x')
2103 LPWSTR ptr;
2104 CHAR byte[5];
2105 LPWSTR deformated = NULL;
2106 int count;
2108 deformat_string(package, &value[2], &deformated);
2110 /* binary value type */
2111 ptr = deformated;
2112 *type = REG_BINARY;
2113 if (strlenW(ptr)%2)
2114 *size = (strlenW(ptr)/2)+1;
2115 else
2116 *size = strlenW(ptr)/2;
2118 data = msi_alloc(*size);
2120 byte[0] = '0';
2121 byte[1] = 'x';
2122 byte[4] = 0;
2123 count = 0;
2124 /* if uneven pad with a zero in front */
2125 if (strlenW(ptr)%2)
2127 byte[2]= '0';
2128 byte[3]= *ptr;
2129 ptr++;
2130 data[count] = (BYTE)strtol(byte,NULL,0);
2131 count ++;
2132 TRACE("Uneven byte count\n");
2134 while (*ptr)
2136 byte[2]= *ptr;
2137 ptr++;
2138 byte[3]= *ptr;
2139 ptr++;
2140 data[count] = (BYTE)strtol(byte,NULL,0);
2141 count ++;
2143 msi_free(deformated);
2145 TRACE("Data %i bytes(%i)\n",*size,count);
2147 else
2149 LPWSTR deformated;
2150 LPWSTR p;
2151 DWORD d = 0;
2152 deformat_string(package, &value[1], &deformated);
2154 *type=REG_DWORD;
2155 *size = sizeof(DWORD);
2156 data = msi_alloc(*size);
2157 p = deformated;
2158 if (*p == '-')
2159 p++;
2160 while (*p)
2162 if ( (*p < '0') || (*p > '9') )
2163 break;
2164 d *= 10;
2165 d += (*p - '0');
2166 p++;
2168 if (deformated[0] == '-')
2169 d = -d;
2170 *(LPDWORD)data = d;
2171 TRACE("DWORD %i\n",*(LPDWORD)data);
2173 msi_free(deformated);
2176 else
2178 static const WCHAR szMulti[] = {'[','~',']',0};
2179 LPCWSTR ptr;
2180 *type=REG_SZ;
2182 if (value[0]=='#')
2184 if (value[1]=='%')
2186 ptr = &value[2];
2187 *type=REG_EXPAND_SZ;
2189 else
2190 ptr = &value[1];
2192 else
2193 ptr=value;
2195 if (strstrW(value,szMulti))
2196 *type = REG_MULTI_SZ;
2198 /* remove initial delimiter */
2199 if (!strncmpW(value, szMulti, 3))
2200 ptr = value + 3;
2202 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2204 /* add double NULL terminator */
2205 if (*type == REG_MULTI_SZ)
2207 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2208 data = msi_realloc_zero(data, *size);
2211 return data;
2214 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2216 const WCHAR *ret;
2218 switch (root)
2220 case -1:
2221 if (msi_get_property_int( package, szAllUsers, 0 ))
2223 *root_key = HKEY_LOCAL_MACHINE;
2224 ret = szHLM;
2226 else
2228 *root_key = HKEY_CURRENT_USER;
2229 ret = szHCU;
2231 break;
2232 case 0:
2233 *root_key = HKEY_CLASSES_ROOT;
2234 ret = szHCR;
2235 break;
2236 case 1:
2237 *root_key = HKEY_CURRENT_USER;
2238 ret = szHCU;
2239 break;
2240 case 2:
2241 *root_key = HKEY_LOCAL_MACHINE;
2242 ret = szHLM;
2243 break;
2244 case 3:
2245 *root_key = HKEY_USERS;
2246 ret = szHU;
2247 break;
2248 default:
2249 ERR("Unknown root %i\n", root);
2250 return NULL;
2253 return ret;
2256 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2258 MSIPACKAGE *package = param;
2259 LPSTR value_data = NULL;
2260 HKEY root_key, hkey;
2261 DWORD type,size;
2262 LPWSTR deformated;
2263 LPCWSTR szRoot, component, name, key, value;
2264 MSICOMPONENT *comp;
2265 MSIRECORD * uirow;
2266 LPWSTR uikey;
2267 INT root;
2268 BOOL check_first = FALSE;
2269 UINT rc;
2271 ui_progress(package,2,0,0,0);
2273 value = NULL;
2274 key = NULL;
2275 uikey = NULL;
2276 name = NULL;
2278 component = MSI_RecordGetString(row, 6);
2279 comp = get_loaded_component(package,component);
2280 if (!comp)
2281 return ERROR_SUCCESS;
2283 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2285 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2286 comp->Action = comp->Installed;
2287 return ERROR_SUCCESS;
2289 comp->Action = INSTALLSTATE_LOCAL;
2291 name = MSI_RecordGetString(row, 4);
2292 if( MSI_RecordIsNull(row,5) && name )
2294 /* null values can have special meanings */
2295 if (name[0]=='-' && name[1] == 0)
2296 return ERROR_SUCCESS;
2297 else if ((name[0]=='+' && name[1] == 0) ||
2298 (name[0] == '*' && name[1] == 0))
2299 name = NULL;
2300 check_first = TRUE;
2303 root = MSI_RecordGetInteger(row,2);
2304 key = MSI_RecordGetString(row, 3);
2306 szRoot = get_root_key( package, root, &root_key );
2307 if (!szRoot)
2308 return ERROR_SUCCESS;
2310 deformat_string(package, key , &deformated);
2311 size = strlenW(deformated) + strlenW(szRoot) + 1;
2312 uikey = msi_alloc(size*sizeof(WCHAR));
2313 strcpyW(uikey,szRoot);
2314 strcatW(uikey,deformated);
2316 if (RegCreateKeyW( root_key, deformated, &hkey))
2318 ERR("Could not create key %s\n",debugstr_w(deformated));
2319 msi_free(deformated);
2320 msi_free(uikey);
2321 return ERROR_SUCCESS;
2323 msi_free(deformated);
2325 value = MSI_RecordGetString(row,5);
2326 if (value)
2327 value_data = parse_value(package, value, &type, &size);
2328 else
2330 value_data = (LPSTR)strdupW(szEmpty);
2331 size = sizeof(szEmpty);
2332 type = REG_SZ;
2335 deformat_string(package, name, &deformated);
2337 if (!check_first)
2339 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2340 debugstr_w(uikey));
2341 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2343 else
2345 DWORD sz = 0;
2346 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2347 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2349 TRACE("value %s of %s checked already exists\n",
2350 debugstr_w(deformated), debugstr_w(uikey));
2352 else
2354 TRACE("Checked and setting value %s of %s\n",
2355 debugstr_w(deformated), debugstr_w(uikey));
2356 if (deformated || size)
2357 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2360 RegCloseKey(hkey);
2362 uirow = MSI_CreateRecord(3);
2363 MSI_RecordSetStringW(uirow,2,deformated);
2364 MSI_RecordSetStringW(uirow,1,uikey);
2366 if (type == REG_SZ)
2367 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2368 else
2369 MSI_RecordSetStringW(uirow,3,value);
2371 ui_actiondata(package,szWriteRegistryValues,uirow);
2372 msiobj_release( &uirow->hdr );
2374 msi_free(value_data);
2375 msi_free(deformated);
2376 msi_free(uikey);
2378 return ERROR_SUCCESS;
2381 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2383 UINT rc;
2384 MSIQUERY * view;
2385 static const WCHAR ExecSeqQuery[] =
2386 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2387 '`','R','e','g','i','s','t','r','y','`',0 };
2389 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2390 if (rc != ERROR_SUCCESS)
2391 return ERROR_SUCCESS;
2393 /* increment progress bar each time action data is sent */
2394 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2396 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2398 msiobj_release(&view->hdr);
2399 return rc;
2402 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2404 LONG res;
2405 HKEY hkey;
2406 DWORD num_subkeys, num_values;
2408 if (delete_key)
2410 if ((res = RegDeleteTreeW( hkey_root, key )))
2412 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2414 return;
2417 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2419 if ((res = RegDeleteValueW( hkey, value )))
2421 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2423 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2424 NULL, NULL, NULL, NULL );
2425 RegCloseKey( hkey );
2427 if (!res && !num_subkeys && !num_values)
2429 TRACE("Removing empty key %s\n", debugstr_w(key));
2430 RegDeleteKeyW( hkey_root, key );
2432 return;
2434 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2438 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2440 MSIPACKAGE *package = param;
2441 LPCWSTR component, name, key_str, root_key_str;
2442 LPWSTR deformated_key, deformated_name, ui_key_str;
2443 MSICOMPONENT *comp;
2444 MSIRECORD *uirow;
2445 BOOL delete_key = FALSE;
2446 HKEY hkey_root;
2447 UINT size;
2448 INT root;
2450 ui_progress( package, 2, 0, 0, 0 );
2452 component = MSI_RecordGetString( row, 6 );
2453 comp = get_loaded_component( package, component );
2454 if (!comp)
2455 return ERROR_SUCCESS;
2457 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2459 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2460 comp->Action = comp->Installed;
2461 return ERROR_SUCCESS;
2463 comp->Action = INSTALLSTATE_ABSENT;
2465 name = MSI_RecordGetString( row, 4 );
2466 if (MSI_RecordIsNull( row, 5 ) && name )
2468 if (name[0] == '+' && !name[1])
2469 return ERROR_SUCCESS;
2470 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2472 delete_key = TRUE;
2473 name = NULL;
2477 root = MSI_RecordGetInteger( row, 2 );
2478 key_str = MSI_RecordGetString( row, 3 );
2480 root_key_str = get_root_key( package, root, &hkey_root );
2481 if (!root_key_str)
2482 return ERROR_SUCCESS;
2484 deformat_string( package, key_str, &deformated_key );
2485 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2486 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2487 strcpyW( ui_key_str, root_key_str );
2488 strcatW( ui_key_str, deformated_key );
2490 deformat_string( package, name, &deformated_name );
2492 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2493 msi_free( deformated_key );
2495 uirow = MSI_CreateRecord( 2 );
2496 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2497 MSI_RecordSetStringW( uirow, 2, deformated_name );
2499 ui_actiondata( package, szRemoveRegistryValues, uirow );
2500 msiobj_release( &uirow->hdr );
2502 msi_free( ui_key_str );
2503 msi_free( deformated_name );
2504 return ERROR_SUCCESS;
2507 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2509 MSIPACKAGE *package = param;
2510 LPCWSTR component, name, key_str, root_key_str;
2511 LPWSTR deformated_key, deformated_name, ui_key_str;
2512 MSICOMPONENT *comp;
2513 MSIRECORD *uirow;
2514 BOOL delete_key = FALSE;
2515 HKEY hkey_root;
2516 UINT size;
2517 INT root;
2519 ui_progress( package, 2, 0, 0, 0 );
2521 component = MSI_RecordGetString( row, 5 );
2522 comp = get_loaded_component( package, component );
2523 if (!comp)
2524 return ERROR_SUCCESS;
2526 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2528 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2529 comp->Action = comp->Installed;
2530 return ERROR_SUCCESS;
2532 comp->Action = INSTALLSTATE_LOCAL;
2534 if ((name = MSI_RecordGetString( row, 4 )))
2536 if (name[0] == '-' && !name[1])
2538 delete_key = TRUE;
2539 name = NULL;
2543 root = MSI_RecordGetInteger( row, 2 );
2544 key_str = MSI_RecordGetString( row, 3 );
2546 root_key_str = get_root_key( package, root, &hkey_root );
2547 if (!root_key_str)
2548 return ERROR_SUCCESS;
2550 deformat_string( package, key_str, &deformated_key );
2551 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2552 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2553 strcpyW( ui_key_str, root_key_str );
2554 strcatW( ui_key_str, deformated_key );
2556 deformat_string( package, name, &deformated_name );
2558 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2559 msi_free( deformated_key );
2561 uirow = MSI_CreateRecord( 2 );
2562 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2563 MSI_RecordSetStringW( uirow, 2, deformated_name );
2565 ui_actiondata( package, szRemoveRegistryValues, uirow );
2566 msiobj_release( &uirow->hdr );
2568 msi_free( ui_key_str );
2569 msi_free( deformated_name );
2570 return ERROR_SUCCESS;
2573 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2575 UINT rc;
2576 MSIQUERY *view;
2577 static const WCHAR registry_query[] =
2578 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2579 '`','R','e','g','i','s','t','r','y','`',0 };
2580 static const WCHAR remove_registry_query[] =
2581 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2582 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2584 /* increment progress bar each time action data is sent */
2585 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2587 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2588 if (rc == ERROR_SUCCESS)
2590 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2591 msiobj_release( &view->hdr );
2592 if (rc != ERROR_SUCCESS)
2593 return rc;
2596 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2597 if (rc == ERROR_SUCCESS)
2599 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2600 msiobj_release( &view->hdr );
2601 if (rc != ERROR_SUCCESS)
2602 return rc;
2605 return ERROR_SUCCESS;
2608 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2610 package->script->CurrentlyScripting = TRUE;
2612 return ERROR_SUCCESS;
2616 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2618 MSICOMPONENT *comp;
2619 DWORD progress = 0;
2620 DWORD total = 0;
2621 static const WCHAR q1[]=
2622 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2623 '`','R','e','g','i','s','t','r','y','`',0};
2624 UINT rc;
2625 MSIQUERY * view;
2626 MSIFEATURE *feature;
2627 MSIFILE *file;
2629 TRACE("InstallValidate\n");
2631 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2632 if (rc == ERROR_SUCCESS)
2634 MSI_IterateRecords( view, &progress, NULL, package );
2635 msiobj_release( &view->hdr );
2636 total += progress * REG_PROGRESS_VALUE;
2639 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2640 total += COMPONENT_PROGRESS_VALUE;
2642 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2643 total += file->FileSize;
2645 ui_progress(package,0,total,0,0);
2647 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2649 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2650 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2651 feature->ActionRequest);
2654 return ERROR_SUCCESS;
2657 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2659 MSIPACKAGE* package = param;
2660 LPCWSTR cond = NULL;
2661 LPCWSTR message = NULL;
2662 UINT r;
2664 static const WCHAR title[]=
2665 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2667 cond = MSI_RecordGetString(row,1);
2669 r = MSI_EvaluateConditionW(package,cond);
2670 if (r == MSICONDITION_FALSE)
2672 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2674 LPWSTR deformated;
2675 message = MSI_RecordGetString(row,2);
2676 deformat_string(package,message,&deformated);
2677 MessageBoxW(NULL,deformated,title,MB_OK);
2678 msi_free(deformated);
2681 return ERROR_INSTALL_FAILURE;
2684 return ERROR_SUCCESS;
2687 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2689 UINT rc;
2690 MSIQUERY * view = NULL;
2691 static const WCHAR ExecSeqQuery[] =
2692 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2693 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2695 TRACE("Checking launch conditions\n");
2697 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2698 if (rc != ERROR_SUCCESS)
2699 return ERROR_SUCCESS;
2701 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2702 msiobj_release(&view->hdr);
2704 return rc;
2707 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2710 if (!cmp->KeyPath)
2711 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2713 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2715 MSIRECORD * row = 0;
2716 UINT root,len;
2717 LPWSTR deformated,buffer,deformated_name;
2718 LPCWSTR key,name;
2719 static const WCHAR ExecSeqQuery[] =
2720 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2721 '`','R','e','g','i','s','t','r','y','`',' ',
2722 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2723 ' ','=',' ' ,'\'','%','s','\'',0 };
2724 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2725 static const WCHAR fmt2[]=
2726 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2728 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2729 if (!row)
2730 return NULL;
2732 root = MSI_RecordGetInteger(row,2);
2733 key = MSI_RecordGetString(row, 3);
2734 name = MSI_RecordGetString(row, 4);
2735 deformat_string(package, key , &deformated);
2736 deformat_string(package, name, &deformated_name);
2738 len = strlenW(deformated) + 6;
2739 if (deformated_name)
2740 len+=strlenW(deformated_name);
2742 buffer = msi_alloc( len *sizeof(WCHAR));
2744 if (deformated_name)
2745 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2746 else
2747 sprintfW(buffer,fmt,root,deformated);
2749 msi_free(deformated);
2750 msi_free(deformated_name);
2751 msiobj_release(&row->hdr);
2753 return buffer;
2755 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2757 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2758 return NULL;
2760 else
2762 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2764 if (file)
2765 return strdupW( file->TargetPath );
2767 return NULL;
2770 static HKEY openSharedDLLsKey(void)
2772 HKEY hkey=0;
2773 static const WCHAR path[] =
2774 {'S','o','f','t','w','a','r','e','\\',
2775 'M','i','c','r','o','s','o','f','t','\\',
2776 'W','i','n','d','o','w','s','\\',
2777 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2778 'S','h','a','r','e','d','D','L','L','s',0};
2780 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2781 return hkey;
2784 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2786 HKEY hkey;
2787 DWORD count=0;
2788 DWORD type;
2789 DWORD sz = sizeof(count);
2790 DWORD rc;
2792 hkey = openSharedDLLsKey();
2793 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2794 if (rc != ERROR_SUCCESS)
2795 count = 0;
2796 RegCloseKey(hkey);
2797 return count;
2800 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2802 HKEY hkey;
2804 hkey = openSharedDLLsKey();
2805 if (count > 0)
2806 msi_reg_set_val_dword( hkey, path, count );
2807 else
2808 RegDeleteValueW(hkey,path);
2809 RegCloseKey(hkey);
2810 return count;
2814 * Return TRUE if the count should be written out and FALSE if not
2816 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2818 MSIFEATURE *feature;
2819 INT count = 0;
2820 BOOL write = FALSE;
2822 /* only refcount DLLs */
2823 if (comp->KeyPath == NULL ||
2824 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2825 comp->Attributes & msidbComponentAttributesODBCDataSource)
2826 write = FALSE;
2827 else
2829 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2830 write = (count > 0);
2832 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2833 write = TRUE;
2836 /* increment counts */
2837 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2839 ComponentList *cl;
2841 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2842 continue;
2844 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2846 if ( cl->component == comp )
2847 count++;
2851 /* decrement counts */
2852 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2854 ComponentList *cl;
2856 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2857 continue;
2859 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2861 if ( cl->component == comp )
2862 count--;
2866 /* ref count all the files in the component */
2867 if (write)
2869 MSIFILE *file;
2871 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2873 if (file->Component == comp)
2874 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2878 /* add a count for permanent */
2879 if (comp->Attributes & msidbComponentAttributesPermanent)
2880 count ++;
2882 comp->RefCount = count;
2884 if (write)
2885 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2888 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2890 WCHAR squished_pc[GUID_SIZE];
2891 WCHAR squished_cc[GUID_SIZE];
2892 UINT rc;
2893 MSICOMPONENT *comp;
2894 HKEY hkey;
2896 TRACE("\n");
2898 squash_guid(package->ProductCode,squished_pc);
2899 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2901 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2903 MSIRECORD * uirow;
2905 ui_progress(package,2,0,0,0);
2906 if (!comp->ComponentId)
2907 continue;
2909 squash_guid(comp->ComponentId,squished_cc);
2911 msi_free(comp->FullKeypath);
2912 comp->FullKeypath = resolve_keypath( package, comp );
2914 ACTION_RefCountComponent( package, comp );
2916 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2917 debugstr_w(comp->Component),
2918 debugstr_w(squished_cc),
2919 debugstr_w(comp->FullKeypath),
2920 comp->RefCount);
2922 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2923 comp->ActionRequest == INSTALLSTATE_SOURCE)
2925 if (!comp->FullKeypath)
2926 continue;
2928 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2929 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2930 &hkey, TRUE);
2931 else
2932 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2933 &hkey, TRUE);
2935 if (rc != ERROR_SUCCESS)
2936 continue;
2938 if (comp->Attributes & msidbComponentAttributesPermanent)
2940 static const WCHAR szPermKey[] =
2941 { '0','0','0','0','0','0','0','0','0','0','0','0',
2942 '0','0','0','0','0','0','0','0','0','0','0','0',
2943 '0','0','0','0','0','0','0','0',0 };
2945 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2948 if (comp->Action == INSTALLSTATE_LOCAL)
2949 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2950 else
2952 MSIFILE *file;
2953 MSIRECORD *row;
2954 LPWSTR ptr, ptr2;
2955 WCHAR source[MAX_PATH];
2956 WCHAR base[MAX_PATH];
2957 LPWSTR sourcepath;
2959 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2960 static const WCHAR query[] = {
2961 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2962 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2963 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2964 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2965 '`','D','i','s','k','I','d','`',0};
2967 file = get_loaded_file(package, comp->KeyPath);
2968 if (!file)
2969 continue;
2971 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2972 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2973 ptr2 = strrchrW(source, '\\') + 1;
2974 msiobj_release(&row->hdr);
2976 lstrcpyW(base, package->PackagePath);
2977 ptr = strrchrW(base, '\\');
2978 *(ptr + 1) = '\0';
2980 sourcepath = resolve_file_source(package, file);
2981 ptr = sourcepath + lstrlenW(base);
2982 lstrcpyW(ptr2, ptr);
2983 msi_free(sourcepath);
2985 msi_reg_set_val_str(hkey, squished_pc, source);
2987 RegCloseKey(hkey);
2989 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
2991 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2992 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2993 else
2994 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2997 /* UI stuff */
2998 uirow = MSI_CreateRecord(3);
2999 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3000 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3001 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3002 ui_actiondata(package,szProcessComponents,uirow);
3003 msiobj_release( &uirow->hdr );
3006 return ERROR_SUCCESS;
3009 typedef struct {
3010 CLSID clsid;
3011 LPWSTR source;
3013 LPWSTR path;
3014 ITypeLib *ptLib;
3015 } typelib_struct;
3017 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3018 LPWSTR lpszName, LONG_PTR lParam)
3020 TLIBATTR *attr;
3021 typelib_struct *tl_struct = (typelib_struct*) lParam;
3022 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3023 int sz;
3024 HRESULT res;
3026 if (!IS_INTRESOURCE(lpszName))
3028 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3029 return TRUE;
3032 sz = strlenW(tl_struct->source)+4;
3033 sz *= sizeof(WCHAR);
3035 if ((INT_PTR)lpszName == 1)
3036 tl_struct->path = strdupW(tl_struct->source);
3037 else
3039 tl_struct->path = msi_alloc(sz);
3040 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3043 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3044 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3045 if (FAILED(res))
3047 msi_free(tl_struct->path);
3048 tl_struct->path = NULL;
3050 return TRUE;
3053 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3054 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3056 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3057 return FALSE;
3060 msi_free(tl_struct->path);
3061 tl_struct->path = NULL;
3063 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3064 ITypeLib_Release(tl_struct->ptLib);
3066 return TRUE;
3069 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3071 MSIPACKAGE* package = param;
3072 LPCWSTR component;
3073 MSICOMPONENT *comp;
3074 MSIFILE *file;
3075 typelib_struct tl_struct;
3076 ITypeLib *tlib;
3077 HMODULE module;
3078 HRESULT hr;
3080 component = MSI_RecordGetString(row,3);
3081 comp = get_loaded_component(package,component);
3082 if (!comp)
3083 return ERROR_SUCCESS;
3085 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3087 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3088 comp->Action = comp->Installed;
3089 return ERROR_SUCCESS;
3091 comp->Action = INSTALLSTATE_LOCAL;
3093 file = get_loaded_file( package, comp->KeyPath );
3094 if (!file)
3095 return ERROR_SUCCESS;
3097 ui_actiondata( package, szRegisterTypeLibraries, row );
3099 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3100 if (module)
3102 LPCWSTR guid;
3103 guid = MSI_RecordGetString(row,1);
3104 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
3105 tl_struct.source = strdupW( file->TargetPath );
3106 tl_struct.path = NULL;
3108 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3109 (LONG_PTR)&tl_struct);
3111 if (tl_struct.path)
3113 LPWSTR help = NULL;
3114 LPCWSTR helpid;
3115 HRESULT res;
3117 helpid = MSI_RecordGetString(row,6);
3119 if (helpid)
3120 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3121 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3122 msi_free(help);
3124 if (FAILED(res))
3125 ERR("Failed to register type library %s\n",
3126 debugstr_w(tl_struct.path));
3127 else
3128 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3130 ITypeLib_Release(tl_struct.ptLib);
3131 msi_free(tl_struct.path);
3133 else
3134 ERR("Failed to load type library %s\n",
3135 debugstr_w(tl_struct.source));
3137 FreeLibrary(module);
3138 msi_free(tl_struct.source);
3140 else
3142 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3143 if (FAILED(hr))
3145 ERR("Failed to load type library: %08x\n", hr);
3146 return ERROR_INSTALL_FAILURE;
3149 ITypeLib_Release(tlib);
3152 return ERROR_SUCCESS;
3155 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3158 * OK this is a bit confusing.. I am given a _Component key and I believe
3159 * that the file that is being registered as a type library is the "key file
3160 * of that component" which I interpret to mean "The file in the KeyPath of
3161 * that component".
3163 UINT rc;
3164 MSIQUERY * view;
3165 static const WCHAR Query[] =
3166 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3167 '`','T','y','p','e','L','i','b','`',0};
3169 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3170 if (rc != ERROR_SUCCESS)
3171 return ERROR_SUCCESS;
3173 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3174 msiobj_release(&view->hdr);
3175 return rc;
3178 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3180 MSIPACKAGE *package = param;
3181 LPCWSTR component, guid;
3182 MSICOMPONENT *comp;
3183 GUID libid;
3184 UINT version;
3185 LCID language;
3186 SYSKIND syskind;
3187 HRESULT hr;
3189 component = MSI_RecordGetString( row, 3 );
3190 comp = get_loaded_component( package, component );
3191 if (!comp)
3192 return ERROR_SUCCESS;
3194 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3196 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3197 comp->Action = comp->Installed;
3198 return ERROR_SUCCESS;
3200 comp->Action = INSTALLSTATE_ABSENT;
3202 ui_actiondata( package, szUnregisterTypeLibraries, row );
3204 guid = MSI_RecordGetString( row, 1 );
3205 CLSIDFromString( (LPWSTR)guid, &libid );
3206 version = MSI_RecordGetInteger( row, 4 );
3207 language = MSI_RecordGetInteger( row, 2 );
3209 #ifdef _WIN64
3210 syskind = SYS_WIN64;
3211 #else
3212 syskind = SYS_WIN32;
3213 #endif
3215 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3216 if (FAILED(hr))
3218 WARN("Failed to unregister typelib: %08x\n", hr);
3221 return ERROR_SUCCESS;
3224 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3226 UINT rc;
3227 MSIQUERY *view;
3228 static const WCHAR query[] =
3229 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3230 '`','T','y','p','e','L','i','b','`',0};
3232 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3233 if (rc != ERROR_SUCCESS)
3234 return ERROR_SUCCESS;
3236 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3237 msiobj_release( &view->hdr );
3238 return rc;
3241 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3243 static const WCHAR szlnk[] = {'.','l','n','k',0};
3244 LPCWSTR directory, extension;
3245 LPWSTR link_folder, link_file, filename;
3247 directory = MSI_RecordGetString( row, 2 );
3248 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3250 /* may be needed because of a bug somewhere else */
3251 create_full_pathW( link_folder );
3253 filename = msi_dup_record_field( row, 3 );
3254 reduce_to_longfilename( filename );
3256 extension = strchrW( filename, '.' );
3257 if (!extension || strcmpiW( extension, szlnk ))
3259 int len = strlenW( filename );
3260 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3261 memcpy( filename + len, szlnk, sizeof(szlnk) );
3263 link_file = build_directory_name( 2, link_folder, filename );
3264 msi_free( link_folder );
3265 msi_free( filename );
3267 return link_file;
3270 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3272 MSIPACKAGE *package = param;
3273 LPWSTR link_file, deformated, path;
3274 LPCWSTR component, target;
3275 MSICOMPONENT *comp;
3276 IShellLinkW *sl = NULL;
3277 IPersistFile *pf = NULL;
3278 HRESULT res;
3280 component = MSI_RecordGetString(row, 4);
3281 comp = get_loaded_component(package, component);
3282 if (!comp)
3283 return ERROR_SUCCESS;
3285 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3287 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3288 comp->Action = comp->Installed;
3289 return ERROR_SUCCESS;
3291 comp->Action = INSTALLSTATE_LOCAL;
3293 ui_actiondata(package,szCreateShortcuts,row);
3295 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3296 &IID_IShellLinkW, (LPVOID *) &sl );
3298 if (FAILED( res ))
3300 ERR("CLSID_ShellLink not available\n");
3301 goto err;
3304 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3305 if (FAILED( res ))
3307 ERR("QueryInterface(IID_IPersistFile) failed\n");
3308 goto err;
3311 target = MSI_RecordGetString(row, 5);
3312 if (strchrW(target, '['))
3314 deformat_string(package, target, &deformated);
3315 IShellLinkW_SetPath(sl,deformated);
3316 msi_free(deformated);
3318 else
3320 FIXME("poorly handled shortcut format, advertised shortcut\n");
3321 IShellLinkW_SetPath(sl,comp->FullKeypath);
3324 if (!MSI_RecordIsNull(row,6))
3326 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3327 deformat_string(package, arguments, &deformated);
3328 IShellLinkW_SetArguments(sl,deformated);
3329 msi_free(deformated);
3332 if (!MSI_RecordIsNull(row,7))
3334 LPCWSTR description = MSI_RecordGetString(row, 7);
3335 IShellLinkW_SetDescription(sl, description);
3338 if (!MSI_RecordIsNull(row,8))
3339 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3341 if (!MSI_RecordIsNull(row,9))
3343 INT index;
3344 LPCWSTR icon = MSI_RecordGetString(row, 9);
3346 path = build_icon_path(package, icon);
3347 index = MSI_RecordGetInteger(row,10);
3349 /* no value means 0 */
3350 if (index == MSI_NULL_INTEGER)
3351 index = 0;
3353 IShellLinkW_SetIconLocation(sl, path, index);
3354 msi_free(path);
3357 if (!MSI_RecordIsNull(row,11))
3358 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3360 if (!MSI_RecordIsNull(row,12))
3362 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3363 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3364 if (path)
3365 IShellLinkW_SetWorkingDirectory(sl, path);
3366 msi_free(path);
3369 link_file = get_link_file(package, row);
3371 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3372 IPersistFile_Save(pf, link_file, FALSE);
3374 msi_free(link_file);
3376 err:
3377 if (pf)
3378 IPersistFile_Release( pf );
3379 if (sl)
3380 IShellLinkW_Release( sl );
3382 return ERROR_SUCCESS;
3385 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3387 UINT rc;
3388 HRESULT res;
3389 MSIQUERY * view;
3390 static const WCHAR Query[] =
3391 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3392 '`','S','h','o','r','t','c','u','t','`',0};
3394 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3395 if (rc != ERROR_SUCCESS)
3396 return ERROR_SUCCESS;
3398 res = CoInitialize( NULL );
3400 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3401 msiobj_release(&view->hdr);
3403 if (SUCCEEDED(res))
3404 CoUninitialize();
3406 return rc;
3409 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3411 MSIPACKAGE *package = param;
3412 LPWSTR link_file;
3413 LPCWSTR component;
3414 MSICOMPONENT *comp;
3416 component = MSI_RecordGetString( row, 4 );
3417 comp = get_loaded_component( package, component );
3418 if (!comp)
3419 return ERROR_SUCCESS;
3421 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3423 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3424 comp->Action = comp->Installed;
3425 return ERROR_SUCCESS;
3427 comp->Action = INSTALLSTATE_ABSENT;
3429 ui_actiondata( package, szRemoveShortcuts, row );
3431 link_file = get_link_file( package, row );
3433 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3434 if (!DeleteFileW( link_file ))
3436 WARN("Failed to remove shortcut file %u\n", GetLastError());
3438 msi_free( link_file );
3440 return ERROR_SUCCESS;
3443 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3445 UINT rc;
3446 MSIQUERY *view;
3447 static const WCHAR query[] =
3448 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3449 '`','S','h','o','r','t','c','u','t','`',0};
3451 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3452 if (rc != ERROR_SUCCESS)
3453 return ERROR_SUCCESS;
3455 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3456 msiobj_release( &view->hdr );
3458 return rc;
3461 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3463 MSIPACKAGE* package = param;
3464 HANDLE the_file;
3465 LPWSTR FilePath;
3466 LPCWSTR FileName;
3467 CHAR buffer[1024];
3468 DWORD sz;
3469 UINT rc;
3471 FileName = MSI_RecordGetString(row,1);
3472 if (!FileName)
3474 ERR("Unable to get FileName\n");
3475 return ERROR_SUCCESS;
3478 FilePath = build_icon_path(package,FileName);
3480 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3482 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3483 FILE_ATTRIBUTE_NORMAL, NULL);
3485 if (the_file == INVALID_HANDLE_VALUE)
3487 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3488 msi_free(FilePath);
3489 return ERROR_SUCCESS;
3494 DWORD write;
3495 sz = 1024;
3496 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3497 if (rc != ERROR_SUCCESS)
3499 ERR("Failed to get stream\n");
3500 CloseHandle(the_file);
3501 DeleteFileW(FilePath);
3502 break;
3504 WriteFile(the_file,buffer,sz,&write,NULL);
3505 } while (sz == 1024);
3507 msi_free(FilePath);
3508 CloseHandle(the_file);
3510 return ERROR_SUCCESS;
3513 static UINT msi_publish_icons(MSIPACKAGE *package)
3515 UINT r;
3516 MSIQUERY *view;
3518 static const WCHAR query[]= {
3519 'S','E','L','E','C','T',' ','*',' ',
3520 'F','R','O','M',' ','`','I','c','o','n','`',0};
3522 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3523 if (r == ERROR_SUCCESS)
3525 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3526 msiobj_release(&view->hdr);
3529 return ERROR_SUCCESS;
3532 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3534 UINT r;
3535 HKEY source;
3536 LPWSTR buffer;
3537 MSIMEDIADISK *disk;
3538 MSISOURCELISTINFO *info;
3540 r = RegCreateKeyW(hkey, szSourceList, &source);
3541 if (r != ERROR_SUCCESS)
3542 return r;
3544 RegCloseKey(source);
3546 buffer = strrchrW(package->PackagePath, '\\') + 1;
3547 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3548 package->Context, MSICODE_PRODUCT,
3549 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3550 if (r != ERROR_SUCCESS)
3551 return r;
3553 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3554 package->Context, MSICODE_PRODUCT,
3555 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3556 if (r != ERROR_SUCCESS)
3557 return r;
3559 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3560 package->Context, MSICODE_PRODUCT,
3561 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3562 if (r != ERROR_SUCCESS)
3563 return r;
3565 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3567 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3568 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3569 info->options, info->value);
3570 else
3571 MsiSourceListSetInfoW(package->ProductCode, NULL,
3572 info->context, info->options,
3573 info->property, info->value);
3576 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3578 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3579 disk->context, disk->options,
3580 disk->disk_id, disk->volume_label, disk->disk_prompt);
3583 return ERROR_SUCCESS;
3586 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3588 MSIHANDLE hdb, suminfo;
3589 WCHAR guids[MAX_PATH];
3590 WCHAR packcode[SQUISH_GUID_SIZE];
3591 LPWSTR buffer;
3592 LPWSTR ptr;
3593 DWORD langid;
3594 DWORD size;
3595 UINT r;
3597 static const WCHAR szProductLanguage[] =
3598 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3599 static const WCHAR szARPProductIcon[] =
3600 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3601 static const WCHAR szProductVersion[] =
3602 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3603 static const WCHAR szAssignment[] =
3604 {'A','s','s','i','g','n','m','e','n','t',0};
3605 static const WCHAR szAdvertiseFlags[] =
3606 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3607 static const WCHAR szClients[] =
3608 {'C','l','i','e','n','t','s',0};
3609 static const WCHAR szColon[] = {':',0};
3611 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3612 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3613 msi_free(buffer);
3615 langid = msi_get_property_int(package, szProductLanguage, 0);
3616 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3618 /* FIXME */
3619 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3621 buffer = msi_dup_property(package, szARPProductIcon);
3622 if (buffer)
3624 LPWSTR path = build_icon_path(package,buffer);
3625 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3626 msi_free(path);
3627 msi_free(buffer);
3630 buffer = msi_dup_property(package, szProductVersion);
3631 if (buffer)
3633 DWORD verdword = msi_version_str_to_dword(buffer);
3634 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3635 msi_free(buffer);
3638 msi_reg_set_val_dword(hkey, szAssignment, 0);
3639 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3640 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3641 msi_reg_set_val_str(hkey, szClients, szColon);
3643 hdb = alloc_msihandle(&package->db->hdr);
3644 if (!hdb)
3645 return ERROR_NOT_ENOUGH_MEMORY;
3647 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3648 MsiCloseHandle(hdb);
3649 if (r != ERROR_SUCCESS)
3650 goto done;
3652 size = MAX_PATH;
3653 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3654 NULL, guids, &size);
3655 if (r != ERROR_SUCCESS)
3656 goto done;
3658 ptr = strchrW(guids, ';');
3659 if (ptr) *ptr = 0;
3660 squash_guid(guids, packcode);
3661 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3663 done:
3664 MsiCloseHandle(suminfo);
3665 return ERROR_SUCCESS;
3668 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3670 UINT r;
3671 HKEY hkey;
3672 LPWSTR upgrade;
3673 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3675 static const WCHAR szUpgradeCode[] =
3676 {'U','p','g','r','a','d','e','C','o','d','e',0};
3678 upgrade = msi_dup_property(package, szUpgradeCode);
3679 if (!upgrade)
3680 return ERROR_SUCCESS;
3682 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3684 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3685 if (r != ERROR_SUCCESS)
3686 goto done;
3688 else
3690 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3691 if (r != ERROR_SUCCESS)
3692 goto done;
3695 squash_guid(package->ProductCode, squashed_pc);
3696 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3698 RegCloseKey(hkey);
3700 done:
3701 msi_free(upgrade);
3702 return r;
3705 static BOOL msi_check_publish(MSIPACKAGE *package)
3707 MSIFEATURE *feature;
3709 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3711 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3712 return TRUE;
3715 return FALSE;
3718 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3720 MSIFEATURE *feature;
3722 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3724 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3725 return FALSE;
3728 return TRUE;
3731 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3733 WCHAR patch_squashed[GUID_SIZE];
3734 HKEY patches;
3735 LONG res;
3736 UINT r = ERROR_FUNCTION_FAILED;
3738 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3739 &patches, NULL);
3740 if (res != ERROR_SUCCESS)
3741 return ERROR_FUNCTION_FAILED;
3743 squash_guid(package->patch->patchcode, patch_squashed);
3745 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3746 (const BYTE *)patch_squashed,
3747 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3748 if (res != ERROR_SUCCESS)
3749 goto done;
3751 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3752 (const BYTE *)package->patch->transforms,
3753 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3754 if (res == ERROR_SUCCESS)
3755 r = ERROR_SUCCESS;
3757 done:
3758 RegCloseKey(patches);
3759 return r;
3763 * 99% of the work done here is only done for
3764 * advertised installs. However this is where the
3765 * Icon table is processed and written out
3766 * so that is what I am going to do here.
3768 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3770 UINT rc;
3771 HKEY hukey = NULL, hudkey = NULL;
3772 MSIRECORD *uirow;
3774 /* FIXME: also need to publish if the product is in advertise mode */
3775 if (!msi_check_publish(package))
3776 return ERROR_SUCCESS;
3778 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3779 &hukey, TRUE);
3780 if (rc != ERROR_SUCCESS)
3781 goto end;
3783 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3784 NULL, &hudkey, TRUE);
3785 if (rc != ERROR_SUCCESS)
3786 goto end;
3788 rc = msi_publish_upgrade_code(package);
3789 if (rc != ERROR_SUCCESS)
3790 goto end;
3792 if (package->patch)
3794 rc = msi_publish_patch(package, hukey, hudkey);
3795 if (rc != ERROR_SUCCESS)
3796 goto end;
3799 rc = msi_publish_product_properties(package, hukey);
3800 if (rc != ERROR_SUCCESS)
3801 goto end;
3803 rc = msi_publish_sourcelist(package, hukey);
3804 if (rc != ERROR_SUCCESS)
3805 goto end;
3807 rc = msi_publish_icons(package);
3809 end:
3810 uirow = MSI_CreateRecord( 1 );
3811 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3812 ui_actiondata( package, szPublishProduct, uirow );
3813 msiobj_release( &uirow->hdr );
3815 RegCloseKey(hukey);
3816 RegCloseKey(hudkey);
3818 return rc;
3821 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3823 WCHAR *filename, *ptr, *folder, *ret;
3824 const WCHAR *dirprop;
3826 filename = msi_dup_record_field( row, 2 );
3827 if (filename && (ptr = strchrW( filename, '|' )))
3828 ptr++;
3829 else
3830 ptr = filename;
3832 dirprop = MSI_RecordGetString( row, 3 );
3833 if (dirprop)
3835 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3836 if (!folder)
3837 folder = msi_dup_property( package, dirprop );
3839 else
3840 folder = msi_dup_property( package, szWindowsFolder );
3842 if (!folder)
3844 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3845 msi_free( filename );
3846 return NULL;
3849 ret = build_directory_name( 2, folder, ptr );
3851 msi_free( filename );
3852 msi_free( folder );
3853 return ret;
3856 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3858 MSIPACKAGE *package = param;
3859 LPCWSTR component, section, key, value, identifier;
3860 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
3861 MSIRECORD * uirow;
3862 INT action;
3863 MSICOMPONENT *comp;
3865 component = MSI_RecordGetString(row, 8);
3866 comp = get_loaded_component(package,component);
3867 if (!comp)
3868 return ERROR_SUCCESS;
3870 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3872 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3873 comp->Action = comp->Installed;
3874 return ERROR_SUCCESS;
3876 comp->Action = INSTALLSTATE_LOCAL;
3878 identifier = MSI_RecordGetString(row,1);
3879 section = MSI_RecordGetString(row,4);
3880 key = MSI_RecordGetString(row,5);
3881 value = MSI_RecordGetString(row,6);
3882 action = MSI_RecordGetInteger(row,7);
3884 deformat_string(package,section,&deformated_section);
3885 deformat_string(package,key,&deformated_key);
3886 deformat_string(package,value,&deformated_value);
3888 fullname = get_ini_file_name(package, row);
3890 if (action == 0)
3892 TRACE("Adding value %s to section %s in %s\n",
3893 debugstr_w(deformated_key), debugstr_w(deformated_section),
3894 debugstr_w(fullname));
3895 WritePrivateProfileStringW(deformated_section, deformated_key,
3896 deformated_value, fullname);
3898 else if (action == 1)
3900 WCHAR returned[10];
3901 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3902 returned, 10, fullname);
3903 if (returned[0] == 0)
3905 TRACE("Adding value %s to section %s in %s\n",
3906 debugstr_w(deformated_key), debugstr_w(deformated_section),
3907 debugstr_w(fullname));
3909 WritePrivateProfileStringW(deformated_section, deformated_key,
3910 deformated_value, fullname);
3913 else if (action == 3)
3914 FIXME("Append to existing section not yet implemented\n");
3916 uirow = MSI_CreateRecord(4);
3917 MSI_RecordSetStringW(uirow,1,identifier);
3918 MSI_RecordSetStringW(uirow,2,deformated_section);
3919 MSI_RecordSetStringW(uirow,3,deformated_key);
3920 MSI_RecordSetStringW(uirow,4,deformated_value);
3921 ui_actiondata(package,szWriteIniValues,uirow);
3922 msiobj_release( &uirow->hdr );
3924 msi_free(fullname);
3925 msi_free(deformated_key);
3926 msi_free(deformated_value);
3927 msi_free(deformated_section);
3928 return ERROR_SUCCESS;
3931 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3933 UINT rc;
3934 MSIQUERY * view;
3935 static const WCHAR ExecSeqQuery[] =
3936 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3937 '`','I','n','i','F','i','l','e','`',0};
3939 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3940 if (rc != ERROR_SUCCESS)
3942 TRACE("no IniFile table\n");
3943 return ERROR_SUCCESS;
3946 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3947 msiobj_release(&view->hdr);
3948 return rc;
3951 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
3953 MSIPACKAGE *package = param;
3954 LPCWSTR component, section, key, value, identifier;
3955 LPWSTR deformated_section, deformated_key, deformated_value, filename;
3956 MSICOMPONENT *comp;
3957 MSIRECORD *uirow;
3958 INT action;
3960 component = MSI_RecordGetString( row, 8 );
3961 comp = get_loaded_component( package, component );
3962 if (!comp)
3963 return ERROR_SUCCESS;
3965 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3967 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3968 comp->Action = comp->Installed;
3969 return ERROR_SUCCESS;
3971 comp->Action = INSTALLSTATE_ABSENT;
3973 identifier = MSI_RecordGetString( row, 1 );
3974 section = MSI_RecordGetString( row, 4 );
3975 key = MSI_RecordGetString( row, 5 );
3976 value = MSI_RecordGetString( row, 6 );
3977 action = MSI_RecordGetInteger( row, 7 );
3979 deformat_string( package, section, &deformated_section );
3980 deformat_string( package, key, &deformated_key );
3981 deformat_string( package, value, &deformated_value );
3983 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
3985 filename = get_ini_file_name( package, row );
3987 TRACE("Removing key %s from section %s in %s\n",
3988 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
3990 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
3992 WARN("Unable to remove key %u\n", GetLastError());
3994 msi_free( filename );
3996 else
3997 FIXME("Unsupported action %d\n", action);
4000 uirow = MSI_CreateRecord( 4 );
4001 MSI_RecordSetStringW( uirow, 1, identifier );
4002 MSI_RecordSetStringW( uirow, 2, deformated_section );
4003 MSI_RecordSetStringW( uirow, 3, deformated_key );
4004 MSI_RecordSetStringW( uirow, 4, deformated_value );
4005 ui_actiondata( package, szRemoveIniValues, uirow );
4006 msiobj_release( &uirow->hdr );
4008 msi_free( deformated_key );
4009 msi_free( deformated_value );
4010 msi_free( deformated_section );
4011 return ERROR_SUCCESS;
4014 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4016 MSIPACKAGE *package = param;
4017 LPCWSTR component, section, key, value, identifier;
4018 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4019 MSICOMPONENT *comp;
4020 MSIRECORD *uirow;
4021 INT action;
4023 component = MSI_RecordGetString( row, 8 );
4024 comp = get_loaded_component( package, component );
4025 if (!comp)
4026 return ERROR_SUCCESS;
4028 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4030 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4031 comp->Action = comp->Installed;
4032 return ERROR_SUCCESS;
4034 comp->Action = INSTALLSTATE_LOCAL;
4036 identifier = MSI_RecordGetString( row, 1 );
4037 section = MSI_RecordGetString( row, 4 );
4038 key = MSI_RecordGetString( row, 5 );
4039 value = MSI_RecordGetString( row, 6 );
4040 action = MSI_RecordGetInteger( row, 7 );
4042 deformat_string( package, section, &deformated_section );
4043 deformat_string( package, key, &deformated_key );
4044 deformat_string( package, value, &deformated_value );
4046 if (action == msidbIniFileActionRemoveLine)
4048 filename = get_ini_file_name( package, row );
4050 TRACE("Removing key %s from section %s in %s\n",
4051 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4053 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4055 WARN("Unable to remove key %u\n", GetLastError());
4057 msi_free( filename );
4059 else
4060 FIXME("Unsupported action %d\n", action);
4062 uirow = MSI_CreateRecord( 4 );
4063 MSI_RecordSetStringW( uirow, 1, identifier );
4064 MSI_RecordSetStringW( uirow, 2, deformated_section );
4065 MSI_RecordSetStringW( uirow, 3, deformated_key );
4066 MSI_RecordSetStringW( uirow, 4, deformated_value );
4067 ui_actiondata( package, szRemoveIniValues, uirow );
4068 msiobj_release( &uirow->hdr );
4070 msi_free( deformated_key );
4071 msi_free( deformated_value );
4072 msi_free( deformated_section );
4073 return ERROR_SUCCESS;
4076 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4078 UINT rc;
4079 MSIQUERY *view;
4080 static const WCHAR query[] =
4081 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4082 '`','I','n','i','F','i','l','e','`',0};
4083 static const WCHAR remove_query[] =
4084 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4085 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4087 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4088 if (rc == ERROR_SUCCESS)
4090 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4091 msiobj_release( &view->hdr );
4092 if (rc != ERROR_SUCCESS)
4093 return rc;
4096 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4097 if (rc == ERROR_SUCCESS)
4099 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4100 msiobj_release( &view->hdr );
4101 if (rc != ERROR_SUCCESS)
4102 return rc;
4105 return ERROR_SUCCESS;
4108 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4110 MSIPACKAGE *package = param;
4111 LPCWSTR filename;
4112 LPWSTR FullName;
4113 MSIFILE *file;
4114 DWORD len;
4115 static const WCHAR ExeStr[] =
4116 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4117 static const WCHAR close[] = {'\"',0};
4118 STARTUPINFOW si;
4119 PROCESS_INFORMATION info;
4120 BOOL brc;
4121 MSIRECORD *uirow;
4122 LPWSTR uipath, p;
4124 memset(&si,0,sizeof(STARTUPINFOW));
4126 filename = MSI_RecordGetString(row,1);
4127 file = get_loaded_file( package, filename );
4129 if (!file)
4131 ERR("Unable to find file id %s\n",debugstr_w(filename));
4132 return ERROR_SUCCESS;
4135 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4137 FullName = msi_alloc(len*sizeof(WCHAR));
4138 strcpyW(FullName,ExeStr);
4139 strcatW( FullName, file->TargetPath );
4140 strcatW(FullName,close);
4142 TRACE("Registering %s\n",debugstr_w(FullName));
4143 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4144 &si, &info);
4146 if (brc)
4148 CloseHandle(info.hThread);
4149 msi_dialog_check_messages(info.hProcess);
4150 CloseHandle(info.hProcess);
4153 uirow = MSI_CreateRecord( 2 );
4154 MSI_RecordSetStringW( uirow, 1, filename );
4155 uipath = strdupW( file->TargetPath );
4156 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4157 MSI_RecordSetStringW( uirow, 2, uipath );
4158 ui_actiondata( package, szSelfRegModules, uirow );
4159 msiobj_release( &uirow->hdr );
4161 msi_free( FullName );
4162 msi_free( uipath );
4163 return ERROR_SUCCESS;
4166 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4168 UINT rc;
4169 MSIQUERY * view;
4170 static const WCHAR ExecSeqQuery[] =
4171 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4172 '`','S','e','l','f','R','e','g','`',0};
4174 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4175 if (rc != ERROR_SUCCESS)
4177 TRACE("no SelfReg table\n");
4178 return ERROR_SUCCESS;
4181 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4182 msiobj_release(&view->hdr);
4184 return ERROR_SUCCESS;
4187 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4189 static const WCHAR regsvr32[] =
4190 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4191 static const WCHAR close[] = {'\"',0};
4192 MSIPACKAGE *package = param;
4193 LPCWSTR filename;
4194 LPWSTR cmdline;
4195 MSIFILE *file;
4196 DWORD len;
4197 STARTUPINFOW si;
4198 PROCESS_INFORMATION pi;
4199 BOOL ret;
4200 MSIRECORD *uirow;
4201 LPWSTR uipath, p;
4203 memset( &si, 0, sizeof(STARTUPINFOW) );
4205 filename = MSI_RecordGetString( row, 1 );
4206 file = get_loaded_file( package, filename );
4208 if (!file)
4210 ERR("Unable to find file id %s\n", debugstr_w(filename));
4211 return ERROR_SUCCESS;
4214 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4216 cmdline = msi_alloc( len * sizeof(WCHAR) );
4217 strcpyW( cmdline, regsvr32 );
4218 strcatW( cmdline, file->TargetPath );
4219 strcatW( cmdline, close );
4221 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4223 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4224 if (ret)
4226 CloseHandle( pi.hThread );
4227 msi_dialog_check_messages( pi.hProcess );
4228 CloseHandle( pi.hProcess );
4231 uirow = MSI_CreateRecord( 2 );
4232 MSI_RecordSetStringW( uirow, 1, filename );
4233 uipath = strdupW( file->TargetPath );
4234 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4235 MSI_RecordSetStringW( uirow, 2, uipath );
4236 ui_actiondata( package, szSelfUnregModules, uirow );
4237 msiobj_release( &uirow->hdr );
4239 msi_free( cmdline );
4240 msi_free( uipath );
4241 return ERROR_SUCCESS;
4244 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4246 UINT rc;
4247 MSIQUERY *view;
4248 static const WCHAR query[] =
4249 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4250 '`','S','e','l','f','R','e','g','`',0};
4252 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4253 if (rc != ERROR_SUCCESS)
4255 TRACE("no SelfReg table\n");
4256 return ERROR_SUCCESS;
4259 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4260 msiobj_release( &view->hdr );
4262 return ERROR_SUCCESS;
4265 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4267 MSIFEATURE *feature;
4268 UINT rc;
4269 HKEY hkey = NULL, userdata = NULL;
4271 if (!msi_check_publish(package))
4272 return ERROR_SUCCESS;
4274 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4275 &hkey, TRUE);
4276 if (rc != ERROR_SUCCESS)
4277 goto end;
4279 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4280 &userdata, TRUE);
4281 if (rc != ERROR_SUCCESS)
4282 goto end;
4284 /* here the guids are base 85 encoded */
4285 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4287 ComponentList *cl;
4288 LPWSTR data = NULL;
4289 GUID clsid;
4290 INT size;
4291 BOOL absent = FALSE;
4292 MSIRECORD *uirow;
4294 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4295 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4296 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4298 size = 1;
4299 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4301 size += 21;
4303 if (feature->Feature_Parent)
4304 size += strlenW( feature->Feature_Parent )+2;
4306 data = msi_alloc(size * sizeof(WCHAR));
4308 data[0] = 0;
4309 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4311 MSICOMPONENT* component = cl->component;
4312 WCHAR buf[21];
4314 buf[0] = 0;
4315 if (component->ComponentId)
4317 TRACE("From %s\n",debugstr_w(component->ComponentId));
4318 CLSIDFromString(component->ComponentId, &clsid);
4319 encode_base85_guid(&clsid,buf);
4320 TRACE("to %s\n",debugstr_w(buf));
4321 strcatW(data,buf);
4325 if (feature->Feature_Parent)
4327 static const WCHAR sep[] = {'\2',0};
4328 strcatW(data,sep);
4329 strcatW(data,feature->Feature_Parent);
4332 msi_reg_set_val_str( userdata, feature->Feature, data );
4333 msi_free(data);
4335 size = 0;
4336 if (feature->Feature_Parent)
4337 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4338 if (!absent)
4340 size += sizeof(WCHAR);
4341 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4342 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4344 else
4346 size += 2*sizeof(WCHAR);
4347 data = msi_alloc(size);
4348 data[0] = 0x6;
4349 data[1] = 0;
4350 if (feature->Feature_Parent)
4351 strcpyW( &data[1], feature->Feature_Parent );
4352 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4353 (LPBYTE)data,size);
4354 msi_free(data);
4357 /* the UI chunk */
4358 uirow = MSI_CreateRecord( 1 );
4359 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4360 ui_actiondata( package, szPublishFeatures, uirow);
4361 msiobj_release( &uirow->hdr );
4362 /* FIXME: call ui_progress? */
4365 end:
4366 RegCloseKey(hkey);
4367 RegCloseKey(userdata);
4368 return rc;
4371 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4373 UINT r;
4374 HKEY hkey;
4376 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4378 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4379 &hkey, FALSE);
4380 if (r == ERROR_SUCCESS)
4382 RegDeleteValueW(hkey, feature->Feature);
4383 RegCloseKey(hkey);
4386 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4387 &hkey, FALSE);
4388 if (r == ERROR_SUCCESS)
4390 RegDeleteValueW(hkey, feature->Feature);
4391 RegCloseKey(hkey);
4394 return ERROR_SUCCESS;
4397 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4399 MSIFEATURE *feature;
4401 if (!msi_check_unpublish(package))
4402 return ERROR_SUCCESS;
4404 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4406 msi_unpublish_feature(package, feature);
4409 return ERROR_SUCCESS;
4412 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4414 LPWSTR prop, val, key;
4415 SYSTEMTIME systime;
4416 DWORD size, langid;
4417 WCHAR date[9];
4418 LPWSTR buffer;
4420 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4421 static const WCHAR szWindowsInstaller[] =
4422 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4423 static const WCHAR modpath_fmt[] =
4424 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4425 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4426 static const WCHAR szModifyPath[] =
4427 {'M','o','d','i','f','y','P','a','t','h',0};
4428 static const WCHAR szUninstallString[] =
4429 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4430 static const WCHAR szEstimatedSize[] =
4431 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4432 static const WCHAR szProductLanguage[] =
4433 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4434 static const WCHAR szProductVersion[] =
4435 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4436 static const WCHAR szProductName[] =
4437 {'P','r','o','d','u','c','t','N','a','m','e',0};
4438 static const WCHAR szDisplayName[] =
4439 {'D','i','s','p','l','a','y','N','a','m','e',0};
4440 static const WCHAR szDisplayVersion[] =
4441 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4442 static const WCHAR szManufacturer[] =
4443 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4445 static const LPCSTR propval[] = {
4446 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4447 "ARPCONTACT", "Contact",
4448 "ARPCOMMENTS", "Comments",
4449 "ProductName", "DisplayName",
4450 "ProductVersion", "DisplayVersion",
4451 "ARPHELPLINK", "HelpLink",
4452 "ARPHELPTELEPHONE", "HelpTelephone",
4453 "ARPINSTALLLOCATION", "InstallLocation",
4454 "SourceDir", "InstallSource",
4455 "Manufacturer", "Publisher",
4456 "ARPREADME", "Readme",
4457 "ARPSIZE", "Size",
4458 "ARPURLINFOABOUT", "URLInfoAbout",
4459 "ARPURLUPDATEINFO", "URLUpdateInfo",
4460 NULL,
4462 const LPCSTR *p = propval;
4464 while (*p)
4466 prop = strdupAtoW(*p++);
4467 key = strdupAtoW(*p++);
4468 val = msi_dup_property(package, prop);
4469 msi_reg_set_val_str(hkey, key, val);
4470 msi_free(val);
4471 msi_free(key);
4472 msi_free(prop);
4475 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4477 size = deformat_string(package, modpath_fmt, &buffer);
4478 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4479 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4480 msi_free(buffer);
4482 /* FIXME: Write real Estimated Size when we have it */
4483 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4485 buffer = msi_dup_property(package, szProductName);
4486 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4487 msi_free(buffer);
4489 buffer = msi_dup_property(package, cszSourceDir);
4490 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4491 msi_free(buffer);
4493 buffer = msi_dup_property(package, szManufacturer);
4494 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4495 msi_free(buffer);
4497 GetLocalTime(&systime);
4498 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4499 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4501 langid = msi_get_property_int(package, szProductLanguage, 0);
4502 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4504 buffer = msi_dup_property(package, szProductVersion);
4505 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4506 if (buffer)
4508 DWORD verdword = msi_version_str_to_dword(buffer);
4510 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4511 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4512 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4513 msi_free(buffer);
4516 return ERROR_SUCCESS;
4519 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4521 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4522 MSIRECORD *uirow;
4523 LPWSTR upgrade_code;
4524 HKEY hkey, props;
4525 HKEY upgrade;
4526 UINT rc;
4528 static const WCHAR szUpgradeCode[] = {
4529 'U','p','g','r','a','d','e','C','o','d','e',0};
4531 /* FIXME: also need to publish if the product is in advertise mode */
4532 if (!msi_check_publish(package))
4533 return ERROR_SUCCESS;
4535 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4536 if (rc != ERROR_SUCCESS)
4537 return rc;
4539 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4540 NULL, &props, TRUE);
4541 if (rc != ERROR_SUCCESS)
4542 goto done;
4544 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4545 msi_free( package->db->localfile );
4546 package->db->localfile = NULL;
4548 rc = msi_publish_install_properties(package, hkey);
4549 if (rc != ERROR_SUCCESS)
4550 goto done;
4552 rc = msi_publish_install_properties(package, props);
4553 if (rc != ERROR_SUCCESS)
4554 goto done;
4556 upgrade_code = msi_dup_property(package, szUpgradeCode);
4557 if (upgrade_code)
4559 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4560 squash_guid(package->ProductCode, squashed_pc);
4561 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4562 RegCloseKey(upgrade);
4563 msi_free(upgrade_code);
4566 done:
4567 uirow = MSI_CreateRecord( 1 );
4568 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4569 ui_actiondata( package, szRegisterProduct, uirow );
4570 msiobj_release( &uirow->hdr );
4572 RegCloseKey(hkey);
4573 return ERROR_SUCCESS;
4576 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4578 return execute_script(package,INSTALL_SCRIPT);
4581 static UINT msi_unpublish_product(MSIPACKAGE *package)
4583 LPWSTR upgrade;
4584 LPWSTR remove = NULL;
4585 LPWSTR *features = NULL;
4586 BOOL full_uninstall = TRUE;
4587 MSIFEATURE *feature;
4589 static const WCHAR szUpgradeCode[] =
4590 {'U','p','g','r','a','d','e','C','o','d','e',0};
4592 remove = msi_dup_property(package, szRemove);
4593 if (!remove)
4594 return ERROR_SUCCESS;
4596 features = msi_split_string(remove, ',');
4597 if (!features)
4599 msi_free(remove);
4600 ERR("REMOVE feature list is empty!\n");
4601 return ERROR_FUNCTION_FAILED;
4604 if (!lstrcmpW(features[0], szAll))
4605 full_uninstall = TRUE;
4606 else
4608 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4610 if (feature->Action != INSTALLSTATE_ABSENT)
4611 full_uninstall = FALSE;
4615 if (!full_uninstall)
4616 goto done;
4618 MSIREG_DeleteProductKey(package->ProductCode);
4619 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4620 MSIREG_DeleteUninstallKey(package->ProductCode);
4622 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4624 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4625 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4627 else
4629 MSIREG_DeleteUserProductKey(package->ProductCode);
4630 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4633 upgrade = msi_dup_property(package, szUpgradeCode);
4634 if (upgrade)
4636 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4637 msi_free(upgrade);
4640 done:
4641 msi_free(remove);
4642 msi_free(features);
4643 return ERROR_SUCCESS;
4646 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4648 UINT rc;
4650 rc = msi_unpublish_product(package);
4651 if (rc != ERROR_SUCCESS)
4652 return rc;
4654 /* turn off scheduling */
4655 package->script->CurrentlyScripting= FALSE;
4657 /* first do the same as an InstallExecute */
4658 rc = ACTION_InstallExecute(package);
4659 if (rc != ERROR_SUCCESS)
4660 return rc;
4662 /* then handle Commit Actions */
4663 rc = execute_script(package,COMMIT_SCRIPT);
4665 return rc;
4668 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4670 static const WCHAR RunOnce[] = {
4671 'S','o','f','t','w','a','r','e','\\',
4672 'M','i','c','r','o','s','o','f','t','\\',
4673 'W','i','n','d','o','w','s','\\',
4674 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4675 'R','u','n','O','n','c','e',0};
4676 static const WCHAR InstallRunOnce[] = {
4677 'S','o','f','t','w','a','r','e','\\',
4678 'M','i','c','r','o','s','o','f','t','\\',
4679 'W','i','n','d','o','w','s','\\',
4680 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4681 'I','n','s','t','a','l','l','e','r','\\',
4682 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4684 static const WCHAR msiexec_fmt[] = {
4685 '%','s',
4686 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4687 '\"','%','s','\"',0};
4688 static const WCHAR install_fmt[] = {
4689 '/','I',' ','\"','%','s','\"',' ',
4690 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4691 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4692 WCHAR buffer[256], sysdir[MAX_PATH];
4693 HKEY hkey;
4694 WCHAR squished_pc[100];
4696 squash_guid(package->ProductCode,squished_pc);
4698 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4699 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4700 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4701 squished_pc);
4703 msi_reg_set_val_str( hkey, squished_pc, buffer );
4704 RegCloseKey(hkey);
4706 TRACE("Reboot command %s\n",debugstr_w(buffer));
4708 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4709 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4711 msi_reg_set_val_str( hkey, squished_pc, buffer );
4712 RegCloseKey(hkey);
4714 return ERROR_INSTALL_SUSPEND;
4717 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4719 DWORD attrib;
4720 UINT rc;
4723 * We are currently doing what should be done here in the top level Install
4724 * however for Administrative and uninstalls this step will be needed
4726 if (!package->PackagePath)
4727 return ERROR_SUCCESS;
4729 msi_set_sourcedir_props(package, TRUE);
4731 attrib = GetFileAttributesW(package->db->path);
4732 if (attrib == INVALID_FILE_ATTRIBUTES)
4734 LPWSTR prompt;
4735 LPWSTR msg;
4736 DWORD size = 0;
4738 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4739 package->Context, MSICODE_PRODUCT,
4740 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4741 if (rc == ERROR_MORE_DATA)
4743 prompt = msi_alloc(size * sizeof(WCHAR));
4744 MsiSourceListGetInfoW(package->ProductCode, NULL,
4745 package->Context, MSICODE_PRODUCT,
4746 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4748 else
4749 prompt = strdupW(package->db->path);
4751 msg = generate_error_string(package,1302,1,prompt);
4752 while(attrib == INVALID_FILE_ATTRIBUTES)
4754 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4755 if (rc == IDCANCEL)
4757 rc = ERROR_INSTALL_USEREXIT;
4758 break;
4760 attrib = GetFileAttributesW(package->db->path);
4762 msi_free(prompt);
4763 rc = ERROR_SUCCESS;
4765 else
4766 return ERROR_SUCCESS;
4768 return rc;
4771 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4773 HKEY hkey = 0;
4774 LPWSTR buffer, productid = NULL;
4775 UINT i, rc = ERROR_SUCCESS;
4776 MSIRECORD *uirow;
4778 static const WCHAR szPropKeys[][80] =
4780 {'P','r','o','d','u','c','t','I','D',0},
4781 {'U','S','E','R','N','A','M','E',0},
4782 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4783 {0},
4786 static const WCHAR szRegKeys[][80] =
4788 {'P','r','o','d','u','c','t','I','D',0},
4789 {'R','e','g','O','w','n','e','r',0},
4790 {'R','e','g','C','o','m','p','a','n','y',0},
4791 {0},
4794 if (msi_check_unpublish(package))
4796 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4797 goto end;
4800 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4801 if (!productid)
4802 goto end;
4804 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4805 NULL, &hkey, TRUE);
4806 if (rc != ERROR_SUCCESS)
4807 goto end;
4809 for( i = 0; szPropKeys[i][0]; i++ )
4811 buffer = msi_dup_property( package, szPropKeys[i] );
4812 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4813 msi_free( buffer );
4816 end:
4817 uirow = MSI_CreateRecord( 1 );
4818 MSI_RecordSetStringW( uirow, 1, productid );
4819 ui_actiondata( package, szRegisterUser, uirow );
4820 msiobj_release( &uirow->hdr );
4822 msi_free(productid);
4823 RegCloseKey(hkey);
4824 return rc;
4828 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4830 UINT rc;
4832 package->script->InWhatSequence |= SEQUENCE_EXEC;
4833 rc = ACTION_ProcessExecSequence(package,FALSE);
4834 return rc;
4838 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4840 MSIPACKAGE *package = param;
4841 LPCWSTR compgroupid, component, feature, qualifier, text;
4842 LPWSTR advertise = NULL, output = NULL;
4843 HKEY hkey = NULL;
4844 UINT rc;
4845 MSICOMPONENT *comp;
4846 MSIFEATURE *feat;
4847 DWORD sz;
4848 MSIRECORD *uirow;
4850 feature = MSI_RecordGetString(rec, 5);
4851 feat = get_loaded_feature(package, feature);
4852 if (!feat)
4853 return ERROR_SUCCESS;
4855 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4856 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4857 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
4859 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4860 feat->Action = feat->Installed;
4861 return ERROR_SUCCESS;
4864 component = MSI_RecordGetString(rec, 3);
4865 comp = get_loaded_component(package, component);
4866 if (!comp)
4867 return ERROR_SUCCESS;
4869 compgroupid = MSI_RecordGetString(rec,1);
4870 qualifier = MSI_RecordGetString(rec,2);
4872 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4873 if (rc != ERROR_SUCCESS)
4874 goto end;
4876 text = MSI_RecordGetString(rec,4);
4877 advertise = create_component_advertise_string(package, comp, feature);
4879 sz = strlenW(advertise);
4881 if (text)
4882 sz += lstrlenW(text);
4884 sz+=3;
4885 sz *= sizeof(WCHAR);
4887 output = msi_alloc_zero(sz);
4888 strcpyW(output,advertise);
4889 msi_free(advertise);
4891 if (text)
4892 strcatW(output,text);
4894 msi_reg_set_val_multi_str( hkey, qualifier, output );
4896 end:
4897 RegCloseKey(hkey);
4898 msi_free(output);
4900 /* the UI chunk */
4901 uirow = MSI_CreateRecord( 2 );
4902 MSI_RecordSetStringW( uirow, 1, compgroupid );
4903 MSI_RecordSetStringW( uirow, 2, qualifier);
4904 ui_actiondata( package, szPublishComponents, uirow);
4905 msiobj_release( &uirow->hdr );
4906 /* FIXME: call ui_progress? */
4908 return rc;
4912 * At present I am ignorning the advertised components part of this and only
4913 * focusing on the qualified component sets
4915 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4917 UINT rc;
4918 MSIQUERY * view;
4919 static const WCHAR ExecSeqQuery[] =
4920 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4921 '`','P','u','b','l','i','s','h',
4922 'C','o','m','p','o','n','e','n','t','`',0};
4924 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4925 if (rc != ERROR_SUCCESS)
4926 return ERROR_SUCCESS;
4928 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4929 msiobj_release(&view->hdr);
4931 return rc;
4934 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
4936 static const WCHAR szInstallerComponents[] = {
4937 'S','o','f','t','w','a','r','e','\\',
4938 'M','i','c','r','o','s','o','f','t','\\',
4939 'I','n','s','t','a','l','l','e','r','\\',
4940 'C','o','m','p','o','n','e','n','t','s','\\',0};
4942 MSIPACKAGE *package = param;
4943 LPCWSTR compgroupid, component, feature, qualifier;
4944 MSICOMPONENT *comp;
4945 MSIFEATURE *feat;
4946 MSIRECORD *uirow;
4947 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
4948 LONG res;
4950 feature = MSI_RecordGetString( rec, 5 );
4951 feat = get_loaded_feature( package, feature );
4952 if (!feat)
4953 return ERROR_SUCCESS;
4955 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
4957 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
4958 feat->Action = feat->Installed;
4959 return ERROR_SUCCESS;
4962 component = MSI_RecordGetString( rec, 3 );
4963 comp = get_loaded_component( package, component );
4964 if (!comp)
4965 return ERROR_SUCCESS;
4967 compgroupid = MSI_RecordGetString( rec, 1 );
4968 qualifier = MSI_RecordGetString( rec, 2 );
4970 squash_guid( compgroupid, squashed );
4971 strcpyW( keypath, szInstallerComponents );
4972 strcatW( keypath, squashed );
4974 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
4975 if (res != ERROR_SUCCESS)
4977 WARN("Unable to delete component key %d\n", res);
4980 uirow = MSI_CreateRecord( 2 );
4981 MSI_RecordSetStringW( uirow, 1, compgroupid );
4982 MSI_RecordSetStringW( uirow, 2, qualifier );
4983 ui_actiondata( package, szUnpublishComponents, uirow );
4984 msiobj_release( &uirow->hdr );
4986 return ERROR_SUCCESS;
4989 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
4991 UINT rc;
4992 MSIQUERY *view;
4993 static const WCHAR query[] =
4994 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4995 '`','P','u','b','l','i','s','h',
4996 'C','o','m','p','o','n','e','n','t','`',0};
4998 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4999 if (rc != ERROR_SUCCESS)
5000 return ERROR_SUCCESS;
5002 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5003 msiobj_release( &view->hdr );
5005 return rc;
5008 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5010 MSIPACKAGE *package = param;
5011 MSIRECORD *row;
5012 MSIFILE *file;
5013 SC_HANDLE hscm, service = NULL;
5014 LPCWSTR comp, depends, pass;
5015 LPWSTR name = NULL, disp = NULL;
5016 LPCWSTR load_order, serv_name, key;
5017 DWORD serv_type, start_type;
5018 DWORD err_control;
5020 static const WCHAR query[] =
5021 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5022 '`','C','o','m','p','o','n','e','n','t','`',' ',
5023 'W','H','E','R','E',' ',
5024 '`','C','o','m','p','o','n','e','n','t','`',' ',
5025 '=','\'','%','s','\'',0};
5027 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5028 if (!hscm)
5030 ERR("Failed to open the SC Manager!\n");
5031 goto done;
5034 start_type = MSI_RecordGetInteger(rec, 5);
5035 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5036 goto done;
5038 depends = MSI_RecordGetString(rec, 8);
5039 if (depends && *depends)
5040 FIXME("Dependency list unhandled!\n");
5042 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5043 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5044 serv_type = MSI_RecordGetInteger(rec, 4);
5045 err_control = MSI_RecordGetInteger(rec, 6);
5046 load_order = MSI_RecordGetString(rec, 7);
5047 serv_name = MSI_RecordGetString(rec, 9);
5048 pass = MSI_RecordGetString(rec, 10);
5049 comp = MSI_RecordGetString(rec, 12);
5051 /* fetch the service path */
5052 row = MSI_QueryGetRecord(package->db, query, comp);
5053 if (!row)
5055 ERR("Control query failed!\n");
5056 goto done;
5059 key = MSI_RecordGetString(row, 6);
5061 file = get_loaded_file(package, key);
5062 msiobj_release(&row->hdr);
5063 if (!file)
5065 ERR("Failed to load the service file\n");
5066 goto done;
5069 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5070 start_type, err_control, file->TargetPath,
5071 load_order, NULL, NULL, serv_name, pass);
5072 if (!service)
5074 if (GetLastError() != ERROR_SERVICE_EXISTS)
5075 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5078 done:
5079 CloseServiceHandle(service);
5080 CloseServiceHandle(hscm);
5081 msi_free(name);
5082 msi_free(disp);
5084 return ERROR_SUCCESS;
5087 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5089 UINT rc;
5090 MSIQUERY * view;
5091 static const WCHAR ExecSeqQuery[] =
5092 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5093 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5095 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5096 if (rc != ERROR_SUCCESS)
5097 return ERROR_SUCCESS;
5099 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5100 msiobj_release(&view->hdr);
5102 return rc;
5105 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5106 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5108 LPCWSTR *vector, *temp_vector;
5109 LPWSTR p, q;
5110 DWORD sep_len;
5112 static const WCHAR separator[] = {'[','~',']',0};
5114 *numargs = 0;
5115 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5117 if (!args)
5118 return NULL;
5120 vector = msi_alloc(sizeof(LPWSTR));
5121 if (!vector)
5122 return NULL;
5124 p = args;
5127 (*numargs)++;
5128 vector[*numargs - 1] = p;
5130 if ((q = strstrW(p, separator)))
5132 *q = '\0';
5134 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5135 if (!temp_vector)
5137 msi_free(vector);
5138 return NULL;
5140 vector = temp_vector;
5142 p = q + sep_len;
5144 } while (q);
5146 return vector;
5149 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5151 MSIPACKAGE *package = param;
5152 MSICOMPONENT *comp;
5153 SC_HANDLE scm = NULL, service = NULL;
5154 LPCWSTR component, *vector = NULL;
5155 LPWSTR name, args;
5156 DWORD event, numargs;
5157 UINT r = ERROR_FUNCTION_FAILED;
5159 component = MSI_RecordGetString(rec, 6);
5160 comp = get_loaded_component(package, component);
5161 if (!comp)
5162 return ERROR_SUCCESS;
5164 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5166 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5167 comp->Action = comp->Installed;
5168 return ERROR_SUCCESS;
5170 comp->Action = INSTALLSTATE_LOCAL;
5172 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5173 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5174 event = MSI_RecordGetInteger(rec, 3);
5176 if (!(event & msidbServiceControlEventStart))
5178 r = ERROR_SUCCESS;
5179 goto done;
5182 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5183 if (!scm)
5185 ERR("Failed to open the service control manager\n");
5186 goto done;
5189 service = OpenServiceW(scm, name, SERVICE_START);
5190 if (!service)
5192 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5193 goto done;
5196 vector = msi_service_args_to_vector(args, &numargs);
5198 if (!StartServiceW(service, numargs, vector) &&
5199 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5201 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5202 goto done;
5205 r = ERROR_SUCCESS;
5207 done:
5208 CloseServiceHandle(service);
5209 CloseServiceHandle(scm);
5211 msi_free(name);
5212 msi_free(args);
5213 msi_free(vector);
5214 return r;
5217 static UINT ACTION_StartServices( MSIPACKAGE *package )
5219 UINT rc;
5220 MSIQUERY *view;
5222 static const WCHAR query[] = {
5223 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5224 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5226 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5227 if (rc != ERROR_SUCCESS)
5228 return ERROR_SUCCESS;
5230 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5231 msiobj_release(&view->hdr);
5233 return rc;
5236 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5238 DWORD i, needed, count;
5239 ENUM_SERVICE_STATUSW *dependencies;
5240 SERVICE_STATUS ss;
5241 SC_HANDLE depserv;
5243 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5244 0, &needed, &count))
5245 return TRUE;
5247 if (GetLastError() != ERROR_MORE_DATA)
5248 return FALSE;
5250 dependencies = msi_alloc(needed);
5251 if (!dependencies)
5252 return FALSE;
5254 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5255 needed, &needed, &count))
5256 goto error;
5258 for (i = 0; i < count; i++)
5260 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5261 SERVICE_STOP | SERVICE_QUERY_STATUS);
5262 if (!depserv)
5263 goto error;
5265 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5266 goto error;
5269 return TRUE;
5271 error:
5272 msi_free(dependencies);
5273 return FALSE;
5276 static UINT stop_service( LPCWSTR name )
5278 SC_HANDLE scm = NULL, service = NULL;
5279 SERVICE_STATUS status;
5280 SERVICE_STATUS_PROCESS ssp;
5281 DWORD needed;
5283 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5284 if (!scm)
5286 WARN("Failed to open the SCM: %d\n", GetLastError());
5287 goto done;
5290 service = OpenServiceW(scm, name,
5291 SERVICE_STOP |
5292 SERVICE_QUERY_STATUS |
5293 SERVICE_ENUMERATE_DEPENDENTS);
5294 if (!service)
5296 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5297 goto done;
5300 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5301 sizeof(SERVICE_STATUS_PROCESS), &needed))
5303 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5304 goto done;
5307 if (ssp.dwCurrentState == SERVICE_STOPPED)
5308 goto done;
5310 stop_service_dependents(scm, service);
5312 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5313 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5315 done:
5316 CloseServiceHandle(service);
5317 CloseServiceHandle(scm);
5319 return ERROR_SUCCESS;
5322 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5324 MSIPACKAGE *package = param;
5325 MSICOMPONENT *comp;
5326 LPCWSTR component;
5327 LPWSTR name;
5328 DWORD event;
5330 event = MSI_RecordGetInteger( rec, 3 );
5331 if (!(event & msidbServiceControlEventStop))
5332 return ERROR_SUCCESS;
5334 component = MSI_RecordGetString( rec, 6 );
5335 comp = get_loaded_component( package, component );
5336 if (!comp)
5337 return ERROR_SUCCESS;
5339 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5341 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5342 comp->Action = comp->Installed;
5343 return ERROR_SUCCESS;
5345 comp->Action = INSTALLSTATE_ABSENT;
5347 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5348 stop_service( name );
5349 msi_free( name );
5351 return ERROR_SUCCESS;
5354 static UINT ACTION_StopServices( MSIPACKAGE *package )
5356 UINT rc;
5357 MSIQUERY *view;
5359 static const WCHAR query[] = {
5360 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5361 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5363 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5364 if (rc != ERROR_SUCCESS)
5365 return ERROR_SUCCESS;
5367 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5368 msiobj_release(&view->hdr);
5370 return rc;
5373 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5375 MSIPACKAGE *package = param;
5376 MSICOMPONENT *comp;
5377 MSIRECORD *uirow;
5378 LPCWSTR component;
5379 LPWSTR name = NULL, display_name = NULL;
5380 DWORD event, len;
5381 SC_HANDLE scm = NULL, service = NULL;
5383 event = MSI_RecordGetInteger( rec, 3 );
5384 if (!(event & msidbServiceControlEventDelete))
5385 return ERROR_SUCCESS;
5387 component = MSI_RecordGetString(rec, 6);
5388 comp = get_loaded_component(package, component);
5389 if (!comp)
5390 return ERROR_SUCCESS;
5392 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5394 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5395 comp->Action = comp->Installed;
5396 return ERROR_SUCCESS;
5398 comp->Action = INSTALLSTATE_ABSENT;
5400 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5401 stop_service( name );
5403 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5404 if (!scm)
5406 WARN("Failed to open the SCM: %d\n", GetLastError());
5407 goto done;
5410 len = 0;
5411 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5412 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5414 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5415 GetServiceDisplayNameW( scm, name, display_name, &len );
5418 service = OpenServiceW( scm, name, DELETE );
5419 if (!service)
5421 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5422 goto done;
5425 if (!DeleteService( service ))
5426 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5428 done:
5429 uirow = MSI_CreateRecord( 2 );
5430 MSI_RecordSetStringW( uirow, 1, display_name );
5431 MSI_RecordSetStringW( uirow, 2, name );
5432 ui_actiondata( package, szDeleteServices, uirow );
5433 msiobj_release( &uirow->hdr );
5435 CloseServiceHandle( service );
5436 CloseServiceHandle( scm );
5437 msi_free( name );
5438 msi_free( display_name );
5440 return ERROR_SUCCESS;
5443 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5445 UINT rc;
5446 MSIQUERY *view;
5448 static const WCHAR query[] = {
5449 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5450 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5452 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5453 if (rc != ERROR_SUCCESS)
5454 return ERROR_SUCCESS;
5456 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5457 msiobj_release( &view->hdr );
5459 return rc;
5462 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5464 MSIFILE *file;
5466 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5468 if (!lstrcmpW(file->File, filename))
5469 return file;
5472 return NULL;
5475 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5477 MSIPACKAGE *package = param;
5478 LPWSTR driver, driver_path, ptr;
5479 WCHAR outpath[MAX_PATH];
5480 MSIFILE *driver_file, *setup_file;
5481 MSIRECORD *uirow;
5482 LPCWSTR desc;
5483 DWORD len, usage;
5484 UINT r = ERROR_SUCCESS;
5486 static const WCHAR driver_fmt[] = {
5487 'D','r','i','v','e','r','=','%','s',0};
5488 static const WCHAR setup_fmt[] = {
5489 'S','e','t','u','p','=','%','s',0};
5490 static const WCHAR usage_fmt[] = {
5491 'F','i','l','e','U','s','a','g','e','=','1',0};
5493 desc = MSI_RecordGetString(rec, 3);
5495 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5496 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5498 if (!driver_file)
5500 ERR("ODBC Driver entry not found!\n");
5501 return ERROR_FUNCTION_FAILED;
5504 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5505 if (setup_file)
5506 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5507 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5509 driver = msi_alloc(len * sizeof(WCHAR));
5510 if (!driver)
5511 return ERROR_OUTOFMEMORY;
5513 ptr = driver;
5514 lstrcpyW(ptr, desc);
5515 ptr += lstrlenW(ptr) + 1;
5517 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5518 ptr += len + 1;
5520 if (setup_file)
5522 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5523 ptr += len + 1;
5526 lstrcpyW(ptr, usage_fmt);
5527 ptr += lstrlenW(ptr) + 1;
5528 *ptr = '\0';
5530 driver_path = strdupW(driver_file->TargetPath);
5531 ptr = strrchrW(driver_path, '\\');
5532 if (ptr) *ptr = '\0';
5534 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5535 NULL, ODBC_INSTALL_COMPLETE, &usage))
5537 ERR("Failed to install SQL driver!\n");
5538 r = ERROR_FUNCTION_FAILED;
5541 uirow = MSI_CreateRecord( 5 );
5542 MSI_RecordSetStringW( uirow, 1, desc );
5543 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5544 MSI_RecordSetStringW( uirow, 3, driver_path );
5545 ui_actiondata( package, szInstallODBC, uirow );
5546 msiobj_release( &uirow->hdr );
5548 msi_free(driver);
5549 msi_free(driver_path);
5551 return r;
5554 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5556 MSIPACKAGE *package = param;
5557 LPWSTR translator, translator_path, ptr;
5558 WCHAR outpath[MAX_PATH];
5559 MSIFILE *translator_file, *setup_file;
5560 MSIRECORD *uirow;
5561 LPCWSTR desc;
5562 DWORD len, usage;
5563 UINT r = ERROR_SUCCESS;
5565 static const WCHAR translator_fmt[] = {
5566 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5567 static const WCHAR setup_fmt[] = {
5568 'S','e','t','u','p','=','%','s',0};
5570 desc = MSI_RecordGetString(rec, 3);
5572 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5573 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5575 if (!translator_file)
5577 ERR("ODBC Translator entry not found!\n");
5578 return ERROR_FUNCTION_FAILED;
5581 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5582 if (setup_file)
5583 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5585 translator = msi_alloc(len * sizeof(WCHAR));
5586 if (!translator)
5587 return ERROR_OUTOFMEMORY;
5589 ptr = translator;
5590 lstrcpyW(ptr, desc);
5591 ptr += lstrlenW(ptr) + 1;
5593 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5594 ptr += len + 1;
5596 if (setup_file)
5598 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5599 ptr += len + 1;
5601 *ptr = '\0';
5603 translator_path = strdupW(translator_file->TargetPath);
5604 ptr = strrchrW(translator_path, '\\');
5605 if (ptr) *ptr = '\0';
5607 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5608 NULL, ODBC_INSTALL_COMPLETE, &usage))
5610 ERR("Failed to install SQL translator!\n");
5611 r = ERROR_FUNCTION_FAILED;
5614 uirow = MSI_CreateRecord( 5 );
5615 MSI_RecordSetStringW( uirow, 1, desc );
5616 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5617 MSI_RecordSetStringW( uirow, 3, translator_path );
5618 ui_actiondata( package, szInstallODBC, uirow );
5619 msiobj_release( &uirow->hdr );
5621 msi_free(translator);
5622 msi_free(translator_path);
5624 return r;
5627 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5629 MSIPACKAGE *package = param;
5630 LPWSTR attrs;
5631 LPCWSTR desc, driver;
5632 WORD request = ODBC_ADD_SYS_DSN;
5633 INT registration;
5634 DWORD len;
5635 UINT r = ERROR_SUCCESS;
5636 MSIRECORD *uirow;
5638 static const WCHAR attrs_fmt[] = {
5639 'D','S','N','=','%','s',0 };
5641 desc = MSI_RecordGetString(rec, 3);
5642 driver = MSI_RecordGetString(rec, 4);
5643 registration = MSI_RecordGetInteger(rec, 5);
5645 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5646 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5648 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5649 attrs = msi_alloc(len * sizeof(WCHAR));
5650 if (!attrs)
5651 return ERROR_OUTOFMEMORY;
5653 len = sprintfW(attrs, attrs_fmt, desc);
5654 attrs[len + 1] = 0;
5656 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5658 ERR("Failed to install SQL data source!\n");
5659 r = ERROR_FUNCTION_FAILED;
5662 uirow = MSI_CreateRecord( 5 );
5663 MSI_RecordSetStringW( uirow, 1, desc );
5664 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5665 MSI_RecordSetInteger( uirow, 3, request );
5666 ui_actiondata( package, szInstallODBC, uirow );
5667 msiobj_release( &uirow->hdr );
5669 msi_free(attrs);
5671 return r;
5674 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5676 UINT rc;
5677 MSIQUERY *view;
5679 static const WCHAR driver_query[] = {
5680 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5681 'O','D','B','C','D','r','i','v','e','r',0 };
5683 static const WCHAR translator_query[] = {
5684 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5685 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5687 static const WCHAR source_query[] = {
5688 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5689 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5691 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5692 if (rc != ERROR_SUCCESS)
5693 return ERROR_SUCCESS;
5695 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5696 msiobj_release(&view->hdr);
5698 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5699 if (rc != ERROR_SUCCESS)
5700 return ERROR_SUCCESS;
5702 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5703 msiobj_release(&view->hdr);
5705 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5706 if (rc != ERROR_SUCCESS)
5707 return ERROR_SUCCESS;
5709 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5710 msiobj_release(&view->hdr);
5712 return rc;
5715 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5717 MSIPACKAGE *package = param;
5718 MSIRECORD *uirow;
5719 DWORD usage;
5720 LPCWSTR desc;
5722 desc = MSI_RecordGetString( rec, 3 );
5723 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5725 WARN("Failed to remove ODBC driver\n");
5727 else if (!usage)
5729 FIXME("Usage count reached 0\n");
5732 uirow = MSI_CreateRecord( 2 );
5733 MSI_RecordSetStringW( uirow, 1, desc );
5734 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5735 ui_actiondata( package, szRemoveODBC, uirow );
5736 msiobj_release( &uirow->hdr );
5738 return ERROR_SUCCESS;
5741 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5743 MSIPACKAGE *package = param;
5744 MSIRECORD *uirow;
5745 DWORD usage;
5746 LPCWSTR desc;
5748 desc = MSI_RecordGetString( rec, 3 );
5749 if (!SQLRemoveTranslatorW( desc, &usage ))
5751 WARN("Failed to remove ODBC translator\n");
5753 else if (!usage)
5755 FIXME("Usage count reached 0\n");
5758 uirow = MSI_CreateRecord( 2 );
5759 MSI_RecordSetStringW( uirow, 1, desc );
5760 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5761 ui_actiondata( package, szRemoveODBC, uirow );
5762 msiobj_release( &uirow->hdr );
5764 return ERROR_SUCCESS;
5767 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5769 MSIPACKAGE *package = param;
5770 MSIRECORD *uirow;
5771 LPWSTR attrs;
5772 LPCWSTR desc, driver;
5773 WORD request = ODBC_REMOVE_SYS_DSN;
5774 INT registration;
5775 DWORD len;
5777 static const WCHAR attrs_fmt[] = {
5778 'D','S','N','=','%','s',0 };
5780 desc = MSI_RecordGetString( rec, 3 );
5781 driver = MSI_RecordGetString( rec, 4 );
5782 registration = MSI_RecordGetInteger( rec, 5 );
5784 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5785 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5787 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
5788 attrs = msi_alloc( len * sizeof(WCHAR) );
5789 if (!attrs)
5790 return ERROR_OUTOFMEMORY;
5792 FIXME("Use ODBCSourceAttribute table\n");
5794 len = sprintfW( attrs, attrs_fmt, desc );
5795 attrs[len + 1] = 0;
5797 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5799 WARN("Failed to remove ODBC data source\n");
5801 msi_free( attrs );
5803 uirow = MSI_CreateRecord( 3 );
5804 MSI_RecordSetStringW( uirow, 1, desc );
5805 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5806 MSI_RecordSetInteger( uirow, 3, request );
5807 ui_actiondata( package, szRemoveODBC, uirow );
5808 msiobj_release( &uirow->hdr );
5810 return ERROR_SUCCESS;
5813 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5815 UINT rc;
5816 MSIQUERY *view;
5818 static const WCHAR driver_query[] = {
5819 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5820 'O','D','B','C','D','r','i','v','e','r',0 };
5822 static const WCHAR translator_query[] = {
5823 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5824 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5826 static const WCHAR source_query[] = {
5827 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5828 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5830 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5831 if (rc != ERROR_SUCCESS)
5832 return ERROR_SUCCESS;
5834 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5835 msiobj_release( &view->hdr );
5837 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5838 if (rc != ERROR_SUCCESS)
5839 return ERROR_SUCCESS;
5841 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5842 msiobj_release( &view->hdr );
5844 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5845 if (rc != ERROR_SUCCESS)
5846 return ERROR_SUCCESS;
5848 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5849 msiobj_release( &view->hdr );
5851 return rc;
5854 #define ENV_ACT_SETALWAYS 0x1
5855 #define ENV_ACT_SETABSENT 0x2
5856 #define ENV_ACT_REMOVE 0x4
5857 #define ENV_ACT_REMOVEMATCH 0x8
5859 #define ENV_MOD_MACHINE 0x20000000
5860 #define ENV_MOD_APPEND 0x40000000
5861 #define ENV_MOD_PREFIX 0x80000000
5862 #define ENV_MOD_MASK 0xC0000000
5864 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5866 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5868 LPCWSTR cptr = *name;
5870 static const WCHAR prefix[] = {'[','~',']',0};
5871 static const int prefix_len = 3;
5873 *flags = 0;
5874 while (*cptr)
5876 if (*cptr == '=')
5877 *flags |= ENV_ACT_SETALWAYS;
5878 else if (*cptr == '+')
5879 *flags |= ENV_ACT_SETABSENT;
5880 else if (*cptr == '-')
5881 *flags |= ENV_ACT_REMOVE;
5882 else if (*cptr == '!')
5883 *flags |= ENV_ACT_REMOVEMATCH;
5884 else if (*cptr == '*')
5885 *flags |= ENV_MOD_MACHINE;
5886 else
5887 break;
5889 cptr++;
5890 (*name)++;
5893 if (!*cptr)
5895 ERR("Missing environment variable\n");
5896 return ERROR_FUNCTION_FAILED;
5899 if (*value)
5901 LPCWSTR ptr = *value;
5902 if (!strncmpW(ptr, prefix, prefix_len))
5904 if (ptr[prefix_len] == szSemiColon[0])
5906 *flags |= ENV_MOD_APPEND;
5907 *value += lstrlenW(prefix);
5909 else
5911 *value = NULL;
5914 else if (lstrlenW(*value) >= prefix_len)
5916 ptr += lstrlenW(ptr) - prefix_len;
5917 if (!lstrcmpW(ptr, prefix))
5919 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5921 *flags |= ENV_MOD_PREFIX;
5922 /* the "[~]" will be removed by deformat_string */;
5924 else
5926 *value = NULL;
5932 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5933 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5934 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5935 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5937 ERR("Invalid flags: %08x\n", *flags);
5938 return ERROR_FUNCTION_FAILED;
5941 if (!*flags)
5942 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5944 return ERROR_SUCCESS;
5947 static UINT open_env_key( DWORD flags, HKEY *key )
5949 static const WCHAR user_env[] =
5950 {'E','n','v','i','r','o','n','m','e','n','t',0};
5951 static const WCHAR machine_env[] =
5952 {'S','y','s','t','e','m','\\',
5953 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5954 'C','o','n','t','r','o','l','\\',
5955 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5956 'E','n','v','i','r','o','n','m','e','n','t',0};
5957 const WCHAR *env;
5958 HKEY root;
5959 LONG res;
5961 if (flags & ENV_MOD_MACHINE)
5963 env = machine_env;
5964 root = HKEY_LOCAL_MACHINE;
5966 else
5968 env = user_env;
5969 root = HKEY_CURRENT_USER;
5972 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
5973 if (res != ERROR_SUCCESS)
5975 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
5976 return ERROR_FUNCTION_FAILED;
5979 return ERROR_SUCCESS;
5982 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5984 MSIPACKAGE *package = param;
5985 LPCWSTR name, value, component;
5986 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
5987 DWORD flags, type, size;
5988 UINT res;
5989 HKEY env = NULL;
5990 MSICOMPONENT *comp;
5991 MSIRECORD *uirow;
5992 int action = 0;
5994 component = MSI_RecordGetString(rec, 4);
5995 comp = get_loaded_component(package, component);
5996 if (!comp)
5997 return ERROR_SUCCESS;
5999 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6001 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6002 comp->Action = comp->Installed;
6003 return ERROR_SUCCESS;
6005 comp->Action = INSTALLSTATE_LOCAL;
6007 name = MSI_RecordGetString(rec, 2);
6008 value = MSI_RecordGetString(rec, 3);
6010 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6012 res = env_parse_flags(&name, &value, &flags);
6013 if (res != ERROR_SUCCESS || !value)
6014 goto done;
6016 if (value && !deformat_string(package, value, &deformatted))
6018 res = ERROR_OUTOFMEMORY;
6019 goto done;
6022 value = deformatted;
6024 res = open_env_key( flags, &env );
6025 if (res != ERROR_SUCCESS)
6026 goto done;
6028 if (flags & ENV_MOD_MACHINE)
6029 action |= 0x20000000;
6031 size = 0;
6032 type = REG_SZ;
6033 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6034 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6035 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6036 goto done;
6038 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6040 action = 0x2;
6042 /* Nothing to do. */
6043 if (!value)
6045 res = ERROR_SUCCESS;
6046 goto done;
6049 /* If we are appending but the string was empty, strip ; */
6050 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6052 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6053 newval = strdupW(value);
6054 if (!newval)
6056 res = ERROR_OUTOFMEMORY;
6057 goto done;
6060 else
6062 action = 0x1;
6064 /* Contrary to MSDN, +-variable to [~];path works */
6065 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6067 res = ERROR_SUCCESS;
6068 goto done;
6071 data = msi_alloc(size);
6072 if (!data)
6074 RegCloseKey(env);
6075 return ERROR_OUTOFMEMORY;
6078 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6079 if (res != ERROR_SUCCESS)
6080 goto done;
6082 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6084 action = 0x4;
6085 res = RegDeleteValueW(env, name);
6086 if (res != ERROR_SUCCESS)
6087 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6088 goto done;
6091 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6092 if (flags & ENV_MOD_MASK)
6094 DWORD mod_size;
6095 int multiplier = 0;
6096 if (flags & ENV_MOD_APPEND) multiplier++;
6097 if (flags & ENV_MOD_PREFIX) multiplier++;
6098 mod_size = lstrlenW(value) * multiplier;
6099 size += mod_size * sizeof(WCHAR);
6102 newval = msi_alloc(size);
6103 ptr = newval;
6104 if (!newval)
6106 res = ERROR_OUTOFMEMORY;
6107 goto done;
6110 if (flags & ENV_MOD_PREFIX)
6112 lstrcpyW(newval, value);
6113 ptr = newval + lstrlenW(value);
6114 action |= 0x80000000;
6117 lstrcpyW(ptr, data);
6119 if (flags & ENV_MOD_APPEND)
6121 lstrcatW(newval, value);
6122 action |= 0x40000000;
6125 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6126 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6127 if (res)
6129 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6132 done:
6133 uirow = MSI_CreateRecord( 3 );
6134 MSI_RecordSetStringW( uirow, 1, name );
6135 MSI_RecordSetStringW( uirow, 2, newval );
6136 MSI_RecordSetInteger( uirow, 3, action );
6137 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6138 msiobj_release( &uirow->hdr );
6140 if (env) RegCloseKey(env);
6141 msi_free(deformatted);
6142 msi_free(data);
6143 msi_free(newval);
6144 return res;
6147 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6149 UINT rc;
6150 MSIQUERY * view;
6151 static const WCHAR ExecSeqQuery[] =
6152 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6153 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6154 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6155 if (rc != ERROR_SUCCESS)
6156 return ERROR_SUCCESS;
6158 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6159 msiobj_release(&view->hdr);
6161 return rc;
6164 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6166 MSIPACKAGE *package = param;
6167 LPCWSTR name, value, component;
6168 LPWSTR deformatted = NULL;
6169 DWORD flags;
6170 HKEY env;
6171 MSICOMPONENT *comp;
6172 MSIRECORD *uirow;
6173 int action = 0;
6174 LONG res;
6175 UINT r;
6177 component = MSI_RecordGetString( rec, 4 );
6178 comp = get_loaded_component( package, component );
6179 if (!comp)
6180 return ERROR_SUCCESS;
6182 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6184 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6185 comp->Action = comp->Installed;
6186 return ERROR_SUCCESS;
6188 comp->Action = INSTALLSTATE_ABSENT;
6190 name = MSI_RecordGetString( rec, 2 );
6191 value = MSI_RecordGetString( rec, 3 );
6193 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6195 r = env_parse_flags( &name, &value, &flags );
6196 if (r != ERROR_SUCCESS)
6197 return r;
6199 if (!(flags & ENV_ACT_REMOVE))
6201 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6202 return ERROR_SUCCESS;
6205 if (value && !deformat_string( package, value, &deformatted ))
6206 return ERROR_OUTOFMEMORY;
6208 value = deformatted;
6210 r = open_env_key( flags, &env );
6211 if (r != ERROR_SUCCESS)
6213 r = ERROR_SUCCESS;
6214 goto done;
6217 if (flags & ENV_MOD_MACHINE)
6218 action |= 0x20000000;
6220 TRACE("Removing %s\n", debugstr_w(name));
6222 res = RegDeleteValueW( env, name );
6223 if (res != ERROR_SUCCESS)
6225 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6226 r = ERROR_SUCCESS;
6229 done:
6230 uirow = MSI_CreateRecord( 3 );
6231 MSI_RecordSetStringW( uirow, 1, name );
6232 MSI_RecordSetStringW( uirow, 2, value );
6233 MSI_RecordSetInteger( uirow, 3, action );
6234 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6235 msiobj_release( &uirow->hdr );
6237 if (env) RegCloseKey( env );
6238 msi_free( deformatted );
6239 return r;
6242 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6244 UINT rc;
6245 MSIQUERY *view;
6246 static const WCHAR query[] =
6247 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6248 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6250 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6251 if (rc != ERROR_SUCCESS)
6252 return ERROR_SUCCESS;
6254 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6255 msiobj_release( &view->hdr );
6257 return rc;
6260 typedef struct tagMSIASSEMBLY
6262 struct list entry;
6263 MSICOMPONENT *component;
6264 MSIFEATURE *feature;
6265 MSIFILE *file;
6266 LPWSTR manifest;
6267 LPWSTR application;
6268 LPWSTR display_name;
6269 DWORD attributes;
6270 BOOL installed;
6271 } MSIASSEMBLY;
6273 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6274 DWORD dwReserved);
6275 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6276 LPVOID pvReserved, HMODULE *phModDll);
6278 static BOOL init_functionpointers(void)
6280 HRESULT hr;
6281 HMODULE hfusion;
6282 HMODULE hmscoree;
6284 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6286 hmscoree = LoadLibraryA("mscoree.dll");
6287 if (!hmscoree)
6289 WARN("mscoree.dll not available\n");
6290 return FALSE;
6293 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6294 if (!pLoadLibraryShim)
6296 WARN("LoadLibraryShim not available\n");
6297 FreeLibrary(hmscoree);
6298 return FALSE;
6301 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6302 if (FAILED(hr))
6304 WARN("fusion.dll not available\n");
6305 FreeLibrary(hmscoree);
6306 return FALSE;
6309 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6311 FreeLibrary(hmscoree);
6312 return TRUE;
6315 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6316 LPWSTR path)
6318 IAssemblyCache *cache;
6319 MSIRECORD *uirow;
6320 HRESULT hr;
6321 UINT r = ERROR_FUNCTION_FAILED;
6323 TRACE("installing assembly: %s\n", debugstr_w(path));
6325 uirow = MSI_CreateRecord( 2 );
6326 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6327 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6328 msiobj_release( &uirow->hdr );
6330 if (assembly->feature)
6331 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6333 if (assembly->manifest)
6334 FIXME("Manifest unhandled\n");
6336 if (assembly->application)
6338 FIXME("Assembly should be privately installed\n");
6339 return ERROR_SUCCESS;
6342 if (assembly->attributes == msidbAssemblyAttributesWin32)
6344 FIXME("Win32 assemblies not handled\n");
6345 return ERROR_SUCCESS;
6348 hr = pCreateAssemblyCache(&cache, 0);
6349 if (FAILED(hr))
6350 goto done;
6352 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6353 if (FAILED(hr))
6354 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6356 r = ERROR_SUCCESS;
6358 done:
6359 IAssemblyCache_Release(cache);
6360 return r;
6363 typedef struct tagASSEMBLY_LIST
6365 MSIPACKAGE *package;
6366 IAssemblyCache *cache;
6367 struct list *assemblies;
6368 } ASSEMBLY_LIST;
6370 typedef struct tagASSEMBLY_NAME
6372 LPWSTR name;
6373 LPWSTR version;
6374 LPWSTR culture;
6375 LPWSTR pubkeytoken;
6376 } ASSEMBLY_NAME;
6378 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6380 ASSEMBLY_NAME *asmname = param;
6381 LPCWSTR name = MSI_RecordGetString(rec, 2);
6382 LPWSTR val = msi_dup_record_field(rec, 3);
6384 static const WCHAR Name[] = {'N','a','m','e',0};
6385 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6386 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6387 static const WCHAR PublicKeyToken[] = {
6388 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6390 if (!strcmpiW(name, Name))
6391 asmname->name = val;
6392 else if (!strcmpiW(name, Version))
6393 asmname->version = val;
6394 else if (!strcmpiW(name, Culture))
6395 asmname->culture = val;
6396 else if (!strcmpiW(name, PublicKeyToken))
6397 asmname->pubkeytoken = val;
6398 else
6399 msi_free(val);
6401 return ERROR_SUCCESS;
6404 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6406 if (!*str)
6408 *size = lstrlenW(append) + 1;
6409 *str = msi_alloc((*size) * sizeof(WCHAR));
6410 lstrcpyW(*str, append);
6411 return;
6414 (*size) += lstrlenW(append);
6415 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6416 lstrcatW(*str, append);
6419 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6421 static const WCHAR separator[] = {',',' ',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[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6425 static const WCHAR query[] = {
6426 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6427 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6428 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6429 '=','\'','%','s','\'',0};
6430 ASSEMBLY_NAME name;
6431 MSIQUERY *view;
6432 LPWSTR display_name;
6433 DWORD size;
6434 UINT r;
6436 display_name = NULL;
6437 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6439 r = MSI_OpenQuery( db, &view, query, comp->Component );
6440 if (r != ERROR_SUCCESS)
6441 return NULL;
6443 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6444 msiobj_release( &view->hdr );
6446 if (!name.name)
6448 ERR("No assembly name specified!\n");
6449 return NULL;
6452 append_str( &display_name, &size, name.name );
6454 if (name.version)
6456 append_str( &display_name, &size, separator );
6457 append_str( &display_name, &size, Version );
6458 append_str( &display_name, &size, name.version );
6460 if (name.culture)
6462 append_str( &display_name, &size, separator );
6463 append_str( &display_name, &size, Culture );
6464 append_str( &display_name, &size, name.culture );
6466 if (name.pubkeytoken)
6468 append_str( &display_name, &size, separator );
6469 append_str( &display_name, &size, PublicKeyToken );
6470 append_str( &display_name, &size, name.pubkeytoken );
6473 msi_free( name.name );
6474 msi_free( name.version );
6475 msi_free( name.culture );
6476 msi_free( name.pubkeytoken );
6478 return display_name;
6481 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6483 ASSEMBLY_INFO asminfo;
6484 LPWSTR disp;
6485 BOOL found = FALSE;
6486 HRESULT hr;
6488 disp = get_assembly_display_name( db, comp );
6489 if (!disp)
6490 return FALSE;
6492 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6493 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6495 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6496 if (SUCCEEDED(hr))
6497 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6499 msi_free( disp );
6500 return found;
6503 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6505 ASSEMBLY_LIST *list = param;
6506 MSIASSEMBLY *assembly;
6507 LPCWSTR component;
6509 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6510 if (!assembly)
6511 return ERROR_OUTOFMEMORY;
6513 component = MSI_RecordGetString(rec, 1);
6514 assembly->component = get_loaded_component(list->package, component);
6515 if (!assembly->component)
6516 return ERROR_SUCCESS;
6518 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6519 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6521 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6522 assembly->component->Action = assembly->component->Installed;
6523 return ERROR_SUCCESS;
6525 assembly->component->Action = assembly->component->ActionRequest;
6527 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6528 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6530 if (!assembly->file)
6532 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6533 return ERROR_FUNCTION_FAILED;
6536 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6537 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6538 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6540 if (assembly->application)
6542 WCHAR version[24];
6543 DWORD size = sizeof(version)/sizeof(WCHAR);
6545 /* FIXME: we should probably check the manifest file here */
6547 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6548 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6550 assembly->installed = TRUE;
6553 else
6554 assembly->installed = check_assembly_installed(list->package->db,
6555 list->cache,
6556 assembly->component);
6558 list_add_head(list->assemblies, &assembly->entry);
6559 return ERROR_SUCCESS;
6562 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6564 IAssemblyCache *cache = NULL;
6565 ASSEMBLY_LIST list;
6566 MSIQUERY *view;
6567 HRESULT hr;
6568 UINT r;
6570 static const WCHAR query[] =
6571 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6572 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6574 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6575 if (r != ERROR_SUCCESS)
6576 return ERROR_SUCCESS;
6578 hr = pCreateAssemblyCache(&cache, 0);
6579 if (FAILED(hr))
6580 return ERROR_FUNCTION_FAILED;
6582 list.package = package;
6583 list.cache = cache;
6584 list.assemblies = assemblies;
6586 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6587 msiobj_release(&view->hdr);
6589 IAssemblyCache_Release(cache);
6591 return r;
6594 static void free_assemblies(struct list *assemblies)
6596 struct list *item, *cursor;
6598 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6600 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6602 list_remove(&assembly->entry);
6603 msi_free(assembly->application);
6604 msi_free(assembly->manifest);
6605 msi_free(assembly->display_name);
6606 msi_free(assembly);
6610 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6612 MSIASSEMBLY *assembly;
6614 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6616 if (!lstrcmpW(assembly->file->File, file))
6618 *out = assembly;
6619 return TRUE;
6623 return FALSE;
6626 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6627 LPWSTR *path, DWORD *attrs, PVOID user)
6629 MSIASSEMBLY *assembly;
6630 WCHAR temppath[MAX_PATH];
6631 struct list *assemblies = user;
6632 UINT r;
6634 if (!find_assembly(assemblies, file, &assembly))
6635 return FALSE;
6637 GetTempPathW(MAX_PATH, temppath);
6638 PathAddBackslashW(temppath);
6639 lstrcatW(temppath, assembly->file->FileName);
6641 if (action == MSICABEXTRACT_BEGINEXTRACT)
6643 if (assembly->installed)
6644 return FALSE;
6646 *path = strdupW(temppath);
6647 *attrs = assembly->file->Attributes;
6649 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6651 assembly->installed = TRUE;
6653 r = install_assembly(package, assembly, temppath);
6654 if (r != ERROR_SUCCESS)
6655 ERR("Failed to install assembly\n");
6658 return TRUE;
6661 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6663 UINT r;
6664 struct list assemblies = LIST_INIT(assemblies);
6665 MSIASSEMBLY *assembly;
6666 MSIMEDIAINFO *mi;
6668 if (!init_functionpointers() || !pCreateAssemblyCache)
6669 return ERROR_FUNCTION_FAILED;
6671 r = load_assemblies(package, &assemblies);
6672 if (r != ERROR_SUCCESS)
6673 goto done;
6675 if (list_empty(&assemblies))
6676 goto done;
6678 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6679 if (!mi)
6681 r = ERROR_OUTOFMEMORY;
6682 goto done;
6685 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6687 if (assembly->installed && !mi->is_continuous)
6688 continue;
6690 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6691 (assembly->file->IsCompressed && !mi->is_extracted))
6693 MSICABDATA data;
6695 r = ready_media(package, assembly->file, mi);
6696 if (r != ERROR_SUCCESS)
6698 ERR("Failed to ready media\n");
6699 break;
6702 data.mi = mi;
6703 data.package = package;
6704 data.cb = installassembly_cb;
6705 data.user = &assemblies;
6707 if (assembly->file->IsCompressed &&
6708 !msi_cabextract(package, mi, &data))
6710 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6711 r = ERROR_FUNCTION_FAILED;
6712 break;
6716 if (!assembly->file->IsCompressed)
6718 LPWSTR source = resolve_file_source(package, assembly->file);
6720 r = install_assembly(package, assembly, source);
6721 if (r != ERROR_SUCCESS)
6722 ERR("Failed to install assembly\n");
6724 msi_free(source);
6727 /* FIXME: write Installer assembly reg values */
6730 done:
6731 free_assemblies(&assemblies);
6732 return r;
6735 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6737 LPWSTR key, template, id;
6738 UINT r = ERROR_SUCCESS;
6740 id = msi_dup_property( package, szProductID );
6741 if (id)
6743 msi_free( id );
6744 return ERROR_SUCCESS;
6746 template = msi_dup_property( package, szPIDTemplate );
6747 key = msi_dup_property( package, szPIDKEY );
6749 if (key && template)
6751 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6752 r = MSI_SetPropertyW( package, szProductID, key );
6754 msi_free( template );
6755 msi_free( key );
6756 return r;
6759 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6761 TRACE("\n");
6762 package->need_reboot = 1;
6763 return ERROR_SUCCESS;
6766 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6768 static const WCHAR szAvailableFreeReg[] =
6769 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6770 MSIRECORD *uirow;
6771 int space = msi_get_property_int( package, szAvailableFreeReg, 0 );
6773 TRACE("%p %d kilobytes\n", package, space);
6775 uirow = MSI_CreateRecord( 1 );
6776 MSI_RecordSetInteger( uirow, 1, space );
6777 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6778 msiobj_release( &uirow->hdr );
6780 return ERROR_SUCCESS;
6783 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6785 FIXME("%p\n", package);
6786 return ERROR_SUCCESS;
6789 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6791 FIXME("%p\n", package);
6792 return ERROR_SUCCESS;
6795 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6796 LPCSTR action, LPCWSTR table )
6798 static const WCHAR query[] = {
6799 'S','E','L','E','C','T',' ','*',' ',
6800 'F','R','O','M',' ','`','%','s','`',0 };
6801 MSIQUERY *view = NULL;
6802 DWORD count = 0;
6803 UINT r;
6805 r = MSI_OpenQuery( package->db, &view, query, table );
6806 if (r == ERROR_SUCCESS)
6808 r = MSI_IterateRecords(view, &count, NULL, package);
6809 msiobj_release(&view->hdr);
6812 if (count)
6813 FIXME("%s -> %u ignored %s table values\n",
6814 action, count, debugstr_w(table));
6816 return ERROR_SUCCESS;
6819 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6821 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6822 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6825 static UINT ACTION_BindImage( MSIPACKAGE *package )
6827 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6828 return msi_unimplemented_action_stub( package, "BindImage", table );
6831 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6833 static const WCHAR table[] = {
6834 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6835 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6838 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6840 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6841 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6844 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6846 static const WCHAR table[] = {
6847 'M','s','i','A','s','s','e','m','b','l','y',0 };
6848 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6851 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6853 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6854 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6857 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6859 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6860 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6863 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6865 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6866 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6869 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6871 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6872 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6875 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6877 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6878 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6881 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6883 static const WCHAR table[] = { 'D','i','r','e','c','t','o','r','y',0 };
6884 return msi_unimplemented_action_stub( package, "SetODBCFolders", table );
6887 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6889 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6890 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6893 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6895 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6896 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6899 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6901 static const WCHAR table[] = { 'M','I','M','E',0 };
6902 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6905 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6907 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6908 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6911 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6913 static const struct
6915 const WCHAR *action;
6916 UINT (*handler)(MSIPACKAGE *);
6918 StandardActions[] =
6920 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6921 { szAppSearch, ACTION_AppSearch },
6922 { szBindImage, ACTION_BindImage },
6923 { szCCPSearch, ACTION_CCPSearch },
6924 { szCostFinalize, ACTION_CostFinalize },
6925 { szCostInitialize, ACTION_CostInitialize },
6926 { szCreateFolders, ACTION_CreateFolders },
6927 { szCreateShortcuts, ACTION_CreateShortcuts },
6928 { szDeleteServices, ACTION_DeleteServices },
6929 { szDisableRollback, ACTION_DisableRollback },
6930 { szDuplicateFiles, ACTION_DuplicateFiles },
6931 { szExecuteAction, ACTION_ExecuteAction },
6932 { szFileCost, ACTION_FileCost },
6933 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6934 { szForceReboot, ACTION_ForceReboot },
6935 { szInstallAdminPackage, ACTION_InstallAdminPackage },
6936 { szInstallExecute, ACTION_InstallExecute },
6937 { szInstallExecuteAgain, ACTION_InstallExecute },
6938 { szInstallFiles, ACTION_InstallFiles},
6939 { szInstallFinalize, ACTION_InstallFinalize },
6940 { szInstallInitialize, ACTION_InstallInitialize },
6941 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6942 { szInstallValidate, ACTION_InstallValidate },
6943 { szIsolateComponents, ACTION_IsolateComponents },
6944 { szLaunchConditions, ACTION_LaunchConditions },
6945 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6946 { szMoveFiles, ACTION_MoveFiles },
6947 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6948 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6949 { szInstallODBC, ACTION_InstallODBC },
6950 { szInstallServices, ACTION_InstallServices },
6951 { szPatchFiles, ACTION_PatchFiles },
6952 { szProcessComponents, ACTION_ProcessComponents },
6953 { szPublishComponents, ACTION_PublishComponents },
6954 { szPublishFeatures, ACTION_PublishFeatures },
6955 { szPublishProduct, ACTION_PublishProduct },
6956 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6957 { szRegisterComPlus, ACTION_RegisterComPlus},
6958 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6959 { szRegisterFonts, ACTION_RegisterFonts },
6960 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6961 { szRegisterProduct, ACTION_RegisterProduct },
6962 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6963 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6964 { szRegisterUser, ACTION_RegisterUser },
6965 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6966 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6967 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6968 { szRemoveFiles, ACTION_RemoveFiles },
6969 { szRemoveFolders, ACTION_RemoveFolders },
6970 { szRemoveIniValues, ACTION_RemoveIniValues },
6971 { szRemoveODBC, ACTION_RemoveODBC },
6972 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6973 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6974 { szResolveSource, ACTION_ResolveSource },
6975 { szRMCCPSearch, ACTION_RMCCPSearch },
6976 { szScheduleReboot, ACTION_ScheduleReboot },
6977 { szSelfRegModules, ACTION_SelfRegModules },
6978 { szSelfUnregModules, ACTION_SelfUnregModules },
6979 { szSetODBCFolders, ACTION_SetODBCFolders },
6980 { szStartServices, ACTION_StartServices },
6981 { szStopServices, ACTION_StopServices },
6982 { szUnpublishComponents, ACTION_UnpublishComponents },
6983 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6984 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6985 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6986 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6987 { szUnregisterFonts, ACTION_UnregisterFonts },
6988 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6989 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6990 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6991 { szValidateProductID, ACTION_ValidateProductID },
6992 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6993 { szWriteIniValues, ACTION_WriteIniValues },
6994 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6995 { NULL, NULL },
6998 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
6999 UINT* rc, BOOL force )
7001 BOOL ret = FALSE;
7002 BOOL run = force;
7003 int i;
7005 if (!run && !package->script->CurrentlyScripting)
7006 run = TRUE;
7008 if (!run)
7010 if (strcmpW(action,szInstallFinalize) == 0 ||
7011 strcmpW(action,szInstallExecute) == 0 ||
7012 strcmpW(action,szInstallExecuteAgain) == 0)
7013 run = TRUE;
7016 i = 0;
7017 while (StandardActions[i].action != NULL)
7019 if (strcmpW(StandardActions[i].action, action)==0)
7021 if (!run)
7023 ui_actioninfo(package, action, TRUE, 0);
7024 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7025 ui_actioninfo(package, action, FALSE, *rc);
7027 else
7029 ui_actionstart(package, action);
7030 if (StandardActions[i].handler)
7032 *rc = StandardActions[i].handler(package);
7034 else
7036 FIXME("unhandled standard action %s\n",debugstr_w(action));
7037 *rc = ERROR_SUCCESS;
7040 ret = TRUE;
7041 break;
7043 i++;
7045 return ret;
7048 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7050 UINT rc = ERROR_SUCCESS;
7051 BOOL handled;
7053 TRACE("Performing action (%s)\n", debugstr_w(action));
7055 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7057 if (!handled)
7058 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7060 if (!handled)
7062 WARN("unhandled msi action %s\n", debugstr_w(action));
7063 rc = ERROR_FUNCTION_NOT_CALLED;
7066 return rc;
7069 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7071 UINT rc = ERROR_SUCCESS;
7072 BOOL handled = FALSE;
7074 TRACE("Performing action (%s)\n", debugstr_w(action));
7076 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7078 if (!handled)
7079 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7081 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7082 handled = TRUE;
7084 if (!handled)
7086 WARN("unhandled msi action %s\n", debugstr_w(action));
7087 rc = ERROR_FUNCTION_NOT_CALLED;
7090 return rc;
7093 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7095 UINT rc = ERROR_SUCCESS;
7096 MSIRECORD *row;
7098 static const WCHAR ExecSeqQuery[] =
7099 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7100 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7101 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7102 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7103 static const WCHAR UISeqQuery[] =
7104 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7105 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7106 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7107 ' ', '=',' ','%','i',0};
7109 if (needs_ui_sequence(package))
7110 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7111 else
7112 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7114 if (row)
7116 LPCWSTR action, cond;
7118 TRACE("Running the actions\n");
7120 /* check conditions */
7121 cond = MSI_RecordGetString(row, 2);
7123 /* this is a hack to skip errors in the condition code */
7124 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7126 msiobj_release(&row->hdr);
7127 return ERROR_SUCCESS;
7130 action = MSI_RecordGetString(row, 1);
7131 if (!action)
7133 ERR("failed to fetch action\n");
7134 msiobj_release(&row->hdr);
7135 return ERROR_FUNCTION_FAILED;
7138 if (needs_ui_sequence(package))
7139 rc = ACTION_PerformUIAction(package, action, -1);
7140 else
7141 rc = ACTION_PerformAction(package, action, -1, FALSE);
7143 msiobj_release(&row->hdr);
7146 return rc;
7149 /****************************************************
7150 * TOP level entry points
7151 *****************************************************/
7153 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7154 LPCWSTR szCommandLine )
7156 UINT rc;
7157 BOOL ui_exists;
7159 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7160 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7162 MSI_SetPropertyW(package, szAction, szInstall);
7164 package->script->InWhatSequence = SEQUENCE_INSTALL;
7166 if (szPackagePath)
7168 LPWSTR p, dir;
7169 LPCWSTR file;
7171 dir = strdupW(szPackagePath);
7172 p = strrchrW(dir, '\\');
7173 if (p)
7175 *(++p) = 0;
7176 file = szPackagePath + (p - dir);
7178 else
7180 msi_free(dir);
7181 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7182 GetCurrentDirectoryW(MAX_PATH, dir);
7183 lstrcatW(dir, szBackSlash);
7184 file = szPackagePath;
7187 msi_free( package->PackagePath );
7188 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7189 if (!package->PackagePath)
7191 msi_free(dir);
7192 return ERROR_OUTOFMEMORY;
7195 lstrcpyW(package->PackagePath, dir);
7196 lstrcatW(package->PackagePath, file);
7197 msi_free(dir);
7199 msi_set_sourcedir_props(package, FALSE);
7202 msi_parse_command_line( package, szCommandLine, FALSE );
7204 msi_apply_transforms( package );
7205 msi_apply_patches( package );
7207 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
7209 TRACE("setting reinstall property\n");
7210 MSI_SetPropertyW( package, szReinstall, szAll );
7213 /* properties may have been added by a transform */
7214 msi_clone_properties( package );
7215 msi_set_context( package );
7217 if (needs_ui_sequence( package))
7219 package->script->InWhatSequence |= SEQUENCE_UI;
7220 rc = ACTION_ProcessUISequence(package);
7221 ui_exists = ui_sequence_exists(package);
7222 if (rc == ERROR_SUCCESS || !ui_exists)
7224 package->script->InWhatSequence |= SEQUENCE_EXEC;
7225 rc = ACTION_ProcessExecSequence(package, ui_exists);
7228 else
7229 rc = ACTION_ProcessExecSequence(package, FALSE);
7231 package->script->CurrentlyScripting = FALSE;
7233 /* process the ending type action */
7234 if (rc == ERROR_SUCCESS)
7235 ACTION_PerformActionSequence(package, -1);
7236 else if (rc == ERROR_INSTALL_USEREXIT)
7237 ACTION_PerformActionSequence(package, -2);
7238 else if (rc == ERROR_INSTALL_SUSPEND)
7239 ACTION_PerformActionSequence(package, -4);
7240 else /* failed */
7241 ACTION_PerformActionSequence(package, -3);
7243 /* finish up running custom actions */
7244 ACTION_FinishCustomActions(package);
7246 if (rc == ERROR_SUCCESS && package->need_reboot)
7247 return ERROR_SUCCESS_REBOOT_REQUIRED;
7249 return rc;