wininet: Support the Cache-Control max-age directive for setting url cache entry...
[wine/testsucceed.git] / dlls / msi / action.c
blob86aa33fc1c5df77c58253ce44de89a5be0b35c45
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 "shlwapi.h"
39 #include "wine/unicode.h"
40 #include "winver.h"
42 #define REG_PROGRESS_VALUE 13200
43 #define COMPONENT_PROGRESS_VALUE 24000
45 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48 * consts and values used
50 static const WCHAR c_colon[] = {'C',':','\\',0};
52 static const WCHAR szCreateFolders[] =
53 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
54 static const WCHAR szCostFinalize[] =
55 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
56 static const WCHAR szWriteRegistryValues[] =
57 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
58 static const WCHAR szCostInitialize[] =
59 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
60 static const WCHAR szFileCost[] =
61 {'F','i','l','e','C','o','s','t',0};
62 static const WCHAR szInstallInitialize[] =
63 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
64 static const WCHAR szInstallValidate[] =
65 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
66 static const WCHAR szLaunchConditions[] =
67 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
68 static const WCHAR szProcessComponents[] =
69 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
70 static const WCHAR szRegisterTypeLibraries[] =
71 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
72 static const WCHAR szCreateShortcuts[] =
73 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
74 static const WCHAR szPublishProduct[] =
75 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
76 static const WCHAR szWriteIniValues[] =
77 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
78 static const WCHAR szSelfRegModules[] =
79 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
80 static const WCHAR szPublishFeatures[] =
81 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
82 static const WCHAR szRegisterProduct[] =
83 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
84 static const WCHAR szInstallExecute[] =
85 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
86 static const WCHAR szInstallExecuteAgain[] =
87 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
88 static const WCHAR szInstallFinalize[] =
89 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
90 static const WCHAR szForceReboot[] =
91 {'F','o','r','c','e','R','e','b','o','o','t',0};
92 static const WCHAR szResolveSource[] =
93 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
94 static const WCHAR szAllocateRegistrySpace[] =
95 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
96 static const WCHAR szBindImage[] =
97 {'B','i','n','d','I','m','a','g','e',0};
98 static const WCHAR szDeleteServices[] =
99 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
100 static const WCHAR szDisableRollback[] =
101 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
102 static const WCHAR szExecuteAction[] =
103 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
104 static const WCHAR szInstallAdminPackage[] =
105 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
106 static const WCHAR szInstallSFPCatalogFile[] =
107 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
108 static const WCHAR szIsolateComponents[] =
109 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
110 static const WCHAR szMigrateFeatureStates[] =
111 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
112 static const WCHAR szMsiUnpublishAssemblies[] =
113 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
114 static const WCHAR szInstallODBC[] =
115 {'I','n','s','t','a','l','l','O','D','B','C',0};
116 static const WCHAR szInstallServices[] =
117 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
118 static const WCHAR szPatchFiles[] =
119 {'P','a','t','c','h','F','i','l','e','s',0};
120 static const WCHAR szPublishComponents[] =
121 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
122 static const WCHAR szRegisterComPlus[] =
123 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
124 static const WCHAR szRegisterUser[] =
125 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
126 static const WCHAR szRemoveEnvironmentStrings[] =
127 {'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};
128 static const WCHAR szRemoveExistingProducts[] =
129 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
130 static const WCHAR szRemoveFolders[] =
131 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
132 static const WCHAR szRemoveIniValues[] =
133 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
134 static const WCHAR szRemoveODBC[] =
135 {'R','e','m','o','v','e','O','D','B','C',0};
136 static const WCHAR szRemoveRegistryValues[] =
137 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
138 static const WCHAR szRemoveShortcuts[] =
139 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
140 static const WCHAR szRMCCPSearch[] =
141 {'R','M','C','C','P','S','e','a','r','c','h',0};
142 static const WCHAR szScheduleReboot[] =
143 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
144 static const WCHAR szSelfUnregModules[] =
145 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
146 static const WCHAR szSetODBCFolders[] =
147 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
148 static const WCHAR szStartServices[] =
149 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
150 static const WCHAR szStopServices[] =
151 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
152 static const WCHAR szUnpublishComponents[] =
153 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
154 static const WCHAR szUnpublishFeatures[] =
155 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
156 static const WCHAR szUnregisterComPlus[] =
157 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
158 static const WCHAR szUnregisterTypeLibraries[] =
159 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
160 static const WCHAR szValidateProductID[] =
161 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
162 static const WCHAR szWriteEnvironmentStrings[] =
163 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
165 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
167 static const WCHAR Query_t[] =
168 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
169 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
170 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
171 ' ','\'','%','s','\'',0};
172 MSIRECORD * row;
174 row = MSI_QueryGetRecord( package->db, Query_t, action );
175 if (!row)
176 return;
177 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
178 msiobj_release(&row->hdr);
181 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
182 UINT rc)
184 MSIRECORD * row;
185 static const WCHAR template_s[]=
186 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
187 '%','s', '.',0};
188 static const WCHAR template_e[]=
189 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
190 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
191 '%','i','.',0};
192 static const WCHAR format[] =
193 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
194 WCHAR message[1024];
195 WCHAR timet[0x100];
197 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
198 if (start)
199 sprintfW(message,template_s,timet,action);
200 else
201 sprintfW(message,template_e,timet,action,rc);
203 row = MSI_CreateRecord(1);
204 MSI_RecordSetStringW(row,1,message);
206 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
207 msiobj_release(&row->hdr);
210 enum parse_state
212 state_whitespace,
213 state_token,
214 state_quote
217 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
219 enum parse_state state = state_quote;
220 const WCHAR *p;
221 WCHAR *out = value;
222 int ignore, in_quotes = 0, count = 0, len = 0;
224 for (p = str; *p; p++)
226 ignore = 0;
227 switch (state)
229 case state_whitespace:
230 switch (*p)
232 case ' ':
233 if (!count) goto done;
234 in_quotes = 1;
235 ignore = 1;
236 break;
237 case '"':
238 state = state_quote;
239 if (in_quotes) count--;
240 else count++;
241 break;
242 default:
243 state = state_token;
244 if (!count) in_quotes = 0;
245 else in_quotes = 1;
246 len++;
247 break;
249 break;
251 case state_token:
252 switch (*p)
254 case '"':
255 state = state_quote;
256 if (in_quotes) count--;
257 else count++;
258 break;
259 case ' ':
260 state = state_whitespace;
261 if (!count) goto done;
262 in_quotes = 1;
263 break;
264 default:
265 if (!count) in_quotes = 0;
266 else in_quotes = 1;
267 len++;
268 break;
270 break;
272 case state_quote:
273 switch (*p)
275 case '"':
276 if (in_quotes) count--;
277 else count++;
278 break;
279 case ' ':
280 state = state_whitespace;
281 if (!count || !len) goto done;
282 in_quotes = 1;
283 break;
284 default:
285 state = state_token;
286 if (!count) in_quotes = 0;
287 else in_quotes = 1;
288 len++;
289 break;
291 break;
293 default: break;
295 if (!ignore) *out++ = *p;
298 done:
299 if (!len) *value = 0;
300 else *out = 0;
302 *quotes = count;
303 return p - str;
306 static void remove_quotes( WCHAR *str )
308 WCHAR *p = str;
309 int len = strlenW( str );
311 while ((p = strchrW( p, '"' )))
313 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
314 p++;
318 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
319 BOOL preserve_case )
321 LPCWSTR ptr, ptr2;
322 int quotes;
323 DWORD len;
324 WCHAR *prop, *val;
325 UINT r;
327 if (!szCommandLine)
328 return ERROR_SUCCESS;
330 ptr = szCommandLine;
331 while (*ptr)
333 while (*ptr == ' ') ptr++;
334 if (!*ptr) break;
336 ptr2 = strchrW( ptr, '=' );
337 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
339 len = ptr2 - ptr;
340 if (!len) return ERROR_INVALID_COMMAND_LINE;
342 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
343 memcpy( prop, ptr, len * sizeof(WCHAR) );
344 prop[len] = 0;
345 if (!preserve_case) struprW( prop );
347 ptr2++;
348 while (*ptr2 == ' ') ptr2++;
350 quotes = 0;
351 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
352 len = parse_prop( ptr2, val, &quotes );
353 if (quotes % 2)
355 WARN("unbalanced quotes\n");
356 msi_free( val );
357 msi_free( prop );
358 return ERROR_INVALID_COMMAND_LINE;
360 remove_quotes( val );
361 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
363 r = msi_set_property( package->db, prop, val );
364 if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
365 msi_reset_folders( package, TRUE );
367 msi_free( val );
368 msi_free( prop );
370 ptr = ptr2 + len;
373 return ERROR_SUCCESS;
376 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
378 LPCWSTR pc;
379 LPWSTR p, *ret = NULL;
380 UINT count = 0;
382 if (!str)
383 return ret;
385 /* count the number of substrings */
386 for ( pc = str, count = 0; pc; count++ )
388 pc = strchrW( pc, sep );
389 if (pc)
390 pc++;
393 /* allocate space for an array of substring pointers and the substrings */
394 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
395 (lstrlenW(str)+1) * sizeof(WCHAR) );
396 if (!ret)
397 return ret;
399 /* copy the string and set the pointers */
400 p = (LPWSTR) &ret[count+1];
401 lstrcpyW( p, str );
402 for( count = 0; (ret[count] = p); count++ )
404 p = strchrW( p, sep );
405 if (p)
406 *p++ = 0;
409 return ret;
412 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
414 static const WCHAR szSystemLanguageID[] =
415 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
417 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
418 UINT ret = ERROR_FUNCTION_FAILED;
420 prod_code = msi_dup_property( package->db, szProductCode );
421 patch_product = msi_get_suminfo_product( patch );
423 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
425 if ( strstrW( patch_product, prod_code ) )
427 MSISUMMARYINFO *si;
428 const WCHAR *p;
430 si = MSI_GetSummaryInformationW( patch, 0 );
431 if (!si)
433 ERR("no summary information!\n");
434 goto end;
437 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
438 if (!template)
440 ERR("no template property!\n");
441 msiobj_release( &si->hdr );
442 goto end;
445 if (!template[0])
447 ret = ERROR_SUCCESS;
448 msiobj_release( &si->hdr );
449 goto end;
452 langid = msi_dup_property( package->db, szSystemLanguageID );
453 if (!langid)
455 msiobj_release( &si->hdr );
456 goto end;
459 p = strchrW( template, ';' );
460 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
462 TRACE("applicable transform\n");
463 ret = ERROR_SUCCESS;
466 /* FIXME: check platform */
468 msiobj_release( &si->hdr );
471 end:
472 msi_free( patch_product );
473 msi_free( prod_code );
474 msi_free( template );
475 msi_free( langid );
477 return ret;
480 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
481 MSIDATABASE *patch_db, LPCWSTR name )
483 UINT ret = ERROR_FUNCTION_FAILED;
484 IStorage *stg = NULL;
485 HRESULT r;
487 TRACE("%p %s\n", package, debugstr_w(name) );
489 if (*name++ != ':')
491 ERR("expected a colon in %s\n", debugstr_w(name));
492 return ERROR_FUNCTION_FAILED;
495 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
496 if (SUCCEEDED(r))
498 ret = msi_check_transform_applicable( package, stg );
499 if (ret == ERROR_SUCCESS)
500 msi_table_apply_transform( package->db, stg );
501 else
502 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
503 IStorage_Release( stg );
505 else
506 ERR("failed to open substorage %s\n", debugstr_w(name));
508 return ERROR_SUCCESS;
511 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
513 LPWSTR guid_list, *guids, product_code;
514 UINT i, ret = ERROR_FUNCTION_FAILED;
516 product_code = msi_dup_property( package->db, szProductCode );
517 if (!product_code)
519 /* FIXME: the property ProductCode should be written into the DB somewhere */
520 ERR("no product code to check\n");
521 return ERROR_SUCCESS;
524 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
525 guids = msi_split_string( guid_list, ';' );
526 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
528 if (!strcmpW( guids[i], product_code ))
529 ret = ERROR_SUCCESS;
531 msi_free( guids );
532 msi_free( guid_list );
533 msi_free( product_code );
535 return ret;
538 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
540 MSIQUERY *view;
541 MSIRECORD *rec = NULL;
542 LPWSTR patch;
543 LPCWSTR prop;
544 UINT r;
546 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
547 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
548 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
549 '`','S','o','u','r','c','e','`',' ','I','S',' ',
550 'N','O','T',' ','N','U','L','L',0};
552 r = MSI_DatabaseOpenViewW(package->db, query, &view);
553 if (r != ERROR_SUCCESS)
554 return r;
556 r = MSI_ViewExecute(view, 0);
557 if (r != ERROR_SUCCESS)
558 goto done;
560 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
562 prop = MSI_RecordGetString(rec, 1);
563 patch = msi_dup_property(package->db, szPatch);
564 msi_set_property(package->db, prop, patch);
565 msi_free(patch);
568 done:
569 if (rec) msiobj_release(&rec->hdr);
570 msiobj_release(&view->hdr);
572 return r;
575 UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
577 MSIPATCHINFO *pi;
578 UINT r = ERROR_SUCCESS;
579 WCHAR *p;
581 pi = msi_alloc_zero( sizeof(MSIPATCHINFO) );
582 if (!pi)
583 return ERROR_OUTOFMEMORY;
585 pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER );
586 if (!pi->patchcode)
588 msi_free( pi );
589 return ERROR_OUTOFMEMORY;
592 p = pi->patchcode;
593 if (*p != '{')
595 msi_free( pi->patchcode );
596 msi_free( pi );
597 return ERROR_PATCH_PACKAGE_INVALID;
600 p = strchrW( p + 1, '}' );
601 if (!p)
603 msi_free( pi->patchcode );
604 msi_free( pi );
605 return ERROR_PATCH_PACKAGE_INVALID;
608 if (p[1])
610 FIXME("patch obsoletes %s\n", debugstr_w(p + 1));
611 p[1] = 0;
614 TRACE("patch code %s\n", debugstr_w(pi->patchcode));
616 pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
617 if (!pi->transforms)
619 msi_free( pi->patchcode );
620 msi_free( pi );
621 return ERROR_OUTOFMEMORY;
624 *patch = pi;
625 return r;
628 UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
630 UINT i, r = ERROR_SUCCESS;
631 WCHAR **substorage;
633 /* apply substorage transforms */
634 substorage = msi_split_string( patch->transforms, ';' );
635 for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
636 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
638 msi_free( substorage );
639 if (r != ERROR_SUCCESS)
640 return r;
642 msi_set_media_source_prop( package );
645 * There might be a CAB file in the patch package,
646 * so append it to the list of storages to search for streams.
648 append_storage_to_db( package->db, patch_db->storage );
650 patch->state = MSIPATCHSTATE_APPLIED;
651 list_add_tail( &package->patches, &patch->entry );
652 return ERROR_SUCCESS;
655 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
657 static const WCHAR dotmsp[] = {'.','m','s','p',0};
658 MSIDATABASE *patch_db = NULL;
659 WCHAR localfile[MAX_PATH];
660 MSISUMMARYINFO *si;
661 MSIPATCHINFO *patch = NULL;
662 UINT r = ERROR_SUCCESS;
664 TRACE("%p %s\n", package, debugstr_w( file ) );
666 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
667 if ( r != ERROR_SUCCESS )
669 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
670 return r;
673 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
674 if (!si)
676 msiobj_release( &patch_db->hdr );
677 return ERROR_FUNCTION_FAILED;
680 r = msi_check_patch_applicable( package, si );
681 if (r != ERROR_SUCCESS)
683 TRACE("patch not applicable\n");
684 r = ERROR_SUCCESS;
685 goto done;
688 r = msi_parse_patch_summary( si, &patch );
689 if ( r != ERROR_SUCCESS )
690 goto done;
692 r = msi_get_local_package_name( localfile, dotmsp );
693 if ( r != ERROR_SUCCESS )
694 goto done;
696 TRACE("copying to local package %s\n", debugstr_w(localfile));
698 if (!CopyFileW( file, localfile, FALSE ))
700 ERR("Unable to copy package (%s -> %s) (error %u)\n",
701 debugstr_w(file), debugstr_w(localfile), GetLastError());
702 r = GetLastError();
703 goto done;
705 patch->localfile = strdupW( localfile );
707 r = msi_apply_patch_db( package, patch_db, patch );
708 if ( r != ERROR_SUCCESS )
709 WARN("patch failed to apply %u\n", r);
711 done:
712 msiobj_release( &si->hdr );
713 msiobj_release( &patch_db->hdr );
714 if (patch && r != ERROR_SUCCESS)
716 if (patch->localfile)
717 DeleteFileW( patch->localfile );
719 msi_free( patch->patchcode );
720 msi_free( patch->transforms );
721 msi_free( patch->localfile );
722 msi_free( patch );
724 return r;
727 /* get the PATCH property, and apply all the patches it specifies */
728 static UINT msi_apply_patches( MSIPACKAGE *package )
730 LPWSTR patch_list, *patches;
731 UINT i, r = ERROR_SUCCESS;
733 patch_list = msi_dup_property( package->db, szPatch );
735 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
737 patches = msi_split_string( patch_list, ';' );
738 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
739 r = msi_apply_patch_package( package, patches[i] );
741 msi_free( patches );
742 msi_free( patch_list );
744 return r;
747 static UINT msi_apply_transforms( MSIPACKAGE *package )
749 static const WCHAR szTransforms[] = {
750 'T','R','A','N','S','F','O','R','M','S',0 };
751 LPWSTR xform_list, *xforms;
752 UINT i, r = ERROR_SUCCESS;
754 xform_list = msi_dup_property( package->db, szTransforms );
755 xforms = msi_split_string( xform_list, ';' );
757 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
759 if (xforms[i][0] == ':')
760 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
761 else
763 WCHAR *transform;
765 if (!PathIsRelativeW( xforms[i] )) transform = xforms[i];
766 else
768 WCHAR *p = strrchrW( package->PackagePath, '\\' );
769 DWORD len = p - package->PackagePath + 1;
771 if (!(transform = msi_alloc( (len + strlenW( xforms[i] ) + 1) * sizeof(WCHAR)) ))
773 msi_free( xforms );
774 msi_free( xform_list );
775 return ERROR_OUTOFMEMORY;
777 memcpy( transform, package->PackagePath, len * sizeof(WCHAR) );
778 memcpy( transform + len, xforms[i], (strlenW( xforms[i] ) + 1) * sizeof(WCHAR) );
780 r = MSI_DatabaseApplyTransformW( package->db, transform, 0 );
781 if (transform != xforms[i]) msi_free( transform );
785 msi_free( xforms );
786 msi_free( xform_list );
788 return r;
791 static BOOL ui_sequence_exists( MSIPACKAGE *package )
793 MSIQUERY *view;
794 UINT rc;
796 static const WCHAR ExecSeqQuery [] =
797 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
798 '`','I','n','s','t','a','l','l',
799 'U','I','S','e','q','u','e','n','c','e','`',
800 ' ','W','H','E','R','E',' ',
801 '`','S','e','q','u','e','n','c','e','`',' ',
802 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
803 '`','S','e','q','u','e','n','c','e','`',0};
805 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
806 if (rc == ERROR_SUCCESS)
808 msiobj_release(&view->hdr);
809 return TRUE;
812 return FALSE;
815 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
817 LPWSTR source, check;
819 if (msi_get_property_int( package->db, szInstalled, 0 ))
821 HKEY hkey;
823 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
824 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
825 RegCloseKey( hkey );
827 else
829 LPWSTR p, db;
830 DWORD len;
832 db = msi_dup_property( package->db, szOriginalDatabase );
833 if (!db)
834 return ERROR_OUTOFMEMORY;
836 p = strrchrW( db, '\\' );
837 if (!p)
839 p = strrchrW( db, '/' );
840 if (!p)
842 msi_free(db);
843 return ERROR_SUCCESS;
847 len = p - db + 2;
848 source = msi_alloc( len * sizeof(WCHAR) );
849 lstrcpynW( source, db, len );
850 msi_free( db );
853 check = msi_dup_property( package->db, cszSourceDir );
854 if (!check || replace)
856 UINT r = msi_set_property( package->db, cszSourceDir, source );
857 if (r == ERROR_SUCCESS)
858 msi_reset_folders( package, TRUE );
860 msi_free( check );
862 check = msi_dup_property( package->db, cszSOURCEDIR );
863 if (!check || replace)
864 msi_set_property( package->db, cszSOURCEDIR, source );
866 msi_free( check );
867 msi_free( source );
869 return ERROR_SUCCESS;
872 static BOOL needs_ui_sequence(MSIPACKAGE *package)
874 INT level = msi_get_property_int(package->db, szUILevel, 0);
875 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
878 UINT msi_set_context(MSIPACKAGE *package)
880 int num;
882 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
884 num = msi_get_property_int(package->db, szAllUsers, 0);
885 if (num == 1 || num == 2)
886 package->Context = MSIINSTALLCONTEXT_MACHINE;
888 return ERROR_SUCCESS;
891 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
893 UINT rc;
894 LPCWSTR cond, action;
895 MSIPACKAGE *package = param;
897 action = MSI_RecordGetString(row,1);
898 if (!action)
900 ERR("Error is retrieving action name\n");
901 return ERROR_FUNCTION_FAILED;
904 /* check conditions */
905 cond = MSI_RecordGetString(row,2);
907 /* this is a hack to skip errors in the condition code */
908 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
910 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
911 return ERROR_SUCCESS;
914 if (needs_ui_sequence(package))
915 rc = ACTION_PerformUIAction(package, action, -1);
916 else
917 rc = ACTION_PerformAction(package, action, -1);
919 msi_dialog_check_messages( NULL );
921 if (package->CurrentInstallState != ERROR_SUCCESS)
922 rc = package->CurrentInstallState;
924 if (rc == ERROR_FUNCTION_NOT_CALLED)
925 rc = ERROR_SUCCESS;
927 if (rc != ERROR_SUCCESS)
928 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
930 return rc;
933 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
935 MSIQUERY * view;
936 UINT r;
937 static const WCHAR query[] =
938 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
939 '`','%','s','`',
940 ' ','W','H','E','R','E',' ',
941 '`','S','e','q','u','e','n','c','e','`',' ',
942 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
943 '`','S','e','q','u','e','n','c','e','`',0};
945 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
947 r = MSI_OpenQuery( package->db, &view, query, szTable );
948 if (r == ERROR_SUCCESS)
950 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
951 msiobj_release(&view->hdr);
954 return r;
957 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
959 MSIQUERY * view;
960 UINT rc;
961 static const WCHAR ExecSeqQuery[] =
962 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
963 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
964 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
965 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
966 'O','R','D','E','R',' ', 'B','Y',' ',
967 '`','S','e','q','u','e','n','c','e','`',0 };
968 static const WCHAR IVQuery[] =
969 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
970 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
971 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
972 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
973 ' ','\'', 'I','n','s','t','a','l','l',
974 'V','a','l','i','d','a','t','e','\'', 0};
975 INT seq = 0;
977 if (package->script->ExecuteSequenceRun)
979 TRACE("Execute Sequence already Run\n");
980 return ERROR_SUCCESS;
983 package->script->ExecuteSequenceRun = TRUE;
985 /* get the sequence number */
986 if (UIran)
988 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
989 if( !row )
990 return ERROR_FUNCTION_FAILED;
991 seq = MSI_RecordGetInteger(row,1);
992 msiobj_release(&row->hdr);
995 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
996 if (rc == ERROR_SUCCESS)
998 TRACE("Running the actions\n");
1000 msi_set_property(package->db, cszSourceDir, NULL);
1002 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1003 msiobj_release(&view->hdr);
1006 return rc;
1009 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1011 MSIQUERY * view;
1012 UINT rc;
1013 static const WCHAR ExecSeqQuery [] =
1014 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1015 '`','I','n','s','t','a','l','l',
1016 'U','I','S','e','q','u','e','n','c','e','`',
1017 ' ','W','H','E','R','E',' ',
1018 '`','S','e','q','u','e','n','c','e','`',' ',
1019 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1020 '`','S','e','q','u','e','n','c','e','`',0};
1022 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1023 if (rc == ERROR_SUCCESS)
1025 TRACE("Running the actions\n");
1027 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1028 msiobj_release(&view->hdr);
1031 return rc;
1034 /********************************************************
1035 * ACTION helper functions and functions that perform the actions
1036 *******************************************************/
1037 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1038 UINT* rc, UINT script, BOOL force )
1040 BOOL ret=FALSE;
1041 UINT arc;
1043 arc = ACTION_CustomAction(package, action, script, force);
1045 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1047 *rc = arc;
1048 ret = TRUE;
1050 return ret;
1054 * Actual Action Handlers
1057 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1059 MSIPACKAGE *package = param;
1060 LPCWSTR dir, component;
1061 LPWSTR full_path;
1062 MSIRECORD *uirow;
1063 MSIFOLDER *folder;
1064 MSICOMPONENT *comp;
1066 component = MSI_RecordGetString(row, 2);
1067 if (!component)
1068 return ERROR_SUCCESS;
1070 comp = get_loaded_component(package, component);
1071 if (!comp)
1072 return ERROR_SUCCESS;
1074 if (!comp->Enabled)
1076 TRACE("component is disabled\n");
1077 return ERROR_SUCCESS;
1080 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
1082 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
1083 comp->Action = comp->Installed;
1084 return ERROR_SUCCESS;
1086 comp->Action = INSTALLSTATE_LOCAL;
1088 dir = MSI_RecordGetString(row,1);
1089 if (!dir)
1091 ERR("Unable to get folder id\n");
1092 return ERROR_SUCCESS;
1095 uirow = MSI_CreateRecord(1);
1096 MSI_RecordSetStringW(uirow, 1, dir);
1097 ui_actiondata(package, szCreateFolders, uirow);
1098 msiobj_release(&uirow->hdr);
1100 full_path = resolve_target_folder( package, dir, FALSE, TRUE, &folder );
1101 if (!full_path)
1103 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1104 return ERROR_SUCCESS;
1107 TRACE("Folder is %s\n",debugstr_w(full_path));
1109 if (folder->State == 0)
1110 create_full_pathW(full_path);
1112 folder->State = 3;
1114 msi_free(full_path);
1115 return ERROR_SUCCESS;
1118 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1120 static const WCHAR query[] =
1121 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1122 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1123 UINT rc;
1124 MSIQUERY *view;
1126 /* create all the empty folders specified in the CreateFolder table */
1127 rc = MSI_DatabaseOpenViewW(package->db, query, &view );
1128 if (rc != ERROR_SUCCESS)
1129 return ERROR_SUCCESS;
1131 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1132 msiobj_release(&view->hdr);
1134 return rc;
1137 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1139 MSIPACKAGE *package = param;
1140 LPCWSTR dir, component;
1141 LPWSTR full_path;
1142 MSIRECORD *uirow;
1143 MSIFOLDER *folder;
1144 MSICOMPONENT *comp;
1146 component = MSI_RecordGetString(row, 2);
1147 if (!component)
1148 return ERROR_SUCCESS;
1150 comp = get_loaded_component(package, component);
1151 if (!comp)
1152 return ERROR_SUCCESS;
1154 if (!comp->Enabled)
1156 TRACE("component is disabled\n");
1157 return ERROR_SUCCESS;
1160 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1162 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1163 comp->Action = comp->Installed;
1164 return ERROR_SUCCESS;
1166 comp->Action = INSTALLSTATE_ABSENT;
1168 dir = MSI_RecordGetString( row, 1 );
1169 if (!dir)
1171 ERR("Unable to get folder id\n");
1172 return ERROR_SUCCESS;
1175 full_path = resolve_target_folder( package, dir, FALSE, TRUE, &folder );
1176 if (!full_path)
1178 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1179 return ERROR_SUCCESS;
1182 TRACE("folder is %s\n", debugstr_w(full_path));
1184 uirow = MSI_CreateRecord( 1 );
1185 MSI_RecordSetStringW( uirow, 1, dir );
1186 ui_actiondata( package, szRemoveFolders, uirow );
1187 msiobj_release( &uirow->hdr );
1189 RemoveDirectoryW( full_path );
1190 folder->State = 0;
1192 msi_free( full_path );
1193 return ERROR_SUCCESS;
1196 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1198 static const WCHAR query[] =
1199 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1200 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1202 MSIQUERY *view;
1203 UINT rc;
1205 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1206 if (rc != ERROR_SUCCESS)
1207 return ERROR_SUCCESS;
1209 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1210 msiobj_release( &view->hdr );
1212 return rc;
1215 static UINT load_component( MSIRECORD *row, LPVOID param )
1217 MSIPACKAGE *package = param;
1218 MSICOMPONENT *comp;
1220 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1221 if (!comp)
1222 return ERROR_FUNCTION_FAILED;
1224 list_add_tail( &package->components, &comp->entry );
1226 /* fill in the data */
1227 comp->Component = msi_dup_record_field( row, 1 );
1229 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1231 comp->ComponentId = msi_dup_record_field( row, 2 );
1232 comp->Directory = msi_dup_record_field( row, 3 );
1233 comp->Attributes = MSI_RecordGetInteger(row,4);
1234 comp->Condition = msi_dup_record_field( row, 5 );
1235 comp->KeyPath = msi_dup_record_field( row, 6 );
1237 comp->Installed = INSTALLSTATE_UNKNOWN;
1238 comp->Action = INSTALLSTATE_UNKNOWN;
1239 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1241 comp->assembly = load_assembly( package, comp );
1242 return ERROR_SUCCESS;
1245 static UINT load_all_components( MSIPACKAGE *package )
1247 static const WCHAR query[] = {
1248 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1249 '`','C','o','m','p','o','n','e','n','t','`',0 };
1250 MSIQUERY *view;
1251 UINT r;
1253 if (!list_empty(&package->components))
1254 return ERROR_SUCCESS;
1256 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1257 if (r != ERROR_SUCCESS)
1258 return r;
1260 r = MSI_IterateRecords(view, NULL, load_component, package);
1261 msiobj_release(&view->hdr);
1262 return r;
1265 typedef struct {
1266 MSIPACKAGE *package;
1267 MSIFEATURE *feature;
1268 } _ilfs;
1270 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1272 ComponentList *cl;
1274 cl = msi_alloc( sizeof (*cl) );
1275 if ( !cl )
1276 return ERROR_NOT_ENOUGH_MEMORY;
1277 cl->component = comp;
1278 list_add_tail( &feature->Components, &cl->entry );
1280 return ERROR_SUCCESS;
1283 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1285 FeatureList *fl;
1287 fl = msi_alloc( sizeof(*fl) );
1288 if ( !fl )
1289 return ERROR_NOT_ENOUGH_MEMORY;
1290 fl->feature = child;
1291 list_add_tail( &parent->Children, &fl->entry );
1293 return ERROR_SUCCESS;
1296 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1298 _ilfs* ilfs = param;
1299 LPCWSTR component;
1300 MSICOMPONENT *comp;
1302 component = MSI_RecordGetString(row,1);
1304 /* check to see if the component is already loaded */
1305 comp = get_loaded_component( ilfs->package, component );
1306 if (!comp)
1308 ERR("unknown component %s\n", debugstr_w(component));
1309 return ERROR_FUNCTION_FAILED;
1312 add_feature_component( ilfs->feature, comp );
1313 comp->Enabled = TRUE;
1315 return ERROR_SUCCESS;
1318 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1320 MSIFEATURE *feature;
1322 if ( !name )
1323 return NULL;
1325 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1327 if ( !strcmpW( feature->Feature, name ) )
1328 return feature;
1331 return NULL;
1334 static UINT load_feature(MSIRECORD * row, LPVOID param)
1336 MSIPACKAGE* package = param;
1337 MSIFEATURE* feature;
1338 static const WCHAR Query1[] =
1339 {'S','E','L','E','C','T',' ',
1340 '`','C','o','m','p','o','n','e','n','t','_','`',
1341 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1342 'C','o','m','p','o','n','e','n','t','s','`',' ',
1343 'W','H','E','R','E',' ',
1344 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1345 MSIQUERY * view;
1346 UINT rc;
1347 _ilfs ilfs;
1349 /* fill in the data */
1351 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1352 if (!feature)
1353 return ERROR_NOT_ENOUGH_MEMORY;
1355 list_init( &feature->Children );
1356 list_init( &feature->Components );
1358 feature->Feature = msi_dup_record_field( row, 1 );
1360 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1362 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1363 feature->Title = msi_dup_record_field( row, 3 );
1364 feature->Description = msi_dup_record_field( row, 4 );
1366 if (!MSI_RecordIsNull(row,5))
1367 feature->Display = MSI_RecordGetInteger(row,5);
1369 feature->Level= MSI_RecordGetInteger(row,6);
1370 feature->Directory = msi_dup_record_field( row, 7 );
1371 feature->Attributes = MSI_RecordGetInteger(row,8);
1373 feature->Installed = INSTALLSTATE_UNKNOWN;
1374 feature->Action = INSTALLSTATE_UNKNOWN;
1375 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1377 list_add_tail( &package->features, &feature->entry );
1379 /* load feature components */
1381 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1382 if (rc != ERROR_SUCCESS)
1383 return ERROR_SUCCESS;
1385 ilfs.package = package;
1386 ilfs.feature = feature;
1388 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1389 msiobj_release(&view->hdr);
1391 return ERROR_SUCCESS;
1394 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1396 MSIPACKAGE* package = param;
1397 MSIFEATURE *parent, *child;
1399 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1400 if (!child)
1401 return ERROR_FUNCTION_FAILED;
1403 if (!child->Feature_Parent)
1404 return ERROR_SUCCESS;
1406 parent = find_feature_by_name( package, child->Feature_Parent );
1407 if (!parent)
1408 return ERROR_FUNCTION_FAILED;
1410 add_feature_child( parent, child );
1411 return ERROR_SUCCESS;
1414 static UINT load_all_features( MSIPACKAGE *package )
1416 static const WCHAR query[] = {
1417 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1418 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1419 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1420 MSIQUERY *view;
1421 UINT r;
1423 if (!list_empty(&package->features))
1424 return ERROR_SUCCESS;
1426 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1427 if (r != ERROR_SUCCESS)
1428 return r;
1430 r = MSI_IterateRecords( view, NULL, load_feature, package );
1431 if (r != ERROR_SUCCESS)
1432 return r;
1434 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1435 msiobj_release( &view->hdr );
1437 return r;
1440 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1442 if (!p)
1443 return p;
1444 p = strchrW(p, ch);
1445 if (!p)
1446 return p;
1447 *p = 0;
1448 return p+1;
1451 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1453 static const WCHAR query[] = {
1454 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1455 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1456 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1457 MSIQUERY *view = NULL;
1458 MSIRECORD *row = NULL;
1459 UINT r;
1461 TRACE("%s\n", debugstr_w(file->File));
1463 r = MSI_OpenQuery(package->db, &view, query, file->File);
1464 if (r != ERROR_SUCCESS)
1465 goto done;
1467 r = MSI_ViewExecute(view, NULL);
1468 if (r != ERROR_SUCCESS)
1469 goto done;
1471 r = MSI_ViewFetch(view, &row);
1472 if (r != ERROR_SUCCESS)
1473 goto done;
1475 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1476 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1477 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1478 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1479 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1481 done:
1482 if (view) msiobj_release(&view->hdr);
1483 if (row) msiobj_release(&row->hdr);
1484 return r;
1487 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1489 MSIRECORD *row;
1490 static const WCHAR query[] = {
1491 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1492 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1493 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1495 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1496 if (!row)
1498 WARN("query failed\n");
1499 return ERROR_FUNCTION_FAILED;
1502 file->disk_id = MSI_RecordGetInteger( row, 1 );
1503 msiobj_release( &row->hdr );
1504 return ERROR_SUCCESS;
1507 static UINT load_file(MSIRECORD *row, LPVOID param)
1509 MSIPACKAGE* package = param;
1510 LPCWSTR component;
1511 MSIFILE *file;
1513 /* fill in the data */
1515 file = msi_alloc_zero( sizeof (MSIFILE) );
1516 if (!file)
1517 return ERROR_NOT_ENOUGH_MEMORY;
1519 file->File = msi_dup_record_field( row, 1 );
1521 component = MSI_RecordGetString( row, 2 );
1522 file->Component = get_loaded_component( package, component );
1524 if (!file->Component)
1526 WARN("Component not found: %s\n", debugstr_w(component));
1527 msi_free(file->File);
1528 msi_free(file);
1529 return ERROR_SUCCESS;
1532 file->FileName = msi_dup_record_field( row, 3 );
1533 reduce_to_longfilename( file->FileName );
1535 file->ShortName = msi_dup_record_field( row, 3 );
1536 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1538 file->FileSize = MSI_RecordGetInteger( row, 4 );
1539 file->Version = msi_dup_record_field( row, 5 );
1540 file->Language = msi_dup_record_field( row, 6 );
1541 file->Attributes = MSI_RecordGetInteger( row, 7 );
1542 file->Sequence = MSI_RecordGetInteger( row, 8 );
1544 file->state = msifs_invalid;
1546 /* if the compressed bits are not set in the file attributes,
1547 * then read the information from the package word count property
1549 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1551 file->IsCompressed = FALSE;
1553 else if (file->Attributes &
1554 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1556 file->IsCompressed = TRUE;
1558 else if (file->Attributes & msidbFileAttributesNoncompressed)
1560 file->IsCompressed = FALSE;
1562 else
1564 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1567 load_file_hash(package, file);
1568 load_file_disk_id(package, file);
1570 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1572 list_add_tail( &package->files, &file->entry );
1574 return ERROR_SUCCESS;
1577 static UINT load_all_files(MSIPACKAGE *package)
1579 MSIQUERY * view;
1580 UINT rc;
1581 static const WCHAR Query[] =
1582 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1583 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1584 '`','S','e','q','u','e','n','c','e','`', 0};
1586 if (!list_empty(&package->files))
1587 return ERROR_SUCCESS;
1589 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1590 if (rc != ERROR_SUCCESS)
1591 return ERROR_SUCCESS;
1593 rc = MSI_IterateRecords(view, NULL, load_file, package);
1594 msiobj_release(&view->hdr);
1596 return ERROR_SUCCESS;
1599 static UINT load_folder( MSIRECORD *row, LPVOID param )
1601 MSIPACKAGE *package = param;
1602 static WCHAR szEmpty[] = { 0 };
1603 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1604 MSIFOLDER *folder;
1606 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1607 if (!folder)
1608 return ERROR_NOT_ENOUGH_MEMORY;
1610 folder->Directory = msi_dup_record_field( row, 1 );
1612 TRACE("%s\n", debugstr_w(folder->Directory));
1614 p = msi_dup_record_field(row, 3);
1616 /* split src and target dir */
1617 tgt_short = p;
1618 src_short = folder_split_path( p, ':' );
1620 /* split the long and short paths */
1621 tgt_long = folder_split_path( tgt_short, '|' );
1622 src_long = folder_split_path( src_short, '|' );
1624 /* check for no-op dirs */
1625 if (tgt_short && !strcmpW( szDot, tgt_short ))
1626 tgt_short = szEmpty;
1627 if (src_short && !strcmpW( szDot, src_short ))
1628 src_short = szEmpty;
1630 if (!tgt_long)
1631 tgt_long = tgt_short;
1633 if (!src_short) {
1634 src_short = tgt_short;
1635 src_long = tgt_long;
1638 if (!src_long)
1639 src_long = src_short;
1641 /* FIXME: use the target short path too */
1642 folder->TargetDefault = strdupW(tgt_long);
1643 folder->SourceShortPath = strdupW(src_short);
1644 folder->SourceLongPath = strdupW(src_long);
1645 msi_free(p);
1647 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1648 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1649 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1651 folder->Parent = msi_dup_record_field( row, 2 );
1653 folder->Property = msi_dup_property( package->db, folder->Directory );
1655 list_add_tail( &package->folders, &folder->entry );
1657 TRACE("returning %p\n", folder);
1659 return ERROR_SUCCESS;
1662 static UINT load_all_folders( MSIPACKAGE *package )
1664 static const WCHAR query[] = {
1665 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1666 '`','D','i','r','e','c','t','o','r','y','`',0 };
1667 MSIQUERY *view;
1668 UINT r;
1670 if (!list_empty(&package->folders))
1671 return ERROR_SUCCESS;
1673 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1674 if (r != ERROR_SUCCESS)
1675 return r;
1677 r = MSI_IterateRecords(view, NULL, load_folder, package);
1678 msiobj_release(&view->hdr);
1679 return r;
1683 * I am not doing any of the costing functionality yet.
1684 * Mostly looking at doing the Component and Feature loading
1686 * The native MSI does A LOT of modification to tables here. Mostly adding
1687 * a lot of temporary columns to the Feature and Component tables.
1689 * note: Native msi also tracks the short filename. But I am only going to
1690 * track the long ones. Also looking at this directory table
1691 * it appears that the directory table does not get the parents
1692 * resolved base on property only based on their entries in the
1693 * directory table.
1695 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1697 static const WCHAR szCosting[] =
1698 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1700 msi_set_property( package->db, szCosting, szZero );
1701 msi_set_property( package->db, cszRootDrive, c_colon );
1703 load_all_folders( package );
1704 load_all_components( package );
1705 load_all_features( package );
1706 load_all_files( package );
1708 return ERROR_SUCCESS;
1711 static UINT execute_script(MSIPACKAGE *package, UINT script )
1713 UINT i;
1714 UINT rc = ERROR_SUCCESS;
1716 TRACE("Executing Script %i\n",script);
1718 if (!package->script)
1720 ERR("no script!\n");
1721 return ERROR_FUNCTION_FAILED;
1724 for (i = 0; i < package->script->ActionCount[script]; i++)
1726 LPWSTR action;
1727 action = package->script->Actions[script][i];
1728 ui_actionstart(package, action);
1729 TRACE("Executing Action (%s)\n",debugstr_w(action));
1730 rc = ACTION_PerformAction(package, action, script);
1731 if (rc != ERROR_SUCCESS)
1732 break;
1734 msi_free_action_script(package, script);
1735 return rc;
1738 static UINT ACTION_FileCost(MSIPACKAGE *package)
1740 return ERROR_SUCCESS;
1743 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1745 MSICOMPONENT *comp;
1746 UINT r;
1748 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1750 if (!comp->ComponentId) continue;
1752 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1753 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1754 &comp->Installed );
1755 if (r != ERROR_SUCCESS)
1756 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1757 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1758 &comp->Installed );
1759 if (r != ERROR_SUCCESS)
1760 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1761 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1762 &comp->Installed );
1763 if (r != ERROR_SUCCESS)
1764 comp->Installed = INSTALLSTATE_ABSENT;
1768 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1770 MSIFEATURE *feature;
1772 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1774 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1776 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1777 feature->Installed = INSTALLSTATE_ABSENT;
1778 else
1779 feature->Installed = state;
1783 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1785 return (feature->Level > 0 && feature->Level <= level);
1788 static BOOL process_state_property(MSIPACKAGE* package, int level,
1789 LPCWSTR property, INSTALLSTATE state)
1791 LPWSTR override;
1792 MSIFEATURE *feature;
1794 override = msi_dup_property( package->db, property );
1795 if (!override)
1796 return FALSE;
1798 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1800 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1801 continue;
1803 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1805 if (!strcmpiW( override, szAll ))
1807 if (feature->Installed != state)
1809 feature->Action = state;
1810 feature->ActionRequest = state;
1813 else
1815 LPWSTR ptr = override;
1816 LPWSTR ptr2 = strchrW(override,',');
1818 while (ptr)
1820 int len = ptr2 - ptr;
1822 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1823 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1825 if (feature->Installed != state)
1827 feature->Action = state;
1828 feature->ActionRequest = state;
1830 break;
1832 if (ptr2)
1834 ptr=ptr2+1;
1835 ptr2 = strchrW(ptr,',');
1837 else
1838 break;
1842 msi_free(override);
1843 return TRUE;
1846 static BOOL process_overrides( MSIPACKAGE *package, int level )
1848 static const WCHAR szAddLocal[] =
1849 {'A','D','D','L','O','C','A','L',0};
1850 static const WCHAR szAddSource[] =
1851 {'A','D','D','S','O','U','R','C','E',0};
1852 static const WCHAR szAdvertise[] =
1853 {'A','D','V','E','R','T','I','S','E',0};
1854 BOOL ret = FALSE;
1856 /* all these activation/deactivation things happen in order and things
1857 * later on the list override things earlier on the list.
1859 * 0 INSTALLLEVEL processing
1860 * 1 ADDLOCAL
1861 * 2 REMOVE
1862 * 3 ADDSOURCE
1863 * 4 ADDDEFAULT
1864 * 5 REINSTALL
1865 * 6 ADVERTISE
1866 * 7 COMPADDLOCAL
1867 * 8 COMPADDSOURCE
1868 * 9 FILEADDLOCAL
1869 * 10 FILEADDSOURCE
1870 * 11 FILEADDDEFAULT
1872 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1873 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1874 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1875 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1876 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1878 if (ret)
1879 msi_set_property( package->db, szPreselected, szOne );
1881 return ret;
1884 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1886 int level;
1887 static const WCHAR szlevel[] =
1888 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1889 MSICOMPONENT* component;
1890 MSIFEATURE *feature;
1892 TRACE("Checking Install Level\n");
1894 level = msi_get_property_int(package->db, szlevel, 1);
1896 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1898 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1900 if (!is_feature_selected( feature, level )) continue;
1902 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1904 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1906 feature->Action = INSTALLSTATE_SOURCE;
1907 feature->ActionRequest = INSTALLSTATE_SOURCE;
1909 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1911 feature->Action = INSTALLSTATE_ADVERTISED;
1912 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1914 else
1916 feature->Action = INSTALLSTATE_LOCAL;
1917 feature->ActionRequest = INSTALLSTATE_LOCAL;
1922 /* disable child features of unselected parent features */
1923 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1925 FeatureList *fl;
1927 if (is_feature_selected( feature, level )) continue;
1929 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1931 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1932 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1936 else /* preselected */
1938 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1940 if (!is_feature_selected( feature, level )) continue;
1942 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1944 if (feature->Installed == INSTALLSTATE_ABSENT)
1946 feature->Action = INSTALLSTATE_UNKNOWN;
1947 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1949 else
1951 feature->Action = feature->Installed;
1952 feature->ActionRequest = feature->Installed;
1958 /* now we want to set component state based based on feature state */
1959 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1961 ComponentList *cl;
1963 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1964 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1965 feature->ActionRequest, feature->Action);
1967 if (!is_feature_selected( feature, level )) continue;
1969 /* features with components that have compressed files are made local */
1970 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1972 if (cl->component->ForceLocalState &&
1973 feature->ActionRequest == INSTALLSTATE_SOURCE)
1975 feature->Action = INSTALLSTATE_LOCAL;
1976 feature->ActionRequest = INSTALLSTATE_LOCAL;
1977 break;
1981 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1983 component = cl->component;
1985 switch (feature->ActionRequest)
1987 case INSTALLSTATE_ABSENT:
1988 component->anyAbsent = 1;
1989 break;
1990 case INSTALLSTATE_ADVERTISED:
1991 component->hasAdvertiseFeature = 1;
1992 break;
1993 case INSTALLSTATE_SOURCE:
1994 component->hasSourceFeature = 1;
1995 break;
1996 case INSTALLSTATE_LOCAL:
1997 component->hasLocalFeature = 1;
1998 break;
1999 case INSTALLSTATE_DEFAULT:
2000 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
2001 component->hasAdvertiseFeature = 1;
2002 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
2003 component->hasSourceFeature = 1;
2004 else
2005 component->hasLocalFeature = 1;
2006 break;
2007 default:
2008 break;
2013 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2015 /* check if it's local or source */
2016 if (!(component->Attributes & msidbComponentAttributesOptional) &&
2017 (component->hasLocalFeature || component->hasSourceFeature))
2019 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
2020 !component->ForceLocalState)
2022 component->Action = INSTALLSTATE_SOURCE;
2023 component->ActionRequest = INSTALLSTATE_SOURCE;
2025 else
2027 component->Action = INSTALLSTATE_LOCAL;
2028 component->ActionRequest = INSTALLSTATE_LOCAL;
2030 continue;
2033 /* if any feature is local, the component must be local too */
2034 if (component->hasLocalFeature)
2036 component->Action = INSTALLSTATE_LOCAL;
2037 component->ActionRequest = INSTALLSTATE_LOCAL;
2038 continue;
2040 if (component->hasSourceFeature)
2042 component->Action = INSTALLSTATE_SOURCE;
2043 component->ActionRequest = INSTALLSTATE_SOURCE;
2044 continue;
2046 if (component->hasAdvertiseFeature)
2048 component->Action = INSTALLSTATE_ADVERTISED;
2049 component->ActionRequest = INSTALLSTATE_ADVERTISED;
2050 continue;
2052 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2053 if (component->anyAbsent &&
2054 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
2056 component->Action = INSTALLSTATE_ABSENT;
2057 component->ActionRequest = INSTALLSTATE_ABSENT;
2061 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2063 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
2065 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2066 component->Action = INSTALLSTATE_LOCAL;
2067 component->ActionRequest = INSTALLSTATE_LOCAL;
2070 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
2071 component->Installed == INSTALLSTATE_SOURCE &&
2072 component->hasSourceFeature)
2074 component->Action = INSTALLSTATE_UNKNOWN;
2075 component->ActionRequest = INSTALLSTATE_UNKNOWN;
2078 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
2079 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2082 return ERROR_SUCCESS;
2085 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2087 MSIPACKAGE *package = param;
2088 LPCWSTR name;
2089 LPWSTR path;
2090 MSIFOLDER *f;
2092 name = MSI_RecordGetString(row,1);
2094 f = get_loaded_folder(package, name);
2095 if (!f) return ERROR_SUCCESS;
2097 /* reset the ResolvedTarget */
2098 msi_free(f->ResolvedTarget);
2099 f->ResolvedTarget = NULL;
2101 TRACE("directory %s ...\n", debugstr_w(name));
2102 path = resolve_target_folder( package, name, TRUE, TRUE, NULL );
2103 TRACE("resolves to %s\n", debugstr_w(path));
2104 msi_free(path);
2106 return ERROR_SUCCESS;
2109 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2111 MSIPACKAGE *package = param;
2112 LPCWSTR name;
2113 MSIFEATURE *feature;
2115 name = MSI_RecordGetString( row, 1 );
2117 feature = get_loaded_feature( package, name );
2118 if (!feature)
2119 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2120 else
2122 LPCWSTR Condition;
2123 Condition = MSI_RecordGetString(row,3);
2125 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2127 int level = MSI_RecordGetInteger(row,2);
2128 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2129 feature->Level = level;
2132 return ERROR_SUCCESS;
2135 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2137 static const WCHAR name[] = {'\\',0};
2138 VS_FIXEDFILEINFO *ptr, *ret;
2139 LPVOID version;
2140 DWORD versize, handle;
2141 UINT sz;
2143 TRACE("%s\n", debugstr_w(filename));
2145 versize = GetFileVersionInfoSizeW( filename, &handle );
2146 if (!versize)
2147 return NULL;
2149 version = msi_alloc( versize );
2150 if (!version)
2151 return NULL;
2153 GetFileVersionInfoW( filename, 0, versize, version );
2155 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2157 msi_free( version );
2158 return NULL;
2161 ret = msi_alloc( sz );
2162 memcpy( ret, ptr, sz );
2164 msi_free( version );
2165 return ret;
2168 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2170 DWORD ms, ls;
2172 msi_parse_version_string( version, &ms, &ls );
2174 if (fi->dwFileVersionMS > ms) return 1;
2175 else if (fi->dwFileVersionMS < ms) return -1;
2176 else if (fi->dwFileVersionLS > ls) return 1;
2177 else if (fi->dwFileVersionLS < ls) return -1;
2178 return 0;
2181 static int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2183 DWORD ms1, ms2;
2185 msi_parse_version_string( ver1, &ms1, NULL );
2186 msi_parse_version_string( ver2, &ms2, NULL );
2188 if (ms1 > ms2) return 1;
2189 else if (ms1 < ms2) return -1;
2190 return 0;
2193 static DWORD get_disk_file_size( LPCWSTR filename )
2195 HANDLE file;
2196 DWORD size;
2198 TRACE("%s\n", debugstr_w(filename));
2200 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2201 if (file == INVALID_HANDLE_VALUE)
2202 return INVALID_FILE_SIZE;
2204 size = GetFileSize( file, NULL );
2205 CloseHandle( file );
2206 return size;
2209 static BOOL hash_matches( MSIFILE *file )
2211 UINT r;
2212 MSIFILEHASHINFO hash;
2214 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2215 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2216 if (r != ERROR_SUCCESS)
2217 return FALSE;
2219 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2222 static WCHAR *get_temp_dir( void )
2224 static UINT id;
2225 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2227 GetTempPathW( MAX_PATH, tmp );
2228 for (;;)
2230 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2231 if (CreateDirectoryW( dir, NULL )) break;
2233 return strdupW( dir );
2236 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2238 MSIASSEMBLY *assembly = file->Component->assembly;
2240 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2242 msi_free( file->TargetPath );
2243 if (assembly && !assembly->application)
2245 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2246 file->TargetPath = build_directory_name( 2, assembly->tempdir, file->FileName );
2247 track_tempfile( package, file->TargetPath );
2249 else
2251 WCHAR *dir = resolve_target_folder( package, file->Component->Directory, FALSE, TRUE, NULL );
2252 file->TargetPath = build_directory_name( 2, dir, file->FileName );
2253 msi_free( dir );
2256 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2259 static UINT set_file_install_states( MSIPACKAGE *package )
2261 VS_FIXEDFILEINFO *file_version;
2262 WCHAR *font_version;
2263 MSIFILE *file;
2265 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2267 MSICOMPONENT *comp = file->Component;
2268 DWORD file_size;
2270 if (!comp->Enabled) continue;
2272 if (file->IsCompressed)
2273 comp->ForceLocalState = TRUE;
2275 set_target_path( package, file );
2277 if ((comp->assembly && !comp->assembly->installed) ||
2278 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2280 file->state = msifs_missing;
2281 comp->Cost += file->FileSize;
2282 continue;
2284 if (file->Version)
2286 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2288 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2289 HIWORD(file_version->dwFileVersionMS),
2290 LOWORD(file_version->dwFileVersionMS),
2291 HIWORD(file_version->dwFileVersionLS),
2292 LOWORD(file_version->dwFileVersionLS));
2294 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2296 file->state = msifs_overwrite;
2297 comp->Cost += file->FileSize;
2299 else
2301 TRACE("Destination file version equal or greater, not overwriting\n");
2302 file->state = msifs_present;
2304 msi_free( file_version );
2305 continue;
2307 else if ((font_version = font_version_from_file( file->TargetPath )))
2309 TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(font_version));
2311 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2313 file->state = msifs_overwrite;
2314 comp->Cost += file->FileSize;
2316 else
2318 TRACE("Destination file version equal or greater, not overwriting\n");
2319 file->state = msifs_present;
2321 msi_free( font_version );
2322 continue;
2325 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2327 file->state = msifs_overwrite;
2328 comp->Cost += file->FileSize - file_size;
2329 continue;
2331 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2333 TRACE("File hashes match, not overwriting\n");
2334 file->state = msifs_present;
2335 continue;
2337 file->state = msifs_overwrite;
2338 comp->Cost += file->FileSize - file_size;
2341 return ERROR_SUCCESS;
2345 * A lot is done in this function aside from just the costing.
2346 * The costing needs to be implemented at some point but for now I am going
2347 * to focus on the directory building
2350 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2352 static const WCHAR ExecSeqQuery[] =
2353 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2354 '`','D','i','r','e','c','t','o','r','y','`',0};
2355 static const WCHAR ConditionQuery[] =
2356 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2357 '`','C','o','n','d','i','t','i','o','n','`',0};
2358 static const WCHAR szCosting[] =
2359 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2360 static const WCHAR szlevel[] =
2361 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2362 static const WCHAR szOutOfDiskSpace[] =
2363 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2364 MSICOMPONENT *comp;
2365 UINT rc = ERROR_SUCCESS;
2366 MSIQUERY * view;
2367 LPWSTR level;
2369 TRACE("Building Directory properties\n");
2371 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2372 if (rc == ERROR_SUCCESS)
2374 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2375 package);
2376 msiobj_release(&view->hdr);
2379 TRACE("Evaluating component conditions\n");
2380 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2382 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2384 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2385 comp->Enabled = FALSE;
2387 else
2388 comp->Enabled = TRUE;
2391 /* read components states from the registry */
2392 ACTION_GetComponentInstallStates(package);
2393 ACTION_GetFeatureInstallStates(package);
2395 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2397 TRACE("Evaluating feature conditions\n");
2399 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2400 if (rc == ERROR_SUCCESS)
2402 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2403 msiobj_release( &view->hdr );
2407 TRACE("Calculating file install states\n");
2408 set_file_install_states( package );
2410 msi_set_property( package->db, szCosting, szOne );
2411 /* set default run level if not set */
2412 level = msi_dup_property( package->db, szlevel );
2413 if (!level)
2414 msi_set_property( package->db, szlevel, szOne );
2415 msi_free(level);
2417 /* FIXME: check volume disk space */
2418 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2420 return MSI_SetFeatureStates(package);
2423 /* OK this value is "interpreted" and then formatted based on the
2424 first few characters */
2425 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2426 DWORD *size)
2428 LPSTR data = NULL;
2430 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2432 if (value[1]=='x')
2434 LPWSTR ptr;
2435 CHAR byte[5];
2436 LPWSTR deformated = NULL;
2437 int count;
2439 deformat_string(package, &value[2], &deformated);
2441 /* binary value type */
2442 ptr = deformated;
2443 *type = REG_BINARY;
2444 if (strlenW(ptr)%2)
2445 *size = (strlenW(ptr)/2)+1;
2446 else
2447 *size = strlenW(ptr)/2;
2449 data = msi_alloc(*size);
2451 byte[0] = '0';
2452 byte[1] = 'x';
2453 byte[4] = 0;
2454 count = 0;
2455 /* if uneven pad with a zero in front */
2456 if (strlenW(ptr)%2)
2458 byte[2]= '0';
2459 byte[3]= *ptr;
2460 ptr++;
2461 data[count] = (BYTE)strtol(byte,NULL,0);
2462 count ++;
2463 TRACE("Uneven byte count\n");
2465 while (*ptr)
2467 byte[2]= *ptr;
2468 ptr++;
2469 byte[3]= *ptr;
2470 ptr++;
2471 data[count] = (BYTE)strtol(byte,NULL,0);
2472 count ++;
2474 msi_free(deformated);
2476 TRACE("Data %i bytes(%i)\n",*size,count);
2478 else
2480 LPWSTR deformated;
2481 LPWSTR p;
2482 DWORD d = 0;
2483 deformat_string(package, &value[1], &deformated);
2485 *type=REG_DWORD;
2486 *size = sizeof(DWORD);
2487 data = msi_alloc(*size);
2488 p = deformated;
2489 if (*p == '-')
2490 p++;
2491 while (*p)
2493 if ( (*p < '0') || (*p > '9') )
2494 break;
2495 d *= 10;
2496 d += (*p - '0');
2497 p++;
2499 if (deformated[0] == '-')
2500 d = -d;
2501 *(LPDWORD)data = d;
2502 TRACE("DWORD %i\n",*(LPDWORD)data);
2504 msi_free(deformated);
2507 else
2509 static const WCHAR szMulti[] = {'[','~',']',0};
2510 LPCWSTR ptr;
2511 *type=REG_SZ;
2513 if (value[0]=='#')
2515 if (value[1]=='%')
2517 ptr = &value[2];
2518 *type=REG_EXPAND_SZ;
2520 else
2521 ptr = &value[1];
2523 else
2524 ptr=value;
2526 if (strstrW(value, szMulti))
2527 *type = REG_MULTI_SZ;
2529 /* remove initial delimiter */
2530 if (!strncmpW(value, szMulti, 3))
2531 ptr = value + 3;
2533 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2535 /* add double NULL terminator */
2536 if (*type == REG_MULTI_SZ)
2538 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2539 data = msi_realloc_zero(data, *size);
2542 return data;
2545 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2547 const WCHAR *ret;
2549 switch (root)
2551 case -1:
2552 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2554 *root_key = HKEY_LOCAL_MACHINE;
2555 ret = szHLM;
2557 else
2559 *root_key = HKEY_CURRENT_USER;
2560 ret = szHCU;
2562 break;
2563 case 0:
2564 *root_key = HKEY_CLASSES_ROOT;
2565 ret = szHCR;
2566 break;
2567 case 1:
2568 *root_key = HKEY_CURRENT_USER;
2569 ret = szHCU;
2570 break;
2571 case 2:
2572 *root_key = HKEY_LOCAL_MACHINE;
2573 ret = szHLM;
2574 break;
2575 case 3:
2576 *root_key = HKEY_USERS;
2577 ret = szHU;
2578 break;
2579 default:
2580 ERR("Unknown root %i\n", root);
2581 return NULL;
2584 return ret;
2587 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2589 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2590 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2592 if (is_64bit && package->platform == PLATFORM_INTEL &&
2593 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2595 UINT size;
2596 WCHAR *path_32node;
2598 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2599 path_32node = msi_alloc( size );
2600 if (!path_32node)
2601 return NULL;
2603 memcpy( path_32node, path, len * sizeof(WCHAR) );
2604 path_32node[len] = 0;
2605 strcatW( path_32node, szWow6432Node );
2606 strcatW( path_32node, szBackSlash );
2607 strcatW( path_32node, path + len );
2608 return path_32node;
2611 return strdupW( path );
2614 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2616 MSIPACKAGE *package = param;
2617 LPSTR value_data = NULL;
2618 HKEY root_key, hkey;
2619 DWORD type,size;
2620 LPWSTR deformated, uikey, keypath;
2621 LPCWSTR szRoot, component, name, key, value;
2622 MSICOMPONENT *comp;
2623 MSIRECORD * uirow;
2624 INT root;
2625 BOOL check_first = FALSE;
2626 UINT rc;
2628 ui_progress(package,2,0,0,0);
2630 component = MSI_RecordGetString(row, 6);
2631 comp = get_loaded_component(package,component);
2632 if (!comp)
2633 return ERROR_SUCCESS;
2635 if (!comp->Enabled)
2637 TRACE("component is disabled\n");
2638 return ERROR_SUCCESS;
2641 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2643 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2644 comp->Action = comp->Installed;
2645 return ERROR_SUCCESS;
2647 comp->Action = INSTALLSTATE_LOCAL;
2649 name = MSI_RecordGetString(row, 4);
2650 if( MSI_RecordIsNull(row,5) && name )
2652 /* null values can have special meanings */
2653 if (name[0]=='-' && name[1] == 0)
2654 return ERROR_SUCCESS;
2655 else if ((name[0]=='+' && name[1] == 0) ||
2656 (name[0] == '*' && name[1] == 0))
2657 name = NULL;
2658 check_first = TRUE;
2661 root = MSI_RecordGetInteger(row,2);
2662 key = MSI_RecordGetString(row, 3);
2664 szRoot = get_root_key( package, root, &root_key );
2665 if (!szRoot)
2666 return ERROR_SUCCESS;
2668 deformat_string(package, key , &deformated);
2669 size = strlenW(deformated) + strlenW(szRoot) + 1;
2670 uikey = msi_alloc(size*sizeof(WCHAR));
2671 strcpyW(uikey,szRoot);
2672 strcatW(uikey,deformated);
2674 keypath = get_keypath( package, root_key, deformated );
2675 msi_free( deformated );
2676 if (RegCreateKeyW( root_key, keypath, &hkey ))
2678 ERR("Could not create key %s\n", debugstr_w(keypath));
2679 msi_free(uikey);
2680 msi_free(keypath);
2681 return ERROR_SUCCESS;
2684 value = MSI_RecordGetString(row,5);
2685 if (value)
2686 value_data = parse_value(package, value, &type, &size);
2687 else
2689 value_data = (LPSTR)strdupW(szEmpty);
2690 size = sizeof(szEmpty);
2691 type = REG_SZ;
2694 deformat_string(package, name, &deformated);
2696 if (!check_first)
2698 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2699 debugstr_w(uikey));
2700 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2702 else
2704 DWORD sz = 0;
2705 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2706 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2708 TRACE("value %s of %s checked already exists\n",
2709 debugstr_w(deformated), debugstr_w(uikey));
2711 else
2713 TRACE("Checked and setting value %s of %s\n",
2714 debugstr_w(deformated), debugstr_w(uikey));
2715 if (deformated || size)
2716 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2719 RegCloseKey(hkey);
2721 uirow = MSI_CreateRecord(3);
2722 MSI_RecordSetStringW(uirow,2,deformated);
2723 MSI_RecordSetStringW(uirow,1,uikey);
2724 if (type == REG_SZ || type == REG_EXPAND_SZ)
2725 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2726 ui_actiondata(package,szWriteRegistryValues,uirow);
2727 msiobj_release( &uirow->hdr );
2729 msi_free(value_data);
2730 msi_free(deformated);
2731 msi_free(uikey);
2732 msi_free(keypath);
2734 return ERROR_SUCCESS;
2737 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2739 UINT rc;
2740 MSIQUERY * view;
2741 static const WCHAR ExecSeqQuery[] =
2742 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2743 '`','R','e','g','i','s','t','r','y','`',0 };
2745 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2746 if (rc != ERROR_SUCCESS)
2747 return ERROR_SUCCESS;
2749 /* increment progress bar each time action data is sent */
2750 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2752 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2754 msiobj_release(&view->hdr);
2755 return rc;
2758 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2760 LONG res;
2761 HKEY hkey;
2762 DWORD num_subkeys, num_values;
2764 if (delete_key)
2766 if ((res = RegDeleteTreeW( hkey_root, key )))
2768 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2770 return;
2773 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2775 if ((res = RegDeleteValueW( hkey, value )))
2777 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2779 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2780 NULL, NULL, NULL, NULL );
2781 RegCloseKey( hkey );
2782 if (!res && !num_subkeys && !num_values)
2784 TRACE("Removing empty key %s\n", debugstr_w(key));
2785 RegDeleteKeyW( hkey_root, key );
2787 return;
2789 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2793 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2795 MSIPACKAGE *package = param;
2796 LPCWSTR component, name, key_str, root_key_str;
2797 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2798 MSICOMPONENT *comp;
2799 MSIRECORD *uirow;
2800 BOOL delete_key = FALSE;
2801 HKEY hkey_root;
2802 UINT size;
2803 INT root;
2805 ui_progress( package, 2, 0, 0, 0 );
2807 component = MSI_RecordGetString( row, 6 );
2808 comp = get_loaded_component( package, component );
2809 if (!comp)
2810 return ERROR_SUCCESS;
2812 if (!comp->Enabled)
2814 TRACE("component is disabled\n");
2815 return ERROR_SUCCESS;
2818 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2820 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2821 comp->Action = comp->Installed;
2822 return ERROR_SUCCESS;
2824 comp->Action = INSTALLSTATE_ABSENT;
2826 name = MSI_RecordGetString( row, 4 );
2827 if (MSI_RecordIsNull( row, 5 ) && name )
2829 if (name[0] == '+' && !name[1])
2830 return ERROR_SUCCESS;
2831 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2833 delete_key = TRUE;
2834 name = NULL;
2838 root = MSI_RecordGetInteger( row, 2 );
2839 key_str = MSI_RecordGetString( row, 3 );
2841 root_key_str = get_root_key( package, root, &hkey_root );
2842 if (!root_key_str)
2843 return ERROR_SUCCESS;
2845 deformat_string( package, key_str, &deformated_key );
2846 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2847 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2848 strcpyW( ui_key_str, root_key_str );
2849 strcatW( ui_key_str, deformated_key );
2851 deformat_string( package, name, &deformated_name );
2853 keypath = get_keypath( package, hkey_root, deformated_key );
2854 msi_free( deformated_key );
2855 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2856 msi_free( keypath );
2858 uirow = MSI_CreateRecord( 2 );
2859 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2860 MSI_RecordSetStringW( uirow, 2, deformated_name );
2862 ui_actiondata( package, szRemoveRegistryValues, uirow );
2863 msiobj_release( &uirow->hdr );
2865 msi_free( ui_key_str );
2866 msi_free( deformated_name );
2867 return ERROR_SUCCESS;
2870 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2872 MSIPACKAGE *package = param;
2873 LPCWSTR component, name, key_str, root_key_str;
2874 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2875 MSICOMPONENT *comp;
2876 MSIRECORD *uirow;
2877 BOOL delete_key = FALSE;
2878 HKEY hkey_root;
2879 UINT size;
2880 INT root;
2882 ui_progress( package, 2, 0, 0, 0 );
2884 component = MSI_RecordGetString( row, 5 );
2885 comp = get_loaded_component( package, component );
2886 if (!comp)
2887 return ERROR_SUCCESS;
2889 if (!comp->Enabled)
2891 TRACE("component is disabled\n");
2892 return ERROR_SUCCESS;
2895 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2897 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2898 comp->Action = comp->Installed;
2899 return ERROR_SUCCESS;
2901 comp->Action = INSTALLSTATE_LOCAL;
2903 if ((name = MSI_RecordGetString( row, 4 )))
2905 if (name[0] == '-' && !name[1])
2907 delete_key = TRUE;
2908 name = NULL;
2912 root = MSI_RecordGetInteger( row, 2 );
2913 key_str = MSI_RecordGetString( row, 3 );
2915 root_key_str = get_root_key( package, root, &hkey_root );
2916 if (!root_key_str)
2917 return ERROR_SUCCESS;
2919 deformat_string( package, key_str, &deformated_key );
2920 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2921 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2922 strcpyW( ui_key_str, root_key_str );
2923 strcatW( ui_key_str, deformated_key );
2925 deformat_string( package, name, &deformated_name );
2927 keypath = get_keypath( package, hkey_root, deformated_key );
2928 msi_free( deformated_key );
2929 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2930 msi_free( keypath );
2932 uirow = MSI_CreateRecord( 2 );
2933 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2934 MSI_RecordSetStringW( uirow, 2, deformated_name );
2936 ui_actiondata( package, szRemoveRegistryValues, uirow );
2937 msiobj_release( &uirow->hdr );
2939 msi_free( ui_key_str );
2940 msi_free( deformated_name );
2941 return ERROR_SUCCESS;
2944 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2946 UINT rc;
2947 MSIQUERY *view;
2948 static const WCHAR registry_query[] =
2949 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2950 '`','R','e','g','i','s','t','r','y','`',0 };
2951 static const WCHAR remove_registry_query[] =
2952 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2953 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2955 /* increment progress bar each time action data is sent */
2956 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2958 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2959 if (rc == ERROR_SUCCESS)
2961 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2962 msiobj_release( &view->hdr );
2963 if (rc != ERROR_SUCCESS)
2964 return rc;
2967 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2968 if (rc == ERROR_SUCCESS)
2970 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2971 msiobj_release( &view->hdr );
2972 if (rc != ERROR_SUCCESS)
2973 return rc;
2976 return ERROR_SUCCESS;
2979 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2981 package->script->CurrentlyScripting = TRUE;
2983 return ERROR_SUCCESS;
2987 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2989 MSICOMPONENT *comp;
2990 DWORD progress = 0;
2991 DWORD total = 0;
2992 static const WCHAR q1[]=
2993 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2994 '`','R','e','g','i','s','t','r','y','`',0};
2995 UINT rc;
2996 MSIQUERY * view;
2997 MSIFEATURE *feature;
2998 MSIFILE *file;
3000 TRACE("InstallValidate\n");
3002 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3003 if (rc == ERROR_SUCCESS)
3005 MSI_IterateRecords( view, &progress, NULL, package );
3006 msiobj_release( &view->hdr );
3007 total += progress * REG_PROGRESS_VALUE;
3010 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3011 total += COMPONENT_PROGRESS_VALUE;
3013 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3014 total += file->FileSize;
3016 ui_progress(package,0,total,0,0);
3018 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3020 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3021 debugstr_w(feature->Feature), feature->Installed,
3022 feature->ActionRequest, feature->Action);
3025 return ERROR_SUCCESS;
3028 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3030 MSIPACKAGE* package = param;
3031 LPCWSTR cond = NULL;
3032 LPCWSTR message = NULL;
3033 UINT r;
3035 static const WCHAR title[]=
3036 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3038 cond = MSI_RecordGetString(row,1);
3040 r = MSI_EvaluateConditionW(package,cond);
3041 if (r == MSICONDITION_FALSE)
3043 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3045 LPWSTR deformated;
3046 message = MSI_RecordGetString(row,2);
3047 deformat_string(package,message,&deformated);
3048 MessageBoxW(NULL,deformated,title,MB_OK);
3049 msi_free(deformated);
3052 return ERROR_INSTALL_FAILURE;
3055 return ERROR_SUCCESS;
3058 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3060 UINT rc;
3061 MSIQUERY * view = NULL;
3062 static const WCHAR ExecSeqQuery[] =
3063 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3064 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3066 TRACE("Checking launch conditions\n");
3068 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3069 if (rc != ERROR_SUCCESS)
3070 return ERROR_SUCCESS;
3072 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3073 msiobj_release(&view->hdr);
3075 return rc;
3078 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3081 if (!cmp->KeyPath)
3082 return resolve_target_folder( package, cmp->Directory, FALSE, TRUE, NULL );
3084 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3086 MSIRECORD * row = 0;
3087 UINT root,len;
3088 LPWSTR deformated,buffer,deformated_name;
3089 LPCWSTR key,name;
3090 static const WCHAR ExecSeqQuery[] =
3091 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3092 '`','R','e','g','i','s','t','r','y','`',' ',
3093 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3094 ' ','=',' ' ,'\'','%','s','\'',0 };
3095 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3096 static const WCHAR fmt2[]=
3097 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3099 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3100 if (!row)
3101 return NULL;
3103 root = MSI_RecordGetInteger(row,2);
3104 key = MSI_RecordGetString(row, 3);
3105 name = MSI_RecordGetString(row, 4);
3106 deformat_string(package, key , &deformated);
3107 deformat_string(package, name, &deformated_name);
3109 len = strlenW(deformated) + 6;
3110 if (deformated_name)
3111 len+=strlenW(deformated_name);
3113 buffer = msi_alloc( len *sizeof(WCHAR));
3115 if (deformated_name)
3116 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3117 else
3118 sprintfW(buffer,fmt,root,deformated);
3120 msi_free(deformated);
3121 msi_free(deformated_name);
3122 msiobj_release(&row->hdr);
3124 return buffer;
3126 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3128 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3129 return NULL;
3131 else
3133 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
3135 if (file)
3136 return strdupW( file->TargetPath );
3138 return NULL;
3141 static HKEY openSharedDLLsKey(void)
3143 HKEY hkey=0;
3144 static const WCHAR path[] =
3145 {'S','o','f','t','w','a','r','e','\\',
3146 'M','i','c','r','o','s','o','f','t','\\',
3147 'W','i','n','d','o','w','s','\\',
3148 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3149 'S','h','a','r','e','d','D','L','L','s',0};
3151 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3152 return hkey;
3155 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3157 HKEY hkey;
3158 DWORD count=0;
3159 DWORD type;
3160 DWORD sz = sizeof(count);
3161 DWORD rc;
3163 hkey = openSharedDLLsKey();
3164 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3165 if (rc != ERROR_SUCCESS)
3166 count = 0;
3167 RegCloseKey(hkey);
3168 return count;
3171 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3173 HKEY hkey;
3175 hkey = openSharedDLLsKey();
3176 if (count > 0)
3177 msi_reg_set_val_dword( hkey, path, count );
3178 else
3179 RegDeleteValueW(hkey,path);
3180 RegCloseKey(hkey);
3181 return count;
3185 * Return TRUE if the count should be written out and FALSE if not
3187 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3189 MSIFEATURE *feature;
3190 INT count = 0;
3191 BOOL write = FALSE;
3193 /* only refcount DLLs */
3194 if (comp->KeyPath == NULL ||
3195 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3196 comp->Attributes & msidbComponentAttributesODBCDataSource)
3197 write = FALSE;
3198 else
3200 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3201 write = (count > 0);
3203 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3204 write = TRUE;
3207 /* increment counts */
3208 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3210 ComponentList *cl;
3212 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3213 continue;
3215 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3217 if ( cl->component == comp )
3218 count++;
3222 /* decrement counts */
3223 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3225 ComponentList *cl;
3227 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3228 continue;
3230 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3232 if ( cl->component == comp )
3233 count--;
3237 /* ref count all the files in the component */
3238 if (write)
3240 MSIFILE *file;
3242 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3244 if (file->Component == comp)
3245 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3249 /* add a count for permanent */
3250 if (comp->Attributes & msidbComponentAttributesPermanent)
3251 count ++;
3253 comp->RefCount = count;
3255 if (write)
3256 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3259 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3261 WCHAR squished_pc[GUID_SIZE];
3262 WCHAR squished_cc[GUID_SIZE];
3263 UINT rc;
3264 MSICOMPONENT *comp;
3265 HKEY hkey;
3267 TRACE("\n");
3269 squash_guid(package->ProductCode,squished_pc);
3270 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3272 msi_set_sourcedir_props(package, FALSE);
3274 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3276 MSIRECORD * uirow;
3278 ui_progress(package,2,0,0,0);
3279 if (!comp->ComponentId)
3280 continue;
3282 squash_guid(comp->ComponentId,squished_cc);
3284 msi_free(comp->FullKeypath);
3285 comp->FullKeypath = resolve_keypath( package, comp );
3287 ACTION_RefCountComponent( package, comp );
3289 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3290 debugstr_w(comp->Component),
3291 debugstr_w(squished_cc),
3292 debugstr_w(comp->FullKeypath),
3293 comp->RefCount,
3294 comp->ActionRequest);
3296 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3297 comp->ActionRequest == INSTALLSTATE_SOURCE)
3299 if (!comp->FullKeypath)
3300 continue;
3302 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3303 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3304 &hkey, TRUE);
3305 else
3306 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3307 &hkey, TRUE);
3309 if (rc != ERROR_SUCCESS)
3310 continue;
3312 if (comp->Attributes & msidbComponentAttributesPermanent)
3314 static const WCHAR szPermKey[] =
3315 { '0','0','0','0','0','0','0','0','0','0','0','0',
3316 '0','0','0','0','0','0','0','0','0','0','0','0',
3317 '0','0','0','0','0','0','0','0',0 };
3319 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3322 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3323 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3324 else
3326 MSIFILE *file;
3327 MSIRECORD *row;
3328 LPWSTR ptr, ptr2;
3329 WCHAR source[MAX_PATH];
3330 WCHAR base[MAX_PATH];
3331 LPWSTR sourcepath;
3333 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3334 static const WCHAR query[] = {
3335 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3336 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3337 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3338 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3339 '`','D','i','s','k','I','d','`',0};
3341 if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
3342 continue;
3344 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3345 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3346 ptr2 = strrchrW(source, '\\') + 1;
3347 msiobj_release(&row->hdr);
3349 lstrcpyW(base, package->PackagePath);
3350 ptr = strrchrW(base, '\\');
3351 *(ptr + 1) = '\0';
3353 sourcepath = resolve_file_source(package, file);
3354 ptr = sourcepath + lstrlenW(base);
3355 lstrcpyW(ptr2, ptr);
3356 msi_free(sourcepath);
3358 msi_reg_set_val_str(hkey, squished_pc, source);
3360 RegCloseKey(hkey);
3362 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3364 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3365 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3366 else
3367 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3369 comp->Action = comp->ActionRequest;
3371 /* UI stuff */
3372 uirow = MSI_CreateRecord(3);
3373 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3374 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3375 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3376 ui_actiondata(package,szProcessComponents,uirow);
3377 msiobj_release( &uirow->hdr );
3380 return ERROR_SUCCESS;
3383 typedef struct {
3384 CLSID clsid;
3385 LPWSTR source;
3387 LPWSTR path;
3388 ITypeLib *ptLib;
3389 } typelib_struct;
3391 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3392 LPWSTR lpszName, LONG_PTR lParam)
3394 TLIBATTR *attr;
3395 typelib_struct *tl_struct = (typelib_struct*) lParam;
3396 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3397 int sz;
3398 HRESULT res;
3400 if (!IS_INTRESOURCE(lpszName))
3402 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3403 return TRUE;
3406 sz = strlenW(tl_struct->source)+4;
3407 sz *= sizeof(WCHAR);
3409 if ((INT_PTR)lpszName == 1)
3410 tl_struct->path = strdupW(tl_struct->source);
3411 else
3413 tl_struct->path = msi_alloc(sz);
3414 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3417 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3418 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3419 if (FAILED(res))
3421 msi_free(tl_struct->path);
3422 tl_struct->path = NULL;
3424 return TRUE;
3427 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3428 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3430 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3431 return FALSE;
3434 msi_free(tl_struct->path);
3435 tl_struct->path = NULL;
3437 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3438 ITypeLib_Release(tl_struct->ptLib);
3440 return TRUE;
3443 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3445 MSIPACKAGE* package = param;
3446 LPCWSTR component;
3447 MSICOMPONENT *comp;
3448 MSIFILE *file;
3449 typelib_struct tl_struct;
3450 ITypeLib *tlib;
3451 HMODULE module;
3452 HRESULT hr;
3454 component = MSI_RecordGetString(row,3);
3455 comp = get_loaded_component(package,component);
3456 if (!comp)
3457 return ERROR_SUCCESS;
3459 if (!comp->Enabled)
3461 TRACE("component is disabled\n");
3462 return ERROR_SUCCESS;
3465 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3467 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3468 comp->Action = comp->Installed;
3469 return ERROR_SUCCESS;
3471 comp->Action = INSTALLSTATE_LOCAL;
3473 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3475 TRACE("component has no key path\n");
3476 return ERROR_SUCCESS;
3478 ui_actiondata( package, szRegisterTypeLibraries, row );
3480 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3481 if (module)
3483 LPCWSTR guid;
3484 guid = MSI_RecordGetString(row,1);
3485 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3486 tl_struct.source = strdupW( file->TargetPath );
3487 tl_struct.path = NULL;
3489 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3490 (LONG_PTR)&tl_struct);
3492 if (tl_struct.path)
3494 LPWSTR help = NULL;
3495 LPCWSTR helpid;
3496 HRESULT res;
3498 helpid = MSI_RecordGetString(row,6);
3500 if (helpid) help = resolve_target_folder( package, helpid, FALSE, TRUE, NULL );
3501 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3502 msi_free(help);
3504 if (FAILED(res))
3505 ERR("Failed to register type library %s\n",
3506 debugstr_w(tl_struct.path));
3507 else
3508 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3510 ITypeLib_Release(tl_struct.ptLib);
3511 msi_free(tl_struct.path);
3513 else
3514 ERR("Failed to load type library %s\n",
3515 debugstr_w(tl_struct.source));
3517 FreeLibrary(module);
3518 msi_free(tl_struct.source);
3520 else
3522 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3523 if (FAILED(hr))
3525 ERR("Failed to load type library: %08x\n", hr);
3526 return ERROR_INSTALL_FAILURE;
3529 ITypeLib_Release(tlib);
3532 return ERROR_SUCCESS;
3535 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3538 * OK this is a bit confusing.. I am given a _Component key and I believe
3539 * that the file that is being registered as a type library is the "key file
3540 * of that component" which I interpret to mean "The file in the KeyPath of
3541 * that component".
3543 UINT rc;
3544 MSIQUERY * view;
3545 static const WCHAR Query[] =
3546 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3547 '`','T','y','p','e','L','i','b','`',0};
3549 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3550 if (rc != ERROR_SUCCESS)
3551 return ERROR_SUCCESS;
3553 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3554 msiobj_release(&view->hdr);
3555 return rc;
3558 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3560 MSIPACKAGE *package = param;
3561 LPCWSTR component, guid;
3562 MSICOMPONENT *comp;
3563 GUID libid;
3564 UINT version;
3565 LCID language;
3566 SYSKIND syskind;
3567 HRESULT hr;
3569 component = MSI_RecordGetString( row, 3 );
3570 comp = get_loaded_component( package, component );
3571 if (!comp)
3572 return ERROR_SUCCESS;
3574 if (!comp->Enabled)
3576 TRACE("component is disabled\n");
3577 return ERROR_SUCCESS;
3580 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3582 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3583 comp->Action = comp->Installed;
3584 return ERROR_SUCCESS;
3586 comp->Action = INSTALLSTATE_ABSENT;
3588 ui_actiondata( package, szUnregisterTypeLibraries, row );
3590 guid = MSI_RecordGetString( row, 1 );
3591 CLSIDFromString( (LPCWSTR)guid, &libid );
3592 version = MSI_RecordGetInteger( row, 4 );
3593 language = MSI_RecordGetInteger( row, 2 );
3595 #ifdef _WIN64
3596 syskind = SYS_WIN64;
3597 #else
3598 syskind = SYS_WIN32;
3599 #endif
3601 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3602 if (FAILED(hr))
3604 WARN("Failed to unregister typelib: %08x\n", hr);
3607 return ERROR_SUCCESS;
3610 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3612 UINT rc;
3613 MSIQUERY *view;
3614 static const WCHAR query[] =
3615 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3616 '`','T','y','p','e','L','i','b','`',0};
3618 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3619 if (rc != ERROR_SUCCESS)
3620 return ERROR_SUCCESS;
3622 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3623 msiobj_release( &view->hdr );
3624 return rc;
3627 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3629 static const WCHAR szlnk[] = {'.','l','n','k',0};
3630 LPCWSTR directory, extension;
3631 LPWSTR link_folder, link_file, filename;
3633 directory = MSI_RecordGetString( row, 2 );
3634 link_folder = resolve_target_folder( package, directory, FALSE, TRUE, NULL );
3636 /* may be needed because of a bug somewhere else */
3637 create_full_pathW( link_folder );
3639 filename = msi_dup_record_field( row, 3 );
3640 reduce_to_longfilename( filename );
3642 extension = strchrW( filename, '.' );
3643 if (!extension || strcmpiW( extension, szlnk ))
3645 int len = strlenW( filename );
3646 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3647 memcpy( filename + len, szlnk, sizeof(szlnk) );
3649 link_file = build_directory_name( 2, link_folder, filename );
3650 msi_free( link_folder );
3651 msi_free( filename );
3653 return link_file;
3656 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3658 MSIPACKAGE *package = param;
3659 LPWSTR link_file, deformated, path;
3660 LPCWSTR component, target;
3661 MSICOMPONENT *comp;
3662 IShellLinkW *sl = NULL;
3663 IPersistFile *pf = NULL;
3664 HRESULT res;
3666 component = MSI_RecordGetString(row, 4);
3667 comp = get_loaded_component(package, component);
3668 if (!comp)
3669 return ERROR_SUCCESS;
3671 if (!comp->Enabled)
3673 TRACE("component is disabled\n");
3674 return ERROR_SUCCESS;
3677 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3679 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3680 comp->Action = comp->Installed;
3681 return ERROR_SUCCESS;
3683 comp->Action = INSTALLSTATE_LOCAL;
3685 ui_actiondata(package,szCreateShortcuts,row);
3687 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3688 &IID_IShellLinkW, (LPVOID *) &sl );
3690 if (FAILED( res ))
3692 ERR("CLSID_ShellLink not available\n");
3693 goto err;
3696 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3697 if (FAILED( res ))
3699 ERR("QueryInterface(IID_IPersistFile) failed\n");
3700 goto err;
3703 target = MSI_RecordGetString(row, 5);
3704 if (strchrW(target, '['))
3706 deformat_string(package, target, &deformated);
3707 IShellLinkW_SetPath(sl,deformated);
3708 msi_free(deformated);
3710 else
3712 FIXME("poorly handled shortcut format, advertised shortcut\n");
3713 IShellLinkW_SetPath(sl,comp->FullKeypath);
3716 if (!MSI_RecordIsNull(row,6))
3718 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3719 deformat_string(package, arguments, &deformated);
3720 IShellLinkW_SetArguments(sl,deformated);
3721 msi_free(deformated);
3724 if (!MSI_RecordIsNull(row,7))
3726 LPCWSTR description = MSI_RecordGetString(row, 7);
3727 IShellLinkW_SetDescription(sl, description);
3730 if (!MSI_RecordIsNull(row,8))
3731 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3733 if (!MSI_RecordIsNull(row,9))
3735 INT index;
3736 LPCWSTR icon = MSI_RecordGetString(row, 9);
3738 path = build_icon_path(package, icon);
3739 index = MSI_RecordGetInteger(row,10);
3741 /* no value means 0 */
3742 if (index == MSI_NULL_INTEGER)
3743 index = 0;
3745 IShellLinkW_SetIconLocation(sl, path, index);
3746 msi_free(path);
3749 if (!MSI_RecordIsNull(row,11))
3750 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3752 if (!MSI_RecordIsNull(row,12))
3754 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3755 path = resolve_target_folder( package, wkdir, FALSE, TRUE, NULL );
3756 if (path)
3757 IShellLinkW_SetWorkingDirectory(sl, path);
3758 msi_free(path);
3761 link_file = get_link_file(package, row);
3763 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3764 IPersistFile_Save(pf, link_file, FALSE);
3766 msi_free(link_file);
3768 err:
3769 if (pf)
3770 IPersistFile_Release( pf );
3771 if (sl)
3772 IShellLinkW_Release( sl );
3774 return ERROR_SUCCESS;
3777 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3779 UINT rc;
3780 HRESULT res;
3781 MSIQUERY * view;
3782 static const WCHAR Query[] =
3783 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3784 '`','S','h','o','r','t','c','u','t','`',0};
3786 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3787 if (rc != ERROR_SUCCESS)
3788 return ERROR_SUCCESS;
3790 res = CoInitialize( NULL );
3792 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3793 msiobj_release(&view->hdr);
3795 if (SUCCEEDED(res))
3796 CoUninitialize();
3798 return rc;
3801 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3803 MSIPACKAGE *package = param;
3804 LPWSTR link_file;
3805 LPCWSTR component;
3806 MSICOMPONENT *comp;
3808 component = MSI_RecordGetString( row, 4 );
3809 comp = get_loaded_component( package, component );
3810 if (!comp)
3811 return ERROR_SUCCESS;
3813 if (!comp->Enabled)
3815 TRACE("component is disabled\n");
3816 return ERROR_SUCCESS;
3819 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3821 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3822 comp->Action = comp->Installed;
3823 return ERROR_SUCCESS;
3825 comp->Action = INSTALLSTATE_ABSENT;
3827 ui_actiondata( package, szRemoveShortcuts, row );
3829 link_file = get_link_file( package, row );
3831 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3832 if (!DeleteFileW( link_file ))
3834 WARN("Failed to remove shortcut file %u\n", GetLastError());
3836 msi_free( link_file );
3838 return ERROR_SUCCESS;
3841 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3843 UINT rc;
3844 MSIQUERY *view;
3845 static const WCHAR query[] =
3846 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3847 '`','S','h','o','r','t','c','u','t','`',0};
3849 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3850 if (rc != ERROR_SUCCESS)
3851 return ERROR_SUCCESS;
3853 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3854 msiobj_release( &view->hdr );
3856 return rc;
3859 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3861 MSIPACKAGE* package = param;
3862 HANDLE the_file;
3863 LPWSTR FilePath;
3864 LPCWSTR FileName;
3865 CHAR buffer[1024];
3866 DWORD sz;
3867 UINT rc;
3869 FileName = MSI_RecordGetString(row,1);
3870 if (!FileName)
3872 ERR("Unable to get FileName\n");
3873 return ERROR_SUCCESS;
3876 FilePath = build_icon_path(package,FileName);
3878 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3880 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3881 FILE_ATTRIBUTE_NORMAL, NULL);
3883 if (the_file == INVALID_HANDLE_VALUE)
3885 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3886 msi_free(FilePath);
3887 return ERROR_SUCCESS;
3892 DWORD write;
3893 sz = 1024;
3894 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3895 if (rc != ERROR_SUCCESS)
3897 ERR("Failed to get stream\n");
3898 CloseHandle(the_file);
3899 DeleteFileW(FilePath);
3900 break;
3902 WriteFile(the_file,buffer,sz,&write,NULL);
3903 } while (sz == 1024);
3905 msi_free(FilePath);
3906 CloseHandle(the_file);
3908 return ERROR_SUCCESS;
3911 static UINT msi_publish_icons(MSIPACKAGE *package)
3913 UINT r;
3914 MSIQUERY *view;
3916 static const WCHAR query[]= {
3917 'S','E','L','E','C','T',' ','*',' ',
3918 'F','R','O','M',' ','`','I','c','o','n','`',0};
3920 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3921 if (r == ERROR_SUCCESS)
3923 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3924 msiobj_release(&view->hdr);
3927 return ERROR_SUCCESS;
3930 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3932 UINT r;
3933 HKEY source;
3934 LPWSTR buffer;
3935 MSIMEDIADISK *disk;
3936 MSISOURCELISTINFO *info;
3938 r = RegCreateKeyW(hkey, szSourceList, &source);
3939 if (r != ERROR_SUCCESS)
3940 return r;
3942 RegCloseKey(source);
3944 buffer = strrchrW(package->PackagePath, '\\') + 1;
3945 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3946 package->Context, MSICODE_PRODUCT,
3947 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3948 if (r != ERROR_SUCCESS)
3949 return r;
3951 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3952 package->Context, MSICODE_PRODUCT,
3953 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3954 if (r != ERROR_SUCCESS)
3955 return r;
3957 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3958 package->Context, MSICODE_PRODUCT,
3959 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3960 if (r != ERROR_SUCCESS)
3961 return r;
3963 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3965 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3966 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3967 info->options, info->value);
3968 else
3969 MsiSourceListSetInfoW(package->ProductCode, NULL,
3970 info->context, info->options,
3971 info->property, info->value);
3974 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3976 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3977 disk->context, disk->options,
3978 disk->disk_id, disk->volume_label, disk->disk_prompt);
3981 return ERROR_SUCCESS;
3984 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3986 MSIHANDLE hdb, suminfo;
3987 WCHAR guids[MAX_PATH];
3988 WCHAR packcode[SQUISH_GUID_SIZE];
3989 LPWSTR buffer;
3990 LPWSTR ptr;
3991 DWORD langid;
3992 DWORD size;
3993 UINT r;
3995 static const WCHAR szProductLanguage[] =
3996 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3997 static const WCHAR szARPProductIcon[] =
3998 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3999 static const WCHAR szProductVersion[] =
4000 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4001 static const WCHAR szAssignment[] =
4002 {'A','s','s','i','g','n','m','e','n','t',0};
4003 static const WCHAR szAdvertiseFlags[] =
4004 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
4005 static const WCHAR szClients[] =
4006 {'C','l','i','e','n','t','s',0};
4007 static const WCHAR szColon[] = {':',0};
4009 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4010 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4011 msi_free(buffer);
4013 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4014 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4016 /* FIXME */
4017 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4019 buffer = msi_dup_property(package->db, szARPProductIcon);
4020 if (buffer)
4022 LPWSTR path = build_icon_path(package,buffer);
4023 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4024 msi_free(path);
4025 msi_free(buffer);
4028 buffer = msi_dup_property(package->db, szProductVersion);
4029 if (buffer)
4031 DWORD verdword = msi_version_str_to_dword(buffer);
4032 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4033 msi_free(buffer);
4036 msi_reg_set_val_dword(hkey, szAssignment, 0);
4037 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4038 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4039 msi_reg_set_val_str(hkey, szClients, szColon);
4041 hdb = alloc_msihandle(&package->db->hdr);
4042 if (!hdb)
4043 return ERROR_NOT_ENOUGH_MEMORY;
4045 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4046 MsiCloseHandle(hdb);
4047 if (r != ERROR_SUCCESS)
4048 goto done;
4050 size = MAX_PATH;
4051 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4052 NULL, guids, &size);
4053 if (r != ERROR_SUCCESS)
4054 goto done;
4056 ptr = strchrW(guids, ';');
4057 if (ptr) *ptr = 0;
4058 squash_guid(guids, packcode);
4059 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4061 done:
4062 MsiCloseHandle(suminfo);
4063 return ERROR_SUCCESS;
4066 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4068 UINT r;
4069 HKEY hkey;
4070 LPWSTR upgrade;
4071 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4073 upgrade = msi_dup_property(package->db, szUpgradeCode);
4074 if (!upgrade)
4075 return ERROR_SUCCESS;
4077 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4079 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4080 if (r != ERROR_SUCCESS)
4081 goto done;
4083 else
4085 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4086 if (r != ERROR_SUCCESS)
4087 goto done;
4090 squash_guid(package->ProductCode, squashed_pc);
4091 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4093 RegCloseKey(hkey);
4095 done:
4096 msi_free(upgrade);
4097 return r;
4100 static BOOL msi_check_publish(MSIPACKAGE *package)
4102 MSIFEATURE *feature;
4104 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4106 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4107 return TRUE;
4110 return FALSE;
4113 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4115 MSIFEATURE *feature;
4117 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4119 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4120 return FALSE;
4123 return TRUE;
4126 static UINT msi_publish_patches( MSIPACKAGE *package )
4128 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4129 WCHAR patch_squashed[GUID_SIZE];
4130 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4131 LONG res;
4132 MSIPATCHINFO *patch;
4133 UINT r;
4134 WCHAR *p, *all_patches = NULL;
4135 DWORD len = 0;
4137 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4138 if (r != ERROR_SUCCESS)
4139 return ERROR_FUNCTION_FAILED;
4141 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4142 if (res != ERROR_SUCCESS)
4144 r = ERROR_FUNCTION_FAILED;
4145 goto done;
4148 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4149 if (r != ERROR_SUCCESS)
4150 goto done;
4152 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4154 squash_guid( patch->patchcode, patch_squashed );
4155 len += strlenW( patch_squashed ) + 1;
4158 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4159 if (!all_patches)
4160 goto done;
4162 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4164 HKEY patch_key;
4166 squash_guid( patch->patchcode, p );
4167 p += strlenW( p ) + 1;
4169 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4170 (const BYTE *)patch->transforms,
4171 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4172 if (res != ERROR_SUCCESS)
4173 goto done;
4175 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4176 if (r != ERROR_SUCCESS)
4177 goto done;
4179 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4180 (const BYTE *)patch->localfile,
4181 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4182 RegCloseKey( patch_key );
4183 if (res != ERROR_SUCCESS)
4184 goto done;
4186 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4187 if (res != ERROR_SUCCESS)
4188 goto done;
4190 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4191 RegCloseKey( patch_key );
4192 if (res != ERROR_SUCCESS)
4193 goto done;
4196 all_patches[len] = 0;
4197 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4198 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4199 if (res != ERROR_SUCCESS)
4200 goto done;
4202 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4203 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4204 if (res != ERROR_SUCCESS)
4205 r = ERROR_FUNCTION_FAILED;
4207 done:
4208 RegCloseKey( product_patches_key );
4209 RegCloseKey( patches_key );
4210 RegCloseKey( product_key );
4211 msi_free( all_patches );
4212 return r;
4216 * 99% of the work done here is only done for
4217 * advertised installs. However this is where the
4218 * Icon table is processed and written out
4219 * so that is what I am going to do here.
4221 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4223 UINT rc;
4224 HKEY hukey = NULL, hudkey = NULL;
4225 MSIRECORD *uirow;
4227 if (!list_empty(&package->patches))
4229 rc = msi_publish_patches(package);
4230 if (rc != ERROR_SUCCESS)
4231 goto end;
4234 /* FIXME: also need to publish if the product is in advertise mode */
4235 if (!msi_check_publish(package))
4236 return ERROR_SUCCESS;
4238 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4239 &hukey, TRUE);
4240 if (rc != ERROR_SUCCESS)
4241 goto end;
4243 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4244 NULL, &hudkey, TRUE);
4245 if (rc != ERROR_SUCCESS)
4246 goto end;
4248 rc = msi_publish_upgrade_code(package);
4249 if (rc != ERROR_SUCCESS)
4250 goto end;
4252 rc = msi_publish_product_properties(package, hukey);
4253 if (rc != ERROR_SUCCESS)
4254 goto end;
4256 rc = msi_publish_sourcelist(package, hukey);
4257 if (rc != ERROR_SUCCESS)
4258 goto end;
4260 rc = msi_publish_icons(package);
4262 end:
4263 uirow = MSI_CreateRecord( 1 );
4264 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4265 ui_actiondata( package, szPublishProduct, uirow );
4266 msiobj_release( &uirow->hdr );
4268 RegCloseKey(hukey);
4269 RegCloseKey(hudkey);
4271 return rc;
4274 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4276 WCHAR *filename, *ptr, *folder, *ret;
4277 const WCHAR *dirprop;
4279 filename = msi_dup_record_field( row, 2 );
4280 if (filename && (ptr = strchrW( filename, '|' )))
4281 ptr++;
4282 else
4283 ptr = filename;
4285 dirprop = MSI_RecordGetString( row, 3 );
4286 if (dirprop)
4288 folder = resolve_target_folder( package, dirprop, FALSE, TRUE, NULL );
4289 if (!folder)
4290 folder = msi_dup_property( package->db, dirprop );
4292 else
4293 folder = msi_dup_property( package->db, szWindowsFolder );
4295 if (!folder)
4297 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4298 msi_free( filename );
4299 return NULL;
4302 ret = build_directory_name( 2, folder, ptr );
4304 msi_free( filename );
4305 msi_free( folder );
4306 return ret;
4309 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4311 MSIPACKAGE *package = param;
4312 LPCWSTR component, section, key, value, identifier;
4313 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4314 MSIRECORD * uirow;
4315 INT action;
4316 MSICOMPONENT *comp;
4318 component = MSI_RecordGetString(row, 8);
4319 comp = get_loaded_component(package,component);
4320 if (!comp)
4321 return ERROR_SUCCESS;
4323 if (!comp->Enabled)
4325 TRACE("component is disabled\n");
4326 return ERROR_SUCCESS;
4329 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4331 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4332 comp->Action = comp->Installed;
4333 return ERROR_SUCCESS;
4335 comp->Action = INSTALLSTATE_LOCAL;
4337 identifier = MSI_RecordGetString(row,1);
4338 section = MSI_RecordGetString(row,4);
4339 key = MSI_RecordGetString(row,5);
4340 value = MSI_RecordGetString(row,6);
4341 action = MSI_RecordGetInteger(row,7);
4343 deformat_string(package,section,&deformated_section);
4344 deformat_string(package,key,&deformated_key);
4345 deformat_string(package,value,&deformated_value);
4347 fullname = get_ini_file_name(package, row);
4349 if (action == 0)
4351 TRACE("Adding value %s to section %s in %s\n",
4352 debugstr_w(deformated_key), debugstr_w(deformated_section),
4353 debugstr_w(fullname));
4354 WritePrivateProfileStringW(deformated_section, deformated_key,
4355 deformated_value, fullname);
4357 else if (action == 1)
4359 WCHAR returned[10];
4360 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4361 returned, 10, fullname);
4362 if (returned[0] == 0)
4364 TRACE("Adding value %s to section %s in %s\n",
4365 debugstr_w(deformated_key), debugstr_w(deformated_section),
4366 debugstr_w(fullname));
4368 WritePrivateProfileStringW(deformated_section, deformated_key,
4369 deformated_value, fullname);
4372 else if (action == 3)
4373 FIXME("Append to existing section not yet implemented\n");
4375 uirow = MSI_CreateRecord(4);
4376 MSI_RecordSetStringW(uirow,1,identifier);
4377 MSI_RecordSetStringW(uirow,2,deformated_section);
4378 MSI_RecordSetStringW(uirow,3,deformated_key);
4379 MSI_RecordSetStringW(uirow,4,deformated_value);
4380 ui_actiondata(package,szWriteIniValues,uirow);
4381 msiobj_release( &uirow->hdr );
4383 msi_free(fullname);
4384 msi_free(deformated_key);
4385 msi_free(deformated_value);
4386 msi_free(deformated_section);
4387 return ERROR_SUCCESS;
4390 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4392 UINT rc;
4393 MSIQUERY * view;
4394 static const WCHAR ExecSeqQuery[] =
4395 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4396 '`','I','n','i','F','i','l','e','`',0};
4398 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4399 if (rc != ERROR_SUCCESS)
4401 TRACE("no IniFile table\n");
4402 return ERROR_SUCCESS;
4405 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4406 msiobj_release(&view->hdr);
4407 return rc;
4410 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4412 MSIPACKAGE *package = param;
4413 LPCWSTR component, section, key, value, identifier;
4414 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4415 MSICOMPONENT *comp;
4416 MSIRECORD *uirow;
4417 INT action;
4419 component = MSI_RecordGetString( row, 8 );
4420 comp = get_loaded_component( package, component );
4421 if (!comp)
4422 return ERROR_SUCCESS;
4424 if (!comp->Enabled)
4426 TRACE("component is disabled\n");
4427 return ERROR_SUCCESS;
4430 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4432 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4433 comp->Action = comp->Installed;
4434 return ERROR_SUCCESS;
4436 comp->Action = INSTALLSTATE_ABSENT;
4438 identifier = MSI_RecordGetString( row, 1 );
4439 section = MSI_RecordGetString( row, 4 );
4440 key = MSI_RecordGetString( row, 5 );
4441 value = MSI_RecordGetString( row, 6 );
4442 action = MSI_RecordGetInteger( row, 7 );
4444 deformat_string( package, section, &deformated_section );
4445 deformat_string( package, key, &deformated_key );
4446 deformat_string( package, value, &deformated_value );
4448 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4450 filename = get_ini_file_name( package, row );
4452 TRACE("Removing key %s from section %s in %s\n",
4453 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4455 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4457 WARN("Unable to remove key %u\n", GetLastError());
4459 msi_free( filename );
4461 else
4462 FIXME("Unsupported action %d\n", action);
4465 uirow = MSI_CreateRecord( 4 );
4466 MSI_RecordSetStringW( uirow, 1, identifier );
4467 MSI_RecordSetStringW( uirow, 2, deformated_section );
4468 MSI_RecordSetStringW( uirow, 3, deformated_key );
4469 MSI_RecordSetStringW( uirow, 4, deformated_value );
4470 ui_actiondata( package, szRemoveIniValues, uirow );
4471 msiobj_release( &uirow->hdr );
4473 msi_free( deformated_key );
4474 msi_free( deformated_value );
4475 msi_free( deformated_section );
4476 return ERROR_SUCCESS;
4479 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4481 MSIPACKAGE *package = param;
4482 LPCWSTR component, section, key, value, identifier;
4483 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4484 MSICOMPONENT *comp;
4485 MSIRECORD *uirow;
4486 INT action;
4488 component = MSI_RecordGetString( row, 8 );
4489 comp = get_loaded_component( package, component );
4490 if (!comp)
4491 return ERROR_SUCCESS;
4493 if (!comp->Enabled)
4495 TRACE("component is disabled\n");
4496 return ERROR_SUCCESS;
4499 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4501 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4502 comp->Action = comp->Installed;
4503 return ERROR_SUCCESS;
4505 comp->Action = INSTALLSTATE_LOCAL;
4507 identifier = MSI_RecordGetString( row, 1 );
4508 section = MSI_RecordGetString( row, 4 );
4509 key = MSI_RecordGetString( row, 5 );
4510 value = MSI_RecordGetString( row, 6 );
4511 action = MSI_RecordGetInteger( row, 7 );
4513 deformat_string( package, section, &deformated_section );
4514 deformat_string( package, key, &deformated_key );
4515 deformat_string( package, value, &deformated_value );
4517 if (action == msidbIniFileActionRemoveLine)
4519 filename = get_ini_file_name( package, row );
4521 TRACE("Removing key %s from section %s in %s\n",
4522 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4524 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4526 WARN("Unable to remove key %u\n", GetLastError());
4528 msi_free( filename );
4530 else
4531 FIXME("Unsupported action %d\n", action);
4533 uirow = MSI_CreateRecord( 4 );
4534 MSI_RecordSetStringW( uirow, 1, identifier );
4535 MSI_RecordSetStringW( uirow, 2, deformated_section );
4536 MSI_RecordSetStringW( uirow, 3, deformated_key );
4537 MSI_RecordSetStringW( uirow, 4, deformated_value );
4538 ui_actiondata( package, szRemoveIniValues, uirow );
4539 msiobj_release( &uirow->hdr );
4541 msi_free( deformated_key );
4542 msi_free( deformated_value );
4543 msi_free( deformated_section );
4544 return ERROR_SUCCESS;
4547 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4549 UINT rc;
4550 MSIQUERY *view;
4551 static const WCHAR query[] =
4552 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4553 '`','I','n','i','F','i','l','e','`',0};
4554 static const WCHAR remove_query[] =
4555 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4556 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4558 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4559 if (rc == ERROR_SUCCESS)
4561 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4562 msiobj_release( &view->hdr );
4563 if (rc != ERROR_SUCCESS)
4564 return rc;
4567 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4568 if (rc == ERROR_SUCCESS)
4570 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4571 msiobj_release( &view->hdr );
4572 if (rc != ERROR_SUCCESS)
4573 return rc;
4576 return ERROR_SUCCESS;
4579 static void register_dll( const WCHAR *dll, BOOL unregister )
4581 HMODULE hmod;
4583 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4584 if (hmod)
4586 HRESULT (WINAPI *func_ptr)( void );
4587 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4589 func_ptr = (void *)GetProcAddress( hmod, func );
4590 if (func_ptr)
4592 HRESULT hr = func_ptr();
4593 if (FAILED( hr ))
4594 WARN("failed to register dll 0x%08x\n", hr);
4596 else
4597 WARN("entry point %s not found\n", func);
4598 FreeLibrary( hmod );
4599 return;
4601 WARN("failed to load library %u\n", GetLastError());
4604 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4606 MSIPACKAGE *package = param;
4607 LPCWSTR filename;
4608 MSIFILE *file;
4609 MSIRECORD *uirow;
4611 filename = MSI_RecordGetString(row,1);
4612 file = get_loaded_file( package, filename );
4614 if (!file)
4616 ERR("Unable to find file id %s\n",debugstr_w(filename));
4617 return ERROR_SUCCESS;
4620 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4622 register_dll( file->TargetPath, FALSE );
4624 uirow = MSI_CreateRecord( 2 );
4625 MSI_RecordSetStringW( uirow, 1, filename );
4626 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4627 ui_actiondata( package, szSelfRegModules, uirow );
4628 msiobj_release( &uirow->hdr );
4630 return ERROR_SUCCESS;
4633 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4635 UINT rc;
4636 MSIQUERY * view;
4637 static const WCHAR ExecSeqQuery[] =
4638 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4639 '`','S','e','l','f','R','e','g','`',0};
4641 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4642 if (rc != ERROR_SUCCESS)
4644 TRACE("no SelfReg table\n");
4645 return ERROR_SUCCESS;
4648 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4649 msiobj_release(&view->hdr);
4651 return ERROR_SUCCESS;
4654 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4656 MSIPACKAGE *package = param;
4657 LPCWSTR filename;
4658 MSIFILE *file;
4659 MSIRECORD *uirow;
4661 filename = MSI_RecordGetString( row, 1 );
4662 file = get_loaded_file( package, filename );
4664 if (!file)
4666 ERR("Unable to find file id %s\n", debugstr_w(filename));
4667 return ERROR_SUCCESS;
4670 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4672 register_dll( file->TargetPath, TRUE );
4674 uirow = MSI_CreateRecord( 2 );
4675 MSI_RecordSetStringW( uirow, 1, filename );
4676 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4677 ui_actiondata( package, szSelfUnregModules, uirow );
4678 msiobj_release( &uirow->hdr );
4680 return ERROR_SUCCESS;
4683 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4685 UINT rc;
4686 MSIQUERY *view;
4687 static const WCHAR query[] =
4688 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4689 '`','S','e','l','f','R','e','g','`',0};
4691 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4692 if (rc != ERROR_SUCCESS)
4694 TRACE("no SelfReg table\n");
4695 return ERROR_SUCCESS;
4698 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4699 msiobj_release( &view->hdr );
4701 return ERROR_SUCCESS;
4704 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4706 MSIFEATURE *feature;
4707 UINT rc;
4708 HKEY hkey = NULL, userdata = NULL;
4710 if (!msi_check_publish(package))
4711 return ERROR_SUCCESS;
4713 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4714 &hkey, TRUE);
4715 if (rc != ERROR_SUCCESS)
4716 goto end;
4718 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4719 &userdata, TRUE);
4720 if (rc != ERROR_SUCCESS)
4721 goto end;
4723 /* here the guids are base 85 encoded */
4724 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4726 ComponentList *cl;
4727 LPWSTR data = NULL;
4728 GUID clsid;
4729 INT size;
4730 BOOL absent = FALSE;
4731 MSIRECORD *uirow;
4733 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4734 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4735 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4737 size = 1;
4738 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4740 size += 21;
4742 if (feature->Feature_Parent)
4743 size += strlenW( feature->Feature_Parent )+2;
4745 data = msi_alloc(size * sizeof(WCHAR));
4747 data[0] = 0;
4748 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4750 MSICOMPONENT* component = cl->component;
4751 WCHAR buf[21];
4753 buf[0] = 0;
4754 if (component->ComponentId)
4756 TRACE("From %s\n",debugstr_w(component->ComponentId));
4757 CLSIDFromString(component->ComponentId, &clsid);
4758 encode_base85_guid(&clsid,buf);
4759 TRACE("to %s\n",debugstr_w(buf));
4760 strcatW(data,buf);
4764 if (feature->Feature_Parent)
4766 static const WCHAR sep[] = {'\2',0};
4767 strcatW(data,sep);
4768 strcatW(data,feature->Feature_Parent);
4771 msi_reg_set_val_str( userdata, feature->Feature, data );
4772 msi_free(data);
4774 size = 0;
4775 if (feature->Feature_Parent)
4776 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4777 if (!absent)
4779 size += sizeof(WCHAR);
4780 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4781 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4783 else
4785 size += 2*sizeof(WCHAR);
4786 data = msi_alloc(size);
4787 data[0] = 0x6;
4788 data[1] = 0;
4789 if (feature->Feature_Parent)
4790 strcpyW( &data[1], feature->Feature_Parent );
4791 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4792 (LPBYTE)data,size);
4793 msi_free(data);
4796 /* the UI chunk */
4797 uirow = MSI_CreateRecord( 1 );
4798 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4799 ui_actiondata( package, szPublishFeatures, uirow);
4800 msiobj_release( &uirow->hdr );
4801 /* FIXME: call ui_progress? */
4804 end:
4805 RegCloseKey(hkey);
4806 RegCloseKey(userdata);
4807 return rc;
4810 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4812 UINT r;
4813 HKEY hkey;
4814 MSIRECORD *uirow;
4816 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4818 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4819 &hkey, FALSE);
4820 if (r == ERROR_SUCCESS)
4822 RegDeleteValueW(hkey, feature->Feature);
4823 RegCloseKey(hkey);
4826 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4827 &hkey, FALSE);
4828 if (r == ERROR_SUCCESS)
4830 RegDeleteValueW(hkey, feature->Feature);
4831 RegCloseKey(hkey);
4834 uirow = MSI_CreateRecord( 1 );
4835 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4836 ui_actiondata( package, szUnpublishFeatures, uirow );
4837 msiobj_release( &uirow->hdr );
4839 return ERROR_SUCCESS;
4842 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4844 MSIFEATURE *feature;
4846 if (!msi_check_unpublish(package))
4847 return ERROR_SUCCESS;
4849 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4851 msi_unpublish_feature(package, feature);
4854 return ERROR_SUCCESS;
4857 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4859 SYSTEMTIME systime;
4860 DWORD size, langid;
4861 WCHAR date[9], *val, *buffer;
4862 const WCHAR *prop, *key;
4864 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4865 static const WCHAR szWindowsInstaller[] =
4866 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4867 static const WCHAR modpath_fmt[] =
4868 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4869 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4870 static const WCHAR szModifyPath[] =
4871 {'M','o','d','i','f','y','P','a','t','h',0};
4872 static const WCHAR szUninstallString[] =
4873 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4874 static const WCHAR szEstimatedSize[] =
4875 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4876 static const WCHAR szProductLanguage[] =
4877 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4878 static const WCHAR szProductVersion[] =
4879 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4880 static const WCHAR szDisplayVersion[] =
4881 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4882 static const WCHAR szInstallSource[] =
4883 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4884 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4885 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4886 static const WCHAR szAuthorizedCDFPrefix[] =
4887 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4888 static const WCHAR szARPCONTACT[] =
4889 {'A','R','P','C','O','N','T','A','C','T',0};
4890 static const WCHAR szContact[] =
4891 {'C','o','n','t','a','c','t',0};
4892 static const WCHAR szARPCOMMENTS[] =
4893 {'A','R','P','C','O','M','M','E','N','T','S',0};
4894 static const WCHAR szComments[] =
4895 {'C','o','m','m','e','n','t','s',0};
4896 static const WCHAR szProductName[] =
4897 {'P','r','o','d','u','c','t','N','a','m','e',0};
4898 static const WCHAR szDisplayName[] =
4899 {'D','i','s','p','l','a','y','N','a','m','e',0};
4900 static const WCHAR szARPHELPLINK[] =
4901 {'A','R','P','H','E','L','P','L','I','N','K',0};
4902 static const WCHAR szHelpLink[] =
4903 {'H','e','l','p','L','i','n','k',0};
4904 static const WCHAR szARPHELPTELEPHONE[] =
4905 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4906 static const WCHAR szHelpTelephone[] =
4907 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4908 static const WCHAR szARPINSTALLLOCATION[] =
4909 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4910 static const WCHAR szInstallLocation[] =
4911 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4912 static const WCHAR szManufacturer[] =
4913 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4914 static const WCHAR szPublisher[] =
4915 {'P','u','b','l','i','s','h','e','r',0};
4916 static const WCHAR szARPREADME[] =
4917 {'A','R','P','R','E','A','D','M','E',0};
4918 static const WCHAR szReadme[] =
4919 {'R','e','a','d','M','e',0};
4920 static const WCHAR szARPSIZE[] =
4921 {'A','R','P','S','I','Z','E',0};
4922 static const WCHAR szSize[] =
4923 {'S','i','z','e',0};
4924 static const WCHAR szARPURLINFOABOUT[] =
4925 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4926 static const WCHAR szURLInfoAbout[] =
4927 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4928 static const WCHAR szARPURLUPDATEINFO[] =
4929 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4930 static const WCHAR szURLUpdateInfo[] =
4931 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4933 static const WCHAR *propval[] = {
4934 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4935 szARPCONTACT, szContact,
4936 szARPCOMMENTS, szComments,
4937 szProductName, szDisplayName,
4938 szARPHELPLINK, szHelpLink,
4939 szARPHELPTELEPHONE, szHelpTelephone,
4940 szARPINSTALLLOCATION, szInstallLocation,
4941 cszSourceDir, szInstallSource,
4942 szManufacturer, szPublisher,
4943 szARPREADME, szReadme,
4944 szARPSIZE, szSize,
4945 szARPURLINFOABOUT, szURLInfoAbout,
4946 szARPURLUPDATEINFO, szURLUpdateInfo,
4947 NULL
4949 const WCHAR **p = propval;
4951 while (*p)
4953 prop = *p++;
4954 key = *p++;
4955 val = msi_dup_property(package->db, prop);
4956 msi_reg_set_val_str(hkey, key, val);
4957 msi_free(val);
4960 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4962 size = deformat_string(package, modpath_fmt, &buffer);
4963 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4964 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4965 msi_free(buffer);
4967 /* FIXME: Write real Estimated Size when we have it */
4968 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4970 GetLocalTime(&systime);
4971 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4972 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4974 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4975 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4977 buffer = msi_dup_property(package->db, szProductVersion);
4978 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4979 if (buffer)
4981 DWORD verdword = msi_version_str_to_dword(buffer);
4983 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4984 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4985 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4986 msi_free(buffer);
4989 return ERROR_SUCCESS;
4992 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4994 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4995 MSIRECORD *uirow;
4996 LPWSTR upgrade_code;
4997 HKEY hkey, props;
4998 HKEY upgrade;
4999 UINT rc;
5001 /* FIXME: also need to publish if the product is in advertise mode */
5002 if (!msi_check_publish(package))
5003 return ERROR_SUCCESS;
5005 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
5006 if (rc != ERROR_SUCCESS)
5007 return rc;
5009 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5010 NULL, &props, TRUE);
5011 if (rc != ERROR_SUCCESS)
5012 goto done;
5014 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
5015 msi_free( package->db->localfile );
5016 package->db->localfile = NULL;
5018 rc = msi_publish_install_properties(package, hkey);
5019 if (rc != ERROR_SUCCESS)
5020 goto done;
5022 rc = msi_publish_install_properties(package, props);
5023 if (rc != ERROR_SUCCESS)
5024 goto done;
5026 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5027 if (upgrade_code)
5029 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
5030 squash_guid(package->ProductCode, squashed_pc);
5031 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
5032 RegCloseKey(upgrade);
5033 msi_free(upgrade_code);
5036 done:
5037 uirow = MSI_CreateRecord( 1 );
5038 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5039 ui_actiondata( package, szRegisterProduct, uirow );
5040 msiobj_release( &uirow->hdr );
5042 RegCloseKey(hkey);
5043 return ERROR_SUCCESS;
5046 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5048 return execute_script(package,INSTALL_SCRIPT);
5051 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
5053 WCHAR *upgrade, **features;
5054 BOOL full_uninstall = TRUE;
5055 MSIFEATURE *feature;
5056 MSIPATCHINFO *patch;
5058 static const WCHAR szUpgradeCode[] =
5059 {'U','p','g','r','a','d','e','C','o','d','e',0};
5061 features = msi_split_string(remove, ',');
5062 if (!features)
5064 ERR("REMOVE feature list is empty!\n");
5065 return ERROR_FUNCTION_FAILED;
5068 if (!strcmpW( features[0], szAll ))
5069 full_uninstall = TRUE;
5070 else
5072 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5074 if (feature->Action != INSTALLSTATE_ABSENT)
5075 full_uninstall = FALSE;
5078 msi_free(features);
5080 if (!full_uninstall)
5081 return ERROR_SUCCESS;
5083 MSIREG_DeleteProductKey(package->ProductCode);
5084 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5085 MSIREG_DeleteUninstallKey(package);
5087 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5088 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5089 MSIREG_DeleteUserProductKey(package->ProductCode);
5090 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5092 upgrade = msi_dup_property(package->db, szUpgradeCode);
5093 if (upgrade)
5095 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5096 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5097 msi_free(upgrade);
5100 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5102 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5105 return ERROR_SUCCESS;
5108 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5110 UINT rc;
5111 WCHAR *remove;
5113 /* turn off scheduling */
5114 package->script->CurrentlyScripting= FALSE;
5116 /* first do the same as an InstallExecute */
5117 rc = ACTION_InstallExecute(package);
5118 if (rc != ERROR_SUCCESS)
5119 return rc;
5121 /* then handle Commit Actions */
5122 rc = execute_script(package,COMMIT_SCRIPT);
5123 if (rc != ERROR_SUCCESS)
5124 return rc;
5126 remove = msi_dup_property(package->db, szRemove);
5127 if (remove)
5128 rc = msi_unpublish_product(package, remove);
5130 msi_free(remove);
5131 return rc;
5134 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5136 static const WCHAR RunOnce[] = {
5137 'S','o','f','t','w','a','r','e','\\',
5138 'M','i','c','r','o','s','o','f','t','\\',
5139 'W','i','n','d','o','w','s','\\',
5140 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5141 'R','u','n','O','n','c','e',0};
5142 static const WCHAR InstallRunOnce[] = {
5143 'S','o','f','t','w','a','r','e','\\',
5144 'M','i','c','r','o','s','o','f','t','\\',
5145 'W','i','n','d','o','w','s','\\',
5146 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5147 'I','n','s','t','a','l','l','e','r','\\',
5148 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5150 static const WCHAR msiexec_fmt[] = {
5151 '%','s',
5152 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5153 '\"','%','s','\"',0};
5154 static const WCHAR install_fmt[] = {
5155 '/','I',' ','\"','%','s','\"',' ',
5156 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5157 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5158 WCHAR buffer[256], sysdir[MAX_PATH];
5159 HKEY hkey;
5160 WCHAR squished_pc[100];
5162 squash_guid(package->ProductCode,squished_pc);
5164 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5165 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5166 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5167 squished_pc);
5169 msi_reg_set_val_str( hkey, squished_pc, buffer );
5170 RegCloseKey(hkey);
5172 TRACE("Reboot command %s\n",debugstr_w(buffer));
5174 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5175 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5177 msi_reg_set_val_str( hkey, squished_pc, buffer );
5178 RegCloseKey(hkey);
5180 return ERROR_INSTALL_SUSPEND;
5183 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5185 DWORD attrib;
5186 UINT rc;
5189 * We are currently doing what should be done here in the top level Install
5190 * however for Administrative and uninstalls this step will be needed
5192 if (!package->PackagePath)
5193 return ERROR_SUCCESS;
5195 msi_set_sourcedir_props(package, TRUE);
5197 attrib = GetFileAttributesW(package->db->path);
5198 if (attrib == INVALID_FILE_ATTRIBUTES)
5200 LPWSTR prompt;
5201 LPWSTR msg;
5202 DWORD size = 0;
5204 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5205 package->Context, MSICODE_PRODUCT,
5206 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5207 if (rc == ERROR_MORE_DATA)
5209 prompt = msi_alloc(size * sizeof(WCHAR));
5210 MsiSourceListGetInfoW(package->ProductCode, NULL,
5211 package->Context, MSICODE_PRODUCT,
5212 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5214 else
5215 prompt = strdupW(package->db->path);
5217 msg = generate_error_string(package,1302,1,prompt);
5218 while(attrib == INVALID_FILE_ATTRIBUTES)
5220 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5221 if (rc == IDCANCEL)
5223 rc = ERROR_INSTALL_USEREXIT;
5224 break;
5226 attrib = GetFileAttributesW(package->db->path);
5228 msi_free(prompt);
5229 rc = ERROR_SUCCESS;
5231 else
5232 return ERROR_SUCCESS;
5234 return rc;
5237 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5239 HKEY hkey = 0;
5240 LPWSTR buffer, productid = NULL;
5241 UINT i, rc = ERROR_SUCCESS;
5242 MSIRECORD *uirow;
5244 static const WCHAR szPropKeys[][80] =
5246 {'P','r','o','d','u','c','t','I','D',0},
5247 {'U','S','E','R','N','A','M','E',0},
5248 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5249 {0},
5252 static const WCHAR szRegKeys[][80] =
5254 {'P','r','o','d','u','c','t','I','D',0},
5255 {'R','e','g','O','w','n','e','r',0},
5256 {'R','e','g','C','o','m','p','a','n','y',0},
5257 {0},
5260 if (msi_check_unpublish(package))
5262 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5263 goto end;
5266 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5267 if (!productid)
5268 goto end;
5270 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5271 NULL, &hkey, TRUE);
5272 if (rc != ERROR_SUCCESS)
5273 goto end;
5275 for( i = 0; szPropKeys[i][0]; i++ )
5277 buffer = msi_dup_property( package->db, szPropKeys[i] );
5278 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5279 msi_free( buffer );
5282 end:
5283 uirow = MSI_CreateRecord( 1 );
5284 MSI_RecordSetStringW( uirow, 1, productid );
5285 ui_actiondata( package, szRegisterUser, uirow );
5286 msiobj_release( &uirow->hdr );
5288 msi_free(productid);
5289 RegCloseKey(hkey);
5290 return rc;
5294 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5296 UINT rc;
5298 package->script->InWhatSequence |= SEQUENCE_EXEC;
5299 rc = ACTION_ProcessExecSequence(package,FALSE);
5300 return rc;
5304 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5306 MSIPACKAGE *package = param;
5307 LPCWSTR compgroupid, component, feature, qualifier, text;
5308 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5309 HKEY hkey = NULL;
5310 UINT rc;
5311 MSICOMPONENT *comp;
5312 MSIFEATURE *feat;
5313 DWORD sz;
5314 MSIRECORD *uirow;
5315 int len;
5317 feature = MSI_RecordGetString(rec, 5);
5318 feat = get_loaded_feature(package, feature);
5319 if (!feat)
5320 return ERROR_SUCCESS;
5322 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5323 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5324 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5326 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5327 feat->Action = feat->Installed;
5328 return ERROR_SUCCESS;
5331 component = MSI_RecordGetString(rec, 3);
5332 comp = get_loaded_component(package, component);
5333 if (!comp)
5334 return ERROR_SUCCESS;
5336 compgroupid = MSI_RecordGetString(rec,1);
5337 qualifier = MSI_RecordGetString(rec,2);
5339 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5340 if (rc != ERROR_SUCCESS)
5341 goto end;
5343 advertise = create_component_advertise_string( package, comp, feature );
5344 text = MSI_RecordGetString( rec, 4 );
5345 if (text)
5347 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5348 strcpyW( p, advertise );
5349 strcatW( p, text );
5350 msi_free( advertise );
5351 advertise = p;
5353 existing = msi_reg_get_val_str( hkey, qualifier );
5355 sz = strlenW( advertise ) + 1;
5356 if (existing)
5358 for (p = existing; *p; p += len)
5360 len = strlenW( p ) + 1;
5361 if (strcmpW( advertise, p )) sz += len;
5364 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5366 rc = ERROR_OUTOFMEMORY;
5367 goto end;
5369 q = output;
5370 if (existing)
5372 for (p = existing; *p; p += len)
5374 len = strlenW( p ) + 1;
5375 if (strcmpW( advertise, p ))
5377 memcpy( q, p, len * sizeof(WCHAR) );
5378 q += len;
5382 strcpyW( q, advertise );
5383 q[strlenW( q ) + 1] = 0;
5385 msi_reg_set_val_multi_str( hkey, qualifier, output );
5387 end:
5388 RegCloseKey(hkey);
5389 msi_free( output );
5390 msi_free( advertise );
5391 msi_free( existing );
5393 /* the UI chunk */
5394 uirow = MSI_CreateRecord( 2 );
5395 MSI_RecordSetStringW( uirow, 1, compgroupid );
5396 MSI_RecordSetStringW( uirow, 2, qualifier);
5397 ui_actiondata( package, szPublishComponents, uirow);
5398 msiobj_release( &uirow->hdr );
5399 /* FIXME: call ui_progress? */
5401 return rc;
5405 * At present I am ignorning the advertised components part of this and only
5406 * focusing on the qualified component sets
5408 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5410 UINT rc;
5411 MSIQUERY * view;
5412 static const WCHAR ExecSeqQuery[] =
5413 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5414 '`','P','u','b','l','i','s','h',
5415 'C','o','m','p','o','n','e','n','t','`',0};
5417 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5418 if (rc != ERROR_SUCCESS)
5419 return ERROR_SUCCESS;
5421 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5422 msiobj_release(&view->hdr);
5424 return rc;
5427 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5429 static const WCHAR szInstallerComponents[] = {
5430 'S','o','f','t','w','a','r','e','\\',
5431 'M','i','c','r','o','s','o','f','t','\\',
5432 'I','n','s','t','a','l','l','e','r','\\',
5433 'C','o','m','p','o','n','e','n','t','s','\\',0};
5435 MSIPACKAGE *package = param;
5436 LPCWSTR compgroupid, component, feature, qualifier;
5437 MSICOMPONENT *comp;
5438 MSIFEATURE *feat;
5439 MSIRECORD *uirow;
5440 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5441 LONG res;
5443 feature = MSI_RecordGetString( rec, 5 );
5444 feat = get_loaded_feature( package, feature );
5445 if (!feat)
5446 return ERROR_SUCCESS;
5448 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5450 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5451 feat->Action = feat->Installed;
5452 return ERROR_SUCCESS;
5455 component = MSI_RecordGetString( rec, 3 );
5456 comp = get_loaded_component( package, component );
5457 if (!comp)
5458 return ERROR_SUCCESS;
5460 compgroupid = MSI_RecordGetString( rec, 1 );
5461 qualifier = MSI_RecordGetString( rec, 2 );
5463 squash_guid( compgroupid, squashed );
5464 strcpyW( keypath, szInstallerComponents );
5465 strcatW( keypath, squashed );
5467 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5468 if (res != ERROR_SUCCESS)
5470 WARN("Unable to delete component key %d\n", res);
5473 uirow = MSI_CreateRecord( 2 );
5474 MSI_RecordSetStringW( uirow, 1, compgroupid );
5475 MSI_RecordSetStringW( uirow, 2, qualifier );
5476 ui_actiondata( package, szUnpublishComponents, uirow );
5477 msiobj_release( &uirow->hdr );
5479 return ERROR_SUCCESS;
5482 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5484 UINT rc;
5485 MSIQUERY *view;
5486 static const WCHAR query[] =
5487 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5488 '`','P','u','b','l','i','s','h',
5489 'C','o','m','p','o','n','e','n','t','`',0};
5491 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5492 if (rc != ERROR_SUCCESS)
5493 return ERROR_SUCCESS;
5495 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5496 msiobj_release( &view->hdr );
5498 return rc;
5501 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5503 MSIPACKAGE *package = param;
5504 MSIRECORD *row;
5505 MSIFILE *file;
5506 SC_HANDLE hscm, service = NULL;
5507 LPCWSTR comp, key;
5508 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5509 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5510 DWORD serv_type, start_type, err_control;
5511 SERVICE_DESCRIPTIONW sd = {NULL};
5513 static const WCHAR query[] =
5514 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5515 '`','C','o','m','p','o','n','e','n','t','`',' ',
5516 'W','H','E','R','E',' ',
5517 '`','C','o','m','p','o','n','e','n','t','`',' ',
5518 '=','\'','%','s','\'',0};
5520 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5521 if (!hscm)
5523 ERR("Failed to open the SC Manager!\n");
5524 goto done;
5527 comp = MSI_RecordGetString( rec, 12 );
5528 if (!get_loaded_component( package, comp ))
5529 goto done;
5531 start_type = MSI_RecordGetInteger(rec, 5);
5532 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5533 goto done;
5535 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5536 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5537 serv_type = MSI_RecordGetInteger(rec, 4);
5538 err_control = MSI_RecordGetInteger(rec, 6);
5539 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5540 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5541 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5542 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5543 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5544 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5546 /* fetch the service path */
5547 row = MSI_QueryGetRecord(package->db, query, comp);
5548 if (!row)
5550 ERR("Control query failed!\n");
5551 goto done;
5553 key = MSI_RecordGetString(row, 6);
5555 file = get_loaded_file(package, key);
5556 msiobj_release(&row->hdr);
5557 if (!file)
5559 ERR("Failed to load the service file\n");
5560 goto done;
5563 if (!args || !args[0]) image_path = file->TargetPath;
5564 else
5566 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5567 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5568 return ERROR_OUTOFMEMORY;
5570 strcpyW(image_path, file->TargetPath);
5571 strcatW(image_path, szSpace);
5572 strcatW(image_path, args);
5574 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5575 start_type, err_control, image_path, load_order,
5576 NULL, depends, serv_name, pass);
5578 if (!service)
5580 if (GetLastError() != ERROR_SERVICE_EXISTS)
5581 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5583 else if (sd.lpDescription)
5585 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5586 WARN("failed to set service description %u\n", GetLastError());
5589 if (image_path != file->TargetPath) msi_free(image_path);
5590 done:
5591 CloseServiceHandle(service);
5592 CloseServiceHandle(hscm);
5593 msi_free(name);
5594 msi_free(disp);
5595 msi_free(sd.lpDescription);
5596 msi_free(load_order);
5597 msi_free(serv_name);
5598 msi_free(pass);
5599 msi_free(depends);
5600 msi_free(args);
5602 return ERROR_SUCCESS;
5605 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5607 UINT rc;
5608 MSIQUERY * view;
5609 static const WCHAR ExecSeqQuery[] =
5610 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5611 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5613 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5614 if (rc != ERROR_SUCCESS)
5615 return ERROR_SUCCESS;
5617 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5618 msiobj_release(&view->hdr);
5620 return rc;
5623 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5624 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5626 LPCWSTR *vector, *temp_vector;
5627 LPWSTR p, q;
5628 DWORD sep_len;
5630 static const WCHAR separator[] = {'[','~',']',0};
5632 *numargs = 0;
5633 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5635 if (!args)
5636 return NULL;
5638 vector = msi_alloc(sizeof(LPWSTR));
5639 if (!vector)
5640 return NULL;
5642 p = args;
5645 (*numargs)++;
5646 vector[*numargs - 1] = p;
5648 if ((q = strstrW(p, separator)))
5650 *q = '\0';
5652 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5653 if (!temp_vector)
5655 msi_free(vector);
5656 return NULL;
5658 vector = temp_vector;
5660 p = q + sep_len;
5662 } while (q);
5664 return vector;
5667 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5669 MSIPACKAGE *package = param;
5670 MSICOMPONENT *comp;
5671 MSIRECORD *uirow;
5672 SC_HANDLE scm = NULL, service = NULL;
5673 LPCWSTR component, *vector = NULL;
5674 LPWSTR name, args, display_name = NULL;
5675 DWORD event, numargs, len;
5676 UINT r = ERROR_FUNCTION_FAILED;
5678 component = MSI_RecordGetString(rec, 6);
5679 comp = get_loaded_component(package, component);
5680 if (!comp)
5681 return ERROR_SUCCESS;
5683 if (!comp->Enabled)
5685 TRACE("component is disabled\n");
5686 return ERROR_SUCCESS;
5689 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5691 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5692 comp->Action = comp->Installed;
5693 return ERROR_SUCCESS;
5695 comp->Action = INSTALLSTATE_LOCAL;
5697 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5698 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5699 event = MSI_RecordGetInteger(rec, 3);
5701 if (!(event & msidbServiceControlEventStart))
5703 r = ERROR_SUCCESS;
5704 goto done;
5707 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5708 if (!scm)
5710 ERR("Failed to open the service control manager\n");
5711 goto done;
5714 len = 0;
5715 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5716 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5718 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5719 GetServiceDisplayNameW( scm, name, display_name, &len );
5722 service = OpenServiceW(scm, name, SERVICE_START);
5723 if (!service)
5725 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5726 goto done;
5729 vector = msi_service_args_to_vector(args, &numargs);
5731 if (!StartServiceW(service, numargs, vector) &&
5732 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5734 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5735 goto done;
5738 r = ERROR_SUCCESS;
5740 done:
5741 uirow = MSI_CreateRecord( 2 );
5742 MSI_RecordSetStringW( uirow, 1, display_name );
5743 MSI_RecordSetStringW( uirow, 2, name );
5744 ui_actiondata( package, szStartServices, uirow );
5745 msiobj_release( &uirow->hdr );
5747 CloseServiceHandle(service);
5748 CloseServiceHandle(scm);
5750 msi_free(name);
5751 msi_free(args);
5752 msi_free(vector);
5753 msi_free(display_name);
5754 return r;
5757 static UINT ACTION_StartServices( MSIPACKAGE *package )
5759 UINT rc;
5760 MSIQUERY *view;
5762 static const WCHAR query[] = {
5763 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5764 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5766 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5767 if (rc != ERROR_SUCCESS)
5768 return ERROR_SUCCESS;
5770 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5771 msiobj_release(&view->hdr);
5773 return rc;
5776 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5778 DWORD i, needed, count;
5779 ENUM_SERVICE_STATUSW *dependencies;
5780 SERVICE_STATUS ss;
5781 SC_HANDLE depserv;
5783 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5784 0, &needed, &count))
5785 return TRUE;
5787 if (GetLastError() != ERROR_MORE_DATA)
5788 return FALSE;
5790 dependencies = msi_alloc(needed);
5791 if (!dependencies)
5792 return FALSE;
5794 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5795 needed, &needed, &count))
5796 goto error;
5798 for (i = 0; i < count; i++)
5800 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5801 SERVICE_STOP | SERVICE_QUERY_STATUS);
5802 if (!depserv)
5803 goto error;
5805 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5806 goto error;
5809 return TRUE;
5811 error:
5812 msi_free(dependencies);
5813 return FALSE;
5816 static UINT stop_service( LPCWSTR name )
5818 SC_HANDLE scm = NULL, service = NULL;
5819 SERVICE_STATUS status;
5820 SERVICE_STATUS_PROCESS ssp;
5821 DWORD needed;
5823 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5824 if (!scm)
5826 WARN("Failed to open the SCM: %d\n", GetLastError());
5827 goto done;
5830 service = OpenServiceW(scm, name,
5831 SERVICE_STOP |
5832 SERVICE_QUERY_STATUS |
5833 SERVICE_ENUMERATE_DEPENDENTS);
5834 if (!service)
5836 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5837 goto done;
5840 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5841 sizeof(SERVICE_STATUS_PROCESS), &needed))
5843 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5844 goto done;
5847 if (ssp.dwCurrentState == SERVICE_STOPPED)
5848 goto done;
5850 stop_service_dependents(scm, service);
5852 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5853 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5855 done:
5856 CloseServiceHandle(service);
5857 CloseServiceHandle(scm);
5859 return ERROR_SUCCESS;
5862 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5864 MSIPACKAGE *package = param;
5865 MSICOMPONENT *comp;
5866 MSIRECORD *uirow;
5867 LPCWSTR component;
5868 LPWSTR name = NULL, display_name = NULL;
5869 DWORD event, len;
5870 SC_HANDLE scm;
5872 event = MSI_RecordGetInteger( rec, 3 );
5873 if (!(event & msidbServiceControlEventStop))
5874 return ERROR_SUCCESS;
5876 component = MSI_RecordGetString( rec, 6 );
5877 comp = get_loaded_component( package, component );
5878 if (!comp)
5879 return ERROR_SUCCESS;
5881 if (!comp->Enabled)
5883 TRACE("component is disabled\n");
5884 return ERROR_SUCCESS;
5887 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5889 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5890 comp->Action = comp->Installed;
5891 return ERROR_SUCCESS;
5893 comp->Action = INSTALLSTATE_ABSENT;
5895 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5896 if (!scm)
5898 ERR("Failed to open the service control manager\n");
5899 goto done;
5902 len = 0;
5903 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5904 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5906 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5907 GetServiceDisplayNameW( scm, name, display_name, &len );
5909 CloseServiceHandle( scm );
5911 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5912 stop_service( name );
5914 done:
5915 uirow = MSI_CreateRecord( 2 );
5916 MSI_RecordSetStringW( uirow, 1, display_name );
5917 MSI_RecordSetStringW( uirow, 2, name );
5918 ui_actiondata( package, szStopServices, uirow );
5919 msiobj_release( &uirow->hdr );
5921 msi_free( name );
5922 msi_free( display_name );
5923 return ERROR_SUCCESS;
5926 static UINT ACTION_StopServices( MSIPACKAGE *package )
5928 UINT rc;
5929 MSIQUERY *view;
5931 static const WCHAR query[] = {
5932 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5933 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5935 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5936 if (rc != ERROR_SUCCESS)
5937 return ERROR_SUCCESS;
5939 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5940 msiobj_release(&view->hdr);
5942 return rc;
5945 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5947 MSIPACKAGE *package = param;
5948 MSICOMPONENT *comp;
5949 MSIRECORD *uirow;
5950 LPCWSTR component;
5951 LPWSTR name = NULL, display_name = NULL;
5952 DWORD event, len;
5953 SC_HANDLE scm = NULL, service = NULL;
5955 event = MSI_RecordGetInteger( rec, 3 );
5956 if (!(event & msidbServiceControlEventDelete))
5957 return ERROR_SUCCESS;
5959 component = MSI_RecordGetString(rec, 6);
5960 comp = get_loaded_component(package, component);
5961 if (!comp)
5962 return ERROR_SUCCESS;
5964 if (!comp->Enabled)
5966 TRACE("component is disabled\n");
5967 return ERROR_SUCCESS;
5970 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5972 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5973 comp->Action = comp->Installed;
5974 return ERROR_SUCCESS;
5976 comp->Action = INSTALLSTATE_ABSENT;
5978 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5979 stop_service( name );
5981 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5982 if (!scm)
5984 WARN("Failed to open the SCM: %d\n", GetLastError());
5985 goto done;
5988 len = 0;
5989 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5990 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5992 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5993 GetServiceDisplayNameW( scm, name, display_name, &len );
5996 service = OpenServiceW( scm, name, DELETE );
5997 if (!service)
5999 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6000 goto done;
6003 if (!DeleteService( service ))
6004 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6006 done:
6007 uirow = MSI_CreateRecord( 2 );
6008 MSI_RecordSetStringW( uirow, 1, display_name );
6009 MSI_RecordSetStringW( uirow, 2, name );
6010 ui_actiondata( package, szDeleteServices, uirow );
6011 msiobj_release( &uirow->hdr );
6013 CloseServiceHandle( service );
6014 CloseServiceHandle( scm );
6015 msi_free( name );
6016 msi_free( display_name );
6018 return ERROR_SUCCESS;
6021 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6023 UINT rc;
6024 MSIQUERY *view;
6026 static const WCHAR query[] = {
6027 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6028 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6030 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6031 if (rc != ERROR_SUCCESS)
6032 return ERROR_SUCCESS;
6034 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6035 msiobj_release( &view->hdr );
6037 return rc;
6040 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6042 MSIPACKAGE *package = param;
6043 LPWSTR driver, driver_path, ptr;
6044 WCHAR outpath[MAX_PATH];
6045 MSIFILE *driver_file = NULL, *setup_file = NULL;
6046 MSICOMPONENT *comp;
6047 MSIRECORD *uirow;
6048 LPCWSTR desc, file_key, component;
6049 DWORD len, usage;
6050 UINT r = ERROR_SUCCESS;
6052 static const WCHAR driver_fmt[] = {
6053 'D','r','i','v','e','r','=','%','s',0};
6054 static const WCHAR setup_fmt[] = {
6055 'S','e','t','u','p','=','%','s',0};
6056 static const WCHAR usage_fmt[] = {
6057 'F','i','l','e','U','s','a','g','e','=','1',0};
6059 component = MSI_RecordGetString( rec, 2 );
6060 comp = get_loaded_component( package, component );
6061 if (!comp)
6062 return ERROR_SUCCESS;
6064 if (!comp->Enabled)
6066 TRACE("component is disabled\n");
6067 return ERROR_SUCCESS;
6070 desc = MSI_RecordGetString(rec, 3);
6072 file_key = MSI_RecordGetString( rec, 4 );
6073 if (file_key) driver_file = get_loaded_file( package, file_key );
6075 file_key = MSI_RecordGetString( rec, 5 );
6076 if (file_key) setup_file = get_loaded_file( package, file_key );
6078 if (!driver_file)
6080 ERR("ODBC Driver entry not found!\n");
6081 return ERROR_FUNCTION_FAILED;
6084 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6085 if (setup_file)
6086 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6087 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6089 driver = msi_alloc(len * sizeof(WCHAR));
6090 if (!driver)
6091 return ERROR_OUTOFMEMORY;
6093 ptr = driver;
6094 lstrcpyW(ptr, desc);
6095 ptr += lstrlenW(ptr) + 1;
6097 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6098 ptr += len + 1;
6100 if (setup_file)
6102 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6103 ptr += len + 1;
6106 lstrcpyW(ptr, usage_fmt);
6107 ptr += lstrlenW(ptr) + 1;
6108 *ptr = '\0';
6110 driver_path = strdupW(driver_file->TargetPath);
6111 ptr = strrchrW(driver_path, '\\');
6112 if (ptr) *ptr = '\0';
6114 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6115 NULL, ODBC_INSTALL_COMPLETE, &usage))
6117 ERR("Failed to install SQL driver!\n");
6118 r = ERROR_FUNCTION_FAILED;
6121 uirow = MSI_CreateRecord( 5 );
6122 MSI_RecordSetStringW( uirow, 1, desc );
6123 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6124 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6125 ui_actiondata( package, szInstallODBC, uirow );
6126 msiobj_release( &uirow->hdr );
6128 msi_free(driver);
6129 msi_free(driver_path);
6131 return r;
6134 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6136 MSIPACKAGE *package = param;
6137 LPWSTR translator, translator_path, ptr;
6138 WCHAR outpath[MAX_PATH];
6139 MSIFILE *translator_file = NULL, *setup_file = NULL;
6140 MSICOMPONENT *comp;
6141 MSIRECORD *uirow;
6142 LPCWSTR desc, file_key, component;
6143 DWORD len, usage;
6144 UINT r = ERROR_SUCCESS;
6146 static const WCHAR translator_fmt[] = {
6147 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6148 static const WCHAR setup_fmt[] = {
6149 'S','e','t','u','p','=','%','s',0};
6151 component = MSI_RecordGetString( rec, 2 );
6152 comp = get_loaded_component( package, component );
6153 if (!comp)
6154 return ERROR_SUCCESS;
6156 if (!comp->Enabled)
6158 TRACE("component is disabled\n");
6159 return ERROR_SUCCESS;
6162 desc = MSI_RecordGetString(rec, 3);
6164 file_key = MSI_RecordGetString( rec, 4 );
6165 if (file_key) translator_file = get_loaded_file( package, file_key );
6167 file_key = MSI_RecordGetString( rec, 5 );
6168 if (file_key) setup_file = get_loaded_file( package, file_key );
6170 if (!translator_file)
6172 ERR("ODBC Translator entry not found!\n");
6173 return ERROR_FUNCTION_FAILED;
6176 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6177 if (setup_file)
6178 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6180 translator = msi_alloc(len * sizeof(WCHAR));
6181 if (!translator)
6182 return ERROR_OUTOFMEMORY;
6184 ptr = translator;
6185 lstrcpyW(ptr, desc);
6186 ptr += lstrlenW(ptr) + 1;
6188 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6189 ptr += len + 1;
6191 if (setup_file)
6193 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6194 ptr += len + 1;
6196 *ptr = '\0';
6198 translator_path = strdupW(translator_file->TargetPath);
6199 ptr = strrchrW(translator_path, '\\');
6200 if (ptr) *ptr = '\0';
6202 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6203 NULL, ODBC_INSTALL_COMPLETE, &usage))
6205 ERR("Failed to install SQL translator!\n");
6206 r = ERROR_FUNCTION_FAILED;
6209 uirow = MSI_CreateRecord( 5 );
6210 MSI_RecordSetStringW( uirow, 1, desc );
6211 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6212 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6213 ui_actiondata( package, szInstallODBC, uirow );
6214 msiobj_release( &uirow->hdr );
6216 msi_free(translator);
6217 msi_free(translator_path);
6219 return r;
6222 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6224 MSIPACKAGE *package = param;
6225 MSICOMPONENT *comp;
6226 LPWSTR attrs;
6227 LPCWSTR desc, driver, component;
6228 WORD request = ODBC_ADD_SYS_DSN;
6229 INT registration;
6230 DWORD len;
6231 UINT r = ERROR_SUCCESS;
6232 MSIRECORD *uirow;
6234 static const WCHAR attrs_fmt[] = {
6235 'D','S','N','=','%','s',0 };
6237 component = MSI_RecordGetString( rec, 2 );
6238 comp = get_loaded_component( package, component );
6239 if (!comp)
6240 return ERROR_SUCCESS;
6242 if (!comp->Enabled)
6244 TRACE("component is disabled\n");
6245 return ERROR_SUCCESS;
6248 desc = MSI_RecordGetString(rec, 3);
6249 driver = MSI_RecordGetString(rec, 4);
6250 registration = MSI_RecordGetInteger(rec, 5);
6252 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6253 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6255 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6256 attrs = msi_alloc(len * sizeof(WCHAR));
6257 if (!attrs)
6258 return ERROR_OUTOFMEMORY;
6260 len = sprintfW(attrs, attrs_fmt, desc);
6261 attrs[len + 1] = 0;
6263 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6265 ERR("Failed to install SQL data source!\n");
6266 r = ERROR_FUNCTION_FAILED;
6269 uirow = MSI_CreateRecord( 5 );
6270 MSI_RecordSetStringW( uirow, 1, desc );
6271 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6272 MSI_RecordSetInteger( uirow, 3, request );
6273 ui_actiondata( package, szInstallODBC, uirow );
6274 msiobj_release( &uirow->hdr );
6276 msi_free(attrs);
6278 return r;
6281 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6283 UINT rc;
6284 MSIQUERY *view;
6286 static const WCHAR driver_query[] = {
6287 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6288 'O','D','B','C','D','r','i','v','e','r',0 };
6290 static const WCHAR translator_query[] = {
6291 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6292 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6294 static const WCHAR source_query[] = {
6295 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6296 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6298 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6299 if (rc != ERROR_SUCCESS)
6300 return ERROR_SUCCESS;
6302 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6303 msiobj_release(&view->hdr);
6305 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6306 if (rc != ERROR_SUCCESS)
6307 return ERROR_SUCCESS;
6309 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6310 msiobj_release(&view->hdr);
6312 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6313 if (rc != ERROR_SUCCESS)
6314 return ERROR_SUCCESS;
6316 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6317 msiobj_release(&view->hdr);
6319 return rc;
6322 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6324 MSIPACKAGE *package = param;
6325 MSICOMPONENT *comp;
6326 MSIRECORD *uirow;
6327 DWORD usage;
6328 LPCWSTR desc, component;
6330 component = MSI_RecordGetString( rec, 2 );
6331 comp = get_loaded_component( package, component );
6332 if (!comp)
6333 return ERROR_SUCCESS;
6335 if (!comp->Enabled)
6337 TRACE("component is disabled\n");
6338 return ERROR_SUCCESS;
6341 desc = MSI_RecordGetString( rec, 3 );
6342 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6344 WARN("Failed to remove ODBC driver\n");
6346 else if (!usage)
6348 FIXME("Usage count reached 0\n");
6351 uirow = MSI_CreateRecord( 2 );
6352 MSI_RecordSetStringW( uirow, 1, desc );
6353 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6354 ui_actiondata( package, szRemoveODBC, uirow );
6355 msiobj_release( &uirow->hdr );
6357 return ERROR_SUCCESS;
6360 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6362 MSIPACKAGE *package = param;
6363 MSICOMPONENT *comp;
6364 MSIRECORD *uirow;
6365 DWORD usage;
6366 LPCWSTR desc, component;
6368 component = MSI_RecordGetString( rec, 2 );
6369 comp = get_loaded_component( package, component );
6370 if (!comp)
6371 return ERROR_SUCCESS;
6373 if (!comp->Enabled)
6375 TRACE("component is disabled\n");
6376 return ERROR_SUCCESS;
6379 desc = MSI_RecordGetString( rec, 3 );
6380 if (!SQLRemoveTranslatorW( desc, &usage ))
6382 WARN("Failed to remove ODBC translator\n");
6384 else if (!usage)
6386 FIXME("Usage count reached 0\n");
6389 uirow = MSI_CreateRecord( 2 );
6390 MSI_RecordSetStringW( uirow, 1, desc );
6391 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6392 ui_actiondata( package, szRemoveODBC, uirow );
6393 msiobj_release( &uirow->hdr );
6395 return ERROR_SUCCESS;
6398 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6400 MSIPACKAGE *package = param;
6401 MSICOMPONENT *comp;
6402 MSIRECORD *uirow;
6403 LPWSTR attrs;
6404 LPCWSTR desc, driver, component;
6405 WORD request = ODBC_REMOVE_SYS_DSN;
6406 INT registration;
6407 DWORD len;
6409 static const WCHAR attrs_fmt[] = {
6410 'D','S','N','=','%','s',0 };
6412 component = MSI_RecordGetString( rec, 2 );
6413 comp = get_loaded_component( package, component );
6414 if (!comp)
6415 return ERROR_SUCCESS;
6417 if (!comp->Enabled)
6419 TRACE("component is disabled\n");
6420 return ERROR_SUCCESS;
6423 desc = MSI_RecordGetString( rec, 3 );
6424 driver = MSI_RecordGetString( rec, 4 );
6425 registration = MSI_RecordGetInteger( rec, 5 );
6427 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6428 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6430 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6431 attrs = msi_alloc( len * sizeof(WCHAR) );
6432 if (!attrs)
6433 return ERROR_OUTOFMEMORY;
6435 FIXME("Use ODBCSourceAttribute table\n");
6437 len = sprintfW( attrs, attrs_fmt, desc );
6438 attrs[len + 1] = 0;
6440 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6442 WARN("Failed to remove ODBC data source\n");
6444 msi_free( attrs );
6446 uirow = MSI_CreateRecord( 3 );
6447 MSI_RecordSetStringW( uirow, 1, desc );
6448 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6449 MSI_RecordSetInteger( uirow, 3, request );
6450 ui_actiondata( package, szRemoveODBC, uirow );
6451 msiobj_release( &uirow->hdr );
6453 return ERROR_SUCCESS;
6456 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6458 UINT rc;
6459 MSIQUERY *view;
6461 static const WCHAR driver_query[] = {
6462 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6463 'O','D','B','C','D','r','i','v','e','r',0 };
6465 static const WCHAR translator_query[] = {
6466 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6467 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6469 static const WCHAR source_query[] = {
6470 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6471 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6473 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6474 if (rc != ERROR_SUCCESS)
6475 return ERROR_SUCCESS;
6477 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6478 msiobj_release( &view->hdr );
6480 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6481 if (rc != ERROR_SUCCESS)
6482 return ERROR_SUCCESS;
6484 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6485 msiobj_release( &view->hdr );
6487 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6488 if (rc != ERROR_SUCCESS)
6489 return ERROR_SUCCESS;
6491 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6492 msiobj_release( &view->hdr );
6494 return rc;
6497 #define ENV_ACT_SETALWAYS 0x1
6498 #define ENV_ACT_SETABSENT 0x2
6499 #define ENV_ACT_REMOVE 0x4
6500 #define ENV_ACT_REMOVEMATCH 0x8
6502 #define ENV_MOD_MACHINE 0x20000000
6503 #define ENV_MOD_APPEND 0x40000000
6504 #define ENV_MOD_PREFIX 0x80000000
6505 #define ENV_MOD_MASK 0xC0000000
6507 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6509 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6511 LPCWSTR cptr = *name;
6513 static const WCHAR prefix[] = {'[','~',']',0};
6514 static const int prefix_len = 3;
6516 *flags = 0;
6517 while (*cptr)
6519 if (*cptr == '=')
6520 *flags |= ENV_ACT_SETALWAYS;
6521 else if (*cptr == '+')
6522 *flags |= ENV_ACT_SETABSENT;
6523 else if (*cptr == '-')
6524 *flags |= ENV_ACT_REMOVE;
6525 else if (*cptr == '!')
6526 *flags |= ENV_ACT_REMOVEMATCH;
6527 else if (*cptr == '*')
6528 *flags |= ENV_MOD_MACHINE;
6529 else
6530 break;
6532 cptr++;
6533 (*name)++;
6536 if (!*cptr)
6538 ERR("Missing environment variable\n");
6539 return ERROR_FUNCTION_FAILED;
6542 if (*value)
6544 LPCWSTR ptr = *value;
6545 if (!strncmpW(ptr, prefix, prefix_len))
6547 if (ptr[prefix_len] == szSemiColon[0])
6549 *flags |= ENV_MOD_APPEND;
6550 *value += lstrlenW(prefix);
6552 else
6554 *value = NULL;
6557 else if (lstrlenW(*value) >= prefix_len)
6559 ptr += lstrlenW(ptr) - prefix_len;
6560 if (!strcmpW( ptr, prefix ))
6562 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6564 *flags |= ENV_MOD_PREFIX;
6565 /* the "[~]" will be removed by deformat_string */;
6567 else
6569 *value = NULL;
6575 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6576 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6577 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6578 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6580 ERR("Invalid flags: %08x\n", *flags);
6581 return ERROR_FUNCTION_FAILED;
6584 if (!*flags)
6585 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6587 return ERROR_SUCCESS;
6590 static UINT open_env_key( DWORD flags, HKEY *key )
6592 static const WCHAR user_env[] =
6593 {'E','n','v','i','r','o','n','m','e','n','t',0};
6594 static const WCHAR machine_env[] =
6595 {'S','y','s','t','e','m','\\',
6596 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6597 'C','o','n','t','r','o','l','\\',
6598 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6599 'E','n','v','i','r','o','n','m','e','n','t',0};
6600 const WCHAR *env;
6601 HKEY root;
6602 LONG res;
6604 if (flags & ENV_MOD_MACHINE)
6606 env = machine_env;
6607 root = HKEY_LOCAL_MACHINE;
6609 else
6611 env = user_env;
6612 root = HKEY_CURRENT_USER;
6615 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6616 if (res != ERROR_SUCCESS)
6618 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6619 return ERROR_FUNCTION_FAILED;
6622 return ERROR_SUCCESS;
6625 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6627 MSIPACKAGE *package = param;
6628 LPCWSTR name, value, component;
6629 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6630 DWORD flags, type, size;
6631 UINT res;
6632 HKEY env = NULL;
6633 MSICOMPONENT *comp;
6634 MSIRECORD *uirow;
6635 int action = 0;
6637 component = MSI_RecordGetString(rec, 4);
6638 comp = get_loaded_component(package, component);
6639 if (!comp)
6640 return ERROR_SUCCESS;
6642 if (!comp->Enabled)
6644 TRACE("component is disabled\n");
6645 return ERROR_SUCCESS;
6648 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6650 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6651 comp->Action = comp->Installed;
6652 return ERROR_SUCCESS;
6654 comp->Action = INSTALLSTATE_LOCAL;
6656 name = MSI_RecordGetString(rec, 2);
6657 value = MSI_RecordGetString(rec, 3);
6659 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6661 res = env_parse_flags(&name, &value, &flags);
6662 if (res != ERROR_SUCCESS || !value)
6663 goto done;
6665 if (value && !deformat_string(package, value, &deformatted))
6667 res = ERROR_OUTOFMEMORY;
6668 goto done;
6671 value = deformatted;
6673 res = open_env_key( flags, &env );
6674 if (res != ERROR_SUCCESS)
6675 goto done;
6677 if (flags & ENV_MOD_MACHINE)
6678 action |= 0x20000000;
6680 size = 0;
6681 type = REG_SZ;
6682 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6683 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6684 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6685 goto done;
6687 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6689 action = 0x2;
6691 /* Nothing to do. */
6692 if (!value)
6694 res = ERROR_SUCCESS;
6695 goto done;
6698 /* If we are appending but the string was empty, strip ; */
6699 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6701 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6702 newval = strdupW(value);
6703 if (!newval)
6705 res = ERROR_OUTOFMEMORY;
6706 goto done;
6709 else
6711 action = 0x1;
6713 /* Contrary to MSDN, +-variable to [~];path works */
6714 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6716 res = ERROR_SUCCESS;
6717 goto done;
6720 data = msi_alloc(size);
6721 if (!data)
6723 RegCloseKey(env);
6724 return ERROR_OUTOFMEMORY;
6727 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6728 if (res != ERROR_SUCCESS)
6729 goto done;
6731 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6733 action = 0x4;
6734 res = RegDeleteValueW(env, name);
6735 if (res != ERROR_SUCCESS)
6736 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6737 goto done;
6740 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6741 if (flags & ENV_MOD_MASK)
6743 DWORD mod_size;
6744 int multiplier = 0;
6745 if (flags & ENV_MOD_APPEND) multiplier++;
6746 if (flags & ENV_MOD_PREFIX) multiplier++;
6747 mod_size = lstrlenW(value) * multiplier;
6748 size += mod_size * sizeof(WCHAR);
6751 newval = msi_alloc(size);
6752 ptr = newval;
6753 if (!newval)
6755 res = ERROR_OUTOFMEMORY;
6756 goto done;
6759 if (flags & ENV_MOD_PREFIX)
6761 lstrcpyW(newval, value);
6762 ptr = newval + lstrlenW(value);
6763 action |= 0x80000000;
6766 lstrcpyW(ptr, data);
6768 if (flags & ENV_MOD_APPEND)
6770 lstrcatW(newval, value);
6771 action |= 0x40000000;
6774 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6775 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6776 if (res)
6778 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6781 done:
6782 uirow = MSI_CreateRecord( 3 );
6783 MSI_RecordSetStringW( uirow, 1, name );
6784 MSI_RecordSetStringW( uirow, 2, newval );
6785 MSI_RecordSetInteger( uirow, 3, action );
6786 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6787 msiobj_release( &uirow->hdr );
6789 if (env) RegCloseKey(env);
6790 msi_free(deformatted);
6791 msi_free(data);
6792 msi_free(newval);
6793 return res;
6796 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6798 UINT rc;
6799 MSIQUERY * view;
6800 static const WCHAR ExecSeqQuery[] =
6801 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6802 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6803 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6804 if (rc != ERROR_SUCCESS)
6805 return ERROR_SUCCESS;
6807 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6808 msiobj_release(&view->hdr);
6810 return rc;
6813 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6815 MSIPACKAGE *package = param;
6816 LPCWSTR name, value, component;
6817 LPWSTR deformatted = NULL;
6818 DWORD flags;
6819 HKEY env;
6820 MSICOMPONENT *comp;
6821 MSIRECORD *uirow;
6822 int action = 0;
6823 LONG res;
6824 UINT r;
6826 component = MSI_RecordGetString( rec, 4 );
6827 comp = get_loaded_component( package, component );
6828 if (!comp)
6829 return ERROR_SUCCESS;
6831 if (!comp->Enabled)
6833 TRACE("component is disabled\n");
6834 return ERROR_SUCCESS;
6837 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6839 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6840 comp->Action = comp->Installed;
6841 return ERROR_SUCCESS;
6843 comp->Action = INSTALLSTATE_ABSENT;
6845 name = MSI_RecordGetString( rec, 2 );
6846 value = MSI_RecordGetString( rec, 3 );
6848 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6850 r = env_parse_flags( &name, &value, &flags );
6851 if (r != ERROR_SUCCESS)
6852 return r;
6854 if (!(flags & ENV_ACT_REMOVE))
6856 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6857 return ERROR_SUCCESS;
6860 if (value && !deformat_string( package, value, &deformatted ))
6861 return ERROR_OUTOFMEMORY;
6863 value = deformatted;
6865 r = open_env_key( flags, &env );
6866 if (r != ERROR_SUCCESS)
6868 r = ERROR_SUCCESS;
6869 goto done;
6872 if (flags & ENV_MOD_MACHINE)
6873 action |= 0x20000000;
6875 TRACE("Removing %s\n", debugstr_w(name));
6877 res = RegDeleteValueW( env, name );
6878 if (res != ERROR_SUCCESS)
6880 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6881 r = ERROR_SUCCESS;
6884 done:
6885 uirow = MSI_CreateRecord( 3 );
6886 MSI_RecordSetStringW( uirow, 1, name );
6887 MSI_RecordSetStringW( uirow, 2, value );
6888 MSI_RecordSetInteger( uirow, 3, action );
6889 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6890 msiobj_release( &uirow->hdr );
6892 if (env) RegCloseKey( env );
6893 msi_free( deformatted );
6894 return r;
6897 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6899 UINT rc;
6900 MSIQUERY *view;
6901 static const WCHAR query[] =
6902 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6903 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6905 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6906 if (rc != ERROR_SUCCESS)
6907 return ERROR_SUCCESS;
6909 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6910 msiobj_release( &view->hdr );
6912 return rc;
6915 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6917 LPWSTR key, template, id;
6918 UINT r = ERROR_SUCCESS;
6920 id = msi_dup_property( package->db, szProductID );
6921 if (id)
6923 msi_free( id );
6924 return ERROR_SUCCESS;
6926 template = msi_dup_property( package->db, szPIDTemplate );
6927 key = msi_dup_property( package->db, szPIDKEY );
6929 if (key && template)
6931 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6932 r = msi_set_property( package->db, szProductID, key );
6934 msi_free( template );
6935 msi_free( key );
6936 return r;
6939 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6941 TRACE("\n");
6942 package->need_reboot = 1;
6943 return ERROR_SUCCESS;
6946 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6948 static const WCHAR szAvailableFreeReg[] =
6949 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6950 MSIRECORD *uirow;
6951 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6953 TRACE("%p %d kilobytes\n", package, space);
6955 uirow = MSI_CreateRecord( 1 );
6956 MSI_RecordSetInteger( uirow, 1, space );
6957 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6958 msiobj_release( &uirow->hdr );
6960 return ERROR_SUCCESS;
6963 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6965 FIXME("%p\n", package);
6966 return ERROR_SUCCESS;
6969 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6971 FIXME("%p\n", package);
6972 return ERROR_SUCCESS;
6975 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6977 UINT r, count;
6978 MSIQUERY *view;
6980 static const WCHAR driver_query[] = {
6981 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6982 'O','D','B','C','D','r','i','v','e','r',0 };
6984 static const WCHAR translator_query[] = {
6985 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6986 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6988 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6989 if (r == ERROR_SUCCESS)
6991 count = 0;
6992 r = MSI_IterateRecords( view, &count, NULL, package );
6993 msiobj_release( &view->hdr );
6994 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6997 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6998 if (r == ERROR_SUCCESS)
7000 count = 0;
7001 r = MSI_IterateRecords( view, &count, NULL, package );
7002 msiobj_release( &view->hdr );
7003 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7006 return ERROR_SUCCESS;
7009 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7011 MSIPACKAGE *package = param;
7012 const WCHAR *property = MSI_RecordGetString( rec, 1 );
7013 WCHAR *value;
7015 if ((value = msi_dup_property( package->db, property )))
7017 FIXME("remove %s\n", debugstr_w(value));
7018 msi_free( value );
7020 return ERROR_SUCCESS;
7023 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7025 UINT r;
7026 MSIQUERY *view;
7028 static const WCHAR query[] =
7029 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
7030 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7032 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7033 if (r == ERROR_SUCCESS)
7035 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7036 msiobj_release( &view->hdr );
7038 return ERROR_SUCCESS;
7041 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7043 MSIPACKAGE *package = param;
7044 int attributes = MSI_RecordGetInteger( rec, 5 );
7046 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7048 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7049 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7050 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7051 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7052 HKEY hkey;
7053 UINT r;
7055 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7057 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7058 if (r != ERROR_SUCCESS)
7059 return ERROR_SUCCESS;
7061 else
7063 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7064 if (r != ERROR_SUCCESS)
7065 return ERROR_SUCCESS;
7067 RegCloseKey( hkey );
7069 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7070 debugstr_w(upgrade_code), debugstr_w(version_min),
7071 debugstr_w(version_max), debugstr_w(language));
7073 return ERROR_SUCCESS;
7076 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7078 UINT r;
7079 MSIQUERY *view;
7081 static const WCHAR query[] =
7082 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7084 if (msi_get_property_int( package->db, szInstalled, 0 ))
7086 TRACE("product is installed, skipping action\n");
7087 return ERROR_SUCCESS;
7089 if (msi_get_property_int( package->db, szPreselected, 0 ))
7091 TRACE("Preselected property is set, not migrating feature states\n");
7092 return ERROR_SUCCESS;
7095 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7096 if (r == ERROR_SUCCESS)
7098 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7099 msiobj_release( &view->hdr );
7101 return ERROR_SUCCESS;
7104 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7105 LPCSTR action, LPCWSTR table )
7107 static const WCHAR query[] = {
7108 'S','E','L','E','C','T',' ','*',' ',
7109 'F','R','O','M',' ','`','%','s','`',0 };
7110 MSIQUERY *view = NULL;
7111 DWORD count = 0;
7112 UINT r;
7114 r = MSI_OpenQuery( package->db, &view, query, table );
7115 if (r == ERROR_SUCCESS)
7117 r = MSI_IterateRecords(view, &count, NULL, package);
7118 msiobj_release(&view->hdr);
7121 if (count)
7122 FIXME("%s -> %u ignored %s table values\n",
7123 action, count, debugstr_w(table));
7125 return ERROR_SUCCESS;
7128 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7130 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7131 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7134 static UINT ACTION_BindImage( MSIPACKAGE *package )
7136 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7137 return msi_unimplemented_action_stub( package, "BindImage", table );
7140 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7142 static const WCHAR table[] = {
7143 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7144 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7147 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7149 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7150 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7153 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7155 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7156 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7159 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7161 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7162 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7165 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7167 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7168 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7171 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7173 static const struct
7175 const WCHAR *action;
7176 UINT (*handler)(MSIPACKAGE *);
7178 StandardActions[] =
7180 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7181 { szAppSearch, ACTION_AppSearch },
7182 { szBindImage, ACTION_BindImage },
7183 { szCCPSearch, ACTION_CCPSearch },
7184 { szCostFinalize, ACTION_CostFinalize },
7185 { szCostInitialize, ACTION_CostInitialize },
7186 { szCreateFolders, ACTION_CreateFolders },
7187 { szCreateShortcuts, ACTION_CreateShortcuts },
7188 { szDeleteServices, ACTION_DeleteServices },
7189 { szDisableRollback, ACTION_DisableRollback },
7190 { szDuplicateFiles, ACTION_DuplicateFiles },
7191 { szExecuteAction, ACTION_ExecuteAction },
7192 { szFileCost, ACTION_FileCost },
7193 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7194 { szForceReboot, ACTION_ForceReboot },
7195 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7196 { szInstallExecute, ACTION_InstallExecute },
7197 { szInstallExecuteAgain, ACTION_InstallExecute },
7198 { szInstallFiles, ACTION_InstallFiles},
7199 { szInstallFinalize, ACTION_InstallFinalize },
7200 { szInstallInitialize, ACTION_InstallInitialize },
7201 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7202 { szInstallValidate, ACTION_InstallValidate },
7203 { szIsolateComponents, ACTION_IsolateComponents },
7204 { szLaunchConditions, ACTION_LaunchConditions },
7205 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7206 { szMoveFiles, ACTION_MoveFiles },
7207 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7208 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7209 { szInstallODBC, ACTION_InstallODBC },
7210 { szInstallServices, ACTION_InstallServices },
7211 { szPatchFiles, ACTION_PatchFiles },
7212 { szProcessComponents, ACTION_ProcessComponents },
7213 { szPublishComponents, ACTION_PublishComponents },
7214 { szPublishFeatures, ACTION_PublishFeatures },
7215 { szPublishProduct, ACTION_PublishProduct },
7216 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7217 { szRegisterComPlus, ACTION_RegisterComPlus},
7218 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7219 { szRegisterFonts, ACTION_RegisterFonts },
7220 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7221 { szRegisterProduct, ACTION_RegisterProduct },
7222 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7223 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7224 { szRegisterUser, ACTION_RegisterUser },
7225 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7226 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7227 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7228 { szRemoveFiles, ACTION_RemoveFiles },
7229 { szRemoveFolders, ACTION_RemoveFolders },
7230 { szRemoveIniValues, ACTION_RemoveIniValues },
7231 { szRemoveODBC, ACTION_RemoveODBC },
7232 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7233 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7234 { szResolveSource, ACTION_ResolveSource },
7235 { szRMCCPSearch, ACTION_RMCCPSearch },
7236 { szScheduleReboot, ACTION_ScheduleReboot },
7237 { szSelfRegModules, ACTION_SelfRegModules },
7238 { szSelfUnregModules, ACTION_SelfUnregModules },
7239 { szSetODBCFolders, ACTION_SetODBCFolders },
7240 { szStartServices, ACTION_StartServices },
7241 { szStopServices, ACTION_StopServices },
7242 { szUnpublishComponents, ACTION_UnpublishComponents },
7243 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7244 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7245 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7246 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7247 { szUnregisterFonts, ACTION_UnregisterFonts },
7248 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7249 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7250 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7251 { szValidateProductID, ACTION_ValidateProductID },
7252 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7253 { szWriteIniValues, ACTION_WriteIniValues },
7254 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7255 { NULL, NULL },
7258 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7260 BOOL ret = FALSE;
7261 UINT i;
7263 i = 0;
7264 while (StandardActions[i].action != NULL)
7266 if (!strcmpW( StandardActions[i].action, action ))
7268 ui_actionstart( package, action );
7269 if (StandardActions[i].handler)
7271 ui_actioninfo( package, action, TRUE, 0 );
7272 *rc = StandardActions[i].handler( package );
7273 ui_actioninfo( package, action, FALSE, *rc );
7275 else
7277 FIXME("unhandled standard action %s\n", debugstr_w(action));
7278 *rc = ERROR_SUCCESS;
7280 ret = TRUE;
7281 break;
7283 i++;
7285 return ret;
7288 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7290 UINT rc = ERROR_SUCCESS;
7291 BOOL handled;
7293 TRACE("Performing action (%s)\n", debugstr_w(action));
7295 handled = ACTION_HandleStandardAction(package, action, &rc);
7297 if (!handled)
7298 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7300 if (!handled)
7302 WARN("unhandled msi action %s\n", debugstr_w(action));
7303 rc = ERROR_FUNCTION_NOT_CALLED;
7306 return rc;
7309 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7311 UINT rc = ERROR_SUCCESS;
7312 BOOL handled = FALSE;
7314 TRACE("Performing action (%s)\n", debugstr_w(action));
7316 handled = ACTION_HandleStandardAction(package, action, &rc);
7318 if (!handled)
7319 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7321 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7322 handled = TRUE;
7324 if (!handled)
7326 WARN("unhandled msi action %s\n", debugstr_w(action));
7327 rc = ERROR_FUNCTION_NOT_CALLED;
7330 return rc;
7333 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7335 UINT rc = ERROR_SUCCESS;
7336 MSIRECORD *row;
7338 static const WCHAR ExecSeqQuery[] =
7339 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7340 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7341 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7342 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7343 static const WCHAR UISeqQuery[] =
7344 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7345 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7346 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7347 ' ', '=',' ','%','i',0};
7349 if (needs_ui_sequence(package))
7350 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7351 else
7352 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7354 if (row)
7356 LPCWSTR action, cond;
7358 TRACE("Running the actions\n");
7360 /* check conditions */
7361 cond = MSI_RecordGetString(row, 2);
7363 /* this is a hack to skip errors in the condition code */
7364 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7366 msiobj_release(&row->hdr);
7367 return ERROR_SUCCESS;
7370 action = MSI_RecordGetString(row, 1);
7371 if (!action)
7373 ERR("failed to fetch action\n");
7374 msiobj_release(&row->hdr);
7375 return ERROR_FUNCTION_FAILED;
7378 if (needs_ui_sequence(package))
7379 rc = ACTION_PerformUIAction(package, action, -1);
7380 else
7381 rc = ACTION_PerformAction(package, action, -1);
7383 msiobj_release(&row->hdr);
7386 return rc;
7389 /****************************************************
7390 * TOP level entry points
7391 *****************************************************/
7393 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7394 LPCWSTR szCommandLine )
7396 UINT rc;
7397 BOOL ui_exists;
7399 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7400 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7402 msi_set_property( package->db, szAction, szInstall );
7404 package->script->InWhatSequence = SEQUENCE_INSTALL;
7406 if (szPackagePath)
7408 LPWSTR p, dir;
7409 LPCWSTR file;
7411 dir = strdupW(szPackagePath);
7412 p = strrchrW(dir, '\\');
7413 if (p)
7415 *(++p) = 0;
7416 file = szPackagePath + (p - dir);
7418 else
7420 msi_free(dir);
7421 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7422 GetCurrentDirectoryW(MAX_PATH, dir);
7423 lstrcatW(dir, szBackSlash);
7424 file = szPackagePath;
7427 msi_free( package->PackagePath );
7428 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7429 if (!package->PackagePath)
7431 msi_free(dir);
7432 return ERROR_OUTOFMEMORY;
7435 lstrcpyW(package->PackagePath, dir);
7436 lstrcatW(package->PackagePath, file);
7437 msi_free(dir);
7439 msi_set_sourcedir_props(package, FALSE);
7442 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7443 if (rc != ERROR_SUCCESS)
7444 return rc;
7446 msi_apply_transforms( package );
7447 msi_apply_patches( package );
7449 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7451 TRACE("setting reinstall property\n");
7452 msi_set_property( package->db, szReinstall, szAll );
7455 /* properties may have been added by a transform */
7456 msi_clone_properties( package );
7458 msi_parse_command_line( package, szCommandLine, FALSE );
7459 msi_adjust_privilege_properties( package );
7460 msi_set_context( package );
7462 if (needs_ui_sequence( package))
7464 package->script->InWhatSequence |= SEQUENCE_UI;
7465 rc = ACTION_ProcessUISequence(package);
7466 ui_exists = ui_sequence_exists(package);
7467 if (rc == ERROR_SUCCESS || !ui_exists)
7469 package->script->InWhatSequence |= SEQUENCE_EXEC;
7470 rc = ACTION_ProcessExecSequence(package, ui_exists);
7473 else
7474 rc = ACTION_ProcessExecSequence(package, FALSE);
7476 package->script->CurrentlyScripting = FALSE;
7478 /* process the ending type action */
7479 if (rc == ERROR_SUCCESS)
7480 ACTION_PerformActionSequence(package, -1);
7481 else if (rc == ERROR_INSTALL_USEREXIT)
7482 ACTION_PerformActionSequence(package, -2);
7483 else if (rc == ERROR_INSTALL_SUSPEND)
7484 ACTION_PerformActionSequence(package, -4);
7485 else /* failed */
7486 ACTION_PerformActionSequence(package, -3);
7488 /* finish up running custom actions */
7489 ACTION_FinishCustomActions(package);
7491 if (rc == ERROR_SUCCESS && package->need_reboot)
7492 return ERROR_SUCCESS_REBOOT_REQUIRED;
7494 return rc;