msi: Update the UI in the StartServices and StopServices actions.
[wine/multimedia.git] / dlls / msi / action.c
blob28b0368f4a55bda1c78c31d9dae6877572f8a84a
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);
2365 if (type == REG_SZ || type == REG_EXPAND_SZ)
2366 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2367 ui_actiondata(package,szWriteRegistryValues,uirow);
2368 msiobj_release( &uirow->hdr );
2370 msi_free(value_data);
2371 msi_free(deformated);
2372 msi_free(uikey);
2374 return ERROR_SUCCESS;
2377 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2379 UINT rc;
2380 MSIQUERY * view;
2381 static const WCHAR ExecSeqQuery[] =
2382 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2383 '`','R','e','g','i','s','t','r','y','`',0 };
2385 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2386 if (rc != ERROR_SUCCESS)
2387 return ERROR_SUCCESS;
2389 /* increment progress bar each time action data is sent */
2390 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2392 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2394 msiobj_release(&view->hdr);
2395 return rc;
2398 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2400 LONG res;
2401 HKEY hkey;
2402 DWORD num_subkeys, num_values;
2404 if (delete_key)
2406 if ((res = RegDeleteTreeW( hkey_root, key )))
2408 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2410 return;
2413 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2415 if ((res = RegDeleteValueW( hkey, value )))
2417 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2419 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2420 NULL, NULL, NULL, NULL );
2421 RegCloseKey( hkey );
2423 if (!res && !num_subkeys && !num_values)
2425 TRACE("Removing empty key %s\n", debugstr_w(key));
2426 RegDeleteKeyW( hkey_root, key );
2428 return;
2430 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2434 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2436 MSIPACKAGE *package = param;
2437 LPCWSTR component, name, key_str, root_key_str;
2438 LPWSTR deformated_key, deformated_name, ui_key_str;
2439 MSICOMPONENT *comp;
2440 MSIRECORD *uirow;
2441 BOOL delete_key = FALSE;
2442 HKEY hkey_root;
2443 UINT size;
2444 INT root;
2446 ui_progress( package, 2, 0, 0, 0 );
2448 component = MSI_RecordGetString( row, 6 );
2449 comp = get_loaded_component( package, component );
2450 if (!comp)
2451 return ERROR_SUCCESS;
2453 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2455 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2456 comp->Action = comp->Installed;
2457 return ERROR_SUCCESS;
2459 comp->Action = INSTALLSTATE_ABSENT;
2461 name = MSI_RecordGetString( row, 4 );
2462 if (MSI_RecordIsNull( row, 5 ) && name )
2464 if (name[0] == '+' && !name[1])
2465 return ERROR_SUCCESS;
2466 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2468 delete_key = TRUE;
2469 name = NULL;
2473 root = MSI_RecordGetInteger( row, 2 );
2474 key_str = MSI_RecordGetString( row, 3 );
2476 root_key_str = get_root_key( package, root, &hkey_root );
2477 if (!root_key_str)
2478 return ERROR_SUCCESS;
2480 deformat_string( package, key_str, &deformated_key );
2481 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2482 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2483 strcpyW( ui_key_str, root_key_str );
2484 strcatW( ui_key_str, deformated_key );
2486 deformat_string( package, name, &deformated_name );
2488 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2489 msi_free( deformated_key );
2491 uirow = MSI_CreateRecord( 2 );
2492 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2493 MSI_RecordSetStringW( uirow, 2, deformated_name );
2495 ui_actiondata( package, szRemoveRegistryValues, uirow );
2496 msiobj_release( &uirow->hdr );
2498 msi_free( ui_key_str );
2499 msi_free( deformated_name );
2500 return ERROR_SUCCESS;
2503 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2505 MSIPACKAGE *package = param;
2506 LPCWSTR component, name, key_str, root_key_str;
2507 LPWSTR deformated_key, deformated_name, ui_key_str;
2508 MSICOMPONENT *comp;
2509 MSIRECORD *uirow;
2510 BOOL delete_key = FALSE;
2511 HKEY hkey_root;
2512 UINT size;
2513 INT root;
2515 ui_progress( package, 2, 0, 0, 0 );
2517 component = MSI_RecordGetString( row, 5 );
2518 comp = get_loaded_component( package, component );
2519 if (!comp)
2520 return ERROR_SUCCESS;
2522 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2524 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2525 comp->Action = comp->Installed;
2526 return ERROR_SUCCESS;
2528 comp->Action = INSTALLSTATE_LOCAL;
2530 if ((name = MSI_RecordGetString( row, 4 )))
2532 if (name[0] == '-' && !name[1])
2534 delete_key = TRUE;
2535 name = NULL;
2539 root = MSI_RecordGetInteger( row, 2 );
2540 key_str = MSI_RecordGetString( row, 3 );
2542 root_key_str = get_root_key( package, root, &hkey_root );
2543 if (!root_key_str)
2544 return ERROR_SUCCESS;
2546 deformat_string( package, key_str, &deformated_key );
2547 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2548 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2549 strcpyW( ui_key_str, root_key_str );
2550 strcatW( ui_key_str, deformated_key );
2552 deformat_string( package, name, &deformated_name );
2554 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2555 msi_free( deformated_key );
2557 uirow = MSI_CreateRecord( 2 );
2558 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2559 MSI_RecordSetStringW( uirow, 2, deformated_name );
2561 ui_actiondata( package, szRemoveRegistryValues, uirow );
2562 msiobj_release( &uirow->hdr );
2564 msi_free( ui_key_str );
2565 msi_free( deformated_name );
2566 return ERROR_SUCCESS;
2569 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2571 UINT rc;
2572 MSIQUERY *view;
2573 static const WCHAR registry_query[] =
2574 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2575 '`','R','e','g','i','s','t','r','y','`',0 };
2576 static const WCHAR remove_registry_query[] =
2577 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2578 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2580 /* increment progress bar each time action data is sent */
2581 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2583 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2584 if (rc == ERROR_SUCCESS)
2586 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2587 msiobj_release( &view->hdr );
2588 if (rc != ERROR_SUCCESS)
2589 return rc;
2592 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2593 if (rc == ERROR_SUCCESS)
2595 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2596 msiobj_release( &view->hdr );
2597 if (rc != ERROR_SUCCESS)
2598 return rc;
2601 return ERROR_SUCCESS;
2604 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2606 package->script->CurrentlyScripting = TRUE;
2608 return ERROR_SUCCESS;
2612 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2614 MSICOMPONENT *comp;
2615 DWORD progress = 0;
2616 DWORD total = 0;
2617 static const WCHAR q1[]=
2618 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2619 '`','R','e','g','i','s','t','r','y','`',0};
2620 UINT rc;
2621 MSIQUERY * view;
2622 MSIFEATURE *feature;
2623 MSIFILE *file;
2625 TRACE("InstallValidate\n");
2627 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2628 if (rc == ERROR_SUCCESS)
2630 MSI_IterateRecords( view, &progress, NULL, package );
2631 msiobj_release( &view->hdr );
2632 total += progress * REG_PROGRESS_VALUE;
2635 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2636 total += COMPONENT_PROGRESS_VALUE;
2638 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2639 total += file->FileSize;
2641 ui_progress(package,0,total,0,0);
2643 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2645 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2646 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2647 feature->ActionRequest);
2650 return ERROR_SUCCESS;
2653 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2655 MSIPACKAGE* package = param;
2656 LPCWSTR cond = NULL;
2657 LPCWSTR message = NULL;
2658 UINT r;
2660 static const WCHAR title[]=
2661 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2663 cond = MSI_RecordGetString(row,1);
2665 r = MSI_EvaluateConditionW(package,cond);
2666 if (r == MSICONDITION_FALSE)
2668 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2670 LPWSTR deformated;
2671 message = MSI_RecordGetString(row,2);
2672 deformat_string(package,message,&deformated);
2673 MessageBoxW(NULL,deformated,title,MB_OK);
2674 msi_free(deformated);
2677 return ERROR_INSTALL_FAILURE;
2680 return ERROR_SUCCESS;
2683 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2685 UINT rc;
2686 MSIQUERY * view = NULL;
2687 static const WCHAR ExecSeqQuery[] =
2688 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2689 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2691 TRACE("Checking launch conditions\n");
2693 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2694 if (rc != ERROR_SUCCESS)
2695 return ERROR_SUCCESS;
2697 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2698 msiobj_release(&view->hdr);
2700 return rc;
2703 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2706 if (!cmp->KeyPath)
2707 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2709 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2711 MSIRECORD * row = 0;
2712 UINT root,len;
2713 LPWSTR deformated,buffer,deformated_name;
2714 LPCWSTR key,name;
2715 static const WCHAR ExecSeqQuery[] =
2716 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2717 '`','R','e','g','i','s','t','r','y','`',' ',
2718 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2719 ' ','=',' ' ,'\'','%','s','\'',0 };
2720 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2721 static const WCHAR fmt2[]=
2722 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2724 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2725 if (!row)
2726 return NULL;
2728 root = MSI_RecordGetInteger(row,2);
2729 key = MSI_RecordGetString(row, 3);
2730 name = MSI_RecordGetString(row, 4);
2731 deformat_string(package, key , &deformated);
2732 deformat_string(package, name, &deformated_name);
2734 len = strlenW(deformated) + 6;
2735 if (deformated_name)
2736 len+=strlenW(deformated_name);
2738 buffer = msi_alloc( len *sizeof(WCHAR));
2740 if (deformated_name)
2741 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2742 else
2743 sprintfW(buffer,fmt,root,deformated);
2745 msi_free(deformated);
2746 msi_free(deformated_name);
2747 msiobj_release(&row->hdr);
2749 return buffer;
2751 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2753 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2754 return NULL;
2756 else
2758 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2760 if (file)
2761 return strdupW( file->TargetPath );
2763 return NULL;
2766 static HKEY openSharedDLLsKey(void)
2768 HKEY hkey=0;
2769 static const WCHAR path[] =
2770 {'S','o','f','t','w','a','r','e','\\',
2771 'M','i','c','r','o','s','o','f','t','\\',
2772 'W','i','n','d','o','w','s','\\',
2773 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2774 'S','h','a','r','e','d','D','L','L','s',0};
2776 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2777 return hkey;
2780 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2782 HKEY hkey;
2783 DWORD count=0;
2784 DWORD type;
2785 DWORD sz = sizeof(count);
2786 DWORD rc;
2788 hkey = openSharedDLLsKey();
2789 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2790 if (rc != ERROR_SUCCESS)
2791 count = 0;
2792 RegCloseKey(hkey);
2793 return count;
2796 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2798 HKEY hkey;
2800 hkey = openSharedDLLsKey();
2801 if (count > 0)
2802 msi_reg_set_val_dword( hkey, path, count );
2803 else
2804 RegDeleteValueW(hkey,path);
2805 RegCloseKey(hkey);
2806 return count;
2810 * Return TRUE if the count should be written out and FALSE if not
2812 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2814 MSIFEATURE *feature;
2815 INT count = 0;
2816 BOOL write = FALSE;
2818 /* only refcount DLLs */
2819 if (comp->KeyPath == NULL ||
2820 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2821 comp->Attributes & msidbComponentAttributesODBCDataSource)
2822 write = FALSE;
2823 else
2825 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2826 write = (count > 0);
2828 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2829 write = TRUE;
2832 /* increment counts */
2833 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2835 ComponentList *cl;
2837 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2838 continue;
2840 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2842 if ( cl->component == comp )
2843 count++;
2847 /* decrement counts */
2848 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2850 ComponentList *cl;
2852 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2853 continue;
2855 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2857 if ( cl->component == comp )
2858 count--;
2862 /* ref count all the files in the component */
2863 if (write)
2865 MSIFILE *file;
2867 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2869 if (file->Component == comp)
2870 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2874 /* add a count for permanent */
2875 if (comp->Attributes & msidbComponentAttributesPermanent)
2876 count ++;
2878 comp->RefCount = count;
2880 if (write)
2881 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2884 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2886 WCHAR squished_pc[GUID_SIZE];
2887 WCHAR squished_cc[GUID_SIZE];
2888 UINT rc;
2889 MSICOMPONENT *comp;
2890 HKEY hkey;
2892 TRACE("\n");
2894 squash_guid(package->ProductCode,squished_pc);
2895 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2897 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2899 MSIRECORD * uirow;
2901 ui_progress(package,2,0,0,0);
2902 if (!comp->ComponentId)
2903 continue;
2905 squash_guid(comp->ComponentId,squished_cc);
2907 msi_free(comp->FullKeypath);
2908 comp->FullKeypath = resolve_keypath( package, comp );
2910 ACTION_RefCountComponent( package, comp );
2912 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2913 debugstr_w(comp->Component),
2914 debugstr_w(squished_cc),
2915 debugstr_w(comp->FullKeypath),
2916 comp->RefCount);
2918 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2919 comp->ActionRequest == INSTALLSTATE_SOURCE)
2921 if (!comp->FullKeypath)
2922 continue;
2924 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2925 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2926 &hkey, TRUE);
2927 else
2928 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2929 &hkey, TRUE);
2931 if (rc != ERROR_SUCCESS)
2932 continue;
2934 if (comp->Attributes & msidbComponentAttributesPermanent)
2936 static const WCHAR szPermKey[] =
2937 { '0','0','0','0','0','0','0','0','0','0','0','0',
2938 '0','0','0','0','0','0','0','0','0','0','0','0',
2939 '0','0','0','0','0','0','0','0',0 };
2941 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2944 if (comp->Action == INSTALLSTATE_LOCAL)
2945 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2946 else
2948 MSIFILE *file;
2949 MSIRECORD *row;
2950 LPWSTR ptr, ptr2;
2951 WCHAR source[MAX_PATH];
2952 WCHAR base[MAX_PATH];
2953 LPWSTR sourcepath;
2955 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2956 static const WCHAR query[] = {
2957 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2958 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2959 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2960 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2961 '`','D','i','s','k','I','d','`',0};
2963 file = get_loaded_file(package, comp->KeyPath);
2964 if (!file)
2965 continue;
2967 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2968 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2969 ptr2 = strrchrW(source, '\\') + 1;
2970 msiobj_release(&row->hdr);
2972 lstrcpyW(base, package->PackagePath);
2973 ptr = strrchrW(base, '\\');
2974 *(ptr + 1) = '\0';
2976 sourcepath = resolve_file_source(package, file);
2977 ptr = sourcepath + lstrlenW(base);
2978 lstrcpyW(ptr2, ptr);
2979 msi_free(sourcepath);
2981 msi_reg_set_val_str(hkey, squished_pc, source);
2983 RegCloseKey(hkey);
2985 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
2987 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2988 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2989 else
2990 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2992 comp->Action = comp->ActionRequest;
2994 /* UI stuff */
2995 uirow = MSI_CreateRecord(3);
2996 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2997 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2998 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2999 ui_actiondata(package,szProcessComponents,uirow);
3000 msiobj_release( &uirow->hdr );
3003 return ERROR_SUCCESS;
3006 typedef struct {
3007 CLSID clsid;
3008 LPWSTR source;
3010 LPWSTR path;
3011 ITypeLib *ptLib;
3012 } typelib_struct;
3014 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3015 LPWSTR lpszName, LONG_PTR lParam)
3017 TLIBATTR *attr;
3018 typelib_struct *tl_struct = (typelib_struct*) lParam;
3019 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3020 int sz;
3021 HRESULT res;
3023 if (!IS_INTRESOURCE(lpszName))
3025 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3026 return TRUE;
3029 sz = strlenW(tl_struct->source)+4;
3030 sz *= sizeof(WCHAR);
3032 if ((INT_PTR)lpszName == 1)
3033 tl_struct->path = strdupW(tl_struct->source);
3034 else
3036 tl_struct->path = msi_alloc(sz);
3037 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3040 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3041 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3042 if (FAILED(res))
3044 msi_free(tl_struct->path);
3045 tl_struct->path = NULL;
3047 return TRUE;
3050 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3051 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3053 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3054 return FALSE;
3057 msi_free(tl_struct->path);
3058 tl_struct->path = NULL;
3060 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3061 ITypeLib_Release(tl_struct->ptLib);
3063 return TRUE;
3066 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3068 MSIPACKAGE* package = param;
3069 LPCWSTR component;
3070 MSICOMPONENT *comp;
3071 MSIFILE *file;
3072 typelib_struct tl_struct;
3073 ITypeLib *tlib;
3074 HMODULE module;
3075 HRESULT hr;
3077 component = MSI_RecordGetString(row,3);
3078 comp = get_loaded_component(package,component);
3079 if (!comp)
3080 return ERROR_SUCCESS;
3082 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3084 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3085 comp->Action = comp->Installed;
3086 return ERROR_SUCCESS;
3088 comp->Action = INSTALLSTATE_LOCAL;
3090 file = get_loaded_file( package, comp->KeyPath );
3091 if (!file)
3092 return ERROR_SUCCESS;
3094 ui_actiondata( package, szRegisterTypeLibraries, row );
3096 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3097 if (module)
3099 LPCWSTR guid;
3100 guid = MSI_RecordGetString(row,1);
3101 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
3102 tl_struct.source = strdupW( file->TargetPath );
3103 tl_struct.path = NULL;
3105 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3106 (LONG_PTR)&tl_struct);
3108 if (tl_struct.path)
3110 LPWSTR help = NULL;
3111 LPCWSTR helpid;
3112 HRESULT res;
3114 helpid = MSI_RecordGetString(row,6);
3116 if (helpid)
3117 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3118 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3119 msi_free(help);
3121 if (FAILED(res))
3122 ERR("Failed to register type library %s\n",
3123 debugstr_w(tl_struct.path));
3124 else
3125 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3127 ITypeLib_Release(tl_struct.ptLib);
3128 msi_free(tl_struct.path);
3130 else
3131 ERR("Failed to load type library %s\n",
3132 debugstr_w(tl_struct.source));
3134 FreeLibrary(module);
3135 msi_free(tl_struct.source);
3137 else
3139 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3140 if (FAILED(hr))
3142 ERR("Failed to load type library: %08x\n", hr);
3143 return ERROR_INSTALL_FAILURE;
3146 ITypeLib_Release(tlib);
3149 return ERROR_SUCCESS;
3152 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3155 * OK this is a bit confusing.. I am given a _Component key and I believe
3156 * that the file that is being registered as a type library is the "key file
3157 * of that component" which I interpret to mean "The file in the KeyPath of
3158 * that component".
3160 UINT rc;
3161 MSIQUERY * view;
3162 static const WCHAR Query[] =
3163 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3164 '`','T','y','p','e','L','i','b','`',0};
3166 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3167 if (rc != ERROR_SUCCESS)
3168 return ERROR_SUCCESS;
3170 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3171 msiobj_release(&view->hdr);
3172 return rc;
3175 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3177 MSIPACKAGE *package = param;
3178 LPCWSTR component, guid;
3179 MSICOMPONENT *comp;
3180 GUID libid;
3181 UINT version;
3182 LCID language;
3183 SYSKIND syskind;
3184 HRESULT hr;
3186 component = MSI_RecordGetString( row, 3 );
3187 comp = get_loaded_component( package, component );
3188 if (!comp)
3189 return ERROR_SUCCESS;
3191 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3193 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3194 comp->Action = comp->Installed;
3195 return ERROR_SUCCESS;
3197 comp->Action = INSTALLSTATE_ABSENT;
3199 ui_actiondata( package, szUnregisterTypeLibraries, row );
3201 guid = MSI_RecordGetString( row, 1 );
3202 CLSIDFromString( (LPWSTR)guid, &libid );
3203 version = MSI_RecordGetInteger( row, 4 );
3204 language = MSI_RecordGetInteger( row, 2 );
3206 #ifdef _WIN64
3207 syskind = SYS_WIN64;
3208 #else
3209 syskind = SYS_WIN32;
3210 #endif
3212 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3213 if (FAILED(hr))
3215 WARN("Failed to unregister typelib: %08x\n", hr);
3218 return ERROR_SUCCESS;
3221 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3223 UINT rc;
3224 MSIQUERY *view;
3225 static const WCHAR query[] =
3226 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3227 '`','T','y','p','e','L','i','b','`',0};
3229 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3230 if (rc != ERROR_SUCCESS)
3231 return ERROR_SUCCESS;
3233 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3234 msiobj_release( &view->hdr );
3235 return rc;
3238 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3240 static const WCHAR szlnk[] = {'.','l','n','k',0};
3241 LPCWSTR directory, extension;
3242 LPWSTR link_folder, link_file, filename;
3244 directory = MSI_RecordGetString( row, 2 );
3245 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3247 /* may be needed because of a bug somewhere else */
3248 create_full_pathW( link_folder );
3250 filename = msi_dup_record_field( row, 3 );
3251 reduce_to_longfilename( filename );
3253 extension = strchrW( filename, '.' );
3254 if (!extension || strcmpiW( extension, szlnk ))
3256 int len = strlenW( filename );
3257 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3258 memcpy( filename + len, szlnk, sizeof(szlnk) );
3260 link_file = build_directory_name( 2, link_folder, filename );
3261 msi_free( link_folder );
3262 msi_free( filename );
3264 return link_file;
3267 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3269 MSIPACKAGE *package = param;
3270 LPWSTR link_file, deformated, path;
3271 LPCWSTR component, target;
3272 MSICOMPONENT *comp;
3273 IShellLinkW *sl = NULL;
3274 IPersistFile *pf = NULL;
3275 HRESULT res;
3277 component = MSI_RecordGetString(row, 4);
3278 comp = get_loaded_component(package, component);
3279 if (!comp)
3280 return ERROR_SUCCESS;
3282 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3284 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3285 comp->Action = comp->Installed;
3286 return ERROR_SUCCESS;
3288 comp->Action = INSTALLSTATE_LOCAL;
3290 ui_actiondata(package,szCreateShortcuts,row);
3292 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3293 &IID_IShellLinkW, (LPVOID *) &sl );
3295 if (FAILED( res ))
3297 ERR("CLSID_ShellLink not available\n");
3298 goto err;
3301 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3302 if (FAILED( res ))
3304 ERR("QueryInterface(IID_IPersistFile) failed\n");
3305 goto err;
3308 target = MSI_RecordGetString(row, 5);
3309 if (strchrW(target, '['))
3311 deformat_string(package, target, &deformated);
3312 IShellLinkW_SetPath(sl,deformated);
3313 msi_free(deformated);
3315 else
3317 FIXME("poorly handled shortcut format, advertised shortcut\n");
3318 IShellLinkW_SetPath(sl,comp->FullKeypath);
3321 if (!MSI_RecordIsNull(row,6))
3323 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3324 deformat_string(package, arguments, &deformated);
3325 IShellLinkW_SetArguments(sl,deformated);
3326 msi_free(deformated);
3329 if (!MSI_RecordIsNull(row,7))
3331 LPCWSTR description = MSI_RecordGetString(row, 7);
3332 IShellLinkW_SetDescription(sl, description);
3335 if (!MSI_RecordIsNull(row,8))
3336 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3338 if (!MSI_RecordIsNull(row,9))
3340 INT index;
3341 LPCWSTR icon = MSI_RecordGetString(row, 9);
3343 path = build_icon_path(package, icon);
3344 index = MSI_RecordGetInteger(row,10);
3346 /* no value means 0 */
3347 if (index == MSI_NULL_INTEGER)
3348 index = 0;
3350 IShellLinkW_SetIconLocation(sl, path, index);
3351 msi_free(path);
3354 if (!MSI_RecordIsNull(row,11))
3355 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3357 if (!MSI_RecordIsNull(row,12))
3359 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3360 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3361 if (path)
3362 IShellLinkW_SetWorkingDirectory(sl, path);
3363 msi_free(path);
3366 link_file = get_link_file(package, row);
3368 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3369 IPersistFile_Save(pf, link_file, FALSE);
3371 msi_free(link_file);
3373 err:
3374 if (pf)
3375 IPersistFile_Release( pf );
3376 if (sl)
3377 IShellLinkW_Release( sl );
3379 return ERROR_SUCCESS;
3382 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3384 UINT rc;
3385 HRESULT res;
3386 MSIQUERY * view;
3387 static const WCHAR Query[] =
3388 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3389 '`','S','h','o','r','t','c','u','t','`',0};
3391 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3392 if (rc != ERROR_SUCCESS)
3393 return ERROR_SUCCESS;
3395 res = CoInitialize( NULL );
3397 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3398 msiobj_release(&view->hdr);
3400 if (SUCCEEDED(res))
3401 CoUninitialize();
3403 return rc;
3406 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3408 MSIPACKAGE *package = param;
3409 LPWSTR link_file;
3410 LPCWSTR component;
3411 MSICOMPONENT *comp;
3413 component = MSI_RecordGetString( row, 4 );
3414 comp = get_loaded_component( package, component );
3415 if (!comp)
3416 return ERROR_SUCCESS;
3418 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3420 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3421 comp->Action = comp->Installed;
3422 return ERROR_SUCCESS;
3424 comp->Action = INSTALLSTATE_ABSENT;
3426 ui_actiondata( package, szRemoveShortcuts, row );
3428 link_file = get_link_file( package, row );
3430 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3431 if (!DeleteFileW( link_file ))
3433 WARN("Failed to remove shortcut file %u\n", GetLastError());
3435 msi_free( link_file );
3437 return ERROR_SUCCESS;
3440 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3442 UINT rc;
3443 MSIQUERY *view;
3444 static const WCHAR query[] =
3445 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3446 '`','S','h','o','r','t','c','u','t','`',0};
3448 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3449 if (rc != ERROR_SUCCESS)
3450 return ERROR_SUCCESS;
3452 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3453 msiobj_release( &view->hdr );
3455 return rc;
3458 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3460 MSIPACKAGE* package = param;
3461 HANDLE the_file;
3462 LPWSTR FilePath;
3463 LPCWSTR FileName;
3464 CHAR buffer[1024];
3465 DWORD sz;
3466 UINT rc;
3468 FileName = MSI_RecordGetString(row,1);
3469 if (!FileName)
3471 ERR("Unable to get FileName\n");
3472 return ERROR_SUCCESS;
3475 FilePath = build_icon_path(package,FileName);
3477 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3479 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3480 FILE_ATTRIBUTE_NORMAL, NULL);
3482 if (the_file == INVALID_HANDLE_VALUE)
3484 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3485 msi_free(FilePath);
3486 return ERROR_SUCCESS;
3491 DWORD write;
3492 sz = 1024;
3493 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3494 if (rc != ERROR_SUCCESS)
3496 ERR("Failed to get stream\n");
3497 CloseHandle(the_file);
3498 DeleteFileW(FilePath);
3499 break;
3501 WriteFile(the_file,buffer,sz,&write,NULL);
3502 } while (sz == 1024);
3504 msi_free(FilePath);
3505 CloseHandle(the_file);
3507 return ERROR_SUCCESS;
3510 static UINT msi_publish_icons(MSIPACKAGE *package)
3512 UINT r;
3513 MSIQUERY *view;
3515 static const WCHAR query[]= {
3516 'S','E','L','E','C','T',' ','*',' ',
3517 'F','R','O','M',' ','`','I','c','o','n','`',0};
3519 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3520 if (r == ERROR_SUCCESS)
3522 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3523 msiobj_release(&view->hdr);
3526 return ERROR_SUCCESS;
3529 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3531 UINT r;
3532 HKEY source;
3533 LPWSTR buffer;
3534 MSIMEDIADISK *disk;
3535 MSISOURCELISTINFO *info;
3537 r = RegCreateKeyW(hkey, szSourceList, &source);
3538 if (r != ERROR_SUCCESS)
3539 return r;
3541 RegCloseKey(source);
3543 buffer = strrchrW(package->PackagePath, '\\') + 1;
3544 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3545 package->Context, MSICODE_PRODUCT,
3546 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3547 if (r != ERROR_SUCCESS)
3548 return r;
3550 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3551 package->Context, MSICODE_PRODUCT,
3552 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3553 if (r != ERROR_SUCCESS)
3554 return r;
3556 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3557 package->Context, MSICODE_PRODUCT,
3558 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3559 if (r != ERROR_SUCCESS)
3560 return r;
3562 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3564 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3565 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3566 info->options, info->value);
3567 else
3568 MsiSourceListSetInfoW(package->ProductCode, NULL,
3569 info->context, info->options,
3570 info->property, info->value);
3573 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3575 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3576 disk->context, disk->options,
3577 disk->disk_id, disk->volume_label, disk->disk_prompt);
3580 return ERROR_SUCCESS;
3583 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3585 MSIHANDLE hdb, suminfo;
3586 WCHAR guids[MAX_PATH];
3587 WCHAR packcode[SQUISH_GUID_SIZE];
3588 LPWSTR buffer;
3589 LPWSTR ptr;
3590 DWORD langid;
3591 DWORD size;
3592 UINT r;
3594 static const WCHAR szProductLanguage[] =
3595 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3596 static const WCHAR szARPProductIcon[] =
3597 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3598 static const WCHAR szProductVersion[] =
3599 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3600 static const WCHAR szAssignment[] =
3601 {'A','s','s','i','g','n','m','e','n','t',0};
3602 static const WCHAR szAdvertiseFlags[] =
3603 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3604 static const WCHAR szClients[] =
3605 {'C','l','i','e','n','t','s',0};
3606 static const WCHAR szColon[] = {':',0};
3608 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3609 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3610 msi_free(buffer);
3612 langid = msi_get_property_int(package, szProductLanguage, 0);
3613 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3615 /* FIXME */
3616 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3618 buffer = msi_dup_property(package, szARPProductIcon);
3619 if (buffer)
3621 LPWSTR path = build_icon_path(package,buffer);
3622 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3623 msi_free(path);
3624 msi_free(buffer);
3627 buffer = msi_dup_property(package, szProductVersion);
3628 if (buffer)
3630 DWORD verdword = msi_version_str_to_dword(buffer);
3631 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3632 msi_free(buffer);
3635 msi_reg_set_val_dword(hkey, szAssignment, 0);
3636 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3637 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3638 msi_reg_set_val_str(hkey, szClients, szColon);
3640 hdb = alloc_msihandle(&package->db->hdr);
3641 if (!hdb)
3642 return ERROR_NOT_ENOUGH_MEMORY;
3644 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3645 MsiCloseHandle(hdb);
3646 if (r != ERROR_SUCCESS)
3647 goto done;
3649 size = MAX_PATH;
3650 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3651 NULL, guids, &size);
3652 if (r != ERROR_SUCCESS)
3653 goto done;
3655 ptr = strchrW(guids, ';');
3656 if (ptr) *ptr = 0;
3657 squash_guid(guids, packcode);
3658 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3660 done:
3661 MsiCloseHandle(suminfo);
3662 return ERROR_SUCCESS;
3665 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3667 UINT r;
3668 HKEY hkey;
3669 LPWSTR upgrade;
3670 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3672 static const WCHAR szUpgradeCode[] =
3673 {'U','p','g','r','a','d','e','C','o','d','e',0};
3675 upgrade = msi_dup_property(package, szUpgradeCode);
3676 if (!upgrade)
3677 return ERROR_SUCCESS;
3679 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3681 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3682 if (r != ERROR_SUCCESS)
3683 goto done;
3685 else
3687 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3688 if (r != ERROR_SUCCESS)
3689 goto done;
3692 squash_guid(package->ProductCode, squashed_pc);
3693 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3695 RegCloseKey(hkey);
3697 done:
3698 msi_free(upgrade);
3699 return r;
3702 static BOOL msi_check_publish(MSIPACKAGE *package)
3704 MSIFEATURE *feature;
3706 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3708 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3709 return TRUE;
3712 return FALSE;
3715 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3717 MSIFEATURE *feature;
3719 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3721 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3722 return FALSE;
3725 return TRUE;
3728 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3730 WCHAR patch_squashed[GUID_SIZE];
3731 HKEY patches;
3732 LONG res;
3733 UINT r = ERROR_FUNCTION_FAILED;
3735 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3736 &patches, NULL);
3737 if (res != ERROR_SUCCESS)
3738 return ERROR_FUNCTION_FAILED;
3740 squash_guid(package->patch->patchcode, patch_squashed);
3742 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3743 (const BYTE *)patch_squashed,
3744 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3745 if (res != ERROR_SUCCESS)
3746 goto done;
3748 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3749 (const BYTE *)package->patch->transforms,
3750 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3751 if (res == ERROR_SUCCESS)
3752 r = ERROR_SUCCESS;
3754 done:
3755 RegCloseKey(patches);
3756 return r;
3760 * 99% of the work done here is only done for
3761 * advertised installs. However this is where the
3762 * Icon table is processed and written out
3763 * so that is what I am going to do here.
3765 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3767 UINT rc;
3768 HKEY hukey = NULL, hudkey = NULL;
3769 MSIRECORD *uirow;
3771 /* FIXME: also need to publish if the product is in advertise mode */
3772 if (!msi_check_publish(package))
3773 return ERROR_SUCCESS;
3775 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3776 &hukey, TRUE);
3777 if (rc != ERROR_SUCCESS)
3778 goto end;
3780 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3781 NULL, &hudkey, TRUE);
3782 if (rc != ERROR_SUCCESS)
3783 goto end;
3785 rc = msi_publish_upgrade_code(package);
3786 if (rc != ERROR_SUCCESS)
3787 goto end;
3789 if (package->patch)
3791 rc = msi_publish_patch(package, hukey, hudkey);
3792 if (rc != ERROR_SUCCESS)
3793 goto end;
3796 rc = msi_publish_product_properties(package, hukey);
3797 if (rc != ERROR_SUCCESS)
3798 goto end;
3800 rc = msi_publish_sourcelist(package, hukey);
3801 if (rc != ERROR_SUCCESS)
3802 goto end;
3804 rc = msi_publish_icons(package);
3806 end:
3807 uirow = MSI_CreateRecord( 1 );
3808 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3809 ui_actiondata( package, szPublishProduct, uirow );
3810 msiobj_release( &uirow->hdr );
3812 RegCloseKey(hukey);
3813 RegCloseKey(hudkey);
3815 return rc;
3818 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3820 WCHAR *filename, *ptr, *folder, *ret;
3821 const WCHAR *dirprop;
3823 filename = msi_dup_record_field( row, 2 );
3824 if (filename && (ptr = strchrW( filename, '|' )))
3825 ptr++;
3826 else
3827 ptr = filename;
3829 dirprop = MSI_RecordGetString( row, 3 );
3830 if (dirprop)
3832 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3833 if (!folder)
3834 folder = msi_dup_property( package, dirprop );
3836 else
3837 folder = msi_dup_property( package, szWindowsFolder );
3839 if (!folder)
3841 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3842 msi_free( filename );
3843 return NULL;
3846 ret = build_directory_name( 2, folder, ptr );
3848 msi_free( filename );
3849 msi_free( folder );
3850 return ret;
3853 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3855 MSIPACKAGE *package = param;
3856 LPCWSTR component, section, key, value, identifier;
3857 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
3858 MSIRECORD * uirow;
3859 INT action;
3860 MSICOMPONENT *comp;
3862 component = MSI_RecordGetString(row, 8);
3863 comp = get_loaded_component(package,component);
3864 if (!comp)
3865 return ERROR_SUCCESS;
3867 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3869 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3870 comp->Action = comp->Installed;
3871 return ERROR_SUCCESS;
3873 comp->Action = INSTALLSTATE_LOCAL;
3875 identifier = MSI_RecordGetString(row,1);
3876 section = MSI_RecordGetString(row,4);
3877 key = MSI_RecordGetString(row,5);
3878 value = MSI_RecordGetString(row,6);
3879 action = MSI_RecordGetInteger(row,7);
3881 deformat_string(package,section,&deformated_section);
3882 deformat_string(package,key,&deformated_key);
3883 deformat_string(package,value,&deformated_value);
3885 fullname = get_ini_file_name(package, row);
3887 if (action == 0)
3889 TRACE("Adding value %s to section %s in %s\n",
3890 debugstr_w(deformated_key), debugstr_w(deformated_section),
3891 debugstr_w(fullname));
3892 WritePrivateProfileStringW(deformated_section, deformated_key,
3893 deformated_value, fullname);
3895 else if (action == 1)
3897 WCHAR returned[10];
3898 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3899 returned, 10, fullname);
3900 if (returned[0] == 0)
3902 TRACE("Adding value %s to section %s in %s\n",
3903 debugstr_w(deformated_key), debugstr_w(deformated_section),
3904 debugstr_w(fullname));
3906 WritePrivateProfileStringW(deformated_section, deformated_key,
3907 deformated_value, fullname);
3910 else if (action == 3)
3911 FIXME("Append to existing section not yet implemented\n");
3913 uirow = MSI_CreateRecord(4);
3914 MSI_RecordSetStringW(uirow,1,identifier);
3915 MSI_RecordSetStringW(uirow,2,deformated_section);
3916 MSI_RecordSetStringW(uirow,3,deformated_key);
3917 MSI_RecordSetStringW(uirow,4,deformated_value);
3918 ui_actiondata(package,szWriteIniValues,uirow);
3919 msiobj_release( &uirow->hdr );
3921 msi_free(fullname);
3922 msi_free(deformated_key);
3923 msi_free(deformated_value);
3924 msi_free(deformated_section);
3925 return ERROR_SUCCESS;
3928 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3930 UINT rc;
3931 MSIQUERY * view;
3932 static const WCHAR ExecSeqQuery[] =
3933 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3934 '`','I','n','i','F','i','l','e','`',0};
3936 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3937 if (rc != ERROR_SUCCESS)
3939 TRACE("no IniFile table\n");
3940 return ERROR_SUCCESS;
3943 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3944 msiobj_release(&view->hdr);
3945 return rc;
3948 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
3950 MSIPACKAGE *package = param;
3951 LPCWSTR component, section, key, value, identifier;
3952 LPWSTR deformated_section, deformated_key, deformated_value, filename;
3953 MSICOMPONENT *comp;
3954 MSIRECORD *uirow;
3955 INT action;
3957 component = MSI_RecordGetString( row, 8 );
3958 comp = get_loaded_component( package, component );
3959 if (!comp)
3960 return ERROR_SUCCESS;
3962 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3964 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3965 comp->Action = comp->Installed;
3966 return ERROR_SUCCESS;
3968 comp->Action = INSTALLSTATE_ABSENT;
3970 identifier = MSI_RecordGetString( row, 1 );
3971 section = MSI_RecordGetString( row, 4 );
3972 key = MSI_RecordGetString( row, 5 );
3973 value = MSI_RecordGetString( row, 6 );
3974 action = MSI_RecordGetInteger( row, 7 );
3976 deformat_string( package, section, &deformated_section );
3977 deformat_string( package, key, &deformated_key );
3978 deformat_string( package, value, &deformated_value );
3980 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
3982 filename = get_ini_file_name( package, row );
3984 TRACE("Removing key %s from section %s in %s\n",
3985 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
3987 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
3989 WARN("Unable to remove key %u\n", GetLastError());
3991 msi_free( filename );
3993 else
3994 FIXME("Unsupported action %d\n", action);
3997 uirow = MSI_CreateRecord( 4 );
3998 MSI_RecordSetStringW( uirow, 1, identifier );
3999 MSI_RecordSetStringW( uirow, 2, deformated_section );
4000 MSI_RecordSetStringW( uirow, 3, deformated_key );
4001 MSI_RecordSetStringW( uirow, 4, deformated_value );
4002 ui_actiondata( package, szRemoveIniValues, uirow );
4003 msiobj_release( &uirow->hdr );
4005 msi_free( deformated_key );
4006 msi_free( deformated_value );
4007 msi_free( deformated_section );
4008 return ERROR_SUCCESS;
4011 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4013 MSIPACKAGE *package = param;
4014 LPCWSTR component, section, key, value, identifier;
4015 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4016 MSICOMPONENT *comp;
4017 MSIRECORD *uirow;
4018 INT action;
4020 component = MSI_RecordGetString( row, 8 );
4021 comp = get_loaded_component( package, component );
4022 if (!comp)
4023 return ERROR_SUCCESS;
4025 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4027 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4028 comp->Action = comp->Installed;
4029 return ERROR_SUCCESS;
4031 comp->Action = INSTALLSTATE_LOCAL;
4033 identifier = MSI_RecordGetString( row, 1 );
4034 section = MSI_RecordGetString( row, 4 );
4035 key = MSI_RecordGetString( row, 5 );
4036 value = MSI_RecordGetString( row, 6 );
4037 action = MSI_RecordGetInteger( row, 7 );
4039 deformat_string( package, section, &deformated_section );
4040 deformat_string( package, key, &deformated_key );
4041 deformat_string( package, value, &deformated_value );
4043 if (action == msidbIniFileActionRemoveLine)
4045 filename = get_ini_file_name( package, row );
4047 TRACE("Removing key %s from section %s in %s\n",
4048 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4050 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4052 WARN("Unable to remove key %u\n", GetLastError());
4054 msi_free( filename );
4056 else
4057 FIXME("Unsupported action %d\n", action);
4059 uirow = MSI_CreateRecord( 4 );
4060 MSI_RecordSetStringW( uirow, 1, identifier );
4061 MSI_RecordSetStringW( uirow, 2, deformated_section );
4062 MSI_RecordSetStringW( uirow, 3, deformated_key );
4063 MSI_RecordSetStringW( uirow, 4, deformated_value );
4064 ui_actiondata( package, szRemoveIniValues, uirow );
4065 msiobj_release( &uirow->hdr );
4067 msi_free( deformated_key );
4068 msi_free( deformated_value );
4069 msi_free( deformated_section );
4070 return ERROR_SUCCESS;
4073 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4075 UINT rc;
4076 MSIQUERY *view;
4077 static const WCHAR query[] =
4078 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4079 '`','I','n','i','F','i','l','e','`',0};
4080 static const WCHAR remove_query[] =
4081 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4082 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4084 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4085 if (rc == ERROR_SUCCESS)
4087 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4088 msiobj_release( &view->hdr );
4089 if (rc != ERROR_SUCCESS)
4090 return rc;
4093 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4094 if (rc == ERROR_SUCCESS)
4096 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4097 msiobj_release( &view->hdr );
4098 if (rc != ERROR_SUCCESS)
4099 return rc;
4102 return ERROR_SUCCESS;
4105 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4107 MSIPACKAGE *package = param;
4108 LPCWSTR filename;
4109 LPWSTR FullName;
4110 MSIFILE *file;
4111 DWORD len;
4112 static const WCHAR ExeStr[] =
4113 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4114 static const WCHAR close[] = {'\"',0};
4115 STARTUPINFOW si;
4116 PROCESS_INFORMATION info;
4117 BOOL brc;
4118 MSIRECORD *uirow;
4119 LPWSTR uipath, p;
4121 memset(&si,0,sizeof(STARTUPINFOW));
4123 filename = MSI_RecordGetString(row,1);
4124 file = get_loaded_file( package, filename );
4126 if (!file)
4128 ERR("Unable to find file id %s\n",debugstr_w(filename));
4129 return ERROR_SUCCESS;
4132 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4134 FullName = msi_alloc(len*sizeof(WCHAR));
4135 strcpyW(FullName,ExeStr);
4136 strcatW( FullName, file->TargetPath );
4137 strcatW(FullName,close);
4139 TRACE("Registering %s\n",debugstr_w(FullName));
4140 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4141 &si, &info);
4143 if (brc)
4145 CloseHandle(info.hThread);
4146 msi_dialog_check_messages(info.hProcess);
4147 CloseHandle(info.hProcess);
4150 uirow = MSI_CreateRecord( 2 );
4151 MSI_RecordSetStringW( uirow, 1, filename );
4152 uipath = strdupW( file->TargetPath );
4153 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4154 MSI_RecordSetStringW( uirow, 2, uipath );
4155 ui_actiondata( package, szSelfRegModules, uirow );
4156 msiobj_release( &uirow->hdr );
4158 msi_free( FullName );
4159 msi_free( uipath );
4160 return ERROR_SUCCESS;
4163 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4165 UINT rc;
4166 MSIQUERY * view;
4167 static const WCHAR ExecSeqQuery[] =
4168 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4169 '`','S','e','l','f','R','e','g','`',0};
4171 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4172 if (rc != ERROR_SUCCESS)
4174 TRACE("no SelfReg table\n");
4175 return ERROR_SUCCESS;
4178 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4179 msiobj_release(&view->hdr);
4181 return ERROR_SUCCESS;
4184 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4186 static const WCHAR regsvr32[] =
4187 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4188 static const WCHAR close[] = {'\"',0};
4189 MSIPACKAGE *package = param;
4190 LPCWSTR filename;
4191 LPWSTR cmdline;
4192 MSIFILE *file;
4193 DWORD len;
4194 STARTUPINFOW si;
4195 PROCESS_INFORMATION pi;
4196 BOOL ret;
4197 MSIRECORD *uirow;
4198 LPWSTR uipath, p;
4200 memset( &si, 0, sizeof(STARTUPINFOW) );
4202 filename = MSI_RecordGetString( row, 1 );
4203 file = get_loaded_file( package, filename );
4205 if (!file)
4207 ERR("Unable to find file id %s\n", debugstr_w(filename));
4208 return ERROR_SUCCESS;
4211 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4213 cmdline = msi_alloc( len * sizeof(WCHAR) );
4214 strcpyW( cmdline, regsvr32 );
4215 strcatW( cmdline, file->TargetPath );
4216 strcatW( cmdline, close );
4218 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4220 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4221 if (ret)
4223 CloseHandle( pi.hThread );
4224 msi_dialog_check_messages( pi.hProcess );
4225 CloseHandle( pi.hProcess );
4228 uirow = MSI_CreateRecord( 2 );
4229 MSI_RecordSetStringW( uirow, 1, filename );
4230 uipath = strdupW( file->TargetPath );
4231 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4232 MSI_RecordSetStringW( uirow, 2, uipath );
4233 ui_actiondata( package, szSelfUnregModules, uirow );
4234 msiobj_release( &uirow->hdr );
4236 msi_free( cmdline );
4237 msi_free( uipath );
4238 return ERROR_SUCCESS;
4241 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4243 UINT rc;
4244 MSIQUERY *view;
4245 static const WCHAR query[] =
4246 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4247 '`','S','e','l','f','R','e','g','`',0};
4249 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4250 if (rc != ERROR_SUCCESS)
4252 TRACE("no SelfReg table\n");
4253 return ERROR_SUCCESS;
4256 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4257 msiobj_release( &view->hdr );
4259 return ERROR_SUCCESS;
4262 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4264 MSIFEATURE *feature;
4265 UINT rc;
4266 HKEY hkey = NULL, userdata = NULL;
4268 if (!msi_check_publish(package))
4269 return ERROR_SUCCESS;
4271 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4272 &hkey, TRUE);
4273 if (rc != ERROR_SUCCESS)
4274 goto end;
4276 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4277 &userdata, TRUE);
4278 if (rc != ERROR_SUCCESS)
4279 goto end;
4281 /* here the guids are base 85 encoded */
4282 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4284 ComponentList *cl;
4285 LPWSTR data = NULL;
4286 GUID clsid;
4287 INT size;
4288 BOOL absent = FALSE;
4289 MSIRECORD *uirow;
4291 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4292 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4293 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4295 size = 1;
4296 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4298 size += 21;
4300 if (feature->Feature_Parent)
4301 size += strlenW( feature->Feature_Parent )+2;
4303 data = msi_alloc(size * sizeof(WCHAR));
4305 data[0] = 0;
4306 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4308 MSICOMPONENT* component = cl->component;
4309 WCHAR buf[21];
4311 buf[0] = 0;
4312 if (component->ComponentId)
4314 TRACE("From %s\n",debugstr_w(component->ComponentId));
4315 CLSIDFromString(component->ComponentId, &clsid);
4316 encode_base85_guid(&clsid,buf);
4317 TRACE("to %s\n",debugstr_w(buf));
4318 strcatW(data,buf);
4322 if (feature->Feature_Parent)
4324 static const WCHAR sep[] = {'\2',0};
4325 strcatW(data,sep);
4326 strcatW(data,feature->Feature_Parent);
4329 msi_reg_set_val_str( userdata, feature->Feature, data );
4330 msi_free(data);
4332 size = 0;
4333 if (feature->Feature_Parent)
4334 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4335 if (!absent)
4337 size += sizeof(WCHAR);
4338 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4339 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4341 else
4343 size += 2*sizeof(WCHAR);
4344 data = msi_alloc(size);
4345 data[0] = 0x6;
4346 data[1] = 0;
4347 if (feature->Feature_Parent)
4348 strcpyW( &data[1], feature->Feature_Parent );
4349 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4350 (LPBYTE)data,size);
4351 msi_free(data);
4354 /* the UI chunk */
4355 uirow = MSI_CreateRecord( 1 );
4356 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4357 ui_actiondata( package, szPublishFeatures, uirow);
4358 msiobj_release( &uirow->hdr );
4359 /* FIXME: call ui_progress? */
4362 end:
4363 RegCloseKey(hkey);
4364 RegCloseKey(userdata);
4365 return rc;
4368 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4370 UINT r;
4371 HKEY hkey;
4372 MSIRECORD *uirow;
4374 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4376 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4377 &hkey, FALSE);
4378 if (r == ERROR_SUCCESS)
4380 RegDeleteValueW(hkey, feature->Feature);
4381 RegCloseKey(hkey);
4384 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4385 &hkey, FALSE);
4386 if (r == ERROR_SUCCESS)
4388 RegDeleteValueW(hkey, feature->Feature);
4389 RegCloseKey(hkey);
4392 uirow = MSI_CreateRecord( 1 );
4393 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4394 ui_actiondata( package, szUnpublishFeatures, uirow );
4395 msiobj_release( &uirow->hdr );
4397 return ERROR_SUCCESS;
4400 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4402 MSIFEATURE *feature;
4404 if (!msi_check_unpublish(package))
4405 return ERROR_SUCCESS;
4407 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4409 msi_unpublish_feature(package, feature);
4412 return ERROR_SUCCESS;
4415 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4417 LPWSTR prop, val, key;
4418 SYSTEMTIME systime;
4419 DWORD size, langid;
4420 WCHAR date[9];
4421 LPWSTR buffer;
4423 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4424 static const WCHAR szWindowsInstaller[] =
4425 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4426 static const WCHAR modpath_fmt[] =
4427 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4428 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4429 static const WCHAR szModifyPath[] =
4430 {'M','o','d','i','f','y','P','a','t','h',0};
4431 static const WCHAR szUninstallString[] =
4432 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4433 static const WCHAR szEstimatedSize[] =
4434 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4435 static const WCHAR szProductLanguage[] =
4436 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4437 static const WCHAR szProductVersion[] =
4438 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4439 static const WCHAR szProductName[] =
4440 {'P','r','o','d','u','c','t','N','a','m','e',0};
4441 static const WCHAR szDisplayName[] =
4442 {'D','i','s','p','l','a','y','N','a','m','e',0};
4443 static const WCHAR szDisplayVersion[] =
4444 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4445 static const WCHAR szManufacturer[] =
4446 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4448 static const LPCSTR propval[] = {
4449 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4450 "ARPCONTACT", "Contact",
4451 "ARPCOMMENTS", "Comments",
4452 "ProductName", "DisplayName",
4453 "ProductVersion", "DisplayVersion",
4454 "ARPHELPLINK", "HelpLink",
4455 "ARPHELPTELEPHONE", "HelpTelephone",
4456 "ARPINSTALLLOCATION", "InstallLocation",
4457 "SourceDir", "InstallSource",
4458 "Manufacturer", "Publisher",
4459 "ARPREADME", "Readme",
4460 "ARPSIZE", "Size",
4461 "ARPURLINFOABOUT", "URLInfoAbout",
4462 "ARPURLUPDATEINFO", "URLUpdateInfo",
4463 NULL,
4465 const LPCSTR *p = propval;
4467 while (*p)
4469 prop = strdupAtoW(*p++);
4470 key = strdupAtoW(*p++);
4471 val = msi_dup_property(package, prop);
4472 msi_reg_set_val_str(hkey, key, val);
4473 msi_free(val);
4474 msi_free(key);
4475 msi_free(prop);
4478 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4480 size = deformat_string(package, modpath_fmt, &buffer);
4481 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4482 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4483 msi_free(buffer);
4485 /* FIXME: Write real Estimated Size when we have it */
4486 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4488 buffer = msi_dup_property(package, szProductName);
4489 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4490 msi_free(buffer);
4492 buffer = msi_dup_property(package, cszSourceDir);
4493 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4494 msi_free(buffer);
4496 buffer = msi_dup_property(package, szManufacturer);
4497 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4498 msi_free(buffer);
4500 GetLocalTime(&systime);
4501 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4502 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4504 langid = msi_get_property_int(package, szProductLanguage, 0);
4505 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4507 buffer = msi_dup_property(package, szProductVersion);
4508 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4509 if (buffer)
4511 DWORD verdword = msi_version_str_to_dword(buffer);
4513 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4514 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4515 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4516 msi_free(buffer);
4519 return ERROR_SUCCESS;
4522 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4524 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4525 MSIRECORD *uirow;
4526 LPWSTR upgrade_code;
4527 HKEY hkey, props;
4528 HKEY upgrade;
4529 UINT rc;
4531 static const WCHAR szUpgradeCode[] = {
4532 'U','p','g','r','a','d','e','C','o','d','e',0};
4534 /* FIXME: also need to publish if the product is in advertise mode */
4535 if (!msi_check_publish(package))
4536 return ERROR_SUCCESS;
4538 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4539 if (rc != ERROR_SUCCESS)
4540 return rc;
4542 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4543 NULL, &props, TRUE);
4544 if (rc != ERROR_SUCCESS)
4545 goto done;
4547 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4548 msi_free( package->db->localfile );
4549 package->db->localfile = NULL;
4551 rc = msi_publish_install_properties(package, hkey);
4552 if (rc != ERROR_SUCCESS)
4553 goto done;
4555 rc = msi_publish_install_properties(package, props);
4556 if (rc != ERROR_SUCCESS)
4557 goto done;
4559 upgrade_code = msi_dup_property(package, szUpgradeCode);
4560 if (upgrade_code)
4562 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4563 squash_guid(package->ProductCode, squashed_pc);
4564 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4565 RegCloseKey(upgrade);
4566 msi_free(upgrade_code);
4569 done:
4570 uirow = MSI_CreateRecord( 1 );
4571 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4572 ui_actiondata( package, szRegisterProduct, uirow );
4573 msiobj_release( &uirow->hdr );
4575 RegCloseKey(hkey);
4576 return ERROR_SUCCESS;
4579 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4581 return execute_script(package,INSTALL_SCRIPT);
4584 static UINT msi_unpublish_product(MSIPACKAGE *package)
4586 LPWSTR upgrade;
4587 LPWSTR remove = NULL;
4588 LPWSTR *features = NULL;
4589 BOOL full_uninstall = TRUE;
4590 MSIFEATURE *feature;
4592 static const WCHAR szUpgradeCode[] =
4593 {'U','p','g','r','a','d','e','C','o','d','e',0};
4595 remove = msi_dup_property(package, szRemove);
4596 if (!remove)
4597 return ERROR_SUCCESS;
4599 features = msi_split_string(remove, ',');
4600 if (!features)
4602 msi_free(remove);
4603 ERR("REMOVE feature list is empty!\n");
4604 return ERROR_FUNCTION_FAILED;
4607 if (!lstrcmpW(features[0], szAll))
4608 full_uninstall = TRUE;
4609 else
4611 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4613 if (feature->Action != INSTALLSTATE_ABSENT)
4614 full_uninstall = FALSE;
4618 if (!full_uninstall)
4619 goto done;
4621 MSIREG_DeleteProductKey(package->ProductCode);
4622 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4623 MSIREG_DeleteUninstallKey(package->ProductCode);
4625 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4627 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4628 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4630 else
4632 MSIREG_DeleteUserProductKey(package->ProductCode);
4633 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4636 upgrade = msi_dup_property(package, szUpgradeCode);
4637 if (upgrade)
4639 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4640 msi_free(upgrade);
4643 done:
4644 msi_free(remove);
4645 msi_free(features);
4646 return ERROR_SUCCESS;
4649 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4651 UINT rc;
4653 rc = msi_unpublish_product(package);
4654 if (rc != ERROR_SUCCESS)
4655 return rc;
4657 /* turn off scheduling */
4658 package->script->CurrentlyScripting= FALSE;
4660 /* first do the same as an InstallExecute */
4661 rc = ACTION_InstallExecute(package);
4662 if (rc != ERROR_SUCCESS)
4663 return rc;
4665 /* then handle Commit Actions */
4666 rc = execute_script(package,COMMIT_SCRIPT);
4668 return rc;
4671 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4673 static const WCHAR RunOnce[] = {
4674 'S','o','f','t','w','a','r','e','\\',
4675 'M','i','c','r','o','s','o','f','t','\\',
4676 'W','i','n','d','o','w','s','\\',
4677 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4678 'R','u','n','O','n','c','e',0};
4679 static const WCHAR InstallRunOnce[] = {
4680 'S','o','f','t','w','a','r','e','\\',
4681 'M','i','c','r','o','s','o','f','t','\\',
4682 'W','i','n','d','o','w','s','\\',
4683 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4684 'I','n','s','t','a','l','l','e','r','\\',
4685 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4687 static const WCHAR msiexec_fmt[] = {
4688 '%','s',
4689 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4690 '\"','%','s','\"',0};
4691 static const WCHAR install_fmt[] = {
4692 '/','I',' ','\"','%','s','\"',' ',
4693 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4694 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4695 WCHAR buffer[256], sysdir[MAX_PATH];
4696 HKEY hkey;
4697 WCHAR squished_pc[100];
4699 squash_guid(package->ProductCode,squished_pc);
4701 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4702 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4703 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4704 squished_pc);
4706 msi_reg_set_val_str( hkey, squished_pc, buffer );
4707 RegCloseKey(hkey);
4709 TRACE("Reboot command %s\n",debugstr_w(buffer));
4711 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4712 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4714 msi_reg_set_val_str( hkey, squished_pc, buffer );
4715 RegCloseKey(hkey);
4717 return ERROR_INSTALL_SUSPEND;
4720 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4722 DWORD attrib;
4723 UINT rc;
4726 * We are currently doing what should be done here in the top level Install
4727 * however for Administrative and uninstalls this step will be needed
4729 if (!package->PackagePath)
4730 return ERROR_SUCCESS;
4732 msi_set_sourcedir_props(package, TRUE);
4734 attrib = GetFileAttributesW(package->db->path);
4735 if (attrib == INVALID_FILE_ATTRIBUTES)
4737 LPWSTR prompt;
4738 LPWSTR msg;
4739 DWORD size = 0;
4741 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4742 package->Context, MSICODE_PRODUCT,
4743 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4744 if (rc == ERROR_MORE_DATA)
4746 prompt = msi_alloc(size * sizeof(WCHAR));
4747 MsiSourceListGetInfoW(package->ProductCode, NULL,
4748 package->Context, MSICODE_PRODUCT,
4749 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4751 else
4752 prompt = strdupW(package->db->path);
4754 msg = generate_error_string(package,1302,1,prompt);
4755 while(attrib == INVALID_FILE_ATTRIBUTES)
4757 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4758 if (rc == IDCANCEL)
4760 rc = ERROR_INSTALL_USEREXIT;
4761 break;
4763 attrib = GetFileAttributesW(package->db->path);
4765 msi_free(prompt);
4766 rc = ERROR_SUCCESS;
4768 else
4769 return ERROR_SUCCESS;
4771 return rc;
4774 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4776 HKEY hkey = 0;
4777 LPWSTR buffer, productid = NULL;
4778 UINT i, rc = ERROR_SUCCESS;
4779 MSIRECORD *uirow;
4781 static const WCHAR szPropKeys[][80] =
4783 {'P','r','o','d','u','c','t','I','D',0},
4784 {'U','S','E','R','N','A','M','E',0},
4785 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4786 {0},
4789 static const WCHAR szRegKeys[][80] =
4791 {'P','r','o','d','u','c','t','I','D',0},
4792 {'R','e','g','O','w','n','e','r',0},
4793 {'R','e','g','C','o','m','p','a','n','y',0},
4794 {0},
4797 if (msi_check_unpublish(package))
4799 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4800 goto end;
4803 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4804 if (!productid)
4805 goto end;
4807 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4808 NULL, &hkey, TRUE);
4809 if (rc != ERROR_SUCCESS)
4810 goto end;
4812 for( i = 0; szPropKeys[i][0]; i++ )
4814 buffer = msi_dup_property( package, szPropKeys[i] );
4815 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4816 msi_free( buffer );
4819 end:
4820 uirow = MSI_CreateRecord( 1 );
4821 MSI_RecordSetStringW( uirow, 1, productid );
4822 ui_actiondata( package, szRegisterUser, uirow );
4823 msiobj_release( &uirow->hdr );
4825 msi_free(productid);
4826 RegCloseKey(hkey);
4827 return rc;
4831 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4833 UINT rc;
4835 package->script->InWhatSequence |= SEQUENCE_EXEC;
4836 rc = ACTION_ProcessExecSequence(package,FALSE);
4837 return rc;
4841 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4843 MSIPACKAGE *package = param;
4844 LPCWSTR compgroupid, component, feature, qualifier, text;
4845 LPWSTR advertise = NULL, output = NULL;
4846 HKEY hkey = NULL;
4847 UINT rc;
4848 MSICOMPONENT *comp;
4849 MSIFEATURE *feat;
4850 DWORD sz;
4851 MSIRECORD *uirow;
4853 feature = MSI_RecordGetString(rec, 5);
4854 feat = get_loaded_feature(package, feature);
4855 if (!feat)
4856 return ERROR_SUCCESS;
4858 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4859 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4860 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
4862 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4863 feat->Action = feat->Installed;
4864 return ERROR_SUCCESS;
4867 component = MSI_RecordGetString(rec, 3);
4868 comp = get_loaded_component(package, component);
4869 if (!comp)
4870 return ERROR_SUCCESS;
4872 compgroupid = MSI_RecordGetString(rec,1);
4873 qualifier = MSI_RecordGetString(rec,2);
4875 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4876 if (rc != ERROR_SUCCESS)
4877 goto end;
4879 text = MSI_RecordGetString(rec,4);
4880 advertise = create_component_advertise_string(package, comp, feature);
4882 sz = strlenW(advertise);
4884 if (text)
4885 sz += lstrlenW(text);
4887 sz+=3;
4888 sz *= sizeof(WCHAR);
4890 output = msi_alloc_zero(sz);
4891 strcpyW(output,advertise);
4892 msi_free(advertise);
4894 if (text)
4895 strcatW(output,text);
4897 msi_reg_set_val_multi_str( hkey, qualifier, output );
4899 end:
4900 RegCloseKey(hkey);
4901 msi_free(output);
4903 /* the UI chunk */
4904 uirow = MSI_CreateRecord( 2 );
4905 MSI_RecordSetStringW( uirow, 1, compgroupid );
4906 MSI_RecordSetStringW( uirow, 2, qualifier);
4907 ui_actiondata( package, szPublishComponents, uirow);
4908 msiobj_release( &uirow->hdr );
4909 /* FIXME: call ui_progress? */
4911 return rc;
4915 * At present I am ignorning the advertised components part of this and only
4916 * focusing on the qualified component sets
4918 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4920 UINT rc;
4921 MSIQUERY * view;
4922 static const WCHAR ExecSeqQuery[] =
4923 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4924 '`','P','u','b','l','i','s','h',
4925 'C','o','m','p','o','n','e','n','t','`',0};
4927 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4928 if (rc != ERROR_SUCCESS)
4929 return ERROR_SUCCESS;
4931 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4932 msiobj_release(&view->hdr);
4934 return rc;
4937 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
4939 static const WCHAR szInstallerComponents[] = {
4940 'S','o','f','t','w','a','r','e','\\',
4941 'M','i','c','r','o','s','o','f','t','\\',
4942 'I','n','s','t','a','l','l','e','r','\\',
4943 'C','o','m','p','o','n','e','n','t','s','\\',0};
4945 MSIPACKAGE *package = param;
4946 LPCWSTR compgroupid, component, feature, qualifier;
4947 MSICOMPONENT *comp;
4948 MSIFEATURE *feat;
4949 MSIRECORD *uirow;
4950 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
4951 LONG res;
4953 feature = MSI_RecordGetString( rec, 5 );
4954 feat = get_loaded_feature( package, feature );
4955 if (!feat)
4956 return ERROR_SUCCESS;
4958 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
4960 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
4961 feat->Action = feat->Installed;
4962 return ERROR_SUCCESS;
4965 component = MSI_RecordGetString( rec, 3 );
4966 comp = get_loaded_component( package, component );
4967 if (!comp)
4968 return ERROR_SUCCESS;
4970 compgroupid = MSI_RecordGetString( rec, 1 );
4971 qualifier = MSI_RecordGetString( rec, 2 );
4973 squash_guid( compgroupid, squashed );
4974 strcpyW( keypath, szInstallerComponents );
4975 strcatW( keypath, squashed );
4977 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
4978 if (res != ERROR_SUCCESS)
4980 WARN("Unable to delete component key %d\n", res);
4983 uirow = MSI_CreateRecord( 2 );
4984 MSI_RecordSetStringW( uirow, 1, compgroupid );
4985 MSI_RecordSetStringW( uirow, 2, qualifier );
4986 ui_actiondata( package, szUnpublishComponents, uirow );
4987 msiobj_release( &uirow->hdr );
4989 return ERROR_SUCCESS;
4992 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
4994 UINT rc;
4995 MSIQUERY *view;
4996 static const WCHAR query[] =
4997 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4998 '`','P','u','b','l','i','s','h',
4999 'C','o','m','p','o','n','e','n','t','`',0};
5001 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5002 if (rc != ERROR_SUCCESS)
5003 return ERROR_SUCCESS;
5005 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5006 msiobj_release( &view->hdr );
5008 return rc;
5011 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5013 MSIPACKAGE *package = param;
5014 MSIRECORD *row;
5015 MSIFILE *file;
5016 SC_HANDLE hscm, service = NULL;
5017 LPCWSTR comp, depends, pass;
5018 LPWSTR name = NULL, disp = NULL;
5019 LPCWSTR load_order, serv_name, key;
5020 DWORD serv_type, start_type;
5021 DWORD err_control;
5023 static const WCHAR query[] =
5024 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5025 '`','C','o','m','p','o','n','e','n','t','`',' ',
5026 'W','H','E','R','E',' ',
5027 '`','C','o','m','p','o','n','e','n','t','`',' ',
5028 '=','\'','%','s','\'',0};
5030 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5031 if (!hscm)
5033 ERR("Failed to open the SC Manager!\n");
5034 goto done;
5037 start_type = MSI_RecordGetInteger(rec, 5);
5038 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5039 goto done;
5041 depends = MSI_RecordGetString(rec, 8);
5042 if (depends && *depends)
5043 FIXME("Dependency list unhandled!\n");
5045 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5046 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5047 serv_type = MSI_RecordGetInteger(rec, 4);
5048 err_control = MSI_RecordGetInteger(rec, 6);
5049 load_order = MSI_RecordGetString(rec, 7);
5050 serv_name = MSI_RecordGetString(rec, 9);
5051 pass = MSI_RecordGetString(rec, 10);
5052 comp = MSI_RecordGetString(rec, 12);
5054 /* fetch the service path */
5055 row = MSI_QueryGetRecord(package->db, query, comp);
5056 if (!row)
5058 ERR("Control query failed!\n");
5059 goto done;
5062 key = MSI_RecordGetString(row, 6);
5064 file = get_loaded_file(package, key);
5065 msiobj_release(&row->hdr);
5066 if (!file)
5068 ERR("Failed to load the service file\n");
5069 goto done;
5072 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5073 start_type, err_control, file->TargetPath,
5074 load_order, NULL, NULL, serv_name, pass);
5075 if (!service)
5077 if (GetLastError() != ERROR_SERVICE_EXISTS)
5078 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5081 done:
5082 CloseServiceHandle(service);
5083 CloseServiceHandle(hscm);
5084 msi_free(name);
5085 msi_free(disp);
5087 return ERROR_SUCCESS;
5090 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5092 UINT rc;
5093 MSIQUERY * view;
5094 static const WCHAR ExecSeqQuery[] =
5095 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5096 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5098 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5099 if (rc != ERROR_SUCCESS)
5100 return ERROR_SUCCESS;
5102 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5103 msiobj_release(&view->hdr);
5105 return rc;
5108 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5109 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5111 LPCWSTR *vector, *temp_vector;
5112 LPWSTR p, q;
5113 DWORD sep_len;
5115 static const WCHAR separator[] = {'[','~',']',0};
5117 *numargs = 0;
5118 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5120 if (!args)
5121 return NULL;
5123 vector = msi_alloc(sizeof(LPWSTR));
5124 if (!vector)
5125 return NULL;
5127 p = args;
5130 (*numargs)++;
5131 vector[*numargs - 1] = p;
5133 if ((q = strstrW(p, separator)))
5135 *q = '\0';
5137 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5138 if (!temp_vector)
5140 msi_free(vector);
5141 return NULL;
5143 vector = temp_vector;
5145 p = q + sep_len;
5147 } while (q);
5149 return vector;
5152 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5154 MSIPACKAGE *package = param;
5155 MSICOMPONENT *comp;
5156 MSIRECORD *uirow;
5157 SC_HANDLE scm = NULL, service = NULL;
5158 LPCWSTR component, *vector = NULL;
5159 LPWSTR name, args, display_name = NULL;
5160 DWORD event, numargs, len;
5161 UINT r = ERROR_FUNCTION_FAILED;
5163 component = MSI_RecordGetString(rec, 6);
5164 comp = get_loaded_component(package, component);
5165 if (!comp)
5166 return ERROR_SUCCESS;
5168 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5170 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5171 comp->Action = comp->Installed;
5172 return ERROR_SUCCESS;
5174 comp->Action = INSTALLSTATE_LOCAL;
5176 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5177 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5178 event = MSI_RecordGetInteger(rec, 3);
5180 if (!(event & msidbServiceControlEventStart))
5182 r = ERROR_SUCCESS;
5183 goto done;
5186 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5187 if (!scm)
5189 ERR("Failed to open the service control manager\n");
5190 goto done;
5193 len = 0;
5194 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5195 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5197 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5198 GetServiceDisplayNameW( scm, name, display_name, &len );
5201 service = OpenServiceW(scm, name, SERVICE_START);
5202 if (!service)
5204 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5205 goto done;
5208 vector = msi_service_args_to_vector(args, &numargs);
5210 if (!StartServiceW(service, numargs, vector) &&
5211 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5213 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5214 goto done;
5217 r = ERROR_SUCCESS;
5219 done:
5220 uirow = MSI_CreateRecord( 2 );
5221 MSI_RecordSetStringW( uirow, 1, display_name );
5222 MSI_RecordSetStringW( uirow, 2, name );
5223 ui_actiondata( package, szStartServices, uirow );
5224 msiobj_release( &uirow->hdr );
5226 CloseServiceHandle(service);
5227 CloseServiceHandle(scm);
5229 msi_free(name);
5230 msi_free(args);
5231 msi_free(vector);
5232 msi_free(display_name);
5233 return r;
5236 static UINT ACTION_StartServices( MSIPACKAGE *package )
5238 UINT rc;
5239 MSIQUERY *view;
5241 static const WCHAR query[] = {
5242 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5243 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5245 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5246 if (rc != ERROR_SUCCESS)
5247 return ERROR_SUCCESS;
5249 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5250 msiobj_release(&view->hdr);
5252 return rc;
5255 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5257 DWORD i, needed, count;
5258 ENUM_SERVICE_STATUSW *dependencies;
5259 SERVICE_STATUS ss;
5260 SC_HANDLE depserv;
5262 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5263 0, &needed, &count))
5264 return TRUE;
5266 if (GetLastError() != ERROR_MORE_DATA)
5267 return FALSE;
5269 dependencies = msi_alloc(needed);
5270 if (!dependencies)
5271 return FALSE;
5273 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5274 needed, &needed, &count))
5275 goto error;
5277 for (i = 0; i < count; i++)
5279 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5280 SERVICE_STOP | SERVICE_QUERY_STATUS);
5281 if (!depserv)
5282 goto error;
5284 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5285 goto error;
5288 return TRUE;
5290 error:
5291 msi_free(dependencies);
5292 return FALSE;
5295 static UINT stop_service( LPCWSTR name )
5297 SC_HANDLE scm = NULL, service = NULL;
5298 SERVICE_STATUS status;
5299 SERVICE_STATUS_PROCESS ssp;
5300 DWORD needed;
5302 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5303 if (!scm)
5305 WARN("Failed to open the SCM: %d\n", GetLastError());
5306 goto done;
5309 service = OpenServiceW(scm, name,
5310 SERVICE_STOP |
5311 SERVICE_QUERY_STATUS |
5312 SERVICE_ENUMERATE_DEPENDENTS);
5313 if (!service)
5315 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5316 goto done;
5319 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5320 sizeof(SERVICE_STATUS_PROCESS), &needed))
5322 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5323 goto done;
5326 if (ssp.dwCurrentState == SERVICE_STOPPED)
5327 goto done;
5329 stop_service_dependents(scm, service);
5331 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5332 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5334 done:
5335 CloseServiceHandle(service);
5336 CloseServiceHandle(scm);
5338 return ERROR_SUCCESS;
5341 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5343 MSIPACKAGE *package = param;
5344 MSICOMPONENT *comp;
5345 MSIRECORD *uirow;
5346 LPCWSTR component;
5347 LPWSTR name = NULL, display_name = NULL;
5348 DWORD event, len;
5349 SC_HANDLE scm;
5351 event = MSI_RecordGetInteger( rec, 3 );
5352 if (!(event & msidbServiceControlEventStop))
5353 return ERROR_SUCCESS;
5355 component = MSI_RecordGetString( rec, 6 );
5356 comp = get_loaded_component( package, component );
5357 if (!comp)
5358 return ERROR_SUCCESS;
5360 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5362 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5363 comp->Action = comp->Installed;
5364 return ERROR_SUCCESS;
5366 comp->Action = INSTALLSTATE_ABSENT;
5368 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5369 if (!scm)
5371 ERR("Failed to open the service control manager\n");
5372 goto done;
5375 len = 0;
5376 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5377 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5379 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5380 GetServiceDisplayNameW( scm, name, display_name, &len );
5382 CloseServiceHandle( scm );
5384 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5385 stop_service( name );
5387 done:
5388 uirow = MSI_CreateRecord( 2 );
5389 MSI_RecordSetStringW( uirow, 1, display_name );
5390 MSI_RecordSetStringW( uirow, 2, name );
5391 ui_actiondata( package, szStopServices, uirow );
5392 msiobj_release( &uirow->hdr );
5394 msi_free( name );
5395 msi_free( display_name );
5396 return ERROR_SUCCESS;
5399 static UINT ACTION_StopServices( MSIPACKAGE *package )
5401 UINT rc;
5402 MSIQUERY *view;
5404 static const WCHAR query[] = {
5405 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5406 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5408 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5409 if (rc != ERROR_SUCCESS)
5410 return ERROR_SUCCESS;
5412 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5413 msiobj_release(&view->hdr);
5415 return rc;
5418 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5420 MSIPACKAGE *package = param;
5421 MSICOMPONENT *comp;
5422 MSIRECORD *uirow;
5423 LPCWSTR component;
5424 LPWSTR name = NULL, display_name = NULL;
5425 DWORD event, len;
5426 SC_HANDLE scm = NULL, service = NULL;
5428 event = MSI_RecordGetInteger( rec, 3 );
5429 if (!(event & msidbServiceControlEventDelete))
5430 return ERROR_SUCCESS;
5432 component = MSI_RecordGetString(rec, 6);
5433 comp = get_loaded_component(package, component);
5434 if (!comp)
5435 return ERROR_SUCCESS;
5437 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5439 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5440 comp->Action = comp->Installed;
5441 return ERROR_SUCCESS;
5443 comp->Action = INSTALLSTATE_ABSENT;
5445 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5446 stop_service( name );
5448 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5449 if (!scm)
5451 WARN("Failed to open the SCM: %d\n", GetLastError());
5452 goto done;
5455 len = 0;
5456 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5457 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5459 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5460 GetServiceDisplayNameW( scm, name, display_name, &len );
5463 service = OpenServiceW( scm, name, DELETE );
5464 if (!service)
5466 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5467 goto done;
5470 if (!DeleteService( service ))
5471 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5473 done:
5474 uirow = MSI_CreateRecord( 2 );
5475 MSI_RecordSetStringW( uirow, 1, display_name );
5476 MSI_RecordSetStringW( uirow, 2, name );
5477 ui_actiondata( package, szDeleteServices, uirow );
5478 msiobj_release( &uirow->hdr );
5480 CloseServiceHandle( service );
5481 CloseServiceHandle( scm );
5482 msi_free( name );
5483 msi_free( display_name );
5485 return ERROR_SUCCESS;
5488 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5490 UINT rc;
5491 MSIQUERY *view;
5493 static const WCHAR query[] = {
5494 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5495 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5497 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5498 if (rc != ERROR_SUCCESS)
5499 return ERROR_SUCCESS;
5501 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5502 msiobj_release( &view->hdr );
5504 return rc;
5507 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5509 MSIFILE *file;
5511 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5513 if (!lstrcmpW(file->File, filename))
5514 return file;
5517 return NULL;
5520 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5522 MSIPACKAGE *package = param;
5523 LPWSTR driver, driver_path, ptr;
5524 WCHAR outpath[MAX_PATH];
5525 MSIFILE *driver_file, *setup_file;
5526 MSIRECORD *uirow;
5527 LPCWSTR desc;
5528 DWORD len, usage;
5529 UINT r = ERROR_SUCCESS;
5531 static const WCHAR driver_fmt[] = {
5532 'D','r','i','v','e','r','=','%','s',0};
5533 static const WCHAR setup_fmt[] = {
5534 'S','e','t','u','p','=','%','s',0};
5535 static const WCHAR usage_fmt[] = {
5536 'F','i','l','e','U','s','a','g','e','=','1',0};
5538 desc = MSI_RecordGetString(rec, 3);
5540 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5541 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5543 if (!driver_file)
5545 ERR("ODBC Driver entry not found!\n");
5546 return ERROR_FUNCTION_FAILED;
5549 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5550 if (setup_file)
5551 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5552 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5554 driver = msi_alloc(len * sizeof(WCHAR));
5555 if (!driver)
5556 return ERROR_OUTOFMEMORY;
5558 ptr = driver;
5559 lstrcpyW(ptr, desc);
5560 ptr += lstrlenW(ptr) + 1;
5562 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5563 ptr += len + 1;
5565 if (setup_file)
5567 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5568 ptr += len + 1;
5571 lstrcpyW(ptr, usage_fmt);
5572 ptr += lstrlenW(ptr) + 1;
5573 *ptr = '\0';
5575 driver_path = strdupW(driver_file->TargetPath);
5576 ptr = strrchrW(driver_path, '\\');
5577 if (ptr) *ptr = '\0';
5579 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5580 NULL, ODBC_INSTALL_COMPLETE, &usage))
5582 ERR("Failed to install SQL driver!\n");
5583 r = ERROR_FUNCTION_FAILED;
5586 uirow = MSI_CreateRecord( 5 );
5587 MSI_RecordSetStringW( uirow, 1, desc );
5588 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5589 MSI_RecordSetStringW( uirow, 3, driver_path );
5590 ui_actiondata( package, szInstallODBC, uirow );
5591 msiobj_release( &uirow->hdr );
5593 msi_free(driver);
5594 msi_free(driver_path);
5596 return r;
5599 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5601 MSIPACKAGE *package = param;
5602 LPWSTR translator, translator_path, ptr;
5603 WCHAR outpath[MAX_PATH];
5604 MSIFILE *translator_file, *setup_file;
5605 MSIRECORD *uirow;
5606 LPCWSTR desc;
5607 DWORD len, usage;
5608 UINT r = ERROR_SUCCESS;
5610 static const WCHAR translator_fmt[] = {
5611 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5612 static const WCHAR setup_fmt[] = {
5613 'S','e','t','u','p','=','%','s',0};
5615 desc = MSI_RecordGetString(rec, 3);
5617 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5618 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5620 if (!translator_file)
5622 ERR("ODBC Translator entry not found!\n");
5623 return ERROR_FUNCTION_FAILED;
5626 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5627 if (setup_file)
5628 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5630 translator = msi_alloc(len * sizeof(WCHAR));
5631 if (!translator)
5632 return ERROR_OUTOFMEMORY;
5634 ptr = translator;
5635 lstrcpyW(ptr, desc);
5636 ptr += lstrlenW(ptr) + 1;
5638 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5639 ptr += len + 1;
5641 if (setup_file)
5643 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5644 ptr += len + 1;
5646 *ptr = '\0';
5648 translator_path = strdupW(translator_file->TargetPath);
5649 ptr = strrchrW(translator_path, '\\');
5650 if (ptr) *ptr = '\0';
5652 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5653 NULL, ODBC_INSTALL_COMPLETE, &usage))
5655 ERR("Failed to install SQL translator!\n");
5656 r = ERROR_FUNCTION_FAILED;
5659 uirow = MSI_CreateRecord( 5 );
5660 MSI_RecordSetStringW( uirow, 1, desc );
5661 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5662 MSI_RecordSetStringW( uirow, 3, translator_path );
5663 ui_actiondata( package, szInstallODBC, uirow );
5664 msiobj_release( &uirow->hdr );
5666 msi_free(translator);
5667 msi_free(translator_path);
5669 return r;
5672 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5674 MSIPACKAGE *package = param;
5675 LPWSTR attrs;
5676 LPCWSTR desc, driver;
5677 WORD request = ODBC_ADD_SYS_DSN;
5678 INT registration;
5679 DWORD len;
5680 UINT r = ERROR_SUCCESS;
5681 MSIRECORD *uirow;
5683 static const WCHAR attrs_fmt[] = {
5684 'D','S','N','=','%','s',0 };
5686 desc = MSI_RecordGetString(rec, 3);
5687 driver = MSI_RecordGetString(rec, 4);
5688 registration = MSI_RecordGetInteger(rec, 5);
5690 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5691 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5693 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5694 attrs = msi_alloc(len * sizeof(WCHAR));
5695 if (!attrs)
5696 return ERROR_OUTOFMEMORY;
5698 len = sprintfW(attrs, attrs_fmt, desc);
5699 attrs[len + 1] = 0;
5701 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5703 ERR("Failed to install SQL data source!\n");
5704 r = ERROR_FUNCTION_FAILED;
5707 uirow = MSI_CreateRecord( 5 );
5708 MSI_RecordSetStringW( uirow, 1, desc );
5709 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5710 MSI_RecordSetInteger( uirow, 3, request );
5711 ui_actiondata( package, szInstallODBC, uirow );
5712 msiobj_release( &uirow->hdr );
5714 msi_free(attrs);
5716 return r;
5719 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5721 UINT rc;
5722 MSIQUERY *view;
5724 static const WCHAR driver_query[] = {
5725 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5726 'O','D','B','C','D','r','i','v','e','r',0 };
5728 static const WCHAR translator_query[] = {
5729 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5730 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5732 static const WCHAR source_query[] = {
5733 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5734 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5736 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5737 if (rc != ERROR_SUCCESS)
5738 return ERROR_SUCCESS;
5740 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5741 msiobj_release(&view->hdr);
5743 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5744 if (rc != ERROR_SUCCESS)
5745 return ERROR_SUCCESS;
5747 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5748 msiobj_release(&view->hdr);
5750 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5751 if (rc != ERROR_SUCCESS)
5752 return ERROR_SUCCESS;
5754 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5755 msiobj_release(&view->hdr);
5757 return rc;
5760 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5762 MSIPACKAGE *package = param;
5763 MSIRECORD *uirow;
5764 DWORD usage;
5765 LPCWSTR desc;
5767 desc = MSI_RecordGetString( rec, 3 );
5768 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5770 WARN("Failed to remove ODBC driver\n");
5772 else if (!usage)
5774 FIXME("Usage count reached 0\n");
5777 uirow = MSI_CreateRecord( 2 );
5778 MSI_RecordSetStringW( uirow, 1, desc );
5779 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5780 ui_actiondata( package, szRemoveODBC, uirow );
5781 msiobj_release( &uirow->hdr );
5783 return ERROR_SUCCESS;
5786 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5788 MSIPACKAGE *package = param;
5789 MSIRECORD *uirow;
5790 DWORD usage;
5791 LPCWSTR desc;
5793 desc = MSI_RecordGetString( rec, 3 );
5794 if (!SQLRemoveTranslatorW( desc, &usage ))
5796 WARN("Failed to remove ODBC translator\n");
5798 else if (!usage)
5800 FIXME("Usage count reached 0\n");
5803 uirow = MSI_CreateRecord( 2 );
5804 MSI_RecordSetStringW( uirow, 1, desc );
5805 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5806 ui_actiondata( package, szRemoveODBC, uirow );
5807 msiobj_release( &uirow->hdr );
5809 return ERROR_SUCCESS;
5812 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5814 MSIPACKAGE *package = param;
5815 MSIRECORD *uirow;
5816 LPWSTR attrs;
5817 LPCWSTR desc, driver;
5818 WORD request = ODBC_REMOVE_SYS_DSN;
5819 INT registration;
5820 DWORD len;
5822 static const WCHAR attrs_fmt[] = {
5823 'D','S','N','=','%','s',0 };
5825 desc = MSI_RecordGetString( rec, 3 );
5826 driver = MSI_RecordGetString( rec, 4 );
5827 registration = MSI_RecordGetInteger( rec, 5 );
5829 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5830 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5832 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
5833 attrs = msi_alloc( len * sizeof(WCHAR) );
5834 if (!attrs)
5835 return ERROR_OUTOFMEMORY;
5837 FIXME("Use ODBCSourceAttribute table\n");
5839 len = sprintfW( attrs, attrs_fmt, desc );
5840 attrs[len + 1] = 0;
5842 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5844 WARN("Failed to remove ODBC data source\n");
5846 msi_free( attrs );
5848 uirow = MSI_CreateRecord( 3 );
5849 MSI_RecordSetStringW( uirow, 1, desc );
5850 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5851 MSI_RecordSetInteger( uirow, 3, request );
5852 ui_actiondata( package, szRemoveODBC, uirow );
5853 msiobj_release( &uirow->hdr );
5855 return ERROR_SUCCESS;
5858 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5860 UINT rc;
5861 MSIQUERY *view;
5863 static const WCHAR driver_query[] = {
5864 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5865 'O','D','B','C','D','r','i','v','e','r',0 };
5867 static const WCHAR translator_query[] = {
5868 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5869 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5871 static const WCHAR source_query[] = {
5872 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5873 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5875 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5876 if (rc != ERROR_SUCCESS)
5877 return ERROR_SUCCESS;
5879 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5880 msiobj_release( &view->hdr );
5882 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5883 if (rc != ERROR_SUCCESS)
5884 return ERROR_SUCCESS;
5886 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5887 msiobj_release( &view->hdr );
5889 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5890 if (rc != ERROR_SUCCESS)
5891 return ERROR_SUCCESS;
5893 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5894 msiobj_release( &view->hdr );
5896 return rc;
5899 #define ENV_ACT_SETALWAYS 0x1
5900 #define ENV_ACT_SETABSENT 0x2
5901 #define ENV_ACT_REMOVE 0x4
5902 #define ENV_ACT_REMOVEMATCH 0x8
5904 #define ENV_MOD_MACHINE 0x20000000
5905 #define ENV_MOD_APPEND 0x40000000
5906 #define ENV_MOD_PREFIX 0x80000000
5907 #define ENV_MOD_MASK 0xC0000000
5909 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5911 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5913 LPCWSTR cptr = *name;
5915 static const WCHAR prefix[] = {'[','~',']',0};
5916 static const int prefix_len = 3;
5918 *flags = 0;
5919 while (*cptr)
5921 if (*cptr == '=')
5922 *flags |= ENV_ACT_SETALWAYS;
5923 else if (*cptr == '+')
5924 *flags |= ENV_ACT_SETABSENT;
5925 else if (*cptr == '-')
5926 *flags |= ENV_ACT_REMOVE;
5927 else if (*cptr == '!')
5928 *flags |= ENV_ACT_REMOVEMATCH;
5929 else if (*cptr == '*')
5930 *flags |= ENV_MOD_MACHINE;
5931 else
5932 break;
5934 cptr++;
5935 (*name)++;
5938 if (!*cptr)
5940 ERR("Missing environment variable\n");
5941 return ERROR_FUNCTION_FAILED;
5944 if (*value)
5946 LPCWSTR ptr = *value;
5947 if (!strncmpW(ptr, prefix, prefix_len))
5949 if (ptr[prefix_len] == szSemiColon[0])
5951 *flags |= ENV_MOD_APPEND;
5952 *value += lstrlenW(prefix);
5954 else
5956 *value = NULL;
5959 else if (lstrlenW(*value) >= prefix_len)
5961 ptr += lstrlenW(ptr) - prefix_len;
5962 if (!lstrcmpW(ptr, prefix))
5964 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5966 *flags |= ENV_MOD_PREFIX;
5967 /* the "[~]" will be removed by deformat_string */;
5969 else
5971 *value = NULL;
5977 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5978 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5979 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5980 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5982 ERR("Invalid flags: %08x\n", *flags);
5983 return ERROR_FUNCTION_FAILED;
5986 if (!*flags)
5987 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5989 return ERROR_SUCCESS;
5992 static UINT open_env_key( DWORD flags, HKEY *key )
5994 static const WCHAR user_env[] =
5995 {'E','n','v','i','r','o','n','m','e','n','t',0};
5996 static const WCHAR machine_env[] =
5997 {'S','y','s','t','e','m','\\',
5998 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5999 'C','o','n','t','r','o','l','\\',
6000 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6001 'E','n','v','i','r','o','n','m','e','n','t',0};
6002 const WCHAR *env;
6003 HKEY root;
6004 LONG res;
6006 if (flags & ENV_MOD_MACHINE)
6008 env = machine_env;
6009 root = HKEY_LOCAL_MACHINE;
6011 else
6013 env = user_env;
6014 root = HKEY_CURRENT_USER;
6017 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6018 if (res != ERROR_SUCCESS)
6020 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6021 return ERROR_FUNCTION_FAILED;
6024 return ERROR_SUCCESS;
6027 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6029 MSIPACKAGE *package = param;
6030 LPCWSTR name, value, component;
6031 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6032 DWORD flags, type, size;
6033 UINT res;
6034 HKEY env = NULL;
6035 MSICOMPONENT *comp;
6036 MSIRECORD *uirow;
6037 int action = 0;
6039 component = MSI_RecordGetString(rec, 4);
6040 comp = get_loaded_component(package, component);
6041 if (!comp)
6042 return ERROR_SUCCESS;
6044 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6046 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6047 comp->Action = comp->Installed;
6048 return ERROR_SUCCESS;
6050 comp->Action = INSTALLSTATE_LOCAL;
6052 name = MSI_RecordGetString(rec, 2);
6053 value = MSI_RecordGetString(rec, 3);
6055 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6057 res = env_parse_flags(&name, &value, &flags);
6058 if (res != ERROR_SUCCESS || !value)
6059 goto done;
6061 if (value && !deformat_string(package, value, &deformatted))
6063 res = ERROR_OUTOFMEMORY;
6064 goto done;
6067 value = deformatted;
6069 res = open_env_key( flags, &env );
6070 if (res != ERROR_SUCCESS)
6071 goto done;
6073 if (flags & ENV_MOD_MACHINE)
6074 action |= 0x20000000;
6076 size = 0;
6077 type = REG_SZ;
6078 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6079 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6080 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6081 goto done;
6083 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6085 action = 0x2;
6087 /* Nothing to do. */
6088 if (!value)
6090 res = ERROR_SUCCESS;
6091 goto done;
6094 /* If we are appending but the string was empty, strip ; */
6095 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6097 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6098 newval = strdupW(value);
6099 if (!newval)
6101 res = ERROR_OUTOFMEMORY;
6102 goto done;
6105 else
6107 action = 0x1;
6109 /* Contrary to MSDN, +-variable to [~];path works */
6110 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6112 res = ERROR_SUCCESS;
6113 goto done;
6116 data = msi_alloc(size);
6117 if (!data)
6119 RegCloseKey(env);
6120 return ERROR_OUTOFMEMORY;
6123 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6124 if (res != ERROR_SUCCESS)
6125 goto done;
6127 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6129 action = 0x4;
6130 res = RegDeleteValueW(env, name);
6131 if (res != ERROR_SUCCESS)
6132 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6133 goto done;
6136 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6137 if (flags & ENV_MOD_MASK)
6139 DWORD mod_size;
6140 int multiplier = 0;
6141 if (flags & ENV_MOD_APPEND) multiplier++;
6142 if (flags & ENV_MOD_PREFIX) multiplier++;
6143 mod_size = lstrlenW(value) * multiplier;
6144 size += mod_size * sizeof(WCHAR);
6147 newval = msi_alloc(size);
6148 ptr = newval;
6149 if (!newval)
6151 res = ERROR_OUTOFMEMORY;
6152 goto done;
6155 if (flags & ENV_MOD_PREFIX)
6157 lstrcpyW(newval, value);
6158 ptr = newval + lstrlenW(value);
6159 action |= 0x80000000;
6162 lstrcpyW(ptr, data);
6164 if (flags & ENV_MOD_APPEND)
6166 lstrcatW(newval, value);
6167 action |= 0x40000000;
6170 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6171 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6172 if (res)
6174 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6177 done:
6178 uirow = MSI_CreateRecord( 3 );
6179 MSI_RecordSetStringW( uirow, 1, name );
6180 MSI_RecordSetStringW( uirow, 2, newval );
6181 MSI_RecordSetInteger( uirow, 3, action );
6182 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6183 msiobj_release( &uirow->hdr );
6185 if (env) RegCloseKey(env);
6186 msi_free(deformatted);
6187 msi_free(data);
6188 msi_free(newval);
6189 return res;
6192 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6194 UINT rc;
6195 MSIQUERY * view;
6196 static const WCHAR ExecSeqQuery[] =
6197 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6198 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6199 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6200 if (rc != ERROR_SUCCESS)
6201 return ERROR_SUCCESS;
6203 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6204 msiobj_release(&view->hdr);
6206 return rc;
6209 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6211 MSIPACKAGE *package = param;
6212 LPCWSTR name, value, component;
6213 LPWSTR deformatted = NULL;
6214 DWORD flags;
6215 HKEY env;
6216 MSICOMPONENT *comp;
6217 MSIRECORD *uirow;
6218 int action = 0;
6219 LONG res;
6220 UINT r;
6222 component = MSI_RecordGetString( rec, 4 );
6223 comp = get_loaded_component( package, component );
6224 if (!comp)
6225 return ERROR_SUCCESS;
6227 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6229 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6230 comp->Action = comp->Installed;
6231 return ERROR_SUCCESS;
6233 comp->Action = INSTALLSTATE_ABSENT;
6235 name = MSI_RecordGetString( rec, 2 );
6236 value = MSI_RecordGetString( rec, 3 );
6238 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6240 r = env_parse_flags( &name, &value, &flags );
6241 if (r != ERROR_SUCCESS)
6242 return r;
6244 if (!(flags & ENV_ACT_REMOVE))
6246 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6247 return ERROR_SUCCESS;
6250 if (value && !deformat_string( package, value, &deformatted ))
6251 return ERROR_OUTOFMEMORY;
6253 value = deformatted;
6255 r = open_env_key( flags, &env );
6256 if (r != ERROR_SUCCESS)
6258 r = ERROR_SUCCESS;
6259 goto done;
6262 if (flags & ENV_MOD_MACHINE)
6263 action |= 0x20000000;
6265 TRACE("Removing %s\n", debugstr_w(name));
6267 res = RegDeleteValueW( env, name );
6268 if (res != ERROR_SUCCESS)
6270 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6271 r = ERROR_SUCCESS;
6274 done:
6275 uirow = MSI_CreateRecord( 3 );
6276 MSI_RecordSetStringW( uirow, 1, name );
6277 MSI_RecordSetStringW( uirow, 2, value );
6278 MSI_RecordSetInteger( uirow, 3, action );
6279 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6280 msiobj_release( &uirow->hdr );
6282 if (env) RegCloseKey( env );
6283 msi_free( deformatted );
6284 return r;
6287 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6289 UINT rc;
6290 MSIQUERY *view;
6291 static const WCHAR query[] =
6292 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6293 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6295 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6296 if (rc != ERROR_SUCCESS)
6297 return ERROR_SUCCESS;
6299 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6300 msiobj_release( &view->hdr );
6302 return rc;
6305 typedef struct tagMSIASSEMBLY
6307 struct list entry;
6308 MSICOMPONENT *component;
6309 MSIFEATURE *feature;
6310 MSIFILE *file;
6311 LPWSTR manifest;
6312 LPWSTR application;
6313 LPWSTR display_name;
6314 DWORD attributes;
6315 BOOL installed;
6316 } MSIASSEMBLY;
6318 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6319 DWORD dwReserved);
6320 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6321 LPVOID pvReserved, HMODULE *phModDll);
6323 static BOOL init_functionpointers(void)
6325 HRESULT hr;
6326 HMODULE hfusion;
6327 HMODULE hmscoree;
6329 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6331 hmscoree = LoadLibraryA("mscoree.dll");
6332 if (!hmscoree)
6334 WARN("mscoree.dll not available\n");
6335 return FALSE;
6338 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6339 if (!pLoadLibraryShim)
6341 WARN("LoadLibraryShim not available\n");
6342 FreeLibrary(hmscoree);
6343 return FALSE;
6346 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6347 if (FAILED(hr))
6349 WARN("fusion.dll not available\n");
6350 FreeLibrary(hmscoree);
6351 return FALSE;
6354 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6356 FreeLibrary(hmscoree);
6357 return TRUE;
6360 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6361 LPWSTR path)
6363 IAssemblyCache *cache;
6364 MSIRECORD *uirow;
6365 HRESULT hr;
6366 UINT r = ERROR_FUNCTION_FAILED;
6368 TRACE("installing assembly: %s\n", debugstr_w(path));
6370 uirow = MSI_CreateRecord( 2 );
6371 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6372 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6373 msiobj_release( &uirow->hdr );
6375 if (assembly->feature)
6376 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6378 if (assembly->manifest)
6379 FIXME("Manifest unhandled\n");
6381 if (assembly->application)
6383 FIXME("Assembly should be privately installed\n");
6384 return ERROR_SUCCESS;
6387 if (assembly->attributes == msidbAssemblyAttributesWin32)
6389 FIXME("Win32 assemblies not handled\n");
6390 return ERROR_SUCCESS;
6393 hr = pCreateAssemblyCache(&cache, 0);
6394 if (FAILED(hr))
6395 goto done;
6397 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6398 if (FAILED(hr))
6399 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6401 r = ERROR_SUCCESS;
6403 done:
6404 IAssemblyCache_Release(cache);
6405 return r;
6408 typedef struct tagASSEMBLY_LIST
6410 MSIPACKAGE *package;
6411 IAssemblyCache *cache;
6412 struct list *assemblies;
6413 } ASSEMBLY_LIST;
6415 typedef struct tagASSEMBLY_NAME
6417 LPWSTR name;
6418 LPWSTR version;
6419 LPWSTR culture;
6420 LPWSTR pubkeytoken;
6421 } ASSEMBLY_NAME;
6423 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6425 ASSEMBLY_NAME *asmname = param;
6426 LPCWSTR name = MSI_RecordGetString(rec, 2);
6427 LPWSTR val = msi_dup_record_field(rec, 3);
6429 static const WCHAR Name[] = {'N','a','m','e',0};
6430 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6431 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6432 static const WCHAR PublicKeyToken[] = {
6433 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6435 if (!strcmpiW(name, Name))
6436 asmname->name = val;
6437 else if (!strcmpiW(name, Version))
6438 asmname->version = val;
6439 else if (!strcmpiW(name, Culture))
6440 asmname->culture = val;
6441 else if (!strcmpiW(name, PublicKeyToken))
6442 asmname->pubkeytoken = val;
6443 else
6444 msi_free(val);
6446 return ERROR_SUCCESS;
6449 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6451 if (!*str)
6453 *size = lstrlenW(append) + 1;
6454 *str = msi_alloc((*size) * sizeof(WCHAR));
6455 lstrcpyW(*str, append);
6456 return;
6459 (*size) += lstrlenW(append);
6460 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6461 lstrcatW(*str, append);
6464 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6466 static const WCHAR separator[] = {',',' ',0};
6467 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6468 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6469 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6470 static const WCHAR query[] = {
6471 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6472 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6473 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6474 '=','\'','%','s','\'',0};
6475 ASSEMBLY_NAME name;
6476 MSIQUERY *view;
6477 LPWSTR display_name;
6478 DWORD size;
6479 UINT r;
6481 display_name = NULL;
6482 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6484 r = MSI_OpenQuery( db, &view, query, comp->Component );
6485 if (r != ERROR_SUCCESS)
6486 return NULL;
6488 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6489 msiobj_release( &view->hdr );
6491 if (!name.name)
6493 ERR("No assembly name specified!\n");
6494 return NULL;
6497 append_str( &display_name, &size, name.name );
6499 if (name.version)
6501 append_str( &display_name, &size, separator );
6502 append_str( &display_name, &size, Version );
6503 append_str( &display_name, &size, name.version );
6505 if (name.culture)
6507 append_str( &display_name, &size, separator );
6508 append_str( &display_name, &size, Culture );
6509 append_str( &display_name, &size, name.culture );
6511 if (name.pubkeytoken)
6513 append_str( &display_name, &size, separator );
6514 append_str( &display_name, &size, PublicKeyToken );
6515 append_str( &display_name, &size, name.pubkeytoken );
6518 msi_free( name.name );
6519 msi_free( name.version );
6520 msi_free( name.culture );
6521 msi_free( name.pubkeytoken );
6523 return display_name;
6526 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6528 ASSEMBLY_INFO asminfo;
6529 LPWSTR disp;
6530 BOOL found = FALSE;
6531 HRESULT hr;
6533 disp = get_assembly_display_name( db, comp );
6534 if (!disp)
6535 return FALSE;
6537 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6538 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6540 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6541 if (SUCCEEDED(hr))
6542 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6544 msi_free( disp );
6545 return found;
6548 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6550 ASSEMBLY_LIST *list = param;
6551 MSIASSEMBLY *assembly;
6552 LPCWSTR component;
6554 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6555 if (!assembly)
6556 return ERROR_OUTOFMEMORY;
6558 component = MSI_RecordGetString(rec, 1);
6559 assembly->component = get_loaded_component(list->package, component);
6560 if (!assembly->component)
6561 return ERROR_SUCCESS;
6563 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6564 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6566 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6567 assembly->component->Action = assembly->component->Installed;
6568 return ERROR_SUCCESS;
6570 assembly->component->Action = assembly->component->ActionRequest;
6572 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6573 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6575 if (!assembly->file)
6577 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6578 return ERROR_FUNCTION_FAILED;
6581 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6582 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6583 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6585 if (assembly->application)
6587 WCHAR version[24];
6588 DWORD size = sizeof(version)/sizeof(WCHAR);
6590 /* FIXME: we should probably check the manifest file here */
6592 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6593 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6595 assembly->installed = TRUE;
6598 else
6599 assembly->installed = check_assembly_installed(list->package->db,
6600 list->cache,
6601 assembly->component);
6603 list_add_head(list->assemblies, &assembly->entry);
6604 return ERROR_SUCCESS;
6607 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6609 IAssemblyCache *cache = NULL;
6610 ASSEMBLY_LIST list;
6611 MSIQUERY *view;
6612 HRESULT hr;
6613 UINT r;
6615 static const WCHAR query[] =
6616 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6617 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6619 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6620 if (r != ERROR_SUCCESS)
6621 return ERROR_SUCCESS;
6623 hr = pCreateAssemblyCache(&cache, 0);
6624 if (FAILED(hr))
6625 return ERROR_FUNCTION_FAILED;
6627 list.package = package;
6628 list.cache = cache;
6629 list.assemblies = assemblies;
6631 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6632 msiobj_release(&view->hdr);
6634 IAssemblyCache_Release(cache);
6636 return r;
6639 static void free_assemblies(struct list *assemblies)
6641 struct list *item, *cursor;
6643 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6645 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6647 list_remove(&assembly->entry);
6648 msi_free(assembly->application);
6649 msi_free(assembly->manifest);
6650 msi_free(assembly->display_name);
6651 msi_free(assembly);
6655 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6657 MSIASSEMBLY *assembly;
6659 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6661 if (!lstrcmpW(assembly->file->File, file))
6663 *out = assembly;
6664 return TRUE;
6668 return FALSE;
6671 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6672 LPWSTR *path, DWORD *attrs, PVOID user)
6674 MSIASSEMBLY *assembly;
6675 WCHAR temppath[MAX_PATH];
6676 struct list *assemblies = user;
6677 UINT r;
6679 if (!find_assembly(assemblies, file, &assembly))
6680 return FALSE;
6682 GetTempPathW(MAX_PATH, temppath);
6683 PathAddBackslashW(temppath);
6684 lstrcatW(temppath, assembly->file->FileName);
6686 if (action == MSICABEXTRACT_BEGINEXTRACT)
6688 if (assembly->installed)
6689 return FALSE;
6691 *path = strdupW(temppath);
6692 *attrs = assembly->file->Attributes;
6694 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6696 assembly->installed = TRUE;
6698 r = install_assembly(package, assembly, temppath);
6699 if (r != ERROR_SUCCESS)
6700 ERR("Failed to install assembly\n");
6703 return TRUE;
6706 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6708 UINT r;
6709 struct list assemblies = LIST_INIT(assemblies);
6710 MSIASSEMBLY *assembly;
6711 MSIMEDIAINFO *mi;
6713 if (!init_functionpointers() || !pCreateAssemblyCache)
6714 return ERROR_FUNCTION_FAILED;
6716 r = load_assemblies(package, &assemblies);
6717 if (r != ERROR_SUCCESS)
6718 goto done;
6720 if (list_empty(&assemblies))
6721 goto done;
6723 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6724 if (!mi)
6726 r = ERROR_OUTOFMEMORY;
6727 goto done;
6730 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6732 if (assembly->installed && !mi->is_continuous)
6733 continue;
6735 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6736 (assembly->file->IsCompressed && !mi->is_extracted))
6738 MSICABDATA data;
6740 r = ready_media(package, assembly->file, mi);
6741 if (r != ERROR_SUCCESS)
6743 ERR("Failed to ready media\n");
6744 break;
6747 data.mi = mi;
6748 data.package = package;
6749 data.cb = installassembly_cb;
6750 data.user = &assemblies;
6752 if (assembly->file->IsCompressed &&
6753 !msi_cabextract(package, mi, &data))
6755 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6756 r = ERROR_FUNCTION_FAILED;
6757 break;
6761 if (!assembly->file->IsCompressed)
6763 LPWSTR source = resolve_file_source(package, assembly->file);
6765 r = install_assembly(package, assembly, source);
6766 if (r != ERROR_SUCCESS)
6767 ERR("Failed to install assembly\n");
6769 msi_free(source);
6772 /* FIXME: write Installer assembly reg values */
6775 done:
6776 free_assemblies(&assemblies);
6777 return r;
6780 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6782 LPWSTR key, template, id;
6783 UINT r = ERROR_SUCCESS;
6785 id = msi_dup_property( package, szProductID );
6786 if (id)
6788 msi_free( id );
6789 return ERROR_SUCCESS;
6791 template = msi_dup_property( package, szPIDTemplate );
6792 key = msi_dup_property( package, szPIDKEY );
6794 if (key && template)
6796 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6797 r = MSI_SetPropertyW( package, szProductID, key );
6799 msi_free( template );
6800 msi_free( key );
6801 return r;
6804 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6806 TRACE("\n");
6807 package->need_reboot = 1;
6808 return ERROR_SUCCESS;
6811 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6813 static const WCHAR szAvailableFreeReg[] =
6814 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6815 MSIRECORD *uirow;
6816 int space = msi_get_property_int( package, szAvailableFreeReg, 0 );
6818 TRACE("%p %d kilobytes\n", package, space);
6820 uirow = MSI_CreateRecord( 1 );
6821 MSI_RecordSetInteger( uirow, 1, space );
6822 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6823 msiobj_release( &uirow->hdr );
6825 return ERROR_SUCCESS;
6828 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6830 FIXME("%p\n", package);
6831 return ERROR_SUCCESS;
6834 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6836 FIXME("%p\n", package);
6837 return ERROR_SUCCESS;
6840 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6841 LPCSTR action, LPCWSTR table )
6843 static const WCHAR query[] = {
6844 'S','E','L','E','C','T',' ','*',' ',
6845 'F','R','O','M',' ','`','%','s','`',0 };
6846 MSIQUERY *view = NULL;
6847 DWORD count = 0;
6848 UINT r;
6850 r = MSI_OpenQuery( package->db, &view, query, table );
6851 if (r == ERROR_SUCCESS)
6853 r = MSI_IterateRecords(view, &count, NULL, package);
6854 msiobj_release(&view->hdr);
6857 if (count)
6858 FIXME("%s -> %u ignored %s table values\n",
6859 action, count, debugstr_w(table));
6861 return ERROR_SUCCESS;
6864 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6866 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6867 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6870 static UINT ACTION_BindImage( MSIPACKAGE *package )
6872 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6873 return msi_unimplemented_action_stub( package, "BindImage", table );
6876 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6878 static const WCHAR table[] = {
6879 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6880 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6883 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6885 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6886 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6889 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6891 static const WCHAR table[] = {
6892 'M','s','i','A','s','s','e','m','b','l','y',0 };
6893 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6896 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6898 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6899 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6902 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6904 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6905 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6908 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6910 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6911 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6914 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6916 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6917 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6920 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6922 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6923 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6926 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6928 static const WCHAR table[] = { 'D','i','r','e','c','t','o','r','y',0 };
6929 return msi_unimplemented_action_stub( package, "SetODBCFolders", table );
6932 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6934 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6935 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6938 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6940 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6941 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6944 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6946 static const WCHAR table[] = { 'M','I','M','E',0 };
6947 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6950 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6952 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6953 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6956 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6958 static const struct
6960 const WCHAR *action;
6961 UINT (*handler)(MSIPACKAGE *);
6963 StandardActions[] =
6965 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6966 { szAppSearch, ACTION_AppSearch },
6967 { szBindImage, ACTION_BindImage },
6968 { szCCPSearch, ACTION_CCPSearch },
6969 { szCostFinalize, ACTION_CostFinalize },
6970 { szCostInitialize, ACTION_CostInitialize },
6971 { szCreateFolders, ACTION_CreateFolders },
6972 { szCreateShortcuts, ACTION_CreateShortcuts },
6973 { szDeleteServices, ACTION_DeleteServices },
6974 { szDisableRollback, ACTION_DisableRollback },
6975 { szDuplicateFiles, ACTION_DuplicateFiles },
6976 { szExecuteAction, ACTION_ExecuteAction },
6977 { szFileCost, ACTION_FileCost },
6978 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6979 { szForceReboot, ACTION_ForceReboot },
6980 { szInstallAdminPackage, ACTION_InstallAdminPackage },
6981 { szInstallExecute, ACTION_InstallExecute },
6982 { szInstallExecuteAgain, ACTION_InstallExecute },
6983 { szInstallFiles, ACTION_InstallFiles},
6984 { szInstallFinalize, ACTION_InstallFinalize },
6985 { szInstallInitialize, ACTION_InstallInitialize },
6986 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6987 { szInstallValidate, ACTION_InstallValidate },
6988 { szIsolateComponents, ACTION_IsolateComponents },
6989 { szLaunchConditions, ACTION_LaunchConditions },
6990 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6991 { szMoveFiles, ACTION_MoveFiles },
6992 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6993 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6994 { szInstallODBC, ACTION_InstallODBC },
6995 { szInstallServices, ACTION_InstallServices },
6996 { szPatchFiles, ACTION_PatchFiles },
6997 { szProcessComponents, ACTION_ProcessComponents },
6998 { szPublishComponents, ACTION_PublishComponents },
6999 { szPublishFeatures, ACTION_PublishFeatures },
7000 { szPublishProduct, ACTION_PublishProduct },
7001 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7002 { szRegisterComPlus, ACTION_RegisterComPlus},
7003 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7004 { szRegisterFonts, ACTION_RegisterFonts },
7005 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7006 { szRegisterProduct, ACTION_RegisterProduct },
7007 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7008 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7009 { szRegisterUser, ACTION_RegisterUser },
7010 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7011 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7012 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7013 { szRemoveFiles, ACTION_RemoveFiles },
7014 { szRemoveFolders, ACTION_RemoveFolders },
7015 { szRemoveIniValues, ACTION_RemoveIniValues },
7016 { szRemoveODBC, ACTION_RemoveODBC },
7017 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7018 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7019 { szResolveSource, ACTION_ResolveSource },
7020 { szRMCCPSearch, ACTION_RMCCPSearch },
7021 { szScheduleReboot, ACTION_ScheduleReboot },
7022 { szSelfRegModules, ACTION_SelfRegModules },
7023 { szSelfUnregModules, ACTION_SelfUnregModules },
7024 { szSetODBCFolders, ACTION_SetODBCFolders },
7025 { szStartServices, ACTION_StartServices },
7026 { szStopServices, ACTION_StopServices },
7027 { szUnpublishComponents, ACTION_UnpublishComponents },
7028 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7029 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7030 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7031 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7032 { szUnregisterFonts, ACTION_UnregisterFonts },
7033 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7034 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7035 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7036 { szValidateProductID, ACTION_ValidateProductID },
7037 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7038 { szWriteIniValues, ACTION_WriteIniValues },
7039 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7040 { NULL, NULL },
7043 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7044 UINT* rc, BOOL force )
7046 BOOL ret = FALSE;
7047 BOOL run = force;
7048 int i;
7050 if (!run && !package->script->CurrentlyScripting)
7051 run = TRUE;
7053 if (!run)
7055 if (strcmpW(action,szInstallFinalize) == 0 ||
7056 strcmpW(action,szInstallExecute) == 0 ||
7057 strcmpW(action,szInstallExecuteAgain) == 0)
7058 run = TRUE;
7061 i = 0;
7062 while (StandardActions[i].action != NULL)
7064 if (strcmpW(StandardActions[i].action, action)==0)
7066 if (!run)
7068 ui_actioninfo(package, action, TRUE, 0);
7069 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7070 ui_actioninfo(package, action, FALSE, *rc);
7072 else
7074 ui_actionstart(package, action);
7075 if (StandardActions[i].handler)
7077 *rc = StandardActions[i].handler(package);
7079 else
7081 FIXME("unhandled standard action %s\n",debugstr_w(action));
7082 *rc = ERROR_SUCCESS;
7085 ret = TRUE;
7086 break;
7088 i++;
7090 return ret;
7093 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7095 UINT rc = ERROR_SUCCESS;
7096 BOOL handled;
7098 TRACE("Performing action (%s)\n", debugstr_w(action));
7100 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7102 if (!handled)
7103 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7105 if (!handled)
7107 WARN("unhandled msi action %s\n", debugstr_w(action));
7108 rc = ERROR_FUNCTION_NOT_CALLED;
7111 return rc;
7114 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7116 UINT rc = ERROR_SUCCESS;
7117 BOOL handled = FALSE;
7119 TRACE("Performing action (%s)\n", debugstr_w(action));
7121 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7123 if (!handled)
7124 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7126 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7127 handled = TRUE;
7129 if (!handled)
7131 WARN("unhandled msi action %s\n", debugstr_w(action));
7132 rc = ERROR_FUNCTION_NOT_CALLED;
7135 return rc;
7138 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7140 UINT rc = ERROR_SUCCESS;
7141 MSIRECORD *row;
7143 static const WCHAR ExecSeqQuery[] =
7144 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7145 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7146 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7147 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7148 static const WCHAR UISeqQuery[] =
7149 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7150 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7151 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7152 ' ', '=',' ','%','i',0};
7154 if (needs_ui_sequence(package))
7155 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7156 else
7157 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7159 if (row)
7161 LPCWSTR action, cond;
7163 TRACE("Running the actions\n");
7165 /* check conditions */
7166 cond = MSI_RecordGetString(row, 2);
7168 /* this is a hack to skip errors in the condition code */
7169 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7171 msiobj_release(&row->hdr);
7172 return ERROR_SUCCESS;
7175 action = MSI_RecordGetString(row, 1);
7176 if (!action)
7178 ERR("failed to fetch action\n");
7179 msiobj_release(&row->hdr);
7180 return ERROR_FUNCTION_FAILED;
7183 if (needs_ui_sequence(package))
7184 rc = ACTION_PerformUIAction(package, action, -1);
7185 else
7186 rc = ACTION_PerformAction(package, action, -1, FALSE);
7188 msiobj_release(&row->hdr);
7191 return rc;
7194 /****************************************************
7195 * TOP level entry points
7196 *****************************************************/
7198 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7199 LPCWSTR szCommandLine )
7201 UINT rc;
7202 BOOL ui_exists;
7204 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7205 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7207 MSI_SetPropertyW(package, szAction, szInstall);
7209 package->script->InWhatSequence = SEQUENCE_INSTALL;
7211 if (szPackagePath)
7213 LPWSTR p, dir;
7214 LPCWSTR file;
7216 dir = strdupW(szPackagePath);
7217 p = strrchrW(dir, '\\');
7218 if (p)
7220 *(++p) = 0;
7221 file = szPackagePath + (p - dir);
7223 else
7225 msi_free(dir);
7226 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7227 GetCurrentDirectoryW(MAX_PATH, dir);
7228 lstrcatW(dir, szBackSlash);
7229 file = szPackagePath;
7232 msi_free( package->PackagePath );
7233 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7234 if (!package->PackagePath)
7236 msi_free(dir);
7237 return ERROR_OUTOFMEMORY;
7240 lstrcpyW(package->PackagePath, dir);
7241 lstrcatW(package->PackagePath, file);
7242 msi_free(dir);
7244 msi_set_sourcedir_props(package, FALSE);
7247 msi_parse_command_line( package, szCommandLine, FALSE );
7249 msi_apply_transforms( package );
7250 msi_apply_patches( package );
7252 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
7254 TRACE("setting reinstall property\n");
7255 MSI_SetPropertyW( package, szReinstall, szAll );
7258 /* properties may have been added by a transform */
7259 msi_clone_properties( package );
7260 msi_set_context( package );
7262 if (needs_ui_sequence( package))
7264 package->script->InWhatSequence |= SEQUENCE_UI;
7265 rc = ACTION_ProcessUISequence(package);
7266 ui_exists = ui_sequence_exists(package);
7267 if (rc == ERROR_SUCCESS || !ui_exists)
7269 package->script->InWhatSequence |= SEQUENCE_EXEC;
7270 rc = ACTION_ProcessExecSequence(package, ui_exists);
7273 else
7274 rc = ACTION_ProcessExecSequence(package, FALSE);
7276 package->script->CurrentlyScripting = FALSE;
7278 /* process the ending type action */
7279 if (rc == ERROR_SUCCESS)
7280 ACTION_PerformActionSequence(package, -1);
7281 else if (rc == ERROR_INSTALL_USEREXIT)
7282 ACTION_PerformActionSequence(package, -2);
7283 else if (rc == ERROR_INSTALL_SUSPEND)
7284 ACTION_PerformActionSequence(package, -4);
7285 else /* failed */
7286 ACTION_PerformActionSequence(package, -3);
7288 /* finish up running custom actions */
7289 ACTION_FinishCustomActions(package);
7291 if (rc == ERROR_SUCCESS && package->need_reboot)
7292 return ERROR_SUCCESS_REBOOT_REQUIRED;
7294 return rc;