msi: Always check the return value of MSI_IterateRecords.
[wine/multimedia.git] / dlls / msi / action.c
blob9ef6d39a77f4b6c5e744cd52c8aad8a50681fe01
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 "imagehlp.h"
40 #include "wine/unicode.h"
41 #include "winver.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48 static const WCHAR szCreateFolders[] =
49 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
50 static const WCHAR szCostFinalize[] =
51 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
52 static const WCHAR szWriteRegistryValues[] =
53 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
54 static const WCHAR szFileCost[] =
55 {'F','i','l','e','C','o','s','t',0};
56 static const WCHAR szInstallInitialize[] =
57 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
58 static const WCHAR szInstallValidate[] =
59 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
60 static const WCHAR szLaunchConditions[] =
61 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
62 static const WCHAR szProcessComponents[] =
63 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
64 static const WCHAR szRegisterTypeLibraries[] =
65 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
66 static const WCHAR szCreateShortcuts[] =
67 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
68 static const WCHAR szPublishProduct[] =
69 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
70 static const WCHAR szWriteIniValues[] =
71 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
72 static const WCHAR szSelfRegModules[] =
73 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
74 static const WCHAR szPublishFeatures[] =
75 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
76 static const WCHAR szRegisterProduct[] =
77 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
78 static const WCHAR szInstallExecute[] =
79 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
80 static const WCHAR szInstallExecuteAgain[] =
81 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
82 static const WCHAR szInstallFinalize[] =
83 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
84 static const WCHAR szForceReboot[] =
85 {'F','o','r','c','e','R','e','b','o','o','t',0};
86 static const WCHAR szResolveSource[] =
87 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
88 static const WCHAR szAllocateRegistrySpace[] =
89 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
90 static const WCHAR szBindImage[] =
91 {'B','i','n','d','I','m','a','g','e',0};
92 static const WCHAR szDeleteServices[] =
93 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
94 static const WCHAR szDisableRollback[] =
95 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
96 static const WCHAR szExecuteAction[] =
97 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
98 static const WCHAR szInstallAdminPackage[] =
99 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
100 static const WCHAR szInstallSFPCatalogFile[] =
101 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
102 static const WCHAR szIsolateComponents[] =
103 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
104 static const WCHAR szMigrateFeatureStates[] =
105 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
106 static const WCHAR szMsiUnpublishAssemblies[] =
107 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
108 static const WCHAR szInstallODBC[] =
109 {'I','n','s','t','a','l','l','O','D','B','C',0};
110 static const WCHAR szInstallServices[] =
111 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
112 static const WCHAR szPublishComponents[] =
113 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
114 static const WCHAR szRegisterComPlus[] =
115 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
116 static const WCHAR szRegisterUser[] =
117 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
118 static const WCHAR szRemoveEnvironmentStrings[] =
119 {'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};
120 static const WCHAR szRemoveExistingProducts[] =
121 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
122 static const WCHAR szRemoveFolders[] =
123 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
124 static const WCHAR szRemoveIniValues[] =
125 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
126 static const WCHAR szRemoveODBC[] =
127 {'R','e','m','o','v','e','O','D','B','C',0};
128 static const WCHAR szRemoveRegistryValues[] =
129 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
130 static const WCHAR szRemoveShortcuts[] =
131 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
132 static const WCHAR szRMCCPSearch[] =
133 {'R','M','C','C','P','S','e','a','r','c','h',0};
134 static const WCHAR szScheduleReboot[] =
135 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
136 static const WCHAR szSelfUnregModules[] =
137 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
138 static const WCHAR szSetODBCFolders[] =
139 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
140 static const WCHAR szStartServices[] =
141 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
142 static const WCHAR szStopServices[] =
143 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
144 static const WCHAR szUnpublishComponents[] =
145 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
146 static const WCHAR szUnpublishFeatures[] =
147 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
148 static const WCHAR szUnregisterComPlus[] =
149 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
150 static const WCHAR szUnregisterTypeLibraries[] =
151 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
152 static const WCHAR szValidateProductID[] =
153 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
154 static const WCHAR szWriteEnvironmentStrings[] =
155 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
157 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
159 static const WCHAR Query_t[] =
160 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
161 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
162 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
163 ' ','\'','%','s','\'',0};
164 MSIRECORD * row;
166 row = MSI_QueryGetRecord( package->db, Query_t, action );
167 if (!row)
168 return;
169 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
170 msiobj_release(&row->hdr);
173 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
174 UINT rc)
176 MSIRECORD * row;
177 static const WCHAR template_s[]=
178 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
179 '%','s', '.',0};
180 static const WCHAR template_e[]=
181 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
182 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
183 '%','i','.',0};
184 static const WCHAR format[] =
185 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
186 WCHAR message[1024];
187 WCHAR timet[0x100];
189 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
190 if (start)
191 sprintfW(message,template_s,timet,action);
192 else
193 sprintfW(message,template_e,timet,action,rc);
195 row = MSI_CreateRecord(1);
196 MSI_RecordSetStringW(row,1,message);
198 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
199 msiobj_release(&row->hdr);
202 enum parse_state
204 state_whitespace,
205 state_token,
206 state_quote
209 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
211 enum parse_state state = state_quote;
212 const WCHAR *p;
213 WCHAR *out = value;
214 int ignore, in_quotes = 0, count = 0, len = 0;
216 for (p = str; *p; p++)
218 ignore = 0;
219 switch (state)
221 case state_whitespace:
222 switch (*p)
224 case ' ':
225 if (!count) goto done;
226 in_quotes = 1;
227 ignore = 1;
228 len++;
229 break;
230 case '"':
231 state = state_quote;
232 if (in_quotes && p[1] != '\"') count--;
233 else count++;
234 break;
235 default:
236 state = state_token;
237 if (!count) in_quotes = 0;
238 else in_quotes = 1;
239 len++;
240 break;
242 break;
244 case state_token:
245 switch (*p)
247 case '"':
248 state = state_quote;
249 if (in_quotes) count--;
250 else count++;
251 break;
252 case ' ':
253 state = state_whitespace;
254 if (!count) goto done;
255 in_quotes = 1;
256 len++;
257 break;
258 default:
259 if (!count) in_quotes = 0;
260 else in_quotes = 1;
261 len++;
262 break;
264 break;
266 case state_quote:
267 switch (*p)
269 case '"':
270 if (in_quotes && p[1] != '\"') count--;
271 else count++;
272 break;
273 case ' ':
274 state = state_whitespace;
275 if (!count || (count > 1 && !len)) goto done;
276 in_quotes = 1;
277 len++;
278 break;
279 default:
280 state = state_token;
281 if (!count) in_quotes = 0;
282 else in_quotes = 1;
283 len++;
284 break;
286 break;
288 default: break;
290 if (!ignore) *out++ = *p;
293 done:
294 if (!len) *value = 0;
295 else *out = 0;
297 *quotes = count;
298 return p - str;
301 static void remove_quotes( WCHAR *str )
303 WCHAR *p = str;
304 int len = strlenW( str );
306 while ((p = strchrW( p, '"' )))
308 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
309 p++;
313 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
314 BOOL preserve_case )
316 LPCWSTR ptr, ptr2;
317 int num_quotes;
318 DWORD len;
319 WCHAR *prop, *val;
320 UINT r;
322 if (!szCommandLine)
323 return ERROR_SUCCESS;
325 ptr = szCommandLine;
326 while (*ptr)
328 while (*ptr == ' ') ptr++;
329 if (!*ptr) break;
331 ptr2 = strchrW( ptr, '=' );
332 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
334 len = ptr2 - ptr;
335 if (!len) return ERROR_INVALID_COMMAND_LINE;
337 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
338 memcpy( prop, ptr, len * sizeof(WCHAR) );
339 prop[len] = 0;
340 if (!preserve_case) struprW( prop );
342 ptr2++;
343 while (*ptr2 == ' ') ptr2++;
345 num_quotes = 0;
346 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
347 len = parse_prop( ptr2, val, &num_quotes );
348 if (num_quotes % 2)
350 WARN("unbalanced quotes\n");
351 msi_free( val );
352 msi_free( prop );
353 return ERROR_INVALID_COMMAND_LINE;
355 remove_quotes( val );
356 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
358 r = msi_set_property( package->db, prop, val );
359 if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
360 msi_reset_folders( package, TRUE );
362 msi_free( val );
363 msi_free( prop );
365 ptr = ptr2 + len;
368 return ERROR_SUCCESS;
371 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
373 LPCWSTR pc;
374 LPWSTR p, *ret = NULL;
375 UINT count = 0;
377 if (!str)
378 return ret;
380 /* count the number of substrings */
381 for ( pc = str, count = 0; pc; count++ )
383 pc = strchrW( pc, sep );
384 if (pc)
385 pc++;
388 /* allocate space for an array of substring pointers and the substrings */
389 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
390 (lstrlenW(str)+1) * sizeof(WCHAR) );
391 if (!ret)
392 return ret;
394 /* copy the string and set the pointers */
395 p = (LPWSTR) &ret[count+1];
396 lstrcpyW( p, str );
397 for( count = 0; (ret[count] = p); count++ )
399 p = strchrW( p, sep );
400 if (p)
401 *p++ = 0;
404 return ret;
407 static BOOL ui_sequence_exists( MSIPACKAGE *package )
409 static const WCHAR query [] = {
410 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
411 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
412 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
413 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
414 MSIQUERY *view;
415 UINT rc;
417 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
418 if (rc == ERROR_SUCCESS)
420 msiobj_release(&view->hdr);
421 return TRUE;
423 return FALSE;
426 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
428 LPWSTR source, check;
430 if (msi_get_property_int( package->db, szInstalled, 0 ))
432 HKEY hkey;
434 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
435 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
436 RegCloseKey( hkey );
438 else
440 LPWSTR p, db;
441 DWORD len;
443 db = msi_dup_property( package->db, szOriginalDatabase );
444 if (!db)
445 return ERROR_OUTOFMEMORY;
447 p = strrchrW( db, '\\' );
448 if (!p)
450 p = strrchrW( db, '/' );
451 if (!p)
453 msi_free(db);
454 return ERROR_SUCCESS;
458 len = p - db + 2;
459 source = msi_alloc( len * sizeof(WCHAR) );
460 lstrcpynW( source, db, len );
461 msi_free( db );
464 check = msi_dup_property( package->db, szSourceDir );
465 if (!check || replace)
467 UINT r = msi_set_property( package->db, szSourceDir, source );
468 if (r == ERROR_SUCCESS)
469 msi_reset_folders( package, TRUE );
471 msi_free( check );
473 check = msi_dup_property( package->db, szSOURCEDIR );
474 if (!check || replace)
475 msi_set_property( package->db, szSOURCEDIR, source );
477 msi_free( check );
478 msi_free( source );
480 return ERROR_SUCCESS;
483 static BOOL needs_ui_sequence(MSIPACKAGE *package)
485 INT level = msi_get_property_int(package->db, szUILevel, 0);
486 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
489 UINT msi_set_context(MSIPACKAGE *package)
491 int num;
493 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
495 num = msi_get_property_int(package->db, szAllUsers, 0);
496 if (num == 1 || num == 2)
497 package->Context = MSIINSTALLCONTEXT_MACHINE;
499 return ERROR_SUCCESS;
502 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
504 UINT rc;
505 LPCWSTR cond, action;
506 MSIPACKAGE *package = param;
508 action = MSI_RecordGetString(row,1);
509 if (!action)
511 ERR("Error is retrieving action name\n");
512 return ERROR_FUNCTION_FAILED;
515 /* check conditions */
516 cond = MSI_RecordGetString(row,2);
518 /* this is a hack to skip errors in the condition code */
519 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
521 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
522 return ERROR_SUCCESS;
525 if (needs_ui_sequence(package))
526 rc = ACTION_PerformUIAction(package, action, -1);
527 else
528 rc = ACTION_PerformAction(package, action, -1);
530 msi_dialog_check_messages( NULL );
532 if (package->CurrentInstallState != ERROR_SUCCESS)
533 rc = package->CurrentInstallState;
535 if (rc == ERROR_FUNCTION_NOT_CALLED)
536 rc = ERROR_SUCCESS;
538 if (rc != ERROR_SUCCESS)
539 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
541 return rc;
544 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
546 static const WCHAR query[] = {
547 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
548 ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
549 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
550 '`','S','e','q','u','e','n','c','e','`',0};
551 MSIQUERY *view;
552 UINT r;
554 TRACE("%p %s\n", package, debugstr_w(table));
556 r = MSI_OpenQuery( package->db, &view, query, table );
557 if (r == ERROR_SUCCESS)
559 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
560 msiobj_release(&view->hdr);
562 return r;
565 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
567 static const WCHAR query[] = {
568 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
569 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
570 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
571 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
572 'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
573 static const WCHAR query_validate[] = {
574 'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
575 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
576 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
577 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
578 ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
579 MSIQUERY *view;
580 INT seq = 0;
581 UINT rc;
583 if (package->script->ExecuteSequenceRun)
585 TRACE("Execute Sequence already Run\n");
586 return ERROR_SUCCESS;
589 package->script->ExecuteSequenceRun = TRUE;
591 /* get the sequence number */
592 if (UIran)
594 MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
595 if (!row) return ERROR_FUNCTION_FAILED;
596 seq = MSI_RecordGetInteger(row,1);
597 msiobj_release(&row->hdr);
599 rc = MSI_OpenQuery(package->db, &view, query, seq);
600 if (rc == ERROR_SUCCESS)
602 TRACE("Running the actions\n");
604 msi_set_property(package->db, szSourceDir, NULL);
605 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
606 msiobj_release(&view->hdr);
608 return rc;
611 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
613 static const WCHAR query[] = {
614 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
615 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
616 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
617 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
618 MSIQUERY *view;
619 UINT rc;
621 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
622 if (rc == ERROR_SUCCESS)
624 TRACE("Running the actions\n");
625 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
626 msiobj_release(&view->hdr);
628 return rc;
631 /********************************************************
632 * ACTION helper functions and functions that perform the actions
633 *******************************************************/
634 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
635 UINT* rc, UINT script, BOOL force )
637 BOOL ret=FALSE;
638 UINT arc;
640 arc = ACTION_CustomAction(package, action, script, force);
642 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
644 *rc = arc;
645 ret = TRUE;
647 return ret;
650 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
652 MSICOMPONENT *comp;
654 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
656 if (!strcmpW( Component, comp->Component )) return comp;
658 return NULL;
661 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
663 MSIFEATURE *feature;
665 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
667 if (!strcmpW( Feature, feature->Feature )) return feature;
669 return NULL;
672 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
674 MSIFILE *file;
676 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
678 if (!strcmpW( key, file->File )) return file;
680 return NULL;
683 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
685 MSIFILEPATCH *patch;
687 /* FIXME: There might be more than one patch */
688 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
690 if (!strcmpW( key, patch->File->File )) return patch;
692 return NULL;
695 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
697 MSIFOLDER *folder;
699 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
701 if (!strcmpW( dir, folder->Directory )) return folder;
703 return NULL;
707 * Recursively create all directories in the path.
708 * shamelessly stolen from setupapi/queue.c
710 BOOL msi_create_full_path( const WCHAR *path )
712 BOOL ret = TRUE;
713 WCHAR *new_path;
714 int len;
716 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
717 strcpyW( new_path, path );
719 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
720 new_path[len - 1] = 0;
722 while (!CreateDirectoryW( new_path, NULL ))
724 WCHAR *slash;
725 DWORD last_error = GetLastError();
726 if (last_error == ERROR_ALREADY_EXISTS) break;
727 if (last_error != ERROR_PATH_NOT_FOUND)
729 ret = FALSE;
730 break;
732 if (!(slash = strrchrW( new_path, '\\' )))
734 ret = FALSE;
735 break;
737 len = slash - new_path;
738 new_path[len] = 0;
739 if (!msi_create_full_path( new_path ))
741 ret = FALSE;
742 break;
744 new_path[len] = '\\';
746 msi_free( new_path );
747 return ret;
750 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
752 MSIRECORD *row;
754 row = MSI_CreateRecord( 4 );
755 MSI_RecordSetInteger( row, 1, a );
756 MSI_RecordSetInteger( row, 2, b );
757 MSI_RecordSetInteger( row, 3, c );
758 MSI_RecordSetInteger( row, 4, d );
759 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
760 msiobj_release( &row->hdr );
762 msi_dialog_check_messages( NULL );
765 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
767 static const WCHAR query[] =
768 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
769 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
770 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
771 WCHAR message[1024];
772 MSIRECORD *row = 0;
773 DWORD size;
775 if (!package->LastAction || strcmpW( package->LastAction, action ))
777 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
779 if (MSI_RecordIsNull( row, 3 ))
781 msiobj_release( &row->hdr );
782 return;
784 /* update the cached action format */
785 msi_free( package->ActionFormat );
786 package->ActionFormat = msi_dup_record_field( row, 3 );
787 msi_free( package->LastAction );
788 package->LastAction = strdupW( action );
789 msiobj_release( &row->hdr );
791 size = 1024;
792 MSI_RecordSetStringW( record, 0, package->ActionFormat );
793 MSI_FormatRecordW( package, record, message, &size );
794 row = MSI_CreateRecord( 1 );
795 MSI_RecordSetStringW( row, 1, message );
796 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
797 msiobj_release( &row->hdr );
800 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
802 if (!comp->Enabled)
804 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
805 return INSTALLSTATE_UNKNOWN;
807 if (package->need_rollback) return comp->Installed;
808 return comp->ActionRequest;
811 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
813 if (package->need_rollback) return feature->Installed;
814 return feature->ActionRequest;
817 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
819 MSIPACKAGE *package = param;
820 LPCWSTR dir, component, full_path;
821 MSIRECORD *uirow;
822 MSIFOLDER *folder;
823 MSICOMPONENT *comp;
825 component = MSI_RecordGetString(row, 2);
826 if (!component)
827 return ERROR_SUCCESS;
829 comp = msi_get_loaded_component(package, component);
830 if (!comp)
831 return ERROR_SUCCESS;
833 comp->Action = msi_get_component_action( package, comp );
834 if (comp->Action != INSTALLSTATE_LOCAL)
836 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
837 return ERROR_SUCCESS;
840 dir = MSI_RecordGetString(row,1);
841 if (!dir)
843 ERR("Unable to get folder id\n");
844 return ERROR_SUCCESS;
847 uirow = MSI_CreateRecord(1);
848 MSI_RecordSetStringW(uirow, 1, dir);
849 msi_ui_actiondata(package, szCreateFolders, uirow);
850 msiobj_release(&uirow->hdr);
852 full_path = msi_get_target_folder( package, dir );
853 if (!full_path)
855 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
856 return ERROR_SUCCESS;
858 TRACE("folder is %s\n", debugstr_w(full_path));
860 folder = msi_get_loaded_folder( package, dir );
861 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
862 folder->State = FOLDER_STATE_CREATED;
863 return ERROR_SUCCESS;
866 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
868 static const WCHAR query[] = {
869 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
870 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
871 MSIQUERY *view;
872 UINT rc;
874 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
875 if (rc != ERROR_SUCCESS)
876 return ERROR_SUCCESS;
878 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
879 msiobj_release(&view->hdr);
880 return rc;
883 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
885 MSIPACKAGE *package = param;
886 LPCWSTR dir, component, full_path;
887 MSIRECORD *uirow;
888 MSIFOLDER *folder;
889 MSICOMPONENT *comp;
891 component = MSI_RecordGetString(row, 2);
892 if (!component)
893 return ERROR_SUCCESS;
895 comp = msi_get_loaded_component(package, component);
896 if (!comp)
897 return ERROR_SUCCESS;
899 comp->Action = msi_get_component_action( package, comp );
900 if (comp->Action != INSTALLSTATE_ABSENT)
902 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
903 return ERROR_SUCCESS;
906 dir = MSI_RecordGetString( row, 1 );
907 if (!dir)
909 ERR("Unable to get folder id\n");
910 return ERROR_SUCCESS;
913 full_path = msi_get_target_folder( package, dir );
914 if (!full_path)
916 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
917 return ERROR_SUCCESS;
919 TRACE("folder is %s\n", debugstr_w(full_path));
921 uirow = MSI_CreateRecord( 1 );
922 MSI_RecordSetStringW( uirow, 1, dir );
923 msi_ui_actiondata( package, szRemoveFolders, uirow );
924 msiobj_release( &uirow->hdr );
926 RemoveDirectoryW( full_path );
927 folder = msi_get_loaded_folder( package, dir );
928 folder->State = FOLDER_STATE_REMOVED;
929 return ERROR_SUCCESS;
932 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
934 static const WCHAR query[] = {
935 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
936 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
937 MSIQUERY *view;
938 UINT rc;
940 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
941 if (rc != ERROR_SUCCESS)
942 return ERROR_SUCCESS;
944 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
945 msiobj_release( &view->hdr );
946 return rc;
949 static UINT load_component( MSIRECORD *row, LPVOID param )
951 MSIPACKAGE *package = param;
952 MSICOMPONENT *comp;
954 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
955 if (!comp)
956 return ERROR_FUNCTION_FAILED;
958 list_add_tail( &package->components, &comp->entry );
960 /* fill in the data */
961 comp->Component = msi_dup_record_field( row, 1 );
963 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
965 comp->ComponentId = msi_dup_record_field( row, 2 );
966 comp->Directory = msi_dup_record_field( row, 3 );
967 comp->Attributes = MSI_RecordGetInteger(row,4);
968 comp->Condition = msi_dup_record_field( row, 5 );
969 comp->KeyPath = msi_dup_record_field( row, 6 );
971 comp->Installed = INSTALLSTATE_UNKNOWN;
972 comp->Action = INSTALLSTATE_UNKNOWN;
973 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
975 comp->assembly = msi_load_assembly( package, comp );
976 return ERROR_SUCCESS;
979 UINT msi_load_all_components( MSIPACKAGE *package )
981 static const WCHAR query[] = {
982 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
983 '`','C','o','m','p','o','n','e','n','t','`',0};
984 MSIQUERY *view;
985 UINT r;
987 if (!list_empty(&package->components))
988 return ERROR_SUCCESS;
990 r = MSI_DatabaseOpenViewW( package->db, query, &view );
991 if (r != ERROR_SUCCESS)
992 return r;
994 if (!msi_init_assembly_caches( package ))
996 ERR("can't initialize assembly caches\n");
997 msiobj_release( &view->hdr );
998 return ERROR_FUNCTION_FAILED;
1001 r = MSI_IterateRecords(view, NULL, load_component, package);
1002 msiobj_release(&view->hdr);
1003 msi_destroy_assembly_caches( package );
1004 return r;
1007 typedef struct {
1008 MSIPACKAGE *package;
1009 MSIFEATURE *feature;
1010 } _ilfs;
1012 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1014 ComponentList *cl;
1016 cl = msi_alloc( sizeof (*cl) );
1017 if ( !cl )
1018 return ERROR_NOT_ENOUGH_MEMORY;
1019 cl->component = comp;
1020 list_add_tail( &feature->Components, &cl->entry );
1022 return ERROR_SUCCESS;
1025 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1027 FeatureList *fl;
1029 fl = msi_alloc( sizeof(*fl) );
1030 if ( !fl )
1031 return ERROR_NOT_ENOUGH_MEMORY;
1032 fl->feature = child;
1033 list_add_tail( &parent->Children, &fl->entry );
1035 return ERROR_SUCCESS;
1038 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1040 _ilfs* ilfs = param;
1041 LPCWSTR component;
1042 MSICOMPONENT *comp;
1044 component = MSI_RecordGetString(row,1);
1046 /* check to see if the component is already loaded */
1047 comp = msi_get_loaded_component( ilfs->package, component );
1048 if (!comp)
1050 ERR("unknown component %s\n", debugstr_w(component));
1051 return ERROR_FUNCTION_FAILED;
1054 add_feature_component( ilfs->feature, comp );
1055 comp->Enabled = TRUE;
1057 return ERROR_SUCCESS;
1060 static UINT load_feature(MSIRECORD * row, LPVOID param)
1062 static const WCHAR query[] = {
1063 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
1064 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1065 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
1066 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1067 MSIPACKAGE *package = param;
1068 MSIFEATURE *feature;
1069 MSIQUERY *view;
1070 _ilfs ilfs;
1071 UINT rc;
1073 /* fill in the data */
1075 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1076 if (!feature)
1077 return ERROR_NOT_ENOUGH_MEMORY;
1079 list_init( &feature->Children );
1080 list_init( &feature->Components );
1082 feature->Feature = msi_dup_record_field( row, 1 );
1084 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1086 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1087 feature->Title = msi_dup_record_field( row, 3 );
1088 feature->Description = msi_dup_record_field( row, 4 );
1090 if (!MSI_RecordIsNull(row,5))
1091 feature->Display = MSI_RecordGetInteger(row,5);
1093 feature->Level= MSI_RecordGetInteger(row,6);
1094 feature->Directory = msi_dup_record_field( row, 7 );
1095 feature->Attributes = MSI_RecordGetInteger(row,8);
1097 feature->Installed = INSTALLSTATE_UNKNOWN;
1098 feature->Action = INSTALLSTATE_UNKNOWN;
1099 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1101 list_add_tail( &package->features, &feature->entry );
1103 /* load feature components */
1105 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1106 if (rc != ERROR_SUCCESS)
1107 return ERROR_SUCCESS;
1109 ilfs.package = package;
1110 ilfs.feature = feature;
1112 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1113 msiobj_release(&view->hdr);
1114 return rc;
1117 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1119 MSIPACKAGE *package = param;
1120 MSIFEATURE *parent, *child;
1122 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1123 if (!child)
1124 return ERROR_FUNCTION_FAILED;
1126 if (!child->Feature_Parent)
1127 return ERROR_SUCCESS;
1129 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1130 if (!parent)
1131 return ERROR_FUNCTION_FAILED;
1133 add_feature_child( parent, child );
1134 return ERROR_SUCCESS;
1137 UINT msi_load_all_features( MSIPACKAGE *package )
1139 static const WCHAR query[] = {
1140 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1141 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
1142 '`','D','i','s','p','l','a','y','`',0};
1143 MSIQUERY *view;
1144 UINT r;
1146 if (!list_empty(&package->features))
1147 return ERROR_SUCCESS;
1149 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1150 if (r != ERROR_SUCCESS)
1151 return r;
1153 r = MSI_IterateRecords( view, NULL, load_feature, package );
1154 if (r != ERROR_SUCCESS)
1156 msiobj_release( &view->hdr );
1157 return r;
1159 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1160 msiobj_release( &view->hdr );
1161 return r;
1164 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1166 if (!p)
1167 return p;
1168 p = strchrW(p, ch);
1169 if (!p)
1170 return p;
1171 *p = 0;
1172 return p+1;
1175 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1177 static const WCHAR query[] = {
1178 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1179 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1180 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1181 MSIQUERY *view = NULL;
1182 MSIRECORD *row = NULL;
1183 UINT r;
1185 TRACE("%s\n", debugstr_w(file->File));
1187 r = MSI_OpenQuery(package->db, &view, query, file->File);
1188 if (r != ERROR_SUCCESS)
1189 goto done;
1191 r = MSI_ViewExecute(view, NULL);
1192 if (r != ERROR_SUCCESS)
1193 goto done;
1195 r = MSI_ViewFetch(view, &row);
1196 if (r != ERROR_SUCCESS)
1197 goto done;
1199 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1200 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1201 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1202 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1203 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1205 done:
1206 if (view) msiobj_release(&view->hdr);
1207 if (row) msiobj_release(&row->hdr);
1208 return r;
1211 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1213 MSIRECORD *row;
1214 static const WCHAR query[] = {
1215 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1216 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1217 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1219 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1220 if (!row)
1222 WARN("query failed\n");
1223 return ERROR_FUNCTION_FAILED;
1226 file->disk_id = MSI_RecordGetInteger( row, 1 );
1227 msiobj_release( &row->hdr );
1228 return ERROR_SUCCESS;
1231 static UINT load_file(MSIRECORD *row, LPVOID param)
1233 MSIPACKAGE* package = param;
1234 LPCWSTR component;
1235 MSIFILE *file;
1237 /* fill in the data */
1239 file = msi_alloc_zero( sizeof (MSIFILE) );
1240 if (!file)
1241 return ERROR_NOT_ENOUGH_MEMORY;
1243 file->File = msi_dup_record_field( row, 1 );
1245 component = MSI_RecordGetString( row, 2 );
1246 file->Component = msi_get_loaded_component( package, component );
1248 if (!file->Component)
1250 WARN("Component not found: %s\n", debugstr_w(component));
1251 msi_free(file->File);
1252 msi_free(file);
1253 return ERROR_SUCCESS;
1256 file->FileName = msi_dup_record_field( row, 3 );
1257 msi_reduce_to_long_filename( file->FileName );
1259 file->ShortName = msi_dup_record_field( row, 3 );
1260 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1262 file->FileSize = MSI_RecordGetInteger( row, 4 );
1263 file->Version = msi_dup_record_field( row, 5 );
1264 file->Language = msi_dup_record_field( row, 6 );
1265 file->Attributes = MSI_RecordGetInteger( row, 7 );
1266 file->Sequence = MSI_RecordGetInteger( row, 8 );
1268 file->state = msifs_invalid;
1270 /* if the compressed bits are not set in the file attributes,
1271 * then read the information from the package word count property
1273 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1275 file->IsCompressed = FALSE;
1277 else if (file->Attributes &
1278 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1280 file->IsCompressed = TRUE;
1282 else if (file->Attributes & msidbFileAttributesNoncompressed)
1284 file->IsCompressed = FALSE;
1286 else
1288 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1291 load_file_hash(package, file);
1292 load_file_disk_id(package, file);
1294 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1296 list_add_tail( &package->files, &file->entry );
1298 return ERROR_SUCCESS;
1301 static UINT load_all_files(MSIPACKAGE *package)
1303 static const WCHAR query[] = {
1304 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1305 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1306 '`','S','e','q','u','e','n','c','e','`', 0};
1307 MSIQUERY *view;
1308 UINT rc;
1310 if (!list_empty(&package->files))
1311 return ERROR_SUCCESS;
1313 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1314 if (rc != ERROR_SUCCESS)
1315 return ERROR_SUCCESS;
1317 rc = MSI_IterateRecords(view, NULL, load_file, package);
1318 msiobj_release(&view->hdr);
1319 return rc;
1322 static UINT load_media( MSIRECORD *row, LPVOID param )
1324 MSIPACKAGE *package = param;
1325 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1326 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1328 /* FIXME: load external cabinets and directory sources too */
1329 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1330 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1331 return ERROR_SUCCESS;
1334 static UINT load_all_media( MSIPACKAGE *package )
1336 static const WCHAR query[] = {
1337 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
1338 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
1339 '`','D','i','s','k','I','d','`',0};
1340 MSIQUERY *view;
1341 UINT r;
1343 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1344 if (r != ERROR_SUCCESS)
1345 return ERROR_SUCCESS;
1347 r = MSI_IterateRecords( view, NULL, load_media, package );
1348 msiobj_release( &view->hdr );
1349 return r;
1352 static UINT load_patch(MSIRECORD *row, LPVOID param)
1354 MSIPACKAGE *package = param;
1355 MSIFILEPATCH *patch;
1356 LPWSTR file_key;
1358 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1359 if (!patch)
1360 return ERROR_NOT_ENOUGH_MEMORY;
1362 file_key = msi_dup_record_field( row, 1 );
1363 patch->File = msi_get_loaded_file( package, file_key );
1364 msi_free(file_key);
1366 if( !patch->File )
1368 ERR("Failed to find target for patch in File table\n");
1369 msi_free(patch);
1370 return ERROR_FUNCTION_FAILED;
1373 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1375 /* FIXME: The database should be properly transformed */
1376 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1378 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1379 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1380 patch->IsApplied = FALSE;
1382 /* FIXME:
1383 * Header field - for patch validation.
1384 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1387 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1389 list_add_tail( &package->filepatches, &patch->entry );
1391 return ERROR_SUCCESS;
1394 static UINT load_all_patches(MSIPACKAGE *package)
1396 static const WCHAR query[] = {
1397 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1398 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1399 '`','S','e','q','u','e','n','c','e','`',0};
1400 MSIQUERY *view;
1401 UINT rc;
1403 if (!list_empty(&package->filepatches))
1404 return ERROR_SUCCESS;
1406 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1407 if (rc != ERROR_SUCCESS)
1408 return ERROR_SUCCESS;
1410 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1411 msiobj_release(&view->hdr);
1412 return rc;
1415 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1417 static const WCHAR query[] = {
1418 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1419 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1420 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1421 MSIQUERY *view;
1423 folder->persistent = FALSE;
1424 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1426 if (!MSI_ViewExecute( view, NULL ))
1428 MSIRECORD *rec;
1429 if (!MSI_ViewFetch( view, &rec ))
1431 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1432 folder->persistent = TRUE;
1433 msiobj_release( &rec->hdr );
1436 msiobj_release( &view->hdr );
1438 return ERROR_SUCCESS;
1441 static UINT load_folder( MSIRECORD *row, LPVOID param )
1443 MSIPACKAGE *package = param;
1444 static WCHAR szEmpty[] = { 0 };
1445 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1446 MSIFOLDER *folder;
1448 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1449 list_init( &folder->children );
1450 folder->Directory = msi_dup_record_field( row, 1 );
1451 folder->Parent = msi_dup_record_field( row, 2 );
1452 p = msi_dup_record_field(row, 3);
1454 TRACE("%s\n", debugstr_w(folder->Directory));
1456 /* split src and target dir */
1457 tgt_short = p;
1458 src_short = folder_split_path( p, ':' );
1460 /* split the long and short paths */
1461 tgt_long = folder_split_path( tgt_short, '|' );
1462 src_long = folder_split_path( src_short, '|' );
1464 /* check for no-op dirs */
1465 if (tgt_short && !strcmpW( szDot, tgt_short ))
1466 tgt_short = szEmpty;
1467 if (src_short && !strcmpW( szDot, src_short ))
1468 src_short = szEmpty;
1470 if (!tgt_long)
1471 tgt_long = tgt_short;
1473 if (!src_short) {
1474 src_short = tgt_short;
1475 src_long = tgt_long;
1478 if (!src_long)
1479 src_long = src_short;
1481 /* FIXME: use the target short path too */
1482 folder->TargetDefault = strdupW(tgt_long);
1483 folder->SourceShortPath = strdupW(src_short);
1484 folder->SourceLongPath = strdupW(src_long);
1485 msi_free(p);
1487 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1488 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1489 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1491 load_folder_persistence( package, folder );
1493 list_add_tail( &package->folders, &folder->entry );
1494 return ERROR_SUCCESS;
1497 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1499 FolderList *fl;
1501 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1502 fl->folder = child;
1503 list_add_tail( &parent->children, &fl->entry );
1504 return ERROR_SUCCESS;
1507 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1509 MSIPACKAGE *package = param;
1510 MSIFOLDER *parent, *child;
1512 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1513 return ERROR_FUNCTION_FAILED;
1515 if (!child->Parent) return ERROR_SUCCESS;
1517 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1518 return ERROR_FUNCTION_FAILED;
1520 return add_folder_child( parent, child );
1523 static UINT load_all_folders( MSIPACKAGE *package )
1525 static const WCHAR query[] = {
1526 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1527 '`','D','i','r','e','c','t','o','r','y','`',0};
1528 MSIQUERY *view;
1529 UINT r;
1531 if (!list_empty(&package->folders))
1532 return ERROR_SUCCESS;
1534 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1535 if (r != ERROR_SUCCESS)
1536 return r;
1538 r = MSI_IterateRecords( view, NULL, load_folder, package );
1539 if (r != ERROR_SUCCESS)
1541 msiobj_release( &view->hdr );
1542 return r;
1544 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1545 msiobj_release( &view->hdr );
1546 return r;
1549 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1551 msi_set_property( package->db, szCostingComplete, szZero );
1552 msi_set_property( package->db, szRootDrive, szCRoot );
1554 load_all_folders( package );
1555 msi_load_all_components( package );
1556 msi_load_all_features( package );
1557 load_all_files( package );
1558 load_all_patches( package );
1559 load_all_media( package );
1561 return ERROR_SUCCESS;
1564 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1566 const WCHAR *action = package->script->Actions[script][index];
1567 ui_actionstart( package, action );
1568 TRACE("executing %s\n", debugstr_w(action));
1569 return ACTION_PerformAction( package, action, script );
1572 static UINT execute_script( MSIPACKAGE *package, UINT script )
1574 UINT i, rc = ERROR_SUCCESS;
1576 TRACE("executing script %u\n", script);
1578 if (!package->script)
1580 ERR("no script!\n");
1581 return ERROR_FUNCTION_FAILED;
1583 if (script == ROLLBACK_SCRIPT)
1585 for (i = package->script->ActionCount[script]; i > 0; i--)
1587 rc = execute_script_action( package, script, i - 1 );
1588 if (rc != ERROR_SUCCESS) break;
1591 else
1593 for (i = 0; i < package->script->ActionCount[script]; i++)
1595 rc = execute_script_action( package, script, i );
1596 if (rc != ERROR_SUCCESS) break;
1599 msi_free_action_script(package, script);
1600 return rc;
1603 static UINT ACTION_FileCost(MSIPACKAGE *package)
1605 return ERROR_SUCCESS;
1608 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1610 MSICOMPONENT *comp;
1611 UINT r;
1613 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1615 if (!comp->ComponentId) continue;
1617 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1618 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1619 &comp->Installed );
1620 if (r != ERROR_SUCCESS)
1621 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1622 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1623 &comp->Installed );
1624 if (r != ERROR_SUCCESS)
1625 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1626 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1627 &comp->Installed );
1628 if (r != ERROR_SUCCESS)
1629 comp->Installed = INSTALLSTATE_ABSENT;
1633 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1635 MSIFEATURE *feature;
1637 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1639 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1641 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1642 feature->Installed = INSTALLSTATE_ABSENT;
1643 else
1644 feature->Installed = state;
1648 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1650 return (feature->Level > 0 && feature->Level <= level);
1653 static BOOL process_state_property(MSIPACKAGE* package, int level,
1654 LPCWSTR property, INSTALLSTATE state)
1656 LPWSTR override;
1657 MSIFEATURE *feature;
1659 override = msi_dup_property( package->db, property );
1660 if (!override)
1661 return FALSE;
1663 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1665 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1666 continue;
1668 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1670 if (!strcmpiW( override, szAll ))
1672 if (feature->Installed != state)
1674 feature->Action = state;
1675 feature->ActionRequest = state;
1678 else
1680 LPWSTR ptr = override;
1681 LPWSTR ptr2 = strchrW(override,',');
1683 while (ptr)
1685 int len = ptr2 - ptr;
1687 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1688 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1690 if (feature->Installed != state)
1692 feature->Action = state;
1693 feature->ActionRequest = state;
1695 break;
1697 if (ptr2)
1699 ptr=ptr2+1;
1700 ptr2 = strchrW(ptr,',');
1702 else
1703 break;
1707 msi_free(override);
1708 return TRUE;
1711 static BOOL process_overrides( MSIPACKAGE *package, int level )
1713 static const WCHAR szAddLocal[] =
1714 {'A','D','D','L','O','C','A','L',0};
1715 static const WCHAR szAddSource[] =
1716 {'A','D','D','S','O','U','R','C','E',0};
1717 static const WCHAR szAdvertise[] =
1718 {'A','D','V','E','R','T','I','S','E',0};
1719 BOOL ret = FALSE;
1721 /* all these activation/deactivation things happen in order and things
1722 * later on the list override things earlier on the list.
1724 * 0 INSTALLLEVEL processing
1725 * 1 ADDLOCAL
1726 * 2 REMOVE
1727 * 3 ADDSOURCE
1728 * 4 ADDDEFAULT
1729 * 5 REINSTALL
1730 * 6 ADVERTISE
1731 * 7 COMPADDLOCAL
1732 * 8 COMPADDSOURCE
1733 * 9 FILEADDLOCAL
1734 * 10 FILEADDSOURCE
1735 * 11 FILEADDDEFAULT
1737 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1738 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1739 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1740 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1741 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1743 if (ret)
1744 msi_set_property( package->db, szPreselected, szOne );
1746 return ret;
1749 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1751 int level;
1752 MSICOMPONENT* component;
1753 MSIFEATURE *feature;
1755 TRACE("Checking Install Level\n");
1757 level = msi_get_property_int(package->db, szInstallLevel, 1);
1759 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1761 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1763 if (!is_feature_selected( feature, level )) continue;
1765 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1767 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1769 feature->Action = INSTALLSTATE_SOURCE;
1770 feature->ActionRequest = INSTALLSTATE_SOURCE;
1772 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1774 feature->Action = INSTALLSTATE_ADVERTISED;
1775 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1777 else
1779 feature->Action = INSTALLSTATE_LOCAL;
1780 feature->ActionRequest = INSTALLSTATE_LOCAL;
1784 /* disable child features of unselected parent or follow parent */
1785 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1787 FeatureList *fl;
1789 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1791 if (!is_feature_selected( feature, level ))
1793 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1794 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1796 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1798 fl->feature->Action = feature->Action;
1799 fl->feature->ActionRequest = feature->ActionRequest;
1804 else /* preselected */
1806 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1808 if (!is_feature_selected( feature, level )) continue;
1810 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1812 if (feature->Installed == INSTALLSTATE_ABSENT)
1814 feature->Action = INSTALLSTATE_UNKNOWN;
1815 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1817 else
1819 feature->Action = feature->Installed;
1820 feature->ActionRequest = feature->Installed;
1824 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1826 FeatureList *fl;
1828 if (!is_feature_selected( feature, level )) continue;
1830 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1832 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1834 fl->feature->Action = feature->Action;
1835 fl->feature->ActionRequest = feature->ActionRequest;
1841 /* now we want to set component state based based on feature state */
1842 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1844 ComponentList *cl;
1846 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1847 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1848 feature->ActionRequest, feature->Action);
1850 if (!is_feature_selected( feature, level )) continue;
1852 /* features with components that have compressed files are made local */
1853 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1855 if (cl->component->ForceLocalState &&
1856 feature->ActionRequest == INSTALLSTATE_SOURCE)
1858 feature->Action = INSTALLSTATE_LOCAL;
1859 feature->ActionRequest = INSTALLSTATE_LOCAL;
1860 break;
1864 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1866 component = cl->component;
1868 switch (feature->ActionRequest)
1870 case INSTALLSTATE_ABSENT:
1871 component->anyAbsent = 1;
1872 break;
1873 case INSTALLSTATE_ADVERTISED:
1874 component->hasAdvertiseFeature = 1;
1875 break;
1876 case INSTALLSTATE_SOURCE:
1877 component->hasSourceFeature = 1;
1878 break;
1879 case INSTALLSTATE_LOCAL:
1880 component->hasLocalFeature = 1;
1881 break;
1882 case INSTALLSTATE_DEFAULT:
1883 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1884 component->hasAdvertiseFeature = 1;
1885 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1886 component->hasSourceFeature = 1;
1887 else
1888 component->hasLocalFeature = 1;
1889 break;
1890 default:
1891 break;
1896 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1898 /* check if it's local or source */
1899 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1900 (component->hasLocalFeature || component->hasSourceFeature))
1902 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1903 !component->ForceLocalState)
1905 component->Action = INSTALLSTATE_SOURCE;
1906 component->ActionRequest = INSTALLSTATE_SOURCE;
1908 else
1910 component->Action = INSTALLSTATE_LOCAL;
1911 component->ActionRequest = INSTALLSTATE_LOCAL;
1913 continue;
1916 /* if any feature is local, the component must be local too */
1917 if (component->hasLocalFeature)
1919 component->Action = INSTALLSTATE_LOCAL;
1920 component->ActionRequest = INSTALLSTATE_LOCAL;
1921 continue;
1923 if (component->hasSourceFeature)
1925 component->Action = INSTALLSTATE_SOURCE;
1926 component->ActionRequest = INSTALLSTATE_SOURCE;
1927 continue;
1929 if (component->hasAdvertiseFeature)
1931 component->Action = INSTALLSTATE_ADVERTISED;
1932 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1933 continue;
1935 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1936 if (component->anyAbsent &&
1937 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1939 component->Action = INSTALLSTATE_ABSENT;
1940 component->ActionRequest = INSTALLSTATE_ABSENT;
1944 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1946 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1948 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1949 component->Action = INSTALLSTATE_LOCAL;
1950 component->ActionRequest = INSTALLSTATE_LOCAL;
1953 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1954 component->Installed == INSTALLSTATE_SOURCE &&
1955 component->hasSourceFeature)
1957 component->Action = INSTALLSTATE_UNKNOWN;
1958 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1961 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
1962 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1965 return ERROR_SUCCESS;
1968 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1970 MSIPACKAGE *package = param;
1971 LPCWSTR name;
1972 MSIFEATURE *feature;
1974 name = MSI_RecordGetString( row, 1 );
1976 feature = msi_get_loaded_feature( package, name );
1977 if (!feature)
1978 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1979 else
1981 LPCWSTR Condition;
1982 Condition = MSI_RecordGetString(row,3);
1984 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1986 int level = MSI_RecordGetInteger(row,2);
1987 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1988 feature->Level = level;
1991 return ERROR_SUCCESS;
1994 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
1996 static const WCHAR name[] = {'\\',0};
1997 VS_FIXEDFILEINFO *ptr, *ret;
1998 LPVOID version;
1999 DWORD versize, handle;
2000 UINT sz;
2002 versize = GetFileVersionInfoSizeW( filename, &handle );
2003 if (!versize)
2004 return NULL;
2006 version = msi_alloc( versize );
2007 if (!version)
2008 return NULL;
2010 GetFileVersionInfoW( filename, 0, versize, version );
2012 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2014 msi_free( version );
2015 return NULL;
2018 ret = msi_alloc( sz );
2019 memcpy( ret, ptr, sz );
2021 msi_free( version );
2022 return ret;
2025 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2027 DWORD ms, ls;
2029 msi_parse_version_string( version, &ms, &ls );
2031 if (fi->dwFileVersionMS > ms) return 1;
2032 else if (fi->dwFileVersionMS < ms) return -1;
2033 else if (fi->dwFileVersionLS > ls) return 1;
2034 else if (fi->dwFileVersionLS < ls) return -1;
2035 return 0;
2038 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2040 DWORD ms1, ms2;
2042 msi_parse_version_string( ver1, &ms1, NULL );
2043 msi_parse_version_string( ver2, &ms2, NULL );
2045 if (ms1 > ms2) return 1;
2046 else if (ms1 < ms2) return -1;
2047 return 0;
2050 DWORD msi_get_disk_file_size( LPCWSTR filename )
2052 HANDLE file;
2053 DWORD size;
2055 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2056 if (file == INVALID_HANDLE_VALUE)
2057 return INVALID_FILE_SIZE;
2059 size = GetFileSize( file, NULL );
2060 TRACE("size is %u\n", size);
2061 CloseHandle( file );
2062 return size;
2065 BOOL msi_file_hash_matches( MSIFILE *file )
2067 UINT r;
2068 MSIFILEHASHINFO hash;
2070 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2071 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2072 if (r != ERROR_SUCCESS)
2073 return FALSE;
2075 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2078 static WCHAR *get_temp_dir( void )
2080 static UINT id;
2081 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2083 GetTempPathW( MAX_PATH, tmp );
2084 for (;;)
2086 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2087 if (CreateDirectoryW( dir, NULL )) break;
2089 return strdupW( dir );
2093 * msi_build_directory_name()
2095 * This function is to save messing round with directory names
2096 * It handles adding backslashes between path segments,
2097 * and can add \ at the end of the directory name if told to.
2099 * It takes a variable number of arguments.
2100 * It always allocates a new string for the result, so make sure
2101 * to free the return value when finished with it.
2103 * The first arg is the number of path segments that follow.
2104 * The arguments following count are a list of path segments.
2105 * A path segment may be NULL.
2107 * Path segments will be added with a \ separating them.
2108 * A \ will not be added after the last segment, however if the
2109 * last segment is NULL, then the last character will be a \
2111 WCHAR *msi_build_directory_name( DWORD count, ... )
2113 DWORD sz = 1, i;
2114 WCHAR *dir;
2115 va_list va;
2117 va_start( va, count );
2118 for (i = 0; i < count; i++)
2120 const WCHAR *str = va_arg( va, const WCHAR * );
2121 if (str) sz += strlenW( str ) + 1;
2123 va_end( va );
2125 dir = msi_alloc( sz * sizeof(WCHAR) );
2126 dir[0] = 0;
2128 va_start( va, count );
2129 for (i = 0; i < count; i++)
2131 const WCHAR *str = va_arg( va, const WCHAR * );
2132 if (!str) continue;
2133 strcatW( dir, str );
2134 if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2136 va_end( va );
2137 return dir;
2140 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2142 MSIASSEMBLY *assembly = file->Component->assembly;
2144 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2146 msi_free( file->TargetPath );
2147 if (assembly && !assembly->application)
2149 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2150 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2151 msi_track_tempfile( package, file->TargetPath );
2153 else
2155 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2156 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2159 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2162 static UINT calculate_file_cost( MSIPACKAGE *package )
2164 VS_FIXEDFILEINFO *file_version;
2165 WCHAR *font_version;
2166 MSIFILE *file;
2168 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2170 MSICOMPONENT *comp = file->Component;
2171 DWORD file_size;
2173 if (!comp->Enabled) continue;
2175 if (file->IsCompressed)
2176 comp->ForceLocalState = TRUE;
2178 set_target_path( package, file );
2180 if ((comp->assembly && !comp->assembly->installed) ||
2181 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2183 comp->Cost += file->FileSize;
2184 continue;
2186 file_size = msi_get_disk_file_size( file->TargetPath );
2188 if (file->Version)
2190 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2192 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2194 comp->Cost += file->FileSize - file_size;
2196 msi_free( file_version );
2197 continue;
2199 else if ((font_version = font_version_from_file( file->TargetPath )))
2201 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2203 comp->Cost += file->FileSize - file_size;
2205 msi_free( font_version );
2206 continue;
2209 if (file_size != file->FileSize)
2211 comp->Cost += file->FileSize - file_size;
2214 return ERROR_SUCCESS;
2217 void msi_clean_path( WCHAR *p )
2219 WCHAR *q = p;
2220 int n, len = 0;
2222 while (1)
2224 /* copy until the end of the string or a space */
2225 while (*p != ' ' && (*q = *p))
2227 p++, len++;
2228 /* reduce many backslashes to one */
2229 if (*p != '\\' || *q != '\\')
2230 q++;
2233 /* quit at the end of the string */
2234 if (!*p)
2235 break;
2237 /* count the number of spaces */
2238 n = 0;
2239 while (p[n] == ' ')
2240 n++;
2242 /* if it's leading or trailing space, skip it */
2243 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2244 p += n;
2245 else /* copy n spaces */
2246 while (n && (*q++ = *p++)) n--;
2250 static WCHAR *get_target_dir_property( MSIDATABASE *db )
2252 int len;
2253 WCHAR *path, *target_dir = msi_dup_property( db, szTargetDir );
2255 if (!target_dir) return NULL;
2257 len = strlenW( target_dir );
2258 if (target_dir[len - 1] == '\\') return target_dir;
2259 if ((path = msi_alloc( (len + 2) * sizeof(WCHAR) )))
2261 strcpyW( path, target_dir );
2262 path[len] = '\\';
2263 path[len + 1] = 0;
2265 msi_free( target_dir );
2266 return path;
2269 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2271 FolderList *fl;
2272 MSIFOLDER *folder, *parent, *child;
2273 WCHAR *path;
2275 TRACE("resolving %s\n", debugstr_w(name));
2277 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2279 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2281 if (!load_prop || !(path = get_target_dir_property( package->db )))
2283 path = msi_dup_property( package->db, szRootDrive );
2286 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2288 parent = msi_get_loaded_folder( package, folder->Parent );
2289 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2291 msi_clean_path( path );
2292 if (folder->ResolvedTarget && !strcmpiW( path, folder->ResolvedTarget ))
2294 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2295 msi_free( path );
2296 return;
2298 msi_set_property( package->db, folder->Directory, path );
2299 msi_free( folder->ResolvedTarget );
2300 folder->ResolvedTarget = path;
2302 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2304 child = fl->folder;
2305 msi_resolve_target_folder( package, child->Directory, load_prop );
2307 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2310 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2312 static const WCHAR query[] = {
2313 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2314 '`','C','o','n','d','i','t','i','o','n','`',0};
2315 static const WCHAR szOutOfDiskSpace[] = {
2316 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2317 MSICOMPONENT *comp;
2318 MSIQUERY *view;
2319 LPWSTR level;
2320 UINT rc;
2322 TRACE("Building directory properties\n");
2323 msi_resolve_target_folder( package, szTargetDir, TRUE );
2325 TRACE("Evaluating component conditions\n");
2326 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2328 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2330 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2331 comp->Enabled = FALSE;
2333 else
2334 comp->Enabled = TRUE;
2337 /* read components states from the registry */
2338 ACTION_GetComponentInstallStates(package);
2339 ACTION_GetFeatureInstallStates(package);
2341 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2343 TRACE("Evaluating feature conditions\n");
2345 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2346 if (rc == ERROR_SUCCESS)
2348 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2349 msiobj_release( &view->hdr );
2350 if (rc != ERROR_SUCCESS)
2351 return rc;
2355 TRACE("Calculating file cost\n");
2356 calculate_file_cost( package );
2358 msi_set_property( package->db, szCostingComplete, szOne );
2359 /* set default run level if not set */
2360 level = msi_dup_property( package->db, szInstallLevel );
2361 if (!level)
2362 msi_set_property( package->db, szInstallLevel, szOne );
2363 msi_free(level);
2365 /* FIXME: check volume disk space */
2366 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2368 return MSI_SetFeatureStates(package);
2371 /* OK this value is "interpreted" and then formatted based on the
2372 first few characters */
2373 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2374 DWORD *size)
2376 LPSTR data = NULL;
2378 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2380 if (value[1]=='x')
2382 LPWSTR ptr;
2383 CHAR byte[5];
2384 LPWSTR deformated = NULL;
2385 int count;
2387 deformat_string(package, &value[2], &deformated);
2389 /* binary value type */
2390 ptr = deformated;
2391 *type = REG_BINARY;
2392 if (strlenW(ptr)%2)
2393 *size = (strlenW(ptr)/2)+1;
2394 else
2395 *size = strlenW(ptr)/2;
2397 data = msi_alloc(*size);
2399 byte[0] = '0';
2400 byte[1] = 'x';
2401 byte[4] = 0;
2402 count = 0;
2403 /* if uneven pad with a zero in front */
2404 if (strlenW(ptr)%2)
2406 byte[2]= '0';
2407 byte[3]= *ptr;
2408 ptr++;
2409 data[count] = (BYTE)strtol(byte,NULL,0);
2410 count ++;
2411 TRACE("Uneven byte count\n");
2413 while (*ptr)
2415 byte[2]= *ptr;
2416 ptr++;
2417 byte[3]= *ptr;
2418 ptr++;
2419 data[count] = (BYTE)strtol(byte,NULL,0);
2420 count ++;
2422 msi_free(deformated);
2424 TRACE("Data %i bytes(%i)\n",*size,count);
2426 else
2428 LPWSTR deformated;
2429 LPWSTR p;
2430 DWORD d = 0;
2431 deformat_string(package, &value[1], &deformated);
2433 *type=REG_DWORD;
2434 *size = sizeof(DWORD);
2435 data = msi_alloc(*size);
2436 p = deformated;
2437 if (*p == '-')
2438 p++;
2439 while (*p)
2441 if ( (*p < '0') || (*p > '9') )
2442 break;
2443 d *= 10;
2444 d += (*p - '0');
2445 p++;
2447 if (deformated[0] == '-')
2448 d = -d;
2449 *(LPDWORD)data = d;
2450 TRACE("DWORD %i\n",*(LPDWORD)data);
2452 msi_free(deformated);
2455 else
2457 static const WCHAR szMulti[] = {'[','~',']',0};
2458 LPCWSTR ptr;
2459 *type=REG_SZ;
2461 if (value[0]=='#')
2463 if (value[1]=='%')
2465 ptr = &value[2];
2466 *type=REG_EXPAND_SZ;
2468 else
2469 ptr = &value[1];
2471 else
2472 ptr=value;
2474 if (strstrW(value, szMulti))
2475 *type = REG_MULTI_SZ;
2477 /* remove initial delimiter */
2478 if (!strncmpW(value, szMulti, 3))
2479 ptr = value + 3;
2481 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2483 /* add double NULL terminator */
2484 if (*type == REG_MULTI_SZ)
2486 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2487 data = msi_realloc_zero(data, *size);
2490 return data;
2493 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2495 const WCHAR *ret;
2497 switch (root)
2499 case -1:
2500 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2502 *root_key = HKEY_LOCAL_MACHINE;
2503 ret = szHLM;
2505 else
2507 *root_key = HKEY_CURRENT_USER;
2508 ret = szHCU;
2510 break;
2511 case 0:
2512 *root_key = HKEY_CLASSES_ROOT;
2513 ret = szHCR;
2514 break;
2515 case 1:
2516 *root_key = HKEY_CURRENT_USER;
2517 ret = szHCU;
2518 break;
2519 case 2:
2520 *root_key = HKEY_LOCAL_MACHINE;
2521 ret = szHLM;
2522 break;
2523 case 3:
2524 *root_key = HKEY_USERS;
2525 ret = szHU;
2526 break;
2527 default:
2528 ERR("Unknown root %i\n", root);
2529 return NULL;
2532 return ret;
2535 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2537 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2538 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2540 if (is_64bit && package->platform == PLATFORM_INTEL &&
2541 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2543 UINT size;
2544 WCHAR *path_32node;
2546 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2547 if (!(path_32node = msi_alloc( size ))) return NULL;
2549 memcpy( path_32node, path, len * sizeof(WCHAR) );
2550 strcpyW( path_32node + len, szWow6432Node );
2551 strcatW( path_32node, szBackSlash );
2552 strcatW( path_32node, path + len );
2553 return path_32node;
2556 return strdupW( path );
2559 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2561 MSIPACKAGE *package = param;
2562 LPSTR value_data = NULL;
2563 HKEY root_key, hkey;
2564 DWORD type,size;
2565 LPWSTR deformated, uikey, keypath;
2566 LPCWSTR szRoot, component, name, key, value;
2567 MSICOMPONENT *comp;
2568 MSIRECORD * uirow;
2569 INT root;
2570 BOOL check_first = FALSE;
2571 UINT rc;
2573 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2575 component = MSI_RecordGetString(row, 6);
2576 comp = msi_get_loaded_component(package,component);
2577 if (!comp)
2578 return ERROR_SUCCESS;
2580 comp->Action = msi_get_component_action( package, comp );
2581 if (comp->Action != INSTALLSTATE_LOCAL)
2583 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2584 return ERROR_SUCCESS;
2587 name = MSI_RecordGetString(row, 4);
2588 if( MSI_RecordIsNull(row,5) && name )
2590 /* null values can have special meanings */
2591 if (name[0]=='-' && name[1] == 0)
2592 return ERROR_SUCCESS;
2593 else if ((name[0]=='+' && name[1] == 0) ||
2594 (name[0] == '*' && name[1] == 0))
2595 name = NULL;
2596 check_first = TRUE;
2599 root = MSI_RecordGetInteger(row,2);
2600 key = MSI_RecordGetString(row, 3);
2602 szRoot = get_root_key( package, root, &root_key );
2603 if (!szRoot)
2604 return ERROR_SUCCESS;
2606 deformat_string(package, key , &deformated);
2607 size = strlenW(deformated) + strlenW(szRoot) + 1;
2608 uikey = msi_alloc(size*sizeof(WCHAR));
2609 strcpyW(uikey,szRoot);
2610 strcatW(uikey,deformated);
2612 keypath = get_keypath( package, root_key, deformated );
2613 msi_free( deformated );
2614 if (RegCreateKeyW( root_key, keypath, &hkey ))
2616 ERR("Could not create key %s\n", debugstr_w(keypath));
2617 msi_free(uikey);
2618 msi_free(keypath);
2619 return ERROR_SUCCESS;
2622 value = MSI_RecordGetString(row,5);
2623 if (value)
2624 value_data = parse_value(package, value, &type, &size);
2625 else
2627 value_data = (LPSTR)strdupW(szEmpty);
2628 size = sizeof(szEmpty);
2629 type = REG_SZ;
2632 deformat_string(package, name, &deformated);
2634 if (!check_first)
2636 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2637 debugstr_w(uikey));
2638 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2640 else
2642 DWORD sz = 0;
2643 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2644 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2646 TRACE("value %s of %s checked already exists\n",
2647 debugstr_w(deformated), debugstr_w(uikey));
2649 else
2651 TRACE("Checked and setting value %s of %s\n",
2652 debugstr_w(deformated), debugstr_w(uikey));
2653 if (deformated || size)
2654 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2657 RegCloseKey(hkey);
2659 uirow = MSI_CreateRecord(3);
2660 MSI_RecordSetStringW(uirow,2,deformated);
2661 MSI_RecordSetStringW(uirow,1,uikey);
2662 if (type == REG_SZ || type == REG_EXPAND_SZ)
2663 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2664 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2665 msiobj_release( &uirow->hdr );
2667 msi_free(value_data);
2668 msi_free(deformated);
2669 msi_free(uikey);
2670 msi_free(keypath);
2672 return ERROR_SUCCESS;
2675 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2677 static const WCHAR query[] = {
2678 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2679 '`','R','e','g','i','s','t','r','y','`',0};
2680 MSIQUERY *view;
2681 UINT rc;
2683 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2684 if (rc != ERROR_SUCCESS)
2685 return ERROR_SUCCESS;
2687 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2688 msiobj_release(&view->hdr);
2689 return rc;
2692 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2694 LONG res;
2695 HKEY hkey;
2696 DWORD num_subkeys, num_values;
2698 if (delete_key)
2700 if ((res = RegDeleteTreeW( hkey_root, key )))
2702 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2704 return;
2707 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2709 if ((res = RegDeleteValueW( hkey, value )))
2711 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2713 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2714 NULL, NULL, NULL, NULL );
2715 RegCloseKey( hkey );
2716 if (!res && !num_subkeys && !num_values)
2718 TRACE("Removing empty key %s\n", debugstr_w(key));
2719 RegDeleteKeyW( hkey_root, key );
2721 return;
2723 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2727 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2729 MSIPACKAGE *package = param;
2730 LPCWSTR component, name, key_str, root_key_str;
2731 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2732 MSICOMPONENT *comp;
2733 MSIRECORD *uirow;
2734 BOOL delete_key = FALSE;
2735 HKEY hkey_root;
2736 UINT size;
2737 INT root;
2739 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2741 component = MSI_RecordGetString( row, 6 );
2742 comp = msi_get_loaded_component( package, component );
2743 if (!comp)
2744 return ERROR_SUCCESS;
2746 comp->Action = msi_get_component_action( package, comp );
2747 if (comp->Action != INSTALLSTATE_ABSENT)
2749 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2750 return ERROR_SUCCESS;
2753 name = MSI_RecordGetString( row, 4 );
2754 if (MSI_RecordIsNull( row, 5 ) && name )
2756 if (name[0] == '+' && !name[1])
2757 return ERROR_SUCCESS;
2758 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2760 delete_key = TRUE;
2761 name = NULL;
2765 root = MSI_RecordGetInteger( row, 2 );
2766 key_str = MSI_RecordGetString( row, 3 );
2768 root_key_str = get_root_key( package, root, &hkey_root );
2769 if (!root_key_str)
2770 return ERROR_SUCCESS;
2772 deformat_string( package, key_str, &deformated_key );
2773 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2774 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2775 strcpyW( ui_key_str, root_key_str );
2776 strcatW( ui_key_str, deformated_key );
2778 deformat_string( package, name, &deformated_name );
2780 keypath = get_keypath( package, hkey_root, deformated_key );
2781 msi_free( deformated_key );
2782 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2783 msi_free( keypath );
2785 uirow = MSI_CreateRecord( 2 );
2786 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2787 MSI_RecordSetStringW( uirow, 2, deformated_name );
2788 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2789 msiobj_release( &uirow->hdr );
2791 msi_free( ui_key_str );
2792 msi_free( deformated_name );
2793 return ERROR_SUCCESS;
2796 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2798 MSIPACKAGE *package = param;
2799 LPCWSTR component, name, key_str, root_key_str;
2800 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2801 MSICOMPONENT *comp;
2802 MSIRECORD *uirow;
2803 BOOL delete_key = FALSE;
2804 HKEY hkey_root;
2805 UINT size;
2806 INT root;
2808 component = MSI_RecordGetString( row, 5 );
2809 comp = msi_get_loaded_component( package, component );
2810 if (!comp)
2811 return ERROR_SUCCESS;
2813 comp->Action = msi_get_component_action( package, comp );
2814 if (comp->Action != INSTALLSTATE_LOCAL)
2816 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2817 return ERROR_SUCCESS;
2820 if ((name = MSI_RecordGetString( row, 4 )))
2822 if (name[0] == '-' && !name[1])
2824 delete_key = TRUE;
2825 name = NULL;
2829 root = MSI_RecordGetInteger( row, 2 );
2830 key_str = MSI_RecordGetString( row, 3 );
2832 root_key_str = get_root_key( package, root, &hkey_root );
2833 if (!root_key_str)
2834 return ERROR_SUCCESS;
2836 deformat_string( package, key_str, &deformated_key );
2837 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2838 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2839 strcpyW( ui_key_str, root_key_str );
2840 strcatW( ui_key_str, deformated_key );
2842 deformat_string( package, name, &deformated_name );
2844 keypath = get_keypath( package, hkey_root, deformated_key );
2845 msi_free( deformated_key );
2846 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2847 msi_free( keypath );
2849 uirow = MSI_CreateRecord( 2 );
2850 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2851 MSI_RecordSetStringW( uirow, 2, deformated_name );
2852 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2853 msiobj_release( &uirow->hdr );
2855 msi_free( ui_key_str );
2856 msi_free( deformated_name );
2857 return ERROR_SUCCESS;
2860 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2862 static const WCHAR registry_query[] = {
2863 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2864 '`','R','e','g','i','s','t','r','y','`',0};
2865 static const WCHAR remove_registry_query[] = {
2866 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2867 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2868 MSIQUERY *view;
2869 UINT rc;
2871 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2872 if (rc == ERROR_SUCCESS)
2874 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2875 msiobj_release( &view->hdr );
2876 if (rc != ERROR_SUCCESS)
2877 return rc;
2879 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2880 if (rc == ERROR_SUCCESS)
2882 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2883 msiobj_release( &view->hdr );
2884 if (rc != ERROR_SUCCESS)
2885 return rc;
2887 return ERROR_SUCCESS;
2890 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2892 package->script->CurrentlyScripting = TRUE;
2894 return ERROR_SUCCESS;
2898 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2900 static const WCHAR query[]= {
2901 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2902 '`','R','e','g','i','s','t','r','y','`',0};
2903 MSICOMPONENT *comp;
2904 DWORD total = 0, count = 0;
2905 MSIQUERY *view;
2906 MSIFEATURE *feature;
2907 MSIFILE *file;
2908 UINT rc;
2910 TRACE("InstallValidate\n");
2912 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2913 if (rc == ERROR_SUCCESS)
2915 rc = MSI_IterateRecords( view, &count, NULL, package );
2916 msiobj_release( &view->hdr );
2917 if (rc != ERROR_SUCCESS)
2918 return rc;
2919 total += count * REG_PROGRESS_VALUE;
2921 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2922 total += COMPONENT_PROGRESS_VALUE;
2924 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2925 total += file->FileSize;
2927 msi_ui_progress( package, 0, total, 0, 0 );
2929 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2931 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2932 debugstr_w(feature->Feature), feature->Installed,
2933 feature->ActionRequest, feature->Action);
2935 return ERROR_SUCCESS;
2938 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2940 MSIPACKAGE* package = param;
2941 LPCWSTR cond = NULL;
2942 LPCWSTR message = NULL;
2943 UINT r;
2945 static const WCHAR title[]=
2946 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2948 cond = MSI_RecordGetString(row,1);
2950 r = MSI_EvaluateConditionW(package,cond);
2951 if (r == MSICONDITION_FALSE)
2953 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2955 LPWSTR deformated;
2956 message = MSI_RecordGetString(row,2);
2957 deformat_string(package,message,&deformated);
2958 MessageBoxW(NULL,deformated,title,MB_OK);
2959 msi_free(deformated);
2962 return ERROR_INSTALL_FAILURE;
2965 return ERROR_SUCCESS;
2968 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2970 static const WCHAR query[] = {
2971 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2972 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2973 MSIQUERY *view;
2974 UINT rc;
2976 TRACE("Checking launch conditions\n");
2978 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2979 if (rc != ERROR_SUCCESS)
2980 return ERROR_SUCCESS;
2982 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2983 msiobj_release(&view->hdr);
2984 return rc;
2987 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2990 if (!cmp->KeyPath)
2991 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
2993 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2995 static const WCHAR query[] = {
2996 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2997 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
2998 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
2999 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3000 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3001 MSIRECORD *row;
3002 UINT root, len;
3003 LPWSTR deformated, buffer, deformated_name;
3004 LPCWSTR key, name;
3006 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3007 if (!row)
3008 return NULL;
3010 root = MSI_RecordGetInteger(row,2);
3011 key = MSI_RecordGetString(row, 3);
3012 name = MSI_RecordGetString(row, 4);
3013 deformat_string(package, key , &deformated);
3014 deformat_string(package, name, &deformated_name);
3016 len = strlenW(deformated) + 6;
3017 if (deformated_name)
3018 len+=strlenW(deformated_name);
3020 buffer = msi_alloc( len *sizeof(WCHAR));
3022 if (deformated_name)
3023 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3024 else
3025 sprintfW(buffer,fmt,root,deformated);
3027 msi_free(deformated);
3028 msi_free(deformated_name);
3029 msiobj_release(&row->hdr);
3031 return buffer;
3033 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3035 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3036 return NULL;
3038 else
3040 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3042 if (file)
3043 return strdupW( file->TargetPath );
3045 return NULL;
3048 static HKEY openSharedDLLsKey(void)
3050 HKEY hkey=0;
3051 static const WCHAR path[] =
3052 {'S','o','f','t','w','a','r','e','\\',
3053 'M','i','c','r','o','s','o','f','t','\\',
3054 'W','i','n','d','o','w','s','\\',
3055 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3056 'S','h','a','r','e','d','D','L','L','s',0};
3058 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3059 return hkey;
3062 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3064 HKEY hkey;
3065 DWORD count=0;
3066 DWORD type;
3067 DWORD sz = sizeof(count);
3068 DWORD rc;
3070 hkey = openSharedDLLsKey();
3071 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3072 if (rc != ERROR_SUCCESS)
3073 count = 0;
3074 RegCloseKey(hkey);
3075 return count;
3078 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3080 HKEY hkey;
3082 hkey = openSharedDLLsKey();
3083 if (count > 0)
3084 msi_reg_set_val_dword( hkey, path, count );
3085 else
3086 RegDeleteValueW(hkey,path);
3087 RegCloseKey(hkey);
3088 return count;
3091 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3093 MSIFEATURE *feature;
3094 INT count = 0;
3095 BOOL write = FALSE;
3097 /* only refcount DLLs */
3098 if (comp->KeyPath == NULL ||
3099 comp->assembly ||
3100 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3101 comp->Attributes & msidbComponentAttributesODBCDataSource)
3102 write = FALSE;
3103 else
3105 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3106 write = (count > 0);
3108 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3109 write = TRUE;
3112 /* increment counts */
3113 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3115 ComponentList *cl;
3117 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3118 continue;
3120 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3122 if ( cl->component == comp )
3123 count++;
3127 /* decrement counts */
3128 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3130 ComponentList *cl;
3132 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3133 continue;
3135 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3137 if ( cl->component == comp )
3138 count--;
3142 /* ref count all the files in the component */
3143 if (write)
3145 MSIFILE *file;
3147 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3149 if (file->Component == comp)
3150 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3154 /* add a count for permanent */
3155 if (comp->Attributes & msidbComponentAttributesPermanent)
3156 count ++;
3158 comp->RefCount = count;
3160 if (write)
3161 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3164 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3166 if (comp->assembly)
3168 const WCHAR prefixW[] = {'<','\\',0};
3169 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3170 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3172 if (keypath)
3174 strcpyW( keypath, prefixW );
3175 strcatW( keypath, comp->assembly->display_name );
3177 return keypath;
3179 return resolve_keypath( package, comp );
3182 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3184 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3185 UINT rc;
3186 MSICOMPONENT *comp;
3187 HKEY hkey;
3189 TRACE("\n");
3191 squash_guid(package->ProductCode,squished_pc);
3192 msi_set_sourcedir_props(package, FALSE);
3194 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3196 MSIRECORD *uirow;
3197 INSTALLSTATE action;
3199 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3200 if (!comp->ComponentId)
3201 continue;
3203 squash_guid( comp->ComponentId, squished_cc );
3204 msi_free( comp->FullKeypath );
3205 comp->FullKeypath = build_full_keypath( package, comp );
3207 ACTION_RefCountComponent( package, comp );
3209 if (package->need_rollback) action = comp->Installed;
3210 else action = comp->ActionRequest;
3212 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3213 debugstr_w(comp->Component), debugstr_w(squished_cc),
3214 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3216 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3218 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3219 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3220 else
3221 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3223 if (rc != ERROR_SUCCESS)
3224 continue;
3226 if (comp->Attributes & msidbComponentAttributesPermanent)
3228 static const WCHAR szPermKey[] =
3229 { '0','0','0','0','0','0','0','0','0','0','0','0',
3230 '0','0','0','0','0','0','0','0','0','0','0','0',
3231 '0','0','0','0','0','0','0','0',0 };
3233 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3235 if (action == INSTALLSTATE_LOCAL)
3236 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3237 else
3239 MSIFILE *file;
3240 MSIRECORD *row;
3241 LPWSTR ptr, ptr2;
3242 WCHAR source[MAX_PATH];
3243 WCHAR base[MAX_PATH];
3244 LPWSTR sourcepath;
3246 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3247 static const WCHAR query[] = {
3248 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3249 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3250 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3251 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3252 '`','D','i','s','k','I','d','`',0};
3254 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3255 continue;
3257 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3258 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3259 ptr2 = strrchrW(source, '\\') + 1;
3260 msiobj_release(&row->hdr);
3262 lstrcpyW(base, package->PackagePath);
3263 ptr = strrchrW(base, '\\');
3264 *(ptr + 1) = '\0';
3266 sourcepath = msi_resolve_file_source(package, file);
3267 ptr = sourcepath + lstrlenW(base);
3268 lstrcpyW(ptr2, ptr);
3269 msi_free(sourcepath);
3271 msi_reg_set_val_str(hkey, squished_pc, source);
3273 RegCloseKey(hkey);
3275 else if (action == INSTALLSTATE_ABSENT)
3277 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3278 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3279 else
3280 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3283 /* UI stuff */
3284 uirow = MSI_CreateRecord(3);
3285 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3286 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3287 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3288 msi_ui_actiondata( package, szProcessComponents, uirow );
3289 msiobj_release( &uirow->hdr );
3291 return ERROR_SUCCESS;
3294 typedef struct {
3295 CLSID clsid;
3296 LPWSTR source;
3298 LPWSTR path;
3299 ITypeLib *ptLib;
3300 } typelib_struct;
3302 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3303 LPWSTR lpszName, LONG_PTR lParam)
3305 TLIBATTR *attr;
3306 typelib_struct *tl_struct = (typelib_struct*) lParam;
3307 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3308 int sz;
3309 HRESULT res;
3311 if (!IS_INTRESOURCE(lpszName))
3313 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3314 return TRUE;
3317 sz = strlenW(tl_struct->source)+4;
3318 sz *= sizeof(WCHAR);
3320 if ((INT_PTR)lpszName == 1)
3321 tl_struct->path = strdupW(tl_struct->source);
3322 else
3324 tl_struct->path = msi_alloc(sz);
3325 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3328 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3329 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3330 if (FAILED(res))
3332 msi_free(tl_struct->path);
3333 tl_struct->path = NULL;
3335 return TRUE;
3338 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3339 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3341 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3342 return FALSE;
3345 msi_free(tl_struct->path);
3346 tl_struct->path = NULL;
3348 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3349 ITypeLib_Release(tl_struct->ptLib);
3351 return TRUE;
3354 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3356 MSIPACKAGE* package = param;
3357 LPCWSTR component;
3358 MSICOMPONENT *comp;
3359 MSIFILE *file;
3360 typelib_struct tl_struct;
3361 ITypeLib *tlib;
3362 HMODULE module;
3363 HRESULT hr;
3365 component = MSI_RecordGetString(row,3);
3366 comp = msi_get_loaded_component(package,component);
3367 if (!comp)
3368 return ERROR_SUCCESS;
3370 comp->Action = msi_get_component_action( package, comp );
3371 if (comp->Action != INSTALLSTATE_LOCAL)
3373 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3374 return ERROR_SUCCESS;
3377 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3379 TRACE("component has no key path\n");
3380 return ERROR_SUCCESS;
3382 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3384 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3385 if (module)
3387 LPCWSTR guid;
3388 guid = MSI_RecordGetString(row,1);
3389 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3390 tl_struct.source = strdupW( file->TargetPath );
3391 tl_struct.path = NULL;
3393 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3394 (LONG_PTR)&tl_struct);
3396 if (tl_struct.path)
3398 LPCWSTR helpid, help_path = NULL;
3399 HRESULT res;
3401 helpid = MSI_RecordGetString(row,6);
3403 if (helpid) help_path = msi_get_target_folder( package, helpid );
3404 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3406 if (FAILED(res))
3407 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3408 else
3409 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3411 ITypeLib_Release(tl_struct.ptLib);
3412 msi_free(tl_struct.path);
3414 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3416 FreeLibrary(module);
3417 msi_free(tl_struct.source);
3419 else
3421 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3422 if (FAILED(hr))
3424 ERR("Failed to load type library: %08x\n", hr);
3425 return ERROR_INSTALL_FAILURE;
3428 ITypeLib_Release(tlib);
3431 return ERROR_SUCCESS;
3434 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3436 static const WCHAR query[] = {
3437 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3438 '`','T','y','p','e','L','i','b','`',0};
3439 MSIQUERY *view;
3440 UINT rc;
3442 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3443 if (rc != ERROR_SUCCESS)
3444 return ERROR_SUCCESS;
3446 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3447 msiobj_release(&view->hdr);
3448 return rc;
3451 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3453 MSIPACKAGE *package = param;
3454 LPCWSTR component, guid;
3455 MSICOMPONENT *comp;
3456 GUID libid;
3457 UINT version;
3458 LCID language;
3459 SYSKIND syskind;
3460 HRESULT hr;
3462 component = MSI_RecordGetString( row, 3 );
3463 comp = msi_get_loaded_component( package, component );
3464 if (!comp)
3465 return ERROR_SUCCESS;
3467 comp->Action = msi_get_component_action( package, comp );
3468 if (comp->Action != INSTALLSTATE_ABSENT)
3470 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3471 return ERROR_SUCCESS;
3473 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3475 guid = MSI_RecordGetString( row, 1 );
3476 CLSIDFromString( (LPCWSTR)guid, &libid );
3477 version = MSI_RecordGetInteger( row, 4 );
3478 language = MSI_RecordGetInteger( row, 2 );
3480 #ifdef _WIN64
3481 syskind = SYS_WIN64;
3482 #else
3483 syskind = SYS_WIN32;
3484 #endif
3486 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3487 if (FAILED(hr))
3489 WARN("Failed to unregister typelib: %08x\n", hr);
3492 return ERROR_SUCCESS;
3495 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3497 static const WCHAR query[] = {
3498 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3499 '`','T','y','p','e','L','i','b','`',0};
3500 MSIQUERY *view;
3501 UINT rc;
3503 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3504 if (rc != ERROR_SUCCESS)
3505 return ERROR_SUCCESS;
3507 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3508 msiobj_release( &view->hdr );
3509 return rc;
3512 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3514 static const WCHAR szlnk[] = {'.','l','n','k',0};
3515 LPCWSTR directory, extension, link_folder;
3516 LPWSTR link_file, filename;
3518 directory = MSI_RecordGetString( row, 2 );
3519 link_folder = msi_get_target_folder( package, directory );
3521 /* may be needed because of a bug somewhere else */
3522 msi_create_full_path( link_folder );
3524 filename = msi_dup_record_field( row, 3 );
3525 msi_reduce_to_long_filename( filename );
3527 extension = strchrW( filename, '.' );
3528 if (!extension || strcmpiW( extension, szlnk ))
3530 int len = strlenW( filename );
3531 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3532 memcpy( filename + len, szlnk, sizeof(szlnk) );
3534 link_file = msi_build_directory_name( 2, link_folder, filename );
3535 msi_free( filename );
3537 return link_file;
3540 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3542 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3543 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3544 WCHAR *folder, *dest, *path;
3546 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3547 folder = msi_dup_property( package->db, szWindowsFolder );
3548 else
3550 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3551 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3552 msi_free( appdata );
3554 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3555 msi_create_full_path( dest );
3556 path = msi_build_directory_name( 2, dest, icon_name );
3557 msi_free( folder );
3558 msi_free( dest );
3559 return path;
3562 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3564 MSIPACKAGE *package = param;
3565 LPWSTR link_file, deformated, path;
3566 LPCWSTR component, target;
3567 MSICOMPONENT *comp;
3568 IShellLinkW *sl = NULL;
3569 IPersistFile *pf = NULL;
3570 HRESULT res;
3572 component = MSI_RecordGetString(row, 4);
3573 comp = msi_get_loaded_component(package, component);
3574 if (!comp)
3575 return ERROR_SUCCESS;
3577 comp->Action = msi_get_component_action( package, comp );
3578 if (comp->Action != INSTALLSTATE_LOCAL)
3580 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3581 return ERROR_SUCCESS;
3583 msi_ui_actiondata( package, szCreateShortcuts, row );
3585 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3586 &IID_IShellLinkW, (LPVOID *) &sl );
3588 if (FAILED( res ))
3590 ERR("CLSID_ShellLink not available\n");
3591 goto err;
3594 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3595 if (FAILED( res ))
3597 ERR("QueryInterface(IID_IPersistFile) failed\n");
3598 goto err;
3601 target = MSI_RecordGetString(row, 5);
3602 if (strchrW(target, '['))
3604 deformat_string(package, target, &deformated);
3605 IShellLinkW_SetPath(sl,deformated);
3606 msi_free(deformated);
3608 else
3610 FIXME("poorly handled shortcut format, advertised shortcut\n");
3611 IShellLinkW_SetPath(sl,comp->FullKeypath);
3614 if (!MSI_RecordIsNull(row,6))
3616 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3617 deformat_string(package, arguments, &deformated);
3618 IShellLinkW_SetArguments(sl,deformated);
3619 msi_free(deformated);
3622 if (!MSI_RecordIsNull(row,7))
3624 LPCWSTR description = MSI_RecordGetString(row, 7);
3625 IShellLinkW_SetDescription(sl, description);
3628 if (!MSI_RecordIsNull(row,8))
3629 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3631 if (!MSI_RecordIsNull(row,9))
3633 INT index;
3634 LPCWSTR icon = MSI_RecordGetString(row, 9);
3636 path = msi_build_icon_path(package, icon);
3637 index = MSI_RecordGetInteger(row,10);
3639 /* no value means 0 */
3640 if (index == MSI_NULL_INTEGER)
3641 index = 0;
3643 IShellLinkW_SetIconLocation(sl, path, index);
3644 msi_free(path);
3647 if (!MSI_RecordIsNull(row,11))
3648 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3650 if (!MSI_RecordIsNull(row,12))
3652 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3653 full_path = msi_get_target_folder( package, wkdir );
3654 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3656 link_file = get_link_file(package, row);
3658 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3659 IPersistFile_Save(pf, link_file, FALSE);
3660 msi_free(link_file);
3662 err:
3663 if (pf)
3664 IPersistFile_Release( pf );
3665 if (sl)
3666 IShellLinkW_Release( sl );
3668 return ERROR_SUCCESS;
3671 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3673 static const WCHAR query[] = {
3674 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3675 '`','S','h','o','r','t','c','u','t','`',0};
3676 MSIQUERY *view;
3677 HRESULT res;
3678 UINT rc;
3680 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3681 if (rc != ERROR_SUCCESS)
3682 return ERROR_SUCCESS;
3684 res = CoInitialize( NULL );
3686 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3687 msiobj_release(&view->hdr);
3689 if (SUCCEEDED(res)) CoUninitialize();
3690 return rc;
3693 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3695 MSIPACKAGE *package = param;
3696 LPWSTR link_file;
3697 LPCWSTR component;
3698 MSICOMPONENT *comp;
3700 component = MSI_RecordGetString( row, 4 );
3701 comp = msi_get_loaded_component( package, component );
3702 if (!comp)
3703 return ERROR_SUCCESS;
3705 comp->Action = msi_get_component_action( package, comp );
3706 if (comp->Action != INSTALLSTATE_ABSENT)
3708 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3709 return ERROR_SUCCESS;
3711 msi_ui_actiondata( package, szRemoveShortcuts, row );
3713 link_file = get_link_file( package, row );
3715 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3716 if (!DeleteFileW( link_file ))
3718 WARN("Failed to remove shortcut file %u\n", GetLastError());
3720 msi_free( link_file );
3722 return ERROR_SUCCESS;
3725 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3727 static const WCHAR query[] = {
3728 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3729 '`','S','h','o','r','t','c','u','t','`',0};
3730 MSIQUERY *view;
3731 UINT rc;
3733 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3734 if (rc != ERROR_SUCCESS)
3735 return ERROR_SUCCESS;
3737 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3738 msiobj_release( &view->hdr );
3739 return rc;
3742 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3744 MSIPACKAGE* package = param;
3745 HANDLE the_file;
3746 LPWSTR FilePath;
3747 LPCWSTR FileName;
3748 CHAR buffer[1024];
3749 DWORD sz;
3750 UINT rc;
3752 FileName = MSI_RecordGetString(row,1);
3753 if (!FileName)
3755 ERR("Unable to get FileName\n");
3756 return ERROR_SUCCESS;
3759 FilePath = msi_build_icon_path(package, FileName);
3761 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3763 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3764 FILE_ATTRIBUTE_NORMAL, NULL);
3766 if (the_file == INVALID_HANDLE_VALUE)
3768 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3769 msi_free(FilePath);
3770 return ERROR_SUCCESS;
3775 DWORD write;
3776 sz = 1024;
3777 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3778 if (rc != ERROR_SUCCESS)
3780 ERR("Failed to get stream\n");
3781 CloseHandle(the_file);
3782 DeleteFileW(FilePath);
3783 break;
3785 WriteFile(the_file,buffer,sz,&write,NULL);
3786 } while (sz == 1024);
3788 msi_free(FilePath);
3789 CloseHandle(the_file);
3791 return ERROR_SUCCESS;
3794 static UINT msi_publish_icons(MSIPACKAGE *package)
3796 static const WCHAR query[]= {
3797 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3798 '`','I','c','o','n','`',0};
3799 MSIQUERY *view;
3800 UINT r;
3802 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3803 if (r == ERROR_SUCCESS)
3805 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3806 msiobj_release(&view->hdr);
3807 if (r != ERROR_SUCCESS)
3808 return r;
3810 return ERROR_SUCCESS;
3813 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3815 UINT r;
3816 HKEY source;
3817 LPWSTR buffer;
3818 MSIMEDIADISK *disk;
3819 MSISOURCELISTINFO *info;
3821 r = RegCreateKeyW(hkey, szSourceList, &source);
3822 if (r != ERROR_SUCCESS)
3823 return r;
3825 RegCloseKey(source);
3827 buffer = strrchrW(package->PackagePath, '\\') + 1;
3828 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3829 package->Context, MSICODE_PRODUCT,
3830 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3831 if (r != ERROR_SUCCESS)
3832 return r;
3834 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3835 package->Context, MSICODE_PRODUCT,
3836 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3837 if (r != ERROR_SUCCESS)
3838 return r;
3840 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3841 package->Context, MSICODE_PRODUCT,
3842 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3843 if (r != ERROR_SUCCESS)
3844 return r;
3846 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3848 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3849 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3850 info->options, info->value);
3851 else
3852 MsiSourceListSetInfoW(package->ProductCode, NULL,
3853 info->context, info->options,
3854 info->property, info->value);
3857 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3859 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3860 disk->context, disk->options,
3861 disk->disk_id, disk->volume_label, disk->disk_prompt);
3864 return ERROR_SUCCESS;
3867 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3869 MSIHANDLE hdb, suminfo;
3870 WCHAR guids[MAX_PATH];
3871 WCHAR packcode[SQUISH_GUID_SIZE];
3872 LPWSTR buffer;
3873 LPWSTR ptr;
3874 DWORD langid;
3875 DWORD size;
3876 UINT r;
3878 static const WCHAR szARPProductIcon[] =
3879 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3880 static const WCHAR szAssignment[] =
3881 {'A','s','s','i','g','n','m','e','n','t',0};
3882 static const WCHAR szAdvertiseFlags[] =
3883 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3884 static const WCHAR szClients[] =
3885 {'C','l','i','e','n','t','s',0};
3886 static const WCHAR szColon[] = {':',0};
3888 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3889 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3890 msi_free(buffer);
3892 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3893 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3895 /* FIXME */
3896 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3898 buffer = msi_dup_property(package->db, szARPProductIcon);
3899 if (buffer)
3901 LPWSTR path = msi_build_icon_path(package, buffer);
3902 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3903 msi_free(path);
3904 msi_free(buffer);
3907 buffer = msi_dup_property(package->db, szProductVersion);
3908 if (buffer)
3910 DWORD verdword = msi_version_str_to_dword(buffer);
3911 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3912 msi_free(buffer);
3915 msi_reg_set_val_dword(hkey, szAssignment, 0);
3916 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3917 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3918 msi_reg_set_val_str(hkey, szClients, szColon);
3920 hdb = alloc_msihandle(&package->db->hdr);
3921 if (!hdb)
3922 return ERROR_NOT_ENOUGH_MEMORY;
3924 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3925 MsiCloseHandle(hdb);
3926 if (r != ERROR_SUCCESS)
3927 goto done;
3929 size = MAX_PATH;
3930 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3931 NULL, guids, &size);
3932 if (r != ERROR_SUCCESS)
3933 goto done;
3935 ptr = strchrW(guids, ';');
3936 if (ptr) *ptr = 0;
3937 squash_guid(guids, packcode);
3938 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3940 done:
3941 MsiCloseHandle(suminfo);
3942 return ERROR_SUCCESS;
3945 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3947 UINT r;
3948 HKEY hkey;
3949 LPWSTR upgrade;
3950 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3952 upgrade = msi_dup_property(package->db, szUpgradeCode);
3953 if (!upgrade)
3954 return ERROR_SUCCESS;
3956 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3957 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3958 else
3959 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3961 if (r != ERROR_SUCCESS)
3963 WARN("failed to open upgrade code key\n");
3964 msi_free(upgrade);
3965 return ERROR_SUCCESS;
3967 squash_guid(package->ProductCode, squashed_pc);
3968 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3969 RegCloseKey(hkey);
3970 msi_free(upgrade);
3971 return ERROR_SUCCESS;
3974 static BOOL msi_check_publish(MSIPACKAGE *package)
3976 MSIFEATURE *feature;
3978 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3980 feature->Action = msi_get_feature_action( package, feature );
3981 if (feature->Action == INSTALLSTATE_LOCAL)
3982 return TRUE;
3985 return FALSE;
3988 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3990 MSIFEATURE *feature;
3992 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3994 feature->Action = msi_get_feature_action( package, feature );
3995 if (feature->Action != INSTALLSTATE_ABSENT)
3996 return FALSE;
3999 return TRUE;
4002 static UINT msi_publish_patches( MSIPACKAGE *package )
4004 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4005 WCHAR patch_squashed[GUID_SIZE];
4006 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4007 LONG res;
4008 MSIPATCHINFO *patch;
4009 UINT r;
4010 WCHAR *p, *all_patches = NULL;
4011 DWORD len = 0;
4013 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4014 if (r != ERROR_SUCCESS)
4015 return ERROR_FUNCTION_FAILED;
4017 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4018 if (res != ERROR_SUCCESS)
4020 r = ERROR_FUNCTION_FAILED;
4021 goto done;
4024 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4025 if (r != ERROR_SUCCESS)
4026 goto done;
4028 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4030 squash_guid( patch->patchcode, patch_squashed );
4031 len += strlenW( patch_squashed ) + 1;
4034 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4035 if (!all_patches)
4036 goto done;
4038 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4040 HKEY patch_key;
4042 squash_guid( patch->patchcode, p );
4043 p += strlenW( p ) + 1;
4045 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4046 (const BYTE *)patch->transforms,
4047 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4048 if (res != ERROR_SUCCESS)
4049 goto done;
4051 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4052 if (r != ERROR_SUCCESS)
4053 goto done;
4055 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4056 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4057 RegCloseKey( patch_key );
4058 if (res != ERROR_SUCCESS)
4059 goto done;
4061 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4063 res = GetLastError();
4064 ERR("Unable to copy patch package %d\n", res);
4065 goto done;
4067 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4068 if (res != ERROR_SUCCESS)
4069 goto done;
4071 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4072 RegCloseKey( patch_key );
4073 if (res != ERROR_SUCCESS)
4074 goto done;
4077 all_patches[len] = 0;
4078 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4079 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4080 if (res != ERROR_SUCCESS)
4081 goto done;
4083 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4084 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4085 if (res != ERROR_SUCCESS)
4086 r = ERROR_FUNCTION_FAILED;
4088 done:
4089 RegCloseKey( product_patches_key );
4090 RegCloseKey( patches_key );
4091 RegCloseKey( product_key );
4092 msi_free( all_patches );
4093 return r;
4096 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4098 UINT rc;
4099 HKEY hukey = NULL, hudkey = NULL;
4100 MSIRECORD *uirow;
4102 if (!list_empty(&package->patches))
4104 rc = msi_publish_patches(package);
4105 if (rc != ERROR_SUCCESS)
4106 goto end;
4109 /* FIXME: also need to publish if the product is in advertise mode */
4110 if (!msi_check_publish(package))
4111 return ERROR_SUCCESS;
4113 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4114 &hukey, TRUE);
4115 if (rc != ERROR_SUCCESS)
4116 goto end;
4118 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4119 NULL, &hudkey, TRUE);
4120 if (rc != ERROR_SUCCESS)
4121 goto end;
4123 rc = msi_publish_upgrade_code(package);
4124 if (rc != ERROR_SUCCESS)
4125 goto end;
4127 rc = msi_publish_product_properties(package, hukey);
4128 if (rc != ERROR_SUCCESS)
4129 goto end;
4131 rc = msi_publish_sourcelist(package, hukey);
4132 if (rc != ERROR_SUCCESS)
4133 goto end;
4135 rc = msi_publish_icons(package);
4137 end:
4138 uirow = MSI_CreateRecord( 1 );
4139 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4140 msi_ui_actiondata( package, szPublishProduct, uirow );
4141 msiobj_release( &uirow->hdr );
4143 RegCloseKey(hukey);
4144 RegCloseKey(hudkey);
4145 return rc;
4148 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4150 WCHAR *filename, *ptr, *folder, *ret;
4151 const WCHAR *dirprop;
4153 filename = msi_dup_record_field( row, 2 );
4154 if (filename && (ptr = strchrW( filename, '|' )))
4155 ptr++;
4156 else
4157 ptr = filename;
4159 dirprop = MSI_RecordGetString( row, 3 );
4160 if (dirprop)
4162 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4163 if (!folder) folder = msi_dup_property( package->db, dirprop );
4165 else
4166 folder = msi_dup_property( package->db, szWindowsFolder );
4168 if (!folder)
4170 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4171 msi_free( filename );
4172 return NULL;
4175 ret = msi_build_directory_name( 2, folder, ptr );
4177 msi_free( filename );
4178 msi_free( folder );
4179 return ret;
4182 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4184 MSIPACKAGE *package = param;
4185 LPCWSTR component, section, key, value, identifier;
4186 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4187 MSIRECORD * uirow;
4188 INT action;
4189 MSICOMPONENT *comp;
4191 component = MSI_RecordGetString(row, 8);
4192 comp = msi_get_loaded_component(package,component);
4193 if (!comp)
4194 return ERROR_SUCCESS;
4196 comp->Action = msi_get_component_action( package, comp );
4197 if (comp->Action != INSTALLSTATE_LOCAL)
4199 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4200 return ERROR_SUCCESS;
4203 identifier = MSI_RecordGetString(row,1);
4204 section = MSI_RecordGetString(row,4);
4205 key = MSI_RecordGetString(row,5);
4206 value = MSI_RecordGetString(row,6);
4207 action = MSI_RecordGetInteger(row,7);
4209 deformat_string(package,section,&deformated_section);
4210 deformat_string(package,key,&deformated_key);
4211 deformat_string(package,value,&deformated_value);
4213 fullname = get_ini_file_name(package, row);
4215 if (action == 0)
4217 TRACE("Adding value %s to section %s in %s\n",
4218 debugstr_w(deformated_key), debugstr_w(deformated_section),
4219 debugstr_w(fullname));
4220 WritePrivateProfileStringW(deformated_section, deformated_key,
4221 deformated_value, fullname);
4223 else if (action == 1)
4225 WCHAR returned[10];
4226 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4227 returned, 10, fullname);
4228 if (returned[0] == 0)
4230 TRACE("Adding value %s to section %s in %s\n",
4231 debugstr_w(deformated_key), debugstr_w(deformated_section),
4232 debugstr_w(fullname));
4234 WritePrivateProfileStringW(deformated_section, deformated_key,
4235 deformated_value, fullname);
4238 else if (action == 3)
4239 FIXME("Append to existing section not yet implemented\n");
4241 uirow = MSI_CreateRecord(4);
4242 MSI_RecordSetStringW(uirow,1,identifier);
4243 MSI_RecordSetStringW(uirow,2,deformated_section);
4244 MSI_RecordSetStringW(uirow,3,deformated_key);
4245 MSI_RecordSetStringW(uirow,4,deformated_value);
4246 msi_ui_actiondata( package, szWriteIniValues, uirow );
4247 msiobj_release( &uirow->hdr );
4249 msi_free(fullname);
4250 msi_free(deformated_key);
4251 msi_free(deformated_value);
4252 msi_free(deformated_section);
4253 return ERROR_SUCCESS;
4256 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4258 static const WCHAR query[] = {
4259 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4260 '`','I','n','i','F','i','l','e','`',0};
4261 MSIQUERY *view;
4262 UINT rc;
4264 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4265 if (rc != ERROR_SUCCESS)
4266 return ERROR_SUCCESS;
4268 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4269 msiobj_release(&view->hdr);
4270 return rc;
4273 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4275 MSIPACKAGE *package = param;
4276 LPCWSTR component, section, key, value, identifier;
4277 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4278 MSICOMPONENT *comp;
4279 MSIRECORD *uirow;
4280 INT action;
4282 component = MSI_RecordGetString( row, 8 );
4283 comp = msi_get_loaded_component( package, component );
4284 if (!comp)
4285 return ERROR_SUCCESS;
4287 comp->Action = msi_get_component_action( package, comp );
4288 if (comp->Action != INSTALLSTATE_ABSENT)
4290 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4291 return ERROR_SUCCESS;
4294 identifier = MSI_RecordGetString( row, 1 );
4295 section = MSI_RecordGetString( row, 4 );
4296 key = MSI_RecordGetString( row, 5 );
4297 value = MSI_RecordGetString( row, 6 );
4298 action = MSI_RecordGetInteger( row, 7 );
4300 deformat_string( package, section, &deformated_section );
4301 deformat_string( package, key, &deformated_key );
4302 deformat_string( package, value, &deformated_value );
4304 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4306 filename = get_ini_file_name( package, row );
4308 TRACE("Removing key %s from section %s in %s\n",
4309 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4311 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4313 WARN("Unable to remove key %u\n", GetLastError());
4315 msi_free( filename );
4317 else
4318 FIXME("Unsupported action %d\n", action);
4321 uirow = MSI_CreateRecord( 4 );
4322 MSI_RecordSetStringW( uirow, 1, identifier );
4323 MSI_RecordSetStringW( uirow, 2, deformated_section );
4324 MSI_RecordSetStringW( uirow, 3, deformated_key );
4325 MSI_RecordSetStringW( uirow, 4, deformated_value );
4326 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4327 msiobj_release( &uirow->hdr );
4329 msi_free( deformated_key );
4330 msi_free( deformated_value );
4331 msi_free( deformated_section );
4332 return ERROR_SUCCESS;
4335 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4337 MSIPACKAGE *package = param;
4338 LPCWSTR component, section, key, value, identifier;
4339 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4340 MSICOMPONENT *comp;
4341 MSIRECORD *uirow;
4342 INT action;
4344 component = MSI_RecordGetString( row, 8 );
4345 comp = msi_get_loaded_component( package, component );
4346 if (!comp)
4347 return ERROR_SUCCESS;
4349 comp->Action = msi_get_component_action( package, comp );
4350 if (comp->Action != INSTALLSTATE_LOCAL)
4352 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4353 return ERROR_SUCCESS;
4356 identifier = MSI_RecordGetString( row, 1 );
4357 section = MSI_RecordGetString( row, 4 );
4358 key = MSI_RecordGetString( row, 5 );
4359 value = MSI_RecordGetString( row, 6 );
4360 action = MSI_RecordGetInteger( row, 7 );
4362 deformat_string( package, section, &deformated_section );
4363 deformat_string( package, key, &deformated_key );
4364 deformat_string( package, value, &deformated_value );
4366 if (action == msidbIniFileActionRemoveLine)
4368 filename = get_ini_file_name( package, row );
4370 TRACE("Removing key %s from section %s in %s\n",
4371 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4373 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4375 WARN("Unable to remove key %u\n", GetLastError());
4377 msi_free( filename );
4379 else
4380 FIXME("Unsupported action %d\n", action);
4382 uirow = MSI_CreateRecord( 4 );
4383 MSI_RecordSetStringW( uirow, 1, identifier );
4384 MSI_RecordSetStringW( uirow, 2, deformated_section );
4385 MSI_RecordSetStringW( uirow, 3, deformated_key );
4386 MSI_RecordSetStringW( uirow, 4, deformated_value );
4387 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4388 msiobj_release( &uirow->hdr );
4390 msi_free( deformated_key );
4391 msi_free( deformated_value );
4392 msi_free( deformated_section );
4393 return ERROR_SUCCESS;
4396 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4398 static const WCHAR query[] = {
4399 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4400 '`','I','n','i','F','i','l','e','`',0};
4401 static const WCHAR remove_query[] = {
4402 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4403 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4404 MSIQUERY *view;
4405 UINT rc;
4407 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4408 if (rc == ERROR_SUCCESS)
4410 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4411 msiobj_release( &view->hdr );
4412 if (rc != ERROR_SUCCESS)
4413 return rc;
4415 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4416 if (rc == ERROR_SUCCESS)
4418 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4419 msiobj_release( &view->hdr );
4420 if (rc != ERROR_SUCCESS)
4421 return rc;
4423 return ERROR_SUCCESS;
4426 static void register_dll( const WCHAR *dll, BOOL unregister )
4428 HMODULE hmod;
4430 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4431 if (hmod)
4433 HRESULT (WINAPI *func_ptr)( void );
4434 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4436 func_ptr = (void *)GetProcAddress( hmod, func );
4437 if (func_ptr)
4439 HRESULT hr = func_ptr();
4440 if (FAILED( hr ))
4441 WARN("failed to register dll 0x%08x\n", hr);
4443 else
4444 WARN("entry point %s not found\n", func);
4445 FreeLibrary( hmod );
4446 return;
4448 WARN("failed to load library %u\n", GetLastError());
4451 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4453 MSIPACKAGE *package = param;
4454 LPCWSTR filename;
4455 MSIFILE *file;
4456 MSIRECORD *uirow;
4458 filename = MSI_RecordGetString(row,1);
4459 file = msi_get_loaded_file( package, filename );
4460 if (!file)
4462 WARN("unable to find file %s\n", debugstr_w(filename));
4463 return ERROR_SUCCESS;
4465 file->Component->Action = msi_get_component_action( package, file->Component );
4466 if (file->Component->Action != INSTALLSTATE_LOCAL)
4468 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4469 return ERROR_SUCCESS;
4472 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4473 register_dll( file->TargetPath, FALSE );
4475 uirow = MSI_CreateRecord( 2 );
4476 MSI_RecordSetStringW( uirow, 1, filename );
4477 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4478 msi_ui_actiondata( package, szSelfRegModules, uirow );
4479 msiobj_release( &uirow->hdr );
4481 return ERROR_SUCCESS;
4484 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4486 static const WCHAR query[] = {
4487 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4488 '`','S','e','l','f','R','e','g','`',0};
4489 MSIQUERY *view;
4490 UINT rc;
4492 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4493 if (rc != ERROR_SUCCESS)
4494 return ERROR_SUCCESS;
4496 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4497 msiobj_release(&view->hdr);
4498 return rc;
4501 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4503 MSIPACKAGE *package = param;
4504 LPCWSTR filename;
4505 MSIFILE *file;
4506 MSIRECORD *uirow;
4508 filename = MSI_RecordGetString( row, 1 );
4509 file = msi_get_loaded_file( package, filename );
4510 if (!file)
4512 WARN("unable to find file %s\n", debugstr_w(filename));
4513 return ERROR_SUCCESS;
4515 file->Component->Action = msi_get_component_action( package, file->Component );
4516 if (file->Component->Action != INSTALLSTATE_ABSENT)
4518 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4519 return ERROR_SUCCESS;
4522 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4523 register_dll( file->TargetPath, TRUE );
4525 uirow = MSI_CreateRecord( 2 );
4526 MSI_RecordSetStringW( uirow, 1, filename );
4527 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4528 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4529 msiobj_release( &uirow->hdr );
4531 return ERROR_SUCCESS;
4534 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4536 static const WCHAR query[] = {
4537 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4538 '`','S','e','l','f','R','e','g','`',0};
4539 MSIQUERY *view;
4540 UINT rc;
4542 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4543 if (rc != ERROR_SUCCESS)
4544 return ERROR_SUCCESS;
4546 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4547 msiobj_release( &view->hdr );
4548 return rc;
4551 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4553 MSIFEATURE *feature;
4554 UINT rc;
4555 HKEY hkey = NULL, userdata = NULL;
4557 if (!msi_check_publish(package))
4558 return ERROR_SUCCESS;
4560 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4561 &hkey, TRUE);
4562 if (rc != ERROR_SUCCESS)
4563 goto end;
4565 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4566 &userdata, TRUE);
4567 if (rc != ERROR_SUCCESS)
4568 goto end;
4570 /* here the guids are base 85 encoded */
4571 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4573 ComponentList *cl;
4574 LPWSTR data = NULL;
4575 GUID clsid;
4576 INT size;
4577 BOOL absent = FALSE;
4578 MSIRECORD *uirow;
4580 if (feature->Action != INSTALLSTATE_LOCAL &&
4581 feature->Action != INSTALLSTATE_SOURCE &&
4582 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4584 size = 1;
4585 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4587 size += 21;
4589 if (feature->Feature_Parent)
4590 size += strlenW( feature->Feature_Parent )+2;
4592 data = msi_alloc(size * sizeof(WCHAR));
4594 data[0] = 0;
4595 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4597 MSICOMPONENT* component = cl->component;
4598 WCHAR buf[21];
4600 buf[0] = 0;
4601 if (component->ComponentId)
4603 TRACE("From %s\n",debugstr_w(component->ComponentId));
4604 CLSIDFromString(component->ComponentId, &clsid);
4605 encode_base85_guid(&clsid,buf);
4606 TRACE("to %s\n",debugstr_w(buf));
4607 strcatW(data,buf);
4611 if (feature->Feature_Parent)
4613 static const WCHAR sep[] = {'\2',0};
4614 strcatW(data,sep);
4615 strcatW(data,feature->Feature_Parent);
4618 msi_reg_set_val_str( userdata, feature->Feature, data );
4619 msi_free(data);
4621 size = 0;
4622 if (feature->Feature_Parent)
4623 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4624 if (!absent)
4626 size += sizeof(WCHAR);
4627 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4628 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4630 else
4632 size += 2*sizeof(WCHAR);
4633 data = msi_alloc(size);
4634 data[0] = 0x6;
4635 data[1] = 0;
4636 if (feature->Feature_Parent)
4637 strcpyW( &data[1], feature->Feature_Parent );
4638 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4639 (LPBYTE)data,size);
4640 msi_free(data);
4643 /* the UI chunk */
4644 uirow = MSI_CreateRecord( 1 );
4645 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4646 msi_ui_actiondata( package, szPublishFeatures, uirow );
4647 msiobj_release( &uirow->hdr );
4648 /* FIXME: call msi_ui_progress? */
4651 end:
4652 RegCloseKey(hkey);
4653 RegCloseKey(userdata);
4654 return rc;
4657 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4659 UINT r;
4660 HKEY hkey;
4661 MSIRECORD *uirow;
4663 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4665 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4666 &hkey, FALSE);
4667 if (r == ERROR_SUCCESS)
4669 RegDeleteValueW(hkey, feature->Feature);
4670 RegCloseKey(hkey);
4673 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4674 &hkey, FALSE);
4675 if (r == ERROR_SUCCESS)
4677 RegDeleteValueW(hkey, feature->Feature);
4678 RegCloseKey(hkey);
4681 uirow = MSI_CreateRecord( 1 );
4682 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4683 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4684 msiobj_release( &uirow->hdr );
4686 return ERROR_SUCCESS;
4689 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4691 MSIFEATURE *feature;
4693 if (!msi_check_unpublish(package))
4694 return ERROR_SUCCESS;
4696 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4698 msi_unpublish_feature(package, feature);
4701 return ERROR_SUCCESS;
4704 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4706 SYSTEMTIME systime;
4707 DWORD size, langid;
4708 WCHAR date[9], *val, *buffer;
4709 const WCHAR *prop, *key;
4711 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4712 static const WCHAR modpath_fmt[] =
4713 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4714 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4715 static const WCHAR szModifyPath[] =
4716 {'M','o','d','i','f','y','P','a','t','h',0};
4717 static const WCHAR szUninstallString[] =
4718 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4719 static const WCHAR szEstimatedSize[] =
4720 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4721 static const WCHAR szDisplayVersion[] =
4722 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4723 static const WCHAR szInstallSource[] =
4724 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4725 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4726 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4727 static const WCHAR szAuthorizedCDFPrefix[] =
4728 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4729 static const WCHAR szARPCONTACT[] =
4730 {'A','R','P','C','O','N','T','A','C','T',0};
4731 static const WCHAR szContact[] =
4732 {'C','o','n','t','a','c','t',0};
4733 static const WCHAR szARPCOMMENTS[] =
4734 {'A','R','P','C','O','M','M','E','N','T','S',0};
4735 static const WCHAR szComments[] =
4736 {'C','o','m','m','e','n','t','s',0};
4737 static const WCHAR szProductName[] =
4738 {'P','r','o','d','u','c','t','N','a','m','e',0};
4739 static const WCHAR szDisplayName[] =
4740 {'D','i','s','p','l','a','y','N','a','m','e',0};
4741 static const WCHAR szARPHELPLINK[] =
4742 {'A','R','P','H','E','L','P','L','I','N','K',0};
4743 static const WCHAR szHelpLink[] =
4744 {'H','e','l','p','L','i','n','k',0};
4745 static const WCHAR szARPHELPTELEPHONE[] =
4746 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4747 static const WCHAR szHelpTelephone[] =
4748 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4749 static const WCHAR szARPINSTALLLOCATION[] =
4750 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4751 static const WCHAR szInstallLocation[] =
4752 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4753 static const WCHAR szManufacturer[] =
4754 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4755 static const WCHAR szPublisher[] =
4756 {'P','u','b','l','i','s','h','e','r',0};
4757 static const WCHAR szARPREADME[] =
4758 {'A','R','P','R','E','A','D','M','E',0};
4759 static const WCHAR szReadme[] =
4760 {'R','e','a','d','M','e',0};
4761 static const WCHAR szARPSIZE[] =
4762 {'A','R','P','S','I','Z','E',0};
4763 static const WCHAR szSize[] =
4764 {'S','i','z','e',0};
4765 static const WCHAR szARPURLINFOABOUT[] =
4766 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4767 static const WCHAR szURLInfoAbout[] =
4768 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4769 static const WCHAR szARPURLUPDATEINFO[] =
4770 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4771 static const WCHAR szURLUpdateInfo[] =
4772 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4773 static const WCHAR szARPSYSTEMCOMPONENT[] =
4774 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4775 static const WCHAR szSystemComponent[] =
4776 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4778 static const WCHAR *propval[] = {
4779 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4780 szARPCONTACT, szContact,
4781 szARPCOMMENTS, szComments,
4782 szProductName, szDisplayName,
4783 szARPHELPLINK, szHelpLink,
4784 szARPHELPTELEPHONE, szHelpTelephone,
4785 szARPINSTALLLOCATION, szInstallLocation,
4786 szSourceDir, szInstallSource,
4787 szManufacturer, szPublisher,
4788 szARPREADME, szReadme,
4789 szARPSIZE, szSize,
4790 szARPURLINFOABOUT, szURLInfoAbout,
4791 szARPURLUPDATEINFO, szURLUpdateInfo,
4792 NULL
4794 const WCHAR **p = propval;
4796 while (*p)
4798 prop = *p++;
4799 key = *p++;
4800 val = msi_dup_property(package->db, prop);
4801 msi_reg_set_val_str(hkey, key, val);
4802 msi_free(val);
4805 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4806 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4808 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4810 size = deformat_string(package, modpath_fmt, &buffer);
4811 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4812 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4813 msi_free(buffer);
4815 /* FIXME: Write real Estimated Size when we have it */
4816 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4818 GetLocalTime(&systime);
4819 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4820 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4822 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4823 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4825 buffer = msi_dup_property(package->db, szProductVersion);
4826 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4827 if (buffer)
4829 DWORD verdword = msi_version_str_to_dword(buffer);
4831 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4832 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4833 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4834 msi_free(buffer);
4837 return ERROR_SUCCESS;
4840 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4842 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4843 MSIRECORD *uirow;
4844 LPWSTR upgrade_code;
4845 HKEY hkey, props, upgrade_key;
4846 UINT rc;
4848 /* FIXME: also need to publish if the product is in advertise mode */
4849 if (!msi_check_publish(package))
4850 return ERROR_SUCCESS;
4852 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4853 if (rc != ERROR_SUCCESS)
4854 return rc;
4856 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4857 if (rc != ERROR_SUCCESS)
4858 goto done;
4860 if (!msi_get_property_int( package->db, szInstalled, 0 ))
4862 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4863 if (!CopyFileW( package->PackagePath, package->localfile, FALSE ))
4865 rc = GetLastError();
4866 ERR("Unable to copy package %u\n", rc);
4867 goto done;
4870 msi_free( package->localfile );
4871 package->localfile = NULL;
4873 rc = msi_publish_install_properties(package, hkey);
4874 if (rc != ERROR_SUCCESS)
4875 goto done;
4877 rc = msi_publish_install_properties(package, props);
4878 if (rc != ERROR_SUCCESS)
4879 goto done;
4881 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4882 if (upgrade_code)
4884 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4885 if (rc == ERROR_SUCCESS)
4887 squash_guid( package->ProductCode, squashed_pc );
4888 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4889 RegCloseKey( upgrade_key );
4891 msi_free( upgrade_code );
4894 done:
4895 uirow = MSI_CreateRecord( 1 );
4896 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4897 msi_ui_actiondata( package, szRegisterProduct, uirow );
4898 msiobj_release( &uirow->hdr );
4900 RegCloseKey(hkey);
4901 return ERROR_SUCCESS;
4904 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4906 return execute_script(package,INSTALL_SCRIPT);
4909 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4911 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4912 WCHAR *upgrade, **features;
4913 BOOL full_uninstall = TRUE;
4914 MSIFEATURE *feature;
4915 MSIPATCHINFO *patch;
4916 UINT i;
4918 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4920 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4922 features = msi_split_string( remove, ',' );
4923 for (i = 0; features && features[i]; i++)
4925 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4927 msi_free(features);
4929 if (!full_uninstall)
4930 return ERROR_SUCCESS;
4932 MSIREG_DeleteProductKey(package->ProductCode);
4933 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4934 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4936 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4937 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4938 MSIREG_DeleteUserProductKey(package->ProductCode);
4939 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4941 upgrade = msi_dup_property(package->db, szUpgradeCode);
4942 if (upgrade)
4944 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4945 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4946 msi_free(upgrade);
4949 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4951 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4952 /* FIXME: remove local patch package if this is the last product */
4955 TRACE("removing local package %s\n", debugstr_w(package->localfile));
4956 DeleteFileW( package->localfile );
4957 msi_free( package->localfile );
4958 package->localfile = NULL;
4960 return ERROR_SUCCESS;
4963 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4965 UINT rc;
4966 WCHAR *remove;
4968 /* turn off scheduling */
4969 package->script->CurrentlyScripting= FALSE;
4971 /* first do the same as an InstallExecute */
4972 rc = ACTION_InstallExecute(package);
4973 if (rc != ERROR_SUCCESS)
4974 return rc;
4976 /* then handle Commit Actions */
4977 rc = execute_script(package,COMMIT_SCRIPT);
4978 if (rc != ERROR_SUCCESS)
4979 return rc;
4981 remove = msi_dup_property(package->db, szRemove);
4982 rc = msi_unpublish_product(package, remove);
4983 msi_free(remove);
4984 return rc;
4987 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4989 static const WCHAR RunOnce[] = {
4990 'S','o','f','t','w','a','r','e','\\',
4991 'M','i','c','r','o','s','o','f','t','\\',
4992 'W','i','n','d','o','w','s','\\',
4993 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4994 'R','u','n','O','n','c','e',0};
4995 static const WCHAR InstallRunOnce[] = {
4996 'S','o','f','t','w','a','r','e','\\',
4997 'M','i','c','r','o','s','o','f','t','\\',
4998 'W','i','n','d','o','w','s','\\',
4999 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5000 'I','n','s','t','a','l','l','e','r','\\',
5001 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5003 static const WCHAR msiexec_fmt[] = {
5004 '%','s',
5005 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5006 '\"','%','s','\"',0};
5007 static const WCHAR install_fmt[] = {
5008 '/','I',' ','\"','%','s','\"',' ',
5009 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5010 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5011 WCHAR buffer[256], sysdir[MAX_PATH];
5012 HKEY hkey;
5013 WCHAR squished_pc[100];
5015 squash_guid(package->ProductCode,squished_pc);
5017 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5018 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5019 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5020 squished_pc);
5022 msi_reg_set_val_str( hkey, squished_pc, buffer );
5023 RegCloseKey(hkey);
5025 TRACE("Reboot command %s\n",debugstr_w(buffer));
5027 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5028 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5030 msi_reg_set_val_str( hkey, squished_pc, buffer );
5031 RegCloseKey(hkey);
5033 return ERROR_INSTALL_SUSPEND;
5036 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5038 static const WCHAR query[] =
5039 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5040 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5041 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5042 MSIRECORD *rec, *row;
5043 DWORD i, size = 0;
5044 va_list va;
5045 const WCHAR *str;
5046 WCHAR *data;
5048 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5050 rec = MSI_CreateRecord( count + 2 );
5051 str = MSI_RecordGetString( row, 1 );
5052 MSI_RecordSetStringW( rec, 0, str );
5053 msiobj_release( &row->hdr );
5054 MSI_RecordSetInteger( rec, 1, error );
5056 va_start( va, count );
5057 for (i = 0; i < count; i++)
5059 str = va_arg( va, const WCHAR *);
5060 MSI_RecordSetStringW( rec, i + 2, str );
5062 va_end( va );
5064 MSI_FormatRecordW( package, rec, NULL, &size );
5065 size++;
5066 data = msi_alloc( size * sizeof(WCHAR) );
5067 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5068 else data[0] = 0;
5069 msiobj_release( &rec->hdr );
5070 return data;
5073 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5075 DWORD attrib;
5076 UINT rc;
5079 * We are currently doing what should be done here in the top level Install
5080 * however for Administrative and uninstalls this step will be needed
5082 if (!package->PackagePath)
5083 return ERROR_SUCCESS;
5085 msi_set_sourcedir_props(package, TRUE);
5087 attrib = GetFileAttributesW(package->db->path);
5088 if (attrib == INVALID_FILE_ATTRIBUTES)
5090 LPWSTR prompt;
5091 LPWSTR msg;
5092 DWORD size = 0;
5094 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5095 package->Context, MSICODE_PRODUCT,
5096 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5097 if (rc == ERROR_MORE_DATA)
5099 prompt = msi_alloc(size * sizeof(WCHAR));
5100 MsiSourceListGetInfoW(package->ProductCode, NULL,
5101 package->Context, MSICODE_PRODUCT,
5102 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5104 else
5105 prompt = strdupW(package->db->path);
5107 msg = msi_build_error_string(package, 1302, 1, prompt);
5108 while(attrib == INVALID_FILE_ATTRIBUTES)
5110 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5111 if (rc == IDCANCEL)
5113 rc = ERROR_INSTALL_USEREXIT;
5114 break;
5116 attrib = GetFileAttributesW(package->db->path);
5118 msi_free(prompt);
5119 rc = ERROR_SUCCESS;
5121 else
5122 return ERROR_SUCCESS;
5124 return rc;
5127 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5129 HKEY hkey = 0;
5130 LPWSTR buffer, productid = NULL;
5131 UINT i, rc = ERROR_SUCCESS;
5132 MSIRECORD *uirow;
5134 static const WCHAR szPropKeys[][80] =
5136 {'P','r','o','d','u','c','t','I','D',0},
5137 {'U','S','E','R','N','A','M','E',0},
5138 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5139 {0},
5142 static const WCHAR szRegKeys[][80] =
5144 {'P','r','o','d','u','c','t','I','D',0},
5145 {'R','e','g','O','w','n','e','r',0},
5146 {'R','e','g','C','o','m','p','a','n','y',0},
5147 {0},
5150 if (msi_check_unpublish(package))
5152 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5153 goto end;
5156 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5157 if (!productid)
5158 goto end;
5160 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5161 NULL, &hkey, TRUE);
5162 if (rc != ERROR_SUCCESS)
5163 goto end;
5165 for( i = 0; szPropKeys[i][0]; i++ )
5167 buffer = msi_dup_property( package->db, szPropKeys[i] );
5168 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5169 msi_free( buffer );
5172 end:
5173 uirow = MSI_CreateRecord( 1 );
5174 MSI_RecordSetStringW( uirow, 1, productid );
5175 msi_ui_actiondata( package, szRegisterUser, uirow );
5176 msiobj_release( &uirow->hdr );
5178 msi_free(productid);
5179 RegCloseKey(hkey);
5180 return rc;
5184 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5186 UINT rc;
5188 package->script->InWhatSequence |= SEQUENCE_EXEC;
5189 rc = ACTION_ProcessExecSequence(package,FALSE);
5190 return rc;
5193 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5195 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5196 WCHAR productid_85[21], component_85[21], *ret;
5197 GUID clsid;
5198 DWORD sz;
5200 /* > is used if there is a component GUID and < if not. */
5202 productid_85[0] = 0;
5203 component_85[0] = 0;
5204 CLSIDFromString( package->ProductCode, &clsid );
5206 encode_base85_guid( &clsid, productid_85 );
5207 if (component)
5209 CLSIDFromString( component->ComponentId, &clsid );
5210 encode_base85_guid( &clsid, component_85 );
5213 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5214 debugstr_w(component_85));
5216 sz = 20 + strlenW( feature ) + 20 + 3;
5217 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5218 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5219 return ret;
5222 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5224 MSIPACKAGE *package = param;
5225 LPCWSTR compgroupid, component, feature, qualifier, text;
5226 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5227 HKEY hkey = NULL;
5228 UINT rc;
5229 MSICOMPONENT *comp;
5230 MSIFEATURE *feat;
5231 DWORD sz;
5232 MSIRECORD *uirow;
5233 int len;
5235 feature = MSI_RecordGetString(rec, 5);
5236 feat = msi_get_loaded_feature(package, feature);
5237 if (!feat)
5238 return ERROR_SUCCESS;
5240 feat->Action = msi_get_feature_action( package, feat );
5241 if (feat->Action != INSTALLSTATE_LOCAL &&
5242 feat->Action != INSTALLSTATE_SOURCE &&
5243 feat->Action != INSTALLSTATE_ADVERTISED)
5245 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5246 return ERROR_SUCCESS;
5249 component = MSI_RecordGetString(rec, 3);
5250 comp = msi_get_loaded_component(package, component);
5251 if (!comp)
5252 return ERROR_SUCCESS;
5254 compgroupid = MSI_RecordGetString(rec,1);
5255 qualifier = MSI_RecordGetString(rec,2);
5257 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5258 if (rc != ERROR_SUCCESS)
5259 goto end;
5261 advertise = msi_create_component_advertise_string( package, comp, feature );
5262 text = MSI_RecordGetString( rec, 4 );
5263 if (text)
5265 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5266 strcpyW( p, advertise );
5267 strcatW( p, text );
5268 msi_free( advertise );
5269 advertise = p;
5271 existing = msi_reg_get_val_str( hkey, qualifier );
5273 sz = strlenW( advertise ) + 1;
5274 if (existing)
5276 for (p = existing; *p; p += len)
5278 len = strlenW( p ) + 1;
5279 if (strcmpW( advertise, p )) sz += len;
5282 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5284 rc = ERROR_OUTOFMEMORY;
5285 goto end;
5287 q = output;
5288 if (existing)
5290 for (p = existing; *p; p += len)
5292 len = strlenW( p ) + 1;
5293 if (strcmpW( advertise, p ))
5295 memcpy( q, p, len * sizeof(WCHAR) );
5296 q += len;
5300 strcpyW( q, advertise );
5301 q[strlenW( q ) + 1] = 0;
5303 msi_reg_set_val_multi_str( hkey, qualifier, output );
5305 end:
5306 RegCloseKey(hkey);
5307 msi_free( output );
5308 msi_free( advertise );
5309 msi_free( existing );
5311 /* the UI chunk */
5312 uirow = MSI_CreateRecord( 2 );
5313 MSI_RecordSetStringW( uirow, 1, compgroupid );
5314 MSI_RecordSetStringW( uirow, 2, qualifier);
5315 msi_ui_actiondata( package, szPublishComponents, uirow );
5316 msiobj_release( &uirow->hdr );
5317 /* FIXME: call ui_progress? */
5319 return rc;
5323 * At present I am ignorning the advertised components part of this and only
5324 * focusing on the qualified component sets
5326 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5328 static const WCHAR query[] = {
5329 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5330 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5331 MSIQUERY *view;
5332 UINT rc;
5334 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5335 if (rc != ERROR_SUCCESS)
5336 return ERROR_SUCCESS;
5338 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5339 msiobj_release(&view->hdr);
5340 return rc;
5343 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5345 static const WCHAR szInstallerComponents[] = {
5346 'S','o','f','t','w','a','r','e','\\',
5347 'M','i','c','r','o','s','o','f','t','\\',
5348 'I','n','s','t','a','l','l','e','r','\\',
5349 'C','o','m','p','o','n','e','n','t','s','\\',0};
5351 MSIPACKAGE *package = param;
5352 LPCWSTR compgroupid, component, feature, qualifier;
5353 MSICOMPONENT *comp;
5354 MSIFEATURE *feat;
5355 MSIRECORD *uirow;
5356 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5357 LONG res;
5359 feature = MSI_RecordGetString( rec, 5 );
5360 feat = msi_get_loaded_feature( package, feature );
5361 if (!feat)
5362 return ERROR_SUCCESS;
5364 feat->Action = msi_get_feature_action( package, feat );
5365 if (feat->Action != INSTALLSTATE_ABSENT)
5367 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5368 return ERROR_SUCCESS;
5371 component = MSI_RecordGetString( rec, 3 );
5372 comp = msi_get_loaded_component( package, component );
5373 if (!comp)
5374 return ERROR_SUCCESS;
5376 compgroupid = MSI_RecordGetString( rec, 1 );
5377 qualifier = MSI_RecordGetString( rec, 2 );
5379 squash_guid( compgroupid, squashed );
5380 strcpyW( keypath, szInstallerComponents );
5381 strcatW( keypath, squashed );
5383 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5384 if (res != ERROR_SUCCESS)
5386 WARN("Unable to delete component key %d\n", res);
5389 uirow = MSI_CreateRecord( 2 );
5390 MSI_RecordSetStringW( uirow, 1, compgroupid );
5391 MSI_RecordSetStringW( uirow, 2, qualifier );
5392 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5393 msiobj_release( &uirow->hdr );
5395 return ERROR_SUCCESS;
5398 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5400 static const WCHAR query[] = {
5401 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5402 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5403 MSIQUERY *view;
5404 UINT rc;
5406 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5407 if (rc != ERROR_SUCCESS)
5408 return ERROR_SUCCESS;
5410 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5411 msiobj_release( &view->hdr );
5412 return rc;
5415 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5417 static const WCHAR query[] =
5418 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5419 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5420 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5421 MSIPACKAGE *package = param;
5422 MSICOMPONENT *component;
5423 MSIRECORD *row;
5424 MSIFILE *file;
5425 SC_HANDLE hscm = NULL, service = NULL;
5426 LPCWSTR comp, key;
5427 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5428 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5429 DWORD serv_type, start_type, err_control;
5430 SERVICE_DESCRIPTIONW sd = {NULL};
5432 comp = MSI_RecordGetString( rec, 12 );
5433 component = msi_get_loaded_component( package, comp );
5434 if (!component)
5436 WARN("service component not found\n");
5437 goto done;
5439 component->Action = msi_get_component_action( package, component );
5440 if (component->Action != INSTALLSTATE_LOCAL)
5442 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5443 goto done;
5445 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5446 if (!hscm)
5448 ERR("Failed to open the SC Manager!\n");
5449 goto done;
5452 start_type = MSI_RecordGetInteger(rec, 5);
5453 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5454 goto done;
5456 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5457 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5458 serv_type = MSI_RecordGetInteger(rec, 4);
5459 err_control = MSI_RecordGetInteger(rec, 6);
5460 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5461 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5462 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5463 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5464 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5465 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5467 /* fetch the service path */
5468 row = MSI_QueryGetRecord(package->db, query, comp);
5469 if (!row)
5471 ERR("Query failed\n");
5472 goto done;
5474 key = MSI_RecordGetString(row, 6);
5475 file = msi_get_loaded_file(package, key);
5476 msiobj_release(&row->hdr);
5477 if (!file)
5479 ERR("Failed to load the service file\n");
5480 goto done;
5483 if (!args || !args[0]) image_path = file->TargetPath;
5484 else
5486 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5487 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5488 return ERROR_OUTOFMEMORY;
5490 strcpyW(image_path, file->TargetPath);
5491 strcatW(image_path, szSpace);
5492 strcatW(image_path, args);
5494 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5495 start_type, err_control, image_path, load_order,
5496 NULL, depends, serv_name, pass);
5498 if (!service)
5500 if (GetLastError() != ERROR_SERVICE_EXISTS)
5501 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5503 else if (sd.lpDescription)
5505 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5506 WARN("failed to set service description %u\n", GetLastError());
5509 if (image_path != file->TargetPath) msi_free(image_path);
5510 done:
5511 CloseServiceHandle(service);
5512 CloseServiceHandle(hscm);
5513 msi_free(name);
5514 msi_free(disp);
5515 msi_free(sd.lpDescription);
5516 msi_free(load_order);
5517 msi_free(serv_name);
5518 msi_free(pass);
5519 msi_free(depends);
5520 msi_free(args);
5522 return ERROR_SUCCESS;
5525 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5527 static const WCHAR query[] = {
5528 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5529 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5530 MSIQUERY *view;
5531 UINT rc;
5533 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5534 if (rc != ERROR_SUCCESS)
5535 return ERROR_SUCCESS;
5537 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5538 msiobj_release(&view->hdr);
5539 return rc;
5542 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5543 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5545 LPCWSTR *vector, *temp_vector;
5546 LPWSTR p, q;
5547 DWORD sep_len;
5549 static const WCHAR separator[] = {'[','~',']',0};
5551 *numargs = 0;
5552 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5554 if (!args)
5555 return NULL;
5557 vector = msi_alloc(sizeof(LPWSTR));
5558 if (!vector)
5559 return NULL;
5561 p = args;
5564 (*numargs)++;
5565 vector[*numargs - 1] = p;
5567 if ((q = strstrW(p, separator)))
5569 *q = '\0';
5571 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5572 if (!temp_vector)
5574 msi_free(vector);
5575 return NULL;
5577 vector = temp_vector;
5579 p = q + sep_len;
5581 } while (q);
5583 return vector;
5586 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5588 MSIPACKAGE *package = param;
5589 MSICOMPONENT *comp;
5590 MSIRECORD *uirow;
5591 SC_HANDLE scm = NULL, service = NULL;
5592 LPCWSTR component, *vector = NULL;
5593 LPWSTR name, args, display_name = NULL;
5594 DWORD event, numargs, len;
5595 UINT r = ERROR_FUNCTION_FAILED;
5597 component = MSI_RecordGetString(rec, 6);
5598 comp = msi_get_loaded_component(package, component);
5599 if (!comp)
5600 return ERROR_SUCCESS;
5602 comp->Action = msi_get_component_action( package, comp );
5603 if (comp->Action != INSTALLSTATE_LOCAL)
5605 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5606 return ERROR_SUCCESS;
5609 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5610 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5611 event = MSI_RecordGetInteger(rec, 3);
5613 if (!(event & msidbServiceControlEventStart))
5615 r = ERROR_SUCCESS;
5616 goto done;
5619 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5620 if (!scm)
5622 ERR("Failed to open the service control manager\n");
5623 goto done;
5626 len = 0;
5627 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5628 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5630 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5631 GetServiceDisplayNameW( scm, name, display_name, &len );
5634 service = OpenServiceW(scm, name, SERVICE_START);
5635 if (!service)
5637 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5638 goto done;
5641 vector = msi_service_args_to_vector(args, &numargs);
5643 if (!StartServiceW(service, numargs, vector) &&
5644 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5646 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5647 goto done;
5650 r = ERROR_SUCCESS;
5652 done:
5653 uirow = MSI_CreateRecord( 2 );
5654 MSI_RecordSetStringW( uirow, 1, display_name );
5655 MSI_RecordSetStringW( uirow, 2, name );
5656 msi_ui_actiondata( package, szStartServices, uirow );
5657 msiobj_release( &uirow->hdr );
5659 CloseServiceHandle(service);
5660 CloseServiceHandle(scm);
5662 msi_free(name);
5663 msi_free(args);
5664 msi_free(vector);
5665 msi_free(display_name);
5666 return r;
5669 static UINT ACTION_StartServices( MSIPACKAGE *package )
5671 static const WCHAR query[] = {
5672 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5673 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5674 MSIQUERY *view;
5675 UINT rc;
5677 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5678 if (rc != ERROR_SUCCESS)
5679 return ERROR_SUCCESS;
5681 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5682 msiobj_release(&view->hdr);
5683 return rc;
5686 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5688 DWORD i, needed, count;
5689 ENUM_SERVICE_STATUSW *dependencies;
5690 SERVICE_STATUS ss;
5691 SC_HANDLE depserv;
5693 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5694 0, &needed, &count))
5695 return TRUE;
5697 if (GetLastError() != ERROR_MORE_DATA)
5698 return FALSE;
5700 dependencies = msi_alloc(needed);
5701 if (!dependencies)
5702 return FALSE;
5704 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5705 needed, &needed, &count))
5706 goto error;
5708 for (i = 0; i < count; i++)
5710 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5711 SERVICE_STOP | SERVICE_QUERY_STATUS);
5712 if (!depserv)
5713 goto error;
5715 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5716 goto error;
5719 return TRUE;
5721 error:
5722 msi_free(dependencies);
5723 return FALSE;
5726 static UINT stop_service( LPCWSTR name )
5728 SC_HANDLE scm = NULL, service = NULL;
5729 SERVICE_STATUS status;
5730 SERVICE_STATUS_PROCESS ssp;
5731 DWORD needed;
5733 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5734 if (!scm)
5736 WARN("Failed to open the SCM: %d\n", GetLastError());
5737 goto done;
5740 service = OpenServiceW(scm, name,
5741 SERVICE_STOP |
5742 SERVICE_QUERY_STATUS |
5743 SERVICE_ENUMERATE_DEPENDENTS);
5744 if (!service)
5746 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5747 goto done;
5750 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5751 sizeof(SERVICE_STATUS_PROCESS), &needed))
5753 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5754 goto done;
5757 if (ssp.dwCurrentState == SERVICE_STOPPED)
5758 goto done;
5760 stop_service_dependents(scm, service);
5762 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5763 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5765 done:
5766 CloseServiceHandle(service);
5767 CloseServiceHandle(scm);
5769 return ERROR_SUCCESS;
5772 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5774 MSIPACKAGE *package = param;
5775 MSICOMPONENT *comp;
5776 MSIRECORD *uirow;
5777 LPCWSTR component;
5778 LPWSTR name = NULL, display_name = NULL;
5779 DWORD event, len;
5780 SC_HANDLE scm;
5782 event = MSI_RecordGetInteger( rec, 3 );
5783 if (!(event & msidbServiceControlEventStop))
5784 return ERROR_SUCCESS;
5786 component = MSI_RecordGetString( rec, 6 );
5787 comp = msi_get_loaded_component( package, component );
5788 if (!comp)
5789 return ERROR_SUCCESS;
5791 comp->Action = msi_get_component_action( package, comp );
5792 if (comp->Action != INSTALLSTATE_ABSENT)
5794 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5795 return ERROR_SUCCESS;
5798 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5799 if (!scm)
5801 ERR("Failed to open the service control manager\n");
5802 goto done;
5805 len = 0;
5806 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5807 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5809 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5810 GetServiceDisplayNameW( scm, name, display_name, &len );
5812 CloseServiceHandle( scm );
5814 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5815 stop_service( name );
5817 done:
5818 uirow = MSI_CreateRecord( 2 );
5819 MSI_RecordSetStringW( uirow, 1, display_name );
5820 MSI_RecordSetStringW( uirow, 2, name );
5821 msi_ui_actiondata( package, szStopServices, uirow );
5822 msiobj_release( &uirow->hdr );
5824 msi_free( name );
5825 msi_free( display_name );
5826 return ERROR_SUCCESS;
5829 static UINT ACTION_StopServices( MSIPACKAGE *package )
5831 static const WCHAR query[] = {
5832 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5833 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5834 MSIQUERY *view;
5835 UINT rc;
5837 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5838 if (rc != ERROR_SUCCESS)
5839 return ERROR_SUCCESS;
5841 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5842 msiobj_release(&view->hdr);
5843 return rc;
5846 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5848 MSIPACKAGE *package = param;
5849 MSICOMPONENT *comp;
5850 MSIRECORD *uirow;
5851 LPCWSTR component;
5852 LPWSTR name = NULL, display_name = NULL;
5853 DWORD event, len;
5854 SC_HANDLE scm = NULL, service = NULL;
5856 event = MSI_RecordGetInteger( rec, 3 );
5857 if (!(event & msidbServiceControlEventDelete))
5858 return ERROR_SUCCESS;
5860 component = MSI_RecordGetString(rec, 6);
5861 comp = msi_get_loaded_component(package, component);
5862 if (!comp)
5863 return ERROR_SUCCESS;
5865 comp->Action = msi_get_component_action( package, comp );
5866 if (comp->Action != INSTALLSTATE_ABSENT)
5868 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5869 return ERROR_SUCCESS;
5872 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5873 stop_service( name );
5875 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5876 if (!scm)
5878 WARN("Failed to open the SCM: %d\n", GetLastError());
5879 goto done;
5882 len = 0;
5883 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5884 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5886 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5887 GetServiceDisplayNameW( scm, name, display_name, &len );
5890 service = OpenServiceW( scm, name, DELETE );
5891 if (!service)
5893 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5894 goto done;
5897 if (!DeleteService( service ))
5898 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5900 done:
5901 uirow = MSI_CreateRecord( 2 );
5902 MSI_RecordSetStringW( uirow, 1, display_name );
5903 MSI_RecordSetStringW( uirow, 2, name );
5904 msi_ui_actiondata( package, szDeleteServices, uirow );
5905 msiobj_release( &uirow->hdr );
5907 CloseServiceHandle( service );
5908 CloseServiceHandle( scm );
5909 msi_free( name );
5910 msi_free( display_name );
5912 return ERROR_SUCCESS;
5915 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5917 static const WCHAR query[] = {
5918 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5919 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5920 MSIQUERY *view;
5921 UINT rc;
5923 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5924 if (rc != ERROR_SUCCESS)
5925 return ERROR_SUCCESS;
5927 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5928 msiobj_release( &view->hdr );
5929 return rc;
5932 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5934 MSIPACKAGE *package = param;
5935 LPWSTR driver, driver_path, ptr;
5936 WCHAR outpath[MAX_PATH];
5937 MSIFILE *driver_file = NULL, *setup_file = NULL;
5938 MSICOMPONENT *comp;
5939 MSIRECORD *uirow;
5940 LPCWSTR desc, file_key, component;
5941 DWORD len, usage;
5942 UINT r = ERROR_SUCCESS;
5944 static const WCHAR driver_fmt[] = {
5945 'D','r','i','v','e','r','=','%','s',0};
5946 static const WCHAR setup_fmt[] = {
5947 'S','e','t','u','p','=','%','s',0};
5948 static const WCHAR usage_fmt[] = {
5949 'F','i','l','e','U','s','a','g','e','=','1',0};
5951 component = MSI_RecordGetString( rec, 2 );
5952 comp = msi_get_loaded_component( package, component );
5953 if (!comp)
5954 return ERROR_SUCCESS;
5956 comp->Action = msi_get_component_action( package, comp );
5957 if (comp->Action != INSTALLSTATE_LOCAL)
5959 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5960 return ERROR_SUCCESS;
5962 desc = MSI_RecordGetString(rec, 3);
5964 file_key = MSI_RecordGetString( rec, 4 );
5965 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
5967 file_key = MSI_RecordGetString( rec, 5 );
5968 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
5970 if (!driver_file)
5972 ERR("ODBC Driver entry not found!\n");
5973 return ERROR_FUNCTION_FAILED;
5976 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5977 if (setup_file)
5978 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5979 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5981 driver = msi_alloc(len * sizeof(WCHAR));
5982 if (!driver)
5983 return ERROR_OUTOFMEMORY;
5985 ptr = driver;
5986 lstrcpyW(ptr, desc);
5987 ptr += lstrlenW(ptr) + 1;
5989 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5990 ptr += len + 1;
5992 if (setup_file)
5994 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5995 ptr += len + 1;
5998 lstrcpyW(ptr, usage_fmt);
5999 ptr += lstrlenW(ptr) + 1;
6000 *ptr = '\0';
6002 driver_path = strdupW(driver_file->TargetPath);
6003 ptr = strrchrW(driver_path, '\\');
6004 if (ptr) *ptr = '\0';
6006 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6007 NULL, ODBC_INSTALL_COMPLETE, &usage))
6009 ERR("Failed to install SQL driver!\n");
6010 r = ERROR_FUNCTION_FAILED;
6013 uirow = MSI_CreateRecord( 5 );
6014 MSI_RecordSetStringW( uirow, 1, desc );
6015 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6016 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6017 msi_ui_actiondata( package, szInstallODBC, uirow );
6018 msiobj_release( &uirow->hdr );
6020 msi_free(driver);
6021 msi_free(driver_path);
6023 return r;
6026 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6028 MSIPACKAGE *package = param;
6029 LPWSTR translator, translator_path, ptr;
6030 WCHAR outpath[MAX_PATH];
6031 MSIFILE *translator_file = NULL, *setup_file = NULL;
6032 MSICOMPONENT *comp;
6033 MSIRECORD *uirow;
6034 LPCWSTR desc, file_key, component;
6035 DWORD len, usage;
6036 UINT r = ERROR_SUCCESS;
6038 static const WCHAR translator_fmt[] = {
6039 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6040 static const WCHAR setup_fmt[] = {
6041 'S','e','t','u','p','=','%','s',0};
6043 component = MSI_RecordGetString( rec, 2 );
6044 comp = msi_get_loaded_component( package, component );
6045 if (!comp)
6046 return ERROR_SUCCESS;
6048 comp->Action = msi_get_component_action( package, comp );
6049 if (comp->Action != INSTALLSTATE_LOCAL)
6051 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6052 return ERROR_SUCCESS;
6054 desc = MSI_RecordGetString(rec, 3);
6056 file_key = MSI_RecordGetString( rec, 4 );
6057 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6059 file_key = MSI_RecordGetString( rec, 5 );
6060 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6062 if (!translator_file)
6064 ERR("ODBC Translator entry not found!\n");
6065 return ERROR_FUNCTION_FAILED;
6068 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6069 if (setup_file)
6070 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6072 translator = msi_alloc(len * sizeof(WCHAR));
6073 if (!translator)
6074 return ERROR_OUTOFMEMORY;
6076 ptr = translator;
6077 lstrcpyW(ptr, desc);
6078 ptr += lstrlenW(ptr) + 1;
6080 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6081 ptr += len + 1;
6083 if (setup_file)
6085 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6086 ptr += len + 1;
6088 *ptr = '\0';
6090 translator_path = strdupW(translator_file->TargetPath);
6091 ptr = strrchrW(translator_path, '\\');
6092 if (ptr) *ptr = '\0';
6094 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6095 NULL, ODBC_INSTALL_COMPLETE, &usage))
6097 ERR("Failed to install SQL translator!\n");
6098 r = ERROR_FUNCTION_FAILED;
6101 uirow = MSI_CreateRecord( 5 );
6102 MSI_RecordSetStringW( uirow, 1, desc );
6103 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6104 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6105 msi_ui_actiondata( package, szInstallODBC, uirow );
6106 msiobj_release( &uirow->hdr );
6108 msi_free(translator);
6109 msi_free(translator_path);
6111 return r;
6114 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6116 MSIPACKAGE *package = param;
6117 MSICOMPONENT *comp;
6118 LPWSTR attrs;
6119 LPCWSTR desc, driver, component;
6120 WORD request = ODBC_ADD_SYS_DSN;
6121 INT registration;
6122 DWORD len;
6123 UINT r = ERROR_SUCCESS;
6124 MSIRECORD *uirow;
6126 static const WCHAR attrs_fmt[] = {
6127 'D','S','N','=','%','s',0 };
6129 component = MSI_RecordGetString( rec, 2 );
6130 comp = msi_get_loaded_component( package, component );
6131 if (!comp)
6132 return ERROR_SUCCESS;
6134 comp->Action = msi_get_component_action( package, comp );
6135 if (comp->Action != INSTALLSTATE_LOCAL)
6137 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6138 return ERROR_SUCCESS;
6141 desc = MSI_RecordGetString(rec, 3);
6142 driver = MSI_RecordGetString(rec, 4);
6143 registration = MSI_RecordGetInteger(rec, 5);
6145 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6146 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6148 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6149 attrs = msi_alloc(len * sizeof(WCHAR));
6150 if (!attrs)
6151 return ERROR_OUTOFMEMORY;
6153 len = sprintfW(attrs, attrs_fmt, desc);
6154 attrs[len + 1] = 0;
6156 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6158 ERR("Failed to install SQL data source!\n");
6159 r = ERROR_FUNCTION_FAILED;
6162 uirow = MSI_CreateRecord( 5 );
6163 MSI_RecordSetStringW( uirow, 1, desc );
6164 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6165 MSI_RecordSetInteger( uirow, 3, request );
6166 msi_ui_actiondata( package, szInstallODBC, uirow );
6167 msiobj_release( &uirow->hdr );
6169 msi_free(attrs);
6171 return r;
6174 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6176 static const WCHAR driver_query[] = {
6177 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6178 'O','D','B','C','D','r','i','v','e','r',0};
6179 static const WCHAR translator_query[] = {
6180 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6181 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6182 static const WCHAR source_query[] = {
6183 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6184 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6185 MSIQUERY *view;
6186 UINT rc;
6188 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6189 if (rc == ERROR_SUCCESS)
6191 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6192 msiobj_release(&view->hdr);
6193 if (rc != ERROR_SUCCESS)
6194 return rc;
6196 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6197 if (rc == ERROR_SUCCESS)
6199 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6200 msiobj_release(&view->hdr);
6201 if (rc != ERROR_SUCCESS)
6202 return rc;
6204 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6205 if (rc == ERROR_SUCCESS)
6207 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6208 msiobj_release(&view->hdr);
6209 if (rc != ERROR_SUCCESS)
6210 return rc;
6212 return ERROR_SUCCESS;
6215 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6217 MSIPACKAGE *package = param;
6218 MSICOMPONENT *comp;
6219 MSIRECORD *uirow;
6220 DWORD usage;
6221 LPCWSTR desc, component;
6223 component = MSI_RecordGetString( rec, 2 );
6224 comp = msi_get_loaded_component( package, component );
6225 if (!comp)
6226 return ERROR_SUCCESS;
6228 comp->Action = msi_get_component_action( package, comp );
6229 if (comp->Action != INSTALLSTATE_ABSENT)
6231 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6232 return ERROR_SUCCESS;
6235 desc = MSI_RecordGetString( rec, 3 );
6236 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6238 WARN("Failed to remove ODBC driver\n");
6240 else if (!usage)
6242 FIXME("Usage count reached 0\n");
6245 uirow = MSI_CreateRecord( 2 );
6246 MSI_RecordSetStringW( uirow, 1, desc );
6247 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6248 msi_ui_actiondata( package, szRemoveODBC, uirow );
6249 msiobj_release( &uirow->hdr );
6251 return ERROR_SUCCESS;
6254 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6256 MSIPACKAGE *package = param;
6257 MSICOMPONENT *comp;
6258 MSIRECORD *uirow;
6259 DWORD usage;
6260 LPCWSTR desc, component;
6262 component = MSI_RecordGetString( rec, 2 );
6263 comp = msi_get_loaded_component( package, component );
6264 if (!comp)
6265 return ERROR_SUCCESS;
6267 comp->Action = msi_get_component_action( package, comp );
6268 if (comp->Action != INSTALLSTATE_ABSENT)
6270 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6271 return ERROR_SUCCESS;
6274 desc = MSI_RecordGetString( rec, 3 );
6275 if (!SQLRemoveTranslatorW( desc, &usage ))
6277 WARN("Failed to remove ODBC translator\n");
6279 else if (!usage)
6281 FIXME("Usage count reached 0\n");
6284 uirow = MSI_CreateRecord( 2 );
6285 MSI_RecordSetStringW( uirow, 1, desc );
6286 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6287 msi_ui_actiondata( package, szRemoveODBC, uirow );
6288 msiobj_release( &uirow->hdr );
6290 return ERROR_SUCCESS;
6293 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6295 MSIPACKAGE *package = param;
6296 MSICOMPONENT *comp;
6297 MSIRECORD *uirow;
6298 LPWSTR attrs;
6299 LPCWSTR desc, driver, component;
6300 WORD request = ODBC_REMOVE_SYS_DSN;
6301 INT registration;
6302 DWORD len;
6304 static const WCHAR attrs_fmt[] = {
6305 'D','S','N','=','%','s',0 };
6307 component = MSI_RecordGetString( rec, 2 );
6308 comp = msi_get_loaded_component( package, component );
6309 if (!comp)
6310 return ERROR_SUCCESS;
6312 comp->Action = msi_get_component_action( package, comp );
6313 if (comp->Action != INSTALLSTATE_ABSENT)
6315 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6316 return ERROR_SUCCESS;
6319 desc = MSI_RecordGetString( rec, 3 );
6320 driver = MSI_RecordGetString( rec, 4 );
6321 registration = MSI_RecordGetInteger( rec, 5 );
6323 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6324 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6326 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6327 attrs = msi_alloc( len * sizeof(WCHAR) );
6328 if (!attrs)
6329 return ERROR_OUTOFMEMORY;
6331 FIXME("Use ODBCSourceAttribute table\n");
6333 len = sprintfW( attrs, attrs_fmt, desc );
6334 attrs[len + 1] = 0;
6336 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6338 WARN("Failed to remove ODBC data source\n");
6340 msi_free( attrs );
6342 uirow = MSI_CreateRecord( 3 );
6343 MSI_RecordSetStringW( uirow, 1, desc );
6344 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6345 MSI_RecordSetInteger( uirow, 3, request );
6346 msi_ui_actiondata( package, szRemoveODBC, uirow );
6347 msiobj_release( &uirow->hdr );
6349 return ERROR_SUCCESS;
6352 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6354 static const WCHAR driver_query[] = {
6355 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6356 'O','D','B','C','D','r','i','v','e','r',0};
6357 static const WCHAR translator_query[] = {
6358 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6359 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6360 static const WCHAR source_query[] = {
6361 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6362 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6363 MSIQUERY *view;
6364 UINT rc;
6366 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6367 if (rc == ERROR_SUCCESS)
6369 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6370 msiobj_release( &view->hdr );
6371 if (rc != ERROR_SUCCESS)
6372 return rc;
6374 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6375 if (rc == ERROR_SUCCESS)
6377 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6378 msiobj_release( &view->hdr );
6379 if (rc != ERROR_SUCCESS)
6380 return rc;
6382 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6383 if (rc == ERROR_SUCCESS)
6385 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6386 msiobj_release( &view->hdr );
6387 if (rc != ERROR_SUCCESS)
6388 return rc;
6390 return ERROR_SUCCESS;
6393 #define ENV_ACT_SETALWAYS 0x1
6394 #define ENV_ACT_SETABSENT 0x2
6395 #define ENV_ACT_REMOVE 0x4
6396 #define ENV_ACT_REMOVEMATCH 0x8
6398 #define ENV_MOD_MACHINE 0x20000000
6399 #define ENV_MOD_APPEND 0x40000000
6400 #define ENV_MOD_PREFIX 0x80000000
6401 #define ENV_MOD_MASK 0xC0000000
6403 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6405 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6407 LPCWSTR cptr = *name;
6409 static const WCHAR prefix[] = {'[','~',']',0};
6410 static const int prefix_len = 3;
6412 *flags = 0;
6413 while (*cptr)
6415 if (*cptr == '=')
6416 *flags |= ENV_ACT_SETALWAYS;
6417 else if (*cptr == '+')
6418 *flags |= ENV_ACT_SETABSENT;
6419 else if (*cptr == '-')
6420 *flags |= ENV_ACT_REMOVE;
6421 else if (*cptr == '!')
6422 *flags |= ENV_ACT_REMOVEMATCH;
6423 else if (*cptr == '*')
6424 *flags |= ENV_MOD_MACHINE;
6425 else
6426 break;
6428 cptr++;
6429 (*name)++;
6432 if (!*cptr)
6434 ERR("Missing environment variable\n");
6435 return ERROR_FUNCTION_FAILED;
6438 if (*value)
6440 LPCWSTR ptr = *value;
6441 if (!strncmpW(ptr, prefix, prefix_len))
6443 if (ptr[prefix_len] == szSemiColon[0])
6445 *flags |= ENV_MOD_APPEND;
6446 *value += lstrlenW(prefix);
6448 else
6450 *value = NULL;
6453 else if (lstrlenW(*value) >= prefix_len)
6455 ptr += lstrlenW(ptr) - prefix_len;
6456 if (!strcmpW( ptr, prefix ))
6458 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6460 *flags |= ENV_MOD_PREFIX;
6461 /* the "[~]" will be removed by deformat_string */;
6463 else
6465 *value = NULL;
6471 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6472 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6473 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6474 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6476 ERR("Invalid flags: %08x\n", *flags);
6477 return ERROR_FUNCTION_FAILED;
6480 if (!*flags)
6481 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6483 return ERROR_SUCCESS;
6486 static UINT open_env_key( DWORD flags, HKEY *key )
6488 static const WCHAR user_env[] =
6489 {'E','n','v','i','r','o','n','m','e','n','t',0};
6490 static const WCHAR machine_env[] =
6491 {'S','y','s','t','e','m','\\',
6492 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6493 'C','o','n','t','r','o','l','\\',
6494 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6495 'E','n','v','i','r','o','n','m','e','n','t',0};
6496 const WCHAR *env;
6497 HKEY root;
6498 LONG res;
6500 if (flags & ENV_MOD_MACHINE)
6502 env = machine_env;
6503 root = HKEY_LOCAL_MACHINE;
6505 else
6507 env = user_env;
6508 root = HKEY_CURRENT_USER;
6511 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6512 if (res != ERROR_SUCCESS)
6514 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6515 return ERROR_FUNCTION_FAILED;
6518 return ERROR_SUCCESS;
6521 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6523 MSIPACKAGE *package = param;
6524 LPCWSTR name, value, component;
6525 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6526 DWORD flags, type, size;
6527 UINT res;
6528 HKEY env = NULL;
6529 MSICOMPONENT *comp;
6530 MSIRECORD *uirow;
6531 int action = 0;
6533 component = MSI_RecordGetString(rec, 4);
6534 comp = msi_get_loaded_component(package, component);
6535 if (!comp)
6536 return ERROR_SUCCESS;
6538 comp->Action = msi_get_component_action( package, comp );
6539 if (comp->Action != INSTALLSTATE_LOCAL)
6541 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6542 return ERROR_SUCCESS;
6544 name = MSI_RecordGetString(rec, 2);
6545 value = MSI_RecordGetString(rec, 3);
6547 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6549 res = env_parse_flags(&name, &value, &flags);
6550 if (res != ERROR_SUCCESS || !value)
6551 goto done;
6553 if (value && !deformat_string(package, value, &deformatted))
6555 res = ERROR_OUTOFMEMORY;
6556 goto done;
6559 value = deformatted;
6561 res = open_env_key( flags, &env );
6562 if (res != ERROR_SUCCESS)
6563 goto done;
6565 if (flags & ENV_MOD_MACHINE)
6566 action |= 0x20000000;
6568 size = 0;
6569 type = REG_SZ;
6570 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6571 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6572 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6573 goto done;
6575 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6577 action = 0x2;
6579 /* Nothing to do. */
6580 if (!value)
6582 res = ERROR_SUCCESS;
6583 goto done;
6586 /* If we are appending but the string was empty, strip ; */
6587 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6589 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6590 newval = strdupW(value);
6591 if (!newval)
6593 res = ERROR_OUTOFMEMORY;
6594 goto done;
6597 else
6599 action = 0x1;
6601 /* Contrary to MSDN, +-variable to [~];path works */
6602 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6604 res = ERROR_SUCCESS;
6605 goto done;
6608 data = msi_alloc(size);
6609 if (!data)
6611 RegCloseKey(env);
6612 return ERROR_OUTOFMEMORY;
6615 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6616 if (res != ERROR_SUCCESS)
6617 goto done;
6619 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6621 action = 0x4;
6622 res = RegDeleteValueW(env, name);
6623 if (res != ERROR_SUCCESS)
6624 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6625 goto done;
6628 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6629 if (flags & ENV_MOD_MASK)
6631 DWORD mod_size;
6632 int multiplier = 0;
6633 if (flags & ENV_MOD_APPEND) multiplier++;
6634 if (flags & ENV_MOD_PREFIX) multiplier++;
6635 mod_size = lstrlenW(value) * multiplier;
6636 size += mod_size * sizeof(WCHAR);
6639 newval = msi_alloc(size);
6640 ptr = newval;
6641 if (!newval)
6643 res = ERROR_OUTOFMEMORY;
6644 goto done;
6647 if (flags & ENV_MOD_PREFIX)
6649 lstrcpyW(newval, value);
6650 ptr = newval + lstrlenW(value);
6651 action |= 0x80000000;
6654 lstrcpyW(ptr, data);
6656 if (flags & ENV_MOD_APPEND)
6658 lstrcatW(newval, value);
6659 action |= 0x40000000;
6662 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6663 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6664 if (res)
6666 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6669 done:
6670 uirow = MSI_CreateRecord( 3 );
6671 MSI_RecordSetStringW( uirow, 1, name );
6672 MSI_RecordSetStringW( uirow, 2, newval );
6673 MSI_RecordSetInteger( uirow, 3, action );
6674 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6675 msiobj_release( &uirow->hdr );
6677 if (env) RegCloseKey(env);
6678 msi_free(deformatted);
6679 msi_free(data);
6680 msi_free(newval);
6681 return res;
6684 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6686 static const WCHAR query[] = {
6687 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6688 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6689 MSIQUERY *view;
6690 UINT rc;
6692 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6693 if (rc != ERROR_SUCCESS)
6694 return ERROR_SUCCESS;
6696 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6697 msiobj_release(&view->hdr);
6698 return rc;
6701 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6703 MSIPACKAGE *package = param;
6704 LPCWSTR name, value, component;
6705 LPWSTR deformatted = NULL;
6706 DWORD flags;
6707 HKEY env;
6708 MSICOMPONENT *comp;
6709 MSIRECORD *uirow;
6710 int action = 0;
6711 LONG res;
6712 UINT r;
6714 component = MSI_RecordGetString( rec, 4 );
6715 comp = msi_get_loaded_component( package, component );
6716 if (!comp)
6717 return ERROR_SUCCESS;
6719 comp->Action = msi_get_component_action( package, comp );
6720 if (comp->Action != INSTALLSTATE_ABSENT)
6722 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6723 return ERROR_SUCCESS;
6725 name = MSI_RecordGetString( rec, 2 );
6726 value = MSI_RecordGetString( rec, 3 );
6728 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6730 r = env_parse_flags( &name, &value, &flags );
6731 if (r != ERROR_SUCCESS)
6732 return r;
6734 if (!(flags & ENV_ACT_REMOVE))
6736 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6737 return ERROR_SUCCESS;
6740 if (value && !deformat_string( package, value, &deformatted ))
6741 return ERROR_OUTOFMEMORY;
6743 value = deformatted;
6745 r = open_env_key( flags, &env );
6746 if (r != ERROR_SUCCESS)
6748 r = ERROR_SUCCESS;
6749 goto done;
6752 if (flags & ENV_MOD_MACHINE)
6753 action |= 0x20000000;
6755 TRACE("Removing %s\n", debugstr_w(name));
6757 res = RegDeleteValueW( env, name );
6758 if (res != ERROR_SUCCESS)
6760 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6761 r = ERROR_SUCCESS;
6764 done:
6765 uirow = MSI_CreateRecord( 3 );
6766 MSI_RecordSetStringW( uirow, 1, name );
6767 MSI_RecordSetStringW( uirow, 2, value );
6768 MSI_RecordSetInteger( uirow, 3, action );
6769 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6770 msiobj_release( &uirow->hdr );
6772 if (env) RegCloseKey( env );
6773 msi_free( deformatted );
6774 return r;
6777 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6779 static const WCHAR query[] = {
6780 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6781 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6782 MSIQUERY *view;
6783 UINT rc;
6785 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6786 if (rc != ERROR_SUCCESS)
6787 return ERROR_SUCCESS;
6789 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6790 msiobj_release( &view->hdr );
6791 return rc;
6794 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6796 LPWSTR key, template, id;
6797 UINT r = ERROR_SUCCESS;
6799 id = msi_dup_property( package->db, szProductID );
6800 if (id)
6802 msi_free( id );
6803 return ERROR_SUCCESS;
6805 template = msi_dup_property( package->db, szPIDTemplate );
6806 key = msi_dup_property( package->db, szPIDKEY );
6808 if (key && template)
6810 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6811 r = msi_set_property( package->db, szProductID, key );
6813 msi_free( template );
6814 msi_free( key );
6815 return r;
6818 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6820 TRACE("\n");
6821 package->need_reboot = 1;
6822 return ERROR_SUCCESS;
6825 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6827 static const WCHAR szAvailableFreeReg[] =
6828 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6829 MSIRECORD *uirow;
6830 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6832 TRACE("%p %d kilobytes\n", package, space);
6834 uirow = MSI_CreateRecord( 1 );
6835 MSI_RecordSetInteger( uirow, 1, space );
6836 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6837 msiobj_release( &uirow->hdr );
6839 return ERROR_SUCCESS;
6842 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6844 TRACE("%p\n", package);
6846 msi_set_property( package->db, szRollbackDisabled, szOne );
6847 return ERROR_SUCCESS;
6850 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6852 FIXME("%p\n", package);
6853 return ERROR_SUCCESS;
6856 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6858 static const WCHAR driver_query[] = {
6859 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6860 'O','D','B','C','D','r','i','v','e','r',0};
6861 static const WCHAR translator_query[] = {
6862 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6863 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6864 MSIQUERY *view;
6865 UINT r, count;
6867 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6868 if (r == ERROR_SUCCESS)
6870 count = 0;
6871 r = MSI_IterateRecords( view, &count, NULL, package );
6872 msiobj_release( &view->hdr );
6873 if (r != ERROR_SUCCESS)
6874 return r;
6875 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6877 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6878 if (r == ERROR_SUCCESS)
6880 count = 0;
6881 r = MSI_IterateRecords( view, &count, NULL, package );
6882 msiobj_release( &view->hdr );
6883 if (r != ERROR_SUCCESS)
6884 return r;
6885 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6887 return ERROR_SUCCESS;
6890 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6892 MSIPACKAGE *package = param;
6893 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6894 WCHAR *value;
6896 if ((value = msi_dup_property( package->db, property )))
6898 FIXME("remove %s\n", debugstr_w(value));
6899 msi_free( value );
6901 return ERROR_SUCCESS;
6904 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6906 static const WCHAR query[] = {
6907 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
6908 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
6909 MSIQUERY *view;
6910 UINT r;
6912 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6913 if (r == ERROR_SUCCESS)
6915 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
6916 msiobj_release( &view->hdr );
6917 if (r != ERROR_SUCCESS)
6918 return r;
6920 return ERROR_SUCCESS;
6923 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
6925 MSIPACKAGE *package = param;
6926 int attributes = MSI_RecordGetInteger( rec, 5 );
6928 if (attributes & msidbUpgradeAttributesMigrateFeatures)
6930 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
6931 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
6932 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
6933 const WCHAR *language = MSI_RecordGetString( rec, 4 );
6934 HKEY hkey;
6935 UINT r;
6937 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
6939 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6940 if (r != ERROR_SUCCESS)
6941 return ERROR_SUCCESS;
6943 else
6945 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6946 if (r != ERROR_SUCCESS)
6947 return ERROR_SUCCESS;
6949 RegCloseKey( hkey );
6951 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
6952 debugstr_w(upgrade_code), debugstr_w(version_min),
6953 debugstr_w(version_max), debugstr_w(language));
6955 return ERROR_SUCCESS;
6958 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6960 static const WCHAR query[] = {
6961 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6962 'U','p','g','r','a','d','e',0};
6963 MSIQUERY *view;
6964 UINT r;
6966 if (msi_get_property_int( package->db, szInstalled, 0 ))
6968 TRACE("product is installed, skipping action\n");
6969 return ERROR_SUCCESS;
6971 if (msi_get_property_int( package->db, szPreselected, 0 ))
6973 TRACE("Preselected property is set, not migrating feature states\n");
6974 return ERROR_SUCCESS;
6976 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6977 if (r == ERROR_SUCCESS)
6979 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
6980 msiobj_release( &view->hdr );
6981 if (r != ERROR_SUCCESS)
6982 return r;
6984 return ERROR_SUCCESS;
6987 static void bind_image( const char *filename, const char *path )
6989 if (!BindImageEx( 0, filename, path, NULL, NULL ))
6991 WARN("failed to bind image %u\n", GetLastError());
6995 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
6997 UINT i;
6998 MSIFILE *file;
6999 MSIPACKAGE *package = param;
7000 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7001 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7002 char *filenameA, *pathA;
7003 WCHAR *pathW, **path_list;
7005 if (!(file = msi_get_loaded_file( package, key )))
7007 WARN("file %s not found\n", debugstr_w(key));
7008 return ERROR_SUCCESS;
7010 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7011 path_list = msi_split_string( paths, ';' );
7012 if (!path_list) bind_image( filenameA, NULL );
7013 else
7015 for (i = 0; path_list[i] && path_list[i][0]; i++)
7017 deformat_string( package, path_list[i], &pathW );
7018 if ((pathA = strdupWtoA( pathW )))
7020 bind_image( filenameA, pathA );
7021 msi_free( pathA );
7023 msi_free( pathW );
7026 msi_free( path_list );
7027 msi_free( filenameA );
7028 return ERROR_SUCCESS;
7031 static UINT ACTION_BindImage( MSIPACKAGE *package )
7033 static const WCHAR query[] = {
7034 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7035 'B','i','n','d','I','m','a','g','e',0};
7036 MSIQUERY *view;
7037 UINT r;
7039 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7040 if (r == ERROR_SUCCESS)
7042 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7043 msiobj_release( &view->hdr );
7044 if (r != ERROR_SUCCESS)
7045 return r;
7047 return ERROR_SUCCESS;
7050 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7052 static const WCHAR query[] = {
7053 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7054 MSIQUERY *view;
7055 DWORD count = 0;
7056 UINT r;
7058 r = MSI_OpenQuery( package->db, &view, query, table );
7059 if (r == ERROR_SUCCESS)
7061 r = MSI_IterateRecords(view, &count, NULL, package);
7062 msiobj_release(&view->hdr);
7063 if (r != ERROR_SUCCESS)
7064 return r;
7066 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7067 return ERROR_SUCCESS;
7070 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7072 static const WCHAR table[] = {
7073 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7074 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7077 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7079 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7080 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7083 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7085 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7086 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7089 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7091 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7092 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7095 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7097 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7098 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7101 static const struct
7103 const WCHAR *action;
7104 UINT (*handler)(MSIPACKAGE *);
7105 const WCHAR *action_rollback;
7107 StandardActions[] =
7109 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7110 { szAppSearch, ACTION_AppSearch, NULL },
7111 { szBindImage, ACTION_BindImage, NULL },
7112 { szCCPSearch, ACTION_CCPSearch, NULL },
7113 { szCostFinalize, ACTION_CostFinalize, NULL },
7114 { szCostInitialize, ACTION_CostInitialize, NULL },
7115 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7116 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7117 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7118 { szDisableRollback, ACTION_DisableRollback, NULL },
7119 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7120 { szExecuteAction, ACTION_ExecuteAction, NULL },
7121 { szFileCost, ACTION_FileCost, NULL },
7122 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7123 { szForceReboot, ACTION_ForceReboot, NULL },
7124 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7125 { szInstallExecute, ACTION_InstallExecute, NULL },
7126 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7127 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7128 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7129 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7130 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7131 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7132 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7133 { szInstallValidate, ACTION_InstallValidate, NULL },
7134 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7135 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7136 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7137 { szMoveFiles, ACTION_MoveFiles, NULL },
7138 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7139 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7140 { szPatchFiles, ACTION_PatchFiles, NULL },
7141 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7142 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7143 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7144 { szPublishProduct, ACTION_PublishProduct, NULL },
7145 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7146 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7147 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7148 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7149 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7150 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7151 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7152 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7153 { szRegisterUser, ACTION_RegisterUser, NULL },
7154 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7155 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7156 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7157 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7158 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7159 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7160 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7161 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7162 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7163 { szResolveSource, ACTION_ResolveSource, NULL },
7164 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7165 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7166 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7167 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfUnregModules },
7168 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7169 { szStartServices, ACTION_StartServices, szStopServices },
7170 { szStopServices, ACTION_StopServices, szStartServices },
7171 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7172 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7173 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7174 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7175 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7176 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7177 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7178 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7179 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7180 { szValidateProductID, ACTION_ValidateProductID, NULL },
7181 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7182 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7183 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7184 { NULL, NULL, NULL }
7187 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7189 BOOL ret = FALSE;
7190 UINT i;
7192 i = 0;
7193 while (StandardActions[i].action != NULL)
7195 if (!strcmpW( StandardActions[i].action, action ))
7197 ui_actionstart( package, action );
7198 if (StandardActions[i].handler)
7200 ui_actioninfo( package, action, TRUE, 0 );
7201 *rc = StandardActions[i].handler( package );
7202 ui_actioninfo( package, action, FALSE, *rc );
7204 if (StandardActions[i].action_rollback && !package->need_rollback)
7206 TRACE("scheduling rollback action\n");
7207 msi_schedule_action( package, ROLLBACK_SCRIPT, StandardActions[i].action_rollback );
7210 else
7212 FIXME("unhandled standard action %s\n", debugstr_w(action));
7213 *rc = ERROR_SUCCESS;
7215 ret = TRUE;
7216 break;
7218 i++;
7220 return ret;
7223 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7225 UINT rc = ERROR_SUCCESS;
7226 BOOL handled;
7228 TRACE("Performing action (%s)\n", debugstr_w(action));
7230 handled = ACTION_HandleStandardAction(package, action, &rc);
7232 if (!handled)
7233 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7235 if (!handled)
7237 WARN("unhandled msi action %s\n", debugstr_w(action));
7238 rc = ERROR_FUNCTION_NOT_CALLED;
7241 return rc;
7244 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7246 UINT rc = ERROR_SUCCESS;
7247 BOOL handled = FALSE;
7249 TRACE("Performing action (%s)\n", debugstr_w(action));
7251 handled = ACTION_HandleStandardAction(package, action, &rc);
7253 if (!handled)
7254 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7256 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7257 handled = TRUE;
7259 if (!handled)
7261 WARN("unhandled msi action %s\n", debugstr_w(action));
7262 rc = ERROR_FUNCTION_NOT_CALLED;
7265 return rc;
7268 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7270 UINT rc = ERROR_SUCCESS;
7271 MSIRECORD *row;
7273 static const WCHAR query[] =
7274 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7275 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7276 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7277 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7278 static const WCHAR ui_query[] =
7279 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7280 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7281 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7282 ' ', '=',' ','%','i',0};
7284 if (needs_ui_sequence(package))
7285 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7286 else
7287 row = MSI_QueryGetRecord(package->db, query, seq);
7289 if (row)
7291 LPCWSTR action, cond;
7293 TRACE("Running the actions\n");
7295 /* check conditions */
7296 cond = MSI_RecordGetString(row, 2);
7298 /* this is a hack to skip errors in the condition code */
7299 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7301 msiobj_release(&row->hdr);
7302 return ERROR_SUCCESS;
7305 action = MSI_RecordGetString(row, 1);
7306 if (!action)
7308 ERR("failed to fetch action\n");
7309 msiobj_release(&row->hdr);
7310 return ERROR_FUNCTION_FAILED;
7313 if (needs_ui_sequence(package))
7314 rc = ACTION_PerformUIAction(package, action, -1);
7315 else
7316 rc = ACTION_PerformAction(package, action, -1);
7318 msiobj_release(&row->hdr);
7321 return rc;
7324 /****************************************************
7325 * TOP level entry points
7326 *****************************************************/
7328 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7329 LPCWSTR szCommandLine )
7331 UINT rc;
7332 BOOL ui_exists;
7333 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7334 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7335 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7337 msi_set_property( package->db, szAction, szInstall );
7339 package->script->InWhatSequence = SEQUENCE_INSTALL;
7341 if (szPackagePath)
7343 LPWSTR p, dir;
7344 LPCWSTR file;
7346 dir = strdupW(szPackagePath);
7347 p = strrchrW(dir, '\\');
7348 if (p)
7350 *(++p) = 0;
7351 file = szPackagePath + (p - dir);
7353 else
7355 msi_free(dir);
7356 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7357 GetCurrentDirectoryW(MAX_PATH, dir);
7358 lstrcatW(dir, szBackSlash);
7359 file = szPackagePath;
7362 msi_free( package->PackagePath );
7363 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7364 if (!package->PackagePath)
7366 msi_free(dir);
7367 return ERROR_OUTOFMEMORY;
7370 lstrcpyW(package->PackagePath, dir);
7371 lstrcatW(package->PackagePath, file);
7372 msi_free(dir);
7374 msi_set_sourcedir_props(package, FALSE);
7377 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7378 if (rc != ERROR_SUCCESS)
7379 return rc;
7381 msi_apply_transforms( package );
7382 msi_apply_patches( package );
7384 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7386 TRACE("setting reinstall property\n");
7387 msi_set_property( package->db, szReinstall, szAll );
7390 /* properties may have been added by a transform */
7391 msi_clone_properties( package );
7393 msi_parse_command_line( package, szCommandLine, FALSE );
7394 msi_adjust_privilege_properties( package );
7395 msi_set_context( package );
7397 if (msi_get_property_int( package->db, szInstalled, 0 ))
7399 HKEY hkey;
7400 DeleteFileW( package->localfile );
7401 msi_free( package->localfile );
7402 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
7403 package->localfile = msi_reg_get_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW );
7404 RegCloseKey( hkey );
7406 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7408 TRACE("disabling rollback\n");
7409 msi_set_property( package->db, szRollbackDisabled, szOne );
7412 if (needs_ui_sequence( package))
7414 package->script->InWhatSequence |= SEQUENCE_UI;
7415 rc = ACTION_ProcessUISequence(package);
7416 ui_exists = ui_sequence_exists(package);
7417 if (rc == ERROR_SUCCESS || !ui_exists)
7419 package->script->InWhatSequence |= SEQUENCE_EXEC;
7420 rc = ACTION_ProcessExecSequence(package, ui_exists);
7423 else
7424 rc = ACTION_ProcessExecSequence(package, FALSE);
7426 package->script->CurrentlyScripting = FALSE;
7428 /* process the ending type action */
7429 if (rc == ERROR_SUCCESS)
7430 ACTION_PerformActionSequence(package, -1);
7431 else if (rc == ERROR_INSTALL_USEREXIT)
7432 ACTION_PerformActionSequence(package, -2);
7433 else if (rc == ERROR_INSTALL_SUSPEND)
7434 ACTION_PerformActionSequence(package, -4);
7435 else /* failed */
7437 ACTION_PerformActionSequence(package, -3);
7438 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7440 package->need_rollback = TRUE;
7444 /* finish up running custom actions */
7445 ACTION_FinishCustomActions(package);
7447 if (package->need_rollback)
7449 WARN("installation failed, running rollback script\n");
7450 execute_script( package, ROLLBACK_SCRIPT );
7453 if (rc == ERROR_SUCCESS && package->need_reboot)
7454 return ERROR_SUCCESS_REBOOT_REQUIRED;
7456 return rc;