vbscript: Added more IDispatchEx tests.
[wine/multimedia.git] / dlls / msi / action.c
blob478adddf09e11f4de7c360134e97a8999c8c324e
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 UINT r = msi_locate_product( package->ProductCode, &package->Context );
492 if (r != ERROR_SUCCESS)
494 int num = msi_get_property_int( package->db, szAllUsers, 0 );
495 if (num == 1 || num == 2)
496 package->Context = MSIINSTALLCONTEXT_MACHINE;
497 else
498 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
500 return ERROR_SUCCESS;
503 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
505 UINT rc;
506 LPCWSTR cond, action;
507 MSIPACKAGE *package = param;
509 action = MSI_RecordGetString(row,1);
510 if (!action)
512 ERR("Error is retrieving action name\n");
513 return ERROR_FUNCTION_FAILED;
516 /* check conditions */
517 cond = MSI_RecordGetString(row,2);
519 /* this is a hack to skip errors in the condition code */
520 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
522 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
523 return ERROR_SUCCESS;
526 if (needs_ui_sequence(package))
527 rc = ACTION_PerformUIAction(package, action, -1);
528 else
529 rc = ACTION_PerformAction(package, action, -1);
531 msi_dialog_check_messages( NULL );
533 if (package->CurrentInstallState != ERROR_SUCCESS)
534 rc = package->CurrentInstallState;
536 if (rc == ERROR_FUNCTION_NOT_CALLED)
537 rc = ERROR_SUCCESS;
539 if (rc != ERROR_SUCCESS)
540 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
542 return rc;
545 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
547 static const WCHAR query[] = {
548 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
549 ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
550 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
551 '`','S','e','q','u','e','n','c','e','`',0};
552 MSIQUERY *view;
553 UINT r;
555 TRACE("%p %s\n", package, debugstr_w(table));
557 r = MSI_OpenQuery( package->db, &view, query, table );
558 if (r == ERROR_SUCCESS)
560 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
561 msiobj_release(&view->hdr);
563 return r;
566 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
568 static const WCHAR query[] = {
569 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
570 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
571 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
572 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
573 'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
574 static const WCHAR query_validate[] = {
575 'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
576 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
577 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
578 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
579 ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
580 MSIQUERY *view;
581 INT seq = 0;
582 UINT rc;
584 if (package->script->ExecuteSequenceRun)
586 TRACE("Execute Sequence already Run\n");
587 return ERROR_SUCCESS;
590 package->script->ExecuteSequenceRun = TRUE;
592 /* get the sequence number */
593 if (UIran)
595 MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
596 if (!row) return ERROR_FUNCTION_FAILED;
597 seq = MSI_RecordGetInteger(row,1);
598 msiobj_release(&row->hdr);
600 rc = MSI_OpenQuery(package->db, &view, query, seq);
601 if (rc == ERROR_SUCCESS)
603 TRACE("Running the actions\n");
605 msi_set_property(package->db, szSourceDir, NULL);
606 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
607 msiobj_release(&view->hdr);
609 return rc;
612 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
614 static const WCHAR query[] = {
615 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
616 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
617 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
618 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
619 MSIQUERY *view;
620 UINT rc;
622 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
623 if (rc == ERROR_SUCCESS)
625 TRACE("Running the actions\n");
626 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
627 msiobj_release(&view->hdr);
629 return rc;
632 /********************************************************
633 * ACTION helper functions and functions that perform the actions
634 *******************************************************/
635 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
636 UINT* rc, UINT script, BOOL force )
638 BOOL ret=FALSE;
639 UINT arc;
641 arc = ACTION_CustomAction(package, action, script, force);
643 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
645 *rc = arc;
646 ret = TRUE;
648 return ret;
651 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
653 MSICOMPONENT *comp;
655 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
657 if (!strcmpW( Component, comp->Component )) return comp;
659 return NULL;
662 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
664 MSIFEATURE *feature;
666 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
668 if (!strcmpW( Feature, feature->Feature )) return feature;
670 return NULL;
673 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
675 MSIFILE *file;
677 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
679 if (!strcmpW( key, file->File )) return file;
681 return NULL;
684 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
686 MSIFILEPATCH *patch;
688 /* FIXME: There might be more than one patch */
689 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
691 if (!strcmpW( key, patch->File->File )) return patch;
693 return NULL;
696 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
698 MSIFOLDER *folder;
700 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
702 if (!strcmpW( dir, folder->Directory )) return folder;
704 return NULL;
708 * Recursively create all directories in the path.
709 * shamelessly stolen from setupapi/queue.c
711 BOOL msi_create_full_path( const WCHAR *path )
713 BOOL ret = TRUE;
714 WCHAR *new_path;
715 int len;
717 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
718 strcpyW( new_path, path );
720 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
721 new_path[len - 1] = 0;
723 while (!CreateDirectoryW( new_path, NULL ))
725 WCHAR *slash;
726 DWORD last_error = GetLastError();
727 if (last_error == ERROR_ALREADY_EXISTS) break;
728 if (last_error != ERROR_PATH_NOT_FOUND)
730 ret = FALSE;
731 break;
733 if (!(slash = strrchrW( new_path, '\\' )))
735 ret = FALSE;
736 break;
738 len = slash - new_path;
739 new_path[len] = 0;
740 if (!msi_create_full_path( new_path ))
742 ret = FALSE;
743 break;
745 new_path[len] = '\\';
747 msi_free( new_path );
748 return ret;
751 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
753 MSIRECORD *row;
755 row = MSI_CreateRecord( 4 );
756 MSI_RecordSetInteger( row, 1, a );
757 MSI_RecordSetInteger( row, 2, b );
758 MSI_RecordSetInteger( row, 3, c );
759 MSI_RecordSetInteger( row, 4, d );
760 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
761 msiobj_release( &row->hdr );
763 msi_dialog_check_messages( NULL );
766 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
768 static const WCHAR query[] =
769 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
770 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
771 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
772 WCHAR message[1024];
773 MSIRECORD *row = 0;
774 DWORD size;
776 if (!package->LastAction || strcmpW( package->LastAction, action ))
778 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
780 if (MSI_RecordIsNull( row, 3 ))
782 msiobj_release( &row->hdr );
783 return;
785 /* update the cached action format */
786 msi_free( package->ActionFormat );
787 package->ActionFormat = msi_dup_record_field( row, 3 );
788 msi_free( package->LastAction );
789 package->LastAction = strdupW( action );
790 msiobj_release( &row->hdr );
792 size = 1024;
793 MSI_RecordSetStringW( record, 0, package->ActionFormat );
794 MSI_FormatRecordW( package, record, message, &size );
795 row = MSI_CreateRecord( 1 );
796 MSI_RecordSetStringW( row, 1, message );
797 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
798 msiobj_release( &row->hdr );
801 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
803 if (!comp->Enabled)
805 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
806 return INSTALLSTATE_UNKNOWN;
808 if (package->need_rollback) return comp->Installed;
809 return comp->ActionRequest;
812 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
814 if (package->need_rollback) return feature->Installed;
815 return feature->ActionRequest;
818 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
820 MSIPACKAGE *package = param;
821 LPCWSTR dir, component, full_path;
822 MSIRECORD *uirow;
823 MSIFOLDER *folder;
824 MSICOMPONENT *comp;
826 component = MSI_RecordGetString(row, 2);
827 if (!component)
828 return ERROR_SUCCESS;
830 comp = msi_get_loaded_component(package, component);
831 if (!comp)
832 return ERROR_SUCCESS;
834 comp->Action = msi_get_component_action( package, comp );
835 if (comp->Action != INSTALLSTATE_LOCAL)
837 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
838 return ERROR_SUCCESS;
841 dir = MSI_RecordGetString(row,1);
842 if (!dir)
844 ERR("Unable to get folder id\n");
845 return ERROR_SUCCESS;
848 uirow = MSI_CreateRecord(1);
849 MSI_RecordSetStringW(uirow, 1, dir);
850 msi_ui_actiondata(package, szCreateFolders, uirow);
851 msiobj_release(&uirow->hdr);
853 full_path = msi_get_target_folder( package, dir );
854 if (!full_path)
856 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
857 return ERROR_SUCCESS;
859 TRACE("folder is %s\n", debugstr_w(full_path));
861 folder = msi_get_loaded_folder( package, dir );
862 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
863 folder->State = FOLDER_STATE_CREATED;
864 return ERROR_SUCCESS;
867 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
869 static const WCHAR query[] = {
870 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
871 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
872 MSIQUERY *view;
873 UINT rc;
875 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
876 if (rc != ERROR_SUCCESS)
877 return ERROR_SUCCESS;
879 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
880 msiobj_release(&view->hdr);
881 return rc;
884 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
886 MSIPACKAGE *package = param;
887 LPCWSTR dir, component, full_path;
888 MSIRECORD *uirow;
889 MSIFOLDER *folder;
890 MSICOMPONENT *comp;
892 component = MSI_RecordGetString(row, 2);
893 if (!component)
894 return ERROR_SUCCESS;
896 comp = msi_get_loaded_component(package, component);
897 if (!comp)
898 return ERROR_SUCCESS;
900 comp->Action = msi_get_component_action( package, comp );
901 if (comp->Action != INSTALLSTATE_ABSENT)
903 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
904 return ERROR_SUCCESS;
907 dir = MSI_RecordGetString( row, 1 );
908 if (!dir)
910 ERR("Unable to get folder id\n");
911 return ERROR_SUCCESS;
914 full_path = msi_get_target_folder( package, dir );
915 if (!full_path)
917 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
918 return ERROR_SUCCESS;
920 TRACE("folder is %s\n", debugstr_w(full_path));
922 uirow = MSI_CreateRecord( 1 );
923 MSI_RecordSetStringW( uirow, 1, dir );
924 msi_ui_actiondata( package, szRemoveFolders, uirow );
925 msiobj_release( &uirow->hdr );
927 RemoveDirectoryW( full_path );
928 folder = msi_get_loaded_folder( package, dir );
929 folder->State = FOLDER_STATE_REMOVED;
930 return ERROR_SUCCESS;
933 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
935 static const WCHAR query[] = {
936 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
937 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
938 MSIQUERY *view;
939 UINT rc;
941 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
942 if (rc != ERROR_SUCCESS)
943 return ERROR_SUCCESS;
945 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
946 msiobj_release( &view->hdr );
947 return rc;
950 static UINT load_component( MSIRECORD *row, LPVOID param )
952 MSIPACKAGE *package = param;
953 MSICOMPONENT *comp;
955 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
956 if (!comp)
957 return ERROR_FUNCTION_FAILED;
959 list_add_tail( &package->components, &comp->entry );
961 /* fill in the data */
962 comp->Component = msi_dup_record_field( row, 1 );
964 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
966 comp->ComponentId = msi_dup_record_field( row, 2 );
967 comp->Directory = msi_dup_record_field( row, 3 );
968 comp->Attributes = MSI_RecordGetInteger(row,4);
969 comp->Condition = msi_dup_record_field( row, 5 );
970 comp->KeyPath = msi_dup_record_field( row, 6 );
972 comp->Installed = INSTALLSTATE_UNKNOWN;
973 comp->Action = INSTALLSTATE_UNKNOWN;
974 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
976 comp->assembly = msi_load_assembly( package, comp );
977 return ERROR_SUCCESS;
980 UINT msi_load_all_components( MSIPACKAGE *package )
982 static const WCHAR query[] = {
983 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
984 '`','C','o','m','p','o','n','e','n','t','`',0};
985 MSIQUERY *view;
986 UINT r;
988 if (!list_empty(&package->components))
989 return ERROR_SUCCESS;
991 r = MSI_DatabaseOpenViewW( package->db, query, &view );
992 if (r != ERROR_SUCCESS)
993 return r;
995 if (!msi_init_assembly_caches( package ))
997 ERR("can't initialize assembly caches\n");
998 msiobj_release( &view->hdr );
999 return ERROR_FUNCTION_FAILED;
1002 r = MSI_IterateRecords(view, NULL, load_component, package);
1003 msiobj_release(&view->hdr);
1004 msi_destroy_assembly_caches( package );
1005 return r;
1008 typedef struct {
1009 MSIPACKAGE *package;
1010 MSIFEATURE *feature;
1011 } _ilfs;
1013 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1015 ComponentList *cl;
1017 cl = msi_alloc( sizeof (*cl) );
1018 if ( !cl )
1019 return ERROR_NOT_ENOUGH_MEMORY;
1020 cl->component = comp;
1021 list_add_tail( &feature->Components, &cl->entry );
1023 return ERROR_SUCCESS;
1026 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1028 FeatureList *fl;
1030 fl = msi_alloc( sizeof(*fl) );
1031 if ( !fl )
1032 return ERROR_NOT_ENOUGH_MEMORY;
1033 fl->feature = child;
1034 list_add_tail( &parent->Children, &fl->entry );
1036 return ERROR_SUCCESS;
1039 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1041 _ilfs* ilfs = param;
1042 LPCWSTR component;
1043 MSICOMPONENT *comp;
1045 component = MSI_RecordGetString(row,1);
1047 /* check to see if the component is already loaded */
1048 comp = msi_get_loaded_component( ilfs->package, component );
1049 if (!comp)
1051 WARN("ignoring unknown component %s\n", debugstr_w(component));
1052 return ERROR_SUCCESS;
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 );
3520 if (!link_folder)
3522 /* some installers use a separate root */
3523 MSIFOLDER *folder = msi_get_loaded_folder( package, directory );
3524 while (folder->Parent && strcmpW( folder->Parent, folder->Directory ))
3526 folder = msi_get_loaded_folder( package, folder->Parent );
3528 msi_resolve_target_folder( package, folder->Directory, TRUE );
3529 link_folder = msi_get_target_folder( package, directory );
3531 /* may be needed because of a bug somewhere else */
3532 msi_create_full_path( link_folder );
3534 filename = msi_dup_record_field( row, 3 );
3535 msi_reduce_to_long_filename( filename );
3537 extension = strchrW( filename, '.' );
3538 if (!extension || strcmpiW( extension, szlnk ))
3540 int len = strlenW( filename );
3541 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3542 memcpy( filename + len, szlnk, sizeof(szlnk) );
3544 link_file = msi_build_directory_name( 2, link_folder, filename );
3545 msi_free( filename );
3547 return link_file;
3550 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3552 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3553 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3554 WCHAR *folder, *dest, *path;
3556 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3557 folder = msi_dup_property( package->db, szWindowsFolder );
3558 else
3560 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3561 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3562 msi_free( appdata );
3564 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3565 msi_create_full_path( dest );
3566 path = msi_build_directory_name( 2, dest, icon_name );
3567 msi_free( folder );
3568 msi_free( dest );
3569 return path;
3572 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3574 MSIPACKAGE *package = param;
3575 LPWSTR link_file, deformated, path;
3576 LPCWSTR component, target;
3577 MSICOMPONENT *comp;
3578 IShellLinkW *sl = NULL;
3579 IPersistFile *pf = NULL;
3580 HRESULT res;
3582 component = MSI_RecordGetString(row, 4);
3583 comp = msi_get_loaded_component(package, component);
3584 if (!comp)
3585 return ERROR_SUCCESS;
3587 comp->Action = msi_get_component_action( package, comp );
3588 if (comp->Action != INSTALLSTATE_LOCAL)
3590 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3591 return ERROR_SUCCESS;
3593 msi_ui_actiondata( package, szCreateShortcuts, row );
3595 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3596 &IID_IShellLinkW, (LPVOID *) &sl );
3598 if (FAILED( res ))
3600 ERR("CLSID_ShellLink not available\n");
3601 goto err;
3604 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3605 if (FAILED( res ))
3607 ERR("QueryInterface(IID_IPersistFile) failed\n");
3608 goto err;
3611 target = MSI_RecordGetString(row, 5);
3612 if (strchrW(target, '['))
3614 deformat_string(package, target, &deformated);
3615 IShellLinkW_SetPath(sl,deformated);
3616 msi_free(deformated);
3618 else
3620 FIXME("poorly handled shortcut format, advertised shortcut\n");
3621 IShellLinkW_SetPath(sl,comp->FullKeypath);
3624 if (!MSI_RecordIsNull(row,6))
3626 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3627 deformat_string(package, arguments, &deformated);
3628 IShellLinkW_SetArguments(sl,deformated);
3629 msi_free(deformated);
3632 if (!MSI_RecordIsNull(row,7))
3634 LPCWSTR description = MSI_RecordGetString(row, 7);
3635 IShellLinkW_SetDescription(sl, description);
3638 if (!MSI_RecordIsNull(row,8))
3639 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3641 if (!MSI_RecordIsNull(row,9))
3643 INT index;
3644 LPCWSTR icon = MSI_RecordGetString(row, 9);
3646 path = msi_build_icon_path(package, icon);
3647 index = MSI_RecordGetInteger(row,10);
3649 /* no value means 0 */
3650 if (index == MSI_NULL_INTEGER)
3651 index = 0;
3653 IShellLinkW_SetIconLocation(sl, path, index);
3654 msi_free(path);
3657 if (!MSI_RecordIsNull(row,11))
3658 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3660 if (!MSI_RecordIsNull(row,12))
3662 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3663 full_path = msi_get_target_folder( package, wkdir );
3664 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3666 link_file = get_link_file(package, row);
3668 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3669 IPersistFile_Save(pf, link_file, FALSE);
3670 msi_free(link_file);
3672 err:
3673 if (pf)
3674 IPersistFile_Release( pf );
3675 if (sl)
3676 IShellLinkW_Release( sl );
3678 return ERROR_SUCCESS;
3681 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3683 static const WCHAR query[] = {
3684 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3685 '`','S','h','o','r','t','c','u','t','`',0};
3686 MSIQUERY *view;
3687 HRESULT res;
3688 UINT rc;
3690 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3691 if (rc != ERROR_SUCCESS)
3692 return ERROR_SUCCESS;
3694 res = CoInitialize( NULL );
3696 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3697 msiobj_release(&view->hdr);
3699 if (SUCCEEDED(res)) CoUninitialize();
3700 return rc;
3703 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3705 MSIPACKAGE *package = param;
3706 LPWSTR link_file;
3707 LPCWSTR component;
3708 MSICOMPONENT *comp;
3710 component = MSI_RecordGetString( row, 4 );
3711 comp = msi_get_loaded_component( package, component );
3712 if (!comp)
3713 return ERROR_SUCCESS;
3715 comp->Action = msi_get_component_action( package, comp );
3716 if (comp->Action != INSTALLSTATE_ABSENT)
3718 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3719 return ERROR_SUCCESS;
3721 msi_ui_actiondata( package, szRemoveShortcuts, row );
3723 link_file = get_link_file( package, row );
3725 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3726 if (!DeleteFileW( link_file ))
3728 WARN("Failed to remove shortcut file %u\n", GetLastError());
3730 msi_free( link_file );
3732 return ERROR_SUCCESS;
3735 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3737 static const WCHAR query[] = {
3738 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3739 '`','S','h','o','r','t','c','u','t','`',0};
3740 MSIQUERY *view;
3741 UINT rc;
3743 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3744 if (rc != ERROR_SUCCESS)
3745 return ERROR_SUCCESS;
3747 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3748 msiobj_release( &view->hdr );
3749 return rc;
3752 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3754 MSIPACKAGE* package = param;
3755 HANDLE the_file;
3756 LPWSTR FilePath;
3757 LPCWSTR FileName;
3758 CHAR buffer[1024];
3759 DWORD sz;
3760 UINT rc;
3762 FileName = MSI_RecordGetString(row,1);
3763 if (!FileName)
3765 ERR("Unable to get FileName\n");
3766 return ERROR_SUCCESS;
3769 FilePath = msi_build_icon_path(package, FileName);
3771 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3773 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3774 FILE_ATTRIBUTE_NORMAL, NULL);
3776 if (the_file == INVALID_HANDLE_VALUE)
3778 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3779 msi_free(FilePath);
3780 return ERROR_SUCCESS;
3785 DWORD write;
3786 sz = 1024;
3787 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3788 if (rc != ERROR_SUCCESS)
3790 ERR("Failed to get stream\n");
3791 CloseHandle(the_file);
3792 DeleteFileW(FilePath);
3793 break;
3795 WriteFile(the_file,buffer,sz,&write,NULL);
3796 } while (sz == 1024);
3798 msi_free(FilePath);
3799 CloseHandle(the_file);
3801 return ERROR_SUCCESS;
3804 static UINT msi_publish_icons(MSIPACKAGE *package)
3806 static const WCHAR query[]= {
3807 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3808 '`','I','c','o','n','`',0};
3809 MSIQUERY *view;
3810 UINT r;
3812 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3813 if (r == ERROR_SUCCESS)
3815 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3816 msiobj_release(&view->hdr);
3817 if (r != ERROR_SUCCESS)
3818 return r;
3820 return ERROR_SUCCESS;
3823 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3825 UINT r;
3826 HKEY source;
3827 LPWSTR buffer;
3828 MSIMEDIADISK *disk;
3829 MSISOURCELISTINFO *info;
3831 r = RegCreateKeyW(hkey, szSourceList, &source);
3832 if (r != ERROR_SUCCESS)
3833 return r;
3835 RegCloseKey(source);
3837 buffer = strrchrW(package->PackagePath, '\\') + 1;
3838 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3839 package->Context, MSICODE_PRODUCT,
3840 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3841 if (r != ERROR_SUCCESS)
3842 return r;
3844 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3845 package->Context, MSICODE_PRODUCT,
3846 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3847 if (r != ERROR_SUCCESS)
3848 return r;
3850 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3851 package->Context, MSICODE_PRODUCT,
3852 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3853 if (r != ERROR_SUCCESS)
3854 return r;
3856 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3858 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3859 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3860 info->options, info->value);
3861 else
3862 MsiSourceListSetInfoW(package->ProductCode, NULL,
3863 info->context, info->options,
3864 info->property, info->value);
3867 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3869 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3870 disk->context, disk->options,
3871 disk->disk_id, disk->volume_label, disk->disk_prompt);
3874 return ERROR_SUCCESS;
3877 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3879 MSIHANDLE hdb, suminfo;
3880 WCHAR guids[MAX_PATH];
3881 WCHAR packcode[SQUISH_GUID_SIZE];
3882 LPWSTR buffer;
3883 LPWSTR ptr;
3884 DWORD langid;
3885 DWORD size;
3886 UINT r;
3888 static const WCHAR szARPProductIcon[] =
3889 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3890 static const WCHAR szAssignment[] =
3891 {'A','s','s','i','g','n','m','e','n','t',0};
3892 static const WCHAR szAdvertiseFlags[] =
3893 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3894 static const WCHAR szClients[] =
3895 {'C','l','i','e','n','t','s',0};
3896 static const WCHAR szColon[] = {':',0};
3898 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3899 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3900 msi_free(buffer);
3902 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3903 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3905 /* FIXME */
3906 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3908 buffer = msi_dup_property(package->db, szARPProductIcon);
3909 if (buffer)
3911 LPWSTR path = msi_build_icon_path(package, buffer);
3912 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3913 msi_free(path);
3914 msi_free(buffer);
3917 buffer = msi_dup_property(package->db, szProductVersion);
3918 if (buffer)
3920 DWORD verdword = msi_version_str_to_dword(buffer);
3921 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3922 msi_free(buffer);
3925 msi_reg_set_val_dword(hkey, szAssignment, 0);
3926 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3927 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3928 msi_reg_set_val_str(hkey, szClients, szColon);
3930 hdb = alloc_msihandle(&package->db->hdr);
3931 if (!hdb)
3932 return ERROR_NOT_ENOUGH_MEMORY;
3934 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3935 MsiCloseHandle(hdb);
3936 if (r != ERROR_SUCCESS)
3937 goto done;
3939 size = MAX_PATH;
3940 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3941 NULL, guids, &size);
3942 if (r != ERROR_SUCCESS)
3943 goto done;
3945 ptr = strchrW(guids, ';');
3946 if (ptr) *ptr = 0;
3947 squash_guid(guids, packcode);
3948 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3950 done:
3951 MsiCloseHandle(suminfo);
3952 return ERROR_SUCCESS;
3955 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3957 UINT r;
3958 HKEY hkey;
3959 LPWSTR upgrade;
3960 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3962 upgrade = msi_dup_property(package->db, szUpgradeCode);
3963 if (!upgrade)
3964 return ERROR_SUCCESS;
3966 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3967 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3968 else
3969 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3971 if (r != ERROR_SUCCESS)
3973 WARN("failed to open upgrade code key\n");
3974 msi_free(upgrade);
3975 return ERROR_SUCCESS;
3977 squash_guid(package->ProductCode, squashed_pc);
3978 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3979 RegCloseKey(hkey);
3980 msi_free(upgrade);
3981 return ERROR_SUCCESS;
3984 static BOOL msi_check_publish(MSIPACKAGE *package)
3986 MSIFEATURE *feature;
3988 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3990 feature->Action = msi_get_feature_action( package, feature );
3991 if (feature->Action == INSTALLSTATE_LOCAL)
3992 return TRUE;
3995 return FALSE;
3998 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4000 MSIFEATURE *feature;
4002 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4004 feature->Action = msi_get_feature_action( package, feature );
4005 if (feature->Action != INSTALLSTATE_ABSENT)
4006 return FALSE;
4009 return TRUE;
4012 static UINT msi_publish_patches( MSIPACKAGE *package )
4014 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4015 WCHAR patch_squashed[GUID_SIZE];
4016 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4017 LONG res;
4018 MSIPATCHINFO *patch;
4019 UINT r;
4020 WCHAR *p, *all_patches = NULL;
4021 DWORD len = 0;
4023 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4024 if (r != ERROR_SUCCESS)
4025 return ERROR_FUNCTION_FAILED;
4027 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4028 if (res != ERROR_SUCCESS)
4030 r = ERROR_FUNCTION_FAILED;
4031 goto done;
4034 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4035 if (r != ERROR_SUCCESS)
4036 goto done;
4038 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4040 squash_guid( patch->patchcode, patch_squashed );
4041 len += strlenW( patch_squashed ) + 1;
4044 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4045 if (!all_patches)
4046 goto done;
4048 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4050 HKEY patch_key;
4052 squash_guid( patch->patchcode, p );
4053 p += strlenW( p ) + 1;
4055 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4056 (const BYTE *)patch->transforms,
4057 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4058 if (res != ERROR_SUCCESS)
4059 goto done;
4061 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4062 if (r != ERROR_SUCCESS)
4063 goto done;
4065 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4066 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4067 RegCloseKey( patch_key );
4068 if (res != ERROR_SUCCESS)
4069 goto done;
4071 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4073 res = GetLastError();
4074 ERR("Unable to copy patch package %d\n", res);
4075 goto done;
4077 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4078 if (res != ERROR_SUCCESS)
4079 goto done;
4081 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4082 RegCloseKey( patch_key );
4083 if (res != ERROR_SUCCESS)
4084 goto done;
4087 all_patches[len] = 0;
4088 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4089 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4090 if (res != ERROR_SUCCESS)
4091 goto done;
4093 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4094 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4095 if (res != ERROR_SUCCESS)
4096 r = ERROR_FUNCTION_FAILED;
4098 done:
4099 RegCloseKey( product_patches_key );
4100 RegCloseKey( patches_key );
4101 RegCloseKey( product_key );
4102 msi_free( all_patches );
4103 return r;
4106 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4108 UINT rc;
4109 HKEY hukey = NULL, hudkey = NULL;
4110 MSIRECORD *uirow;
4112 if (!list_empty(&package->patches))
4114 rc = msi_publish_patches(package);
4115 if (rc != ERROR_SUCCESS)
4116 goto end;
4119 /* FIXME: also need to publish if the product is in advertise mode */
4120 if (!msi_check_publish(package))
4121 return ERROR_SUCCESS;
4123 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4124 &hukey, TRUE);
4125 if (rc != ERROR_SUCCESS)
4126 goto end;
4128 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4129 NULL, &hudkey, TRUE);
4130 if (rc != ERROR_SUCCESS)
4131 goto end;
4133 rc = msi_publish_upgrade_code(package);
4134 if (rc != ERROR_SUCCESS)
4135 goto end;
4137 rc = msi_publish_product_properties(package, hukey);
4138 if (rc != ERROR_SUCCESS)
4139 goto end;
4141 rc = msi_publish_sourcelist(package, hukey);
4142 if (rc != ERROR_SUCCESS)
4143 goto end;
4145 rc = msi_publish_icons(package);
4147 end:
4148 uirow = MSI_CreateRecord( 1 );
4149 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4150 msi_ui_actiondata( package, szPublishProduct, uirow );
4151 msiobj_release( &uirow->hdr );
4153 RegCloseKey(hukey);
4154 RegCloseKey(hudkey);
4155 return rc;
4158 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4160 WCHAR *filename, *ptr, *folder, *ret;
4161 const WCHAR *dirprop;
4163 filename = msi_dup_record_field( row, 2 );
4164 if (filename && (ptr = strchrW( filename, '|' )))
4165 ptr++;
4166 else
4167 ptr = filename;
4169 dirprop = MSI_RecordGetString( row, 3 );
4170 if (dirprop)
4172 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4173 if (!folder) folder = msi_dup_property( package->db, dirprop );
4175 else
4176 folder = msi_dup_property( package->db, szWindowsFolder );
4178 if (!folder)
4180 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4181 msi_free( filename );
4182 return NULL;
4185 ret = msi_build_directory_name( 2, folder, ptr );
4187 msi_free( filename );
4188 msi_free( folder );
4189 return ret;
4192 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4194 MSIPACKAGE *package = param;
4195 LPCWSTR component, section, key, value, identifier;
4196 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4197 MSIRECORD * uirow;
4198 INT action;
4199 MSICOMPONENT *comp;
4201 component = MSI_RecordGetString(row, 8);
4202 comp = msi_get_loaded_component(package,component);
4203 if (!comp)
4204 return ERROR_SUCCESS;
4206 comp->Action = msi_get_component_action( package, comp );
4207 if (comp->Action != INSTALLSTATE_LOCAL)
4209 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4210 return ERROR_SUCCESS;
4213 identifier = MSI_RecordGetString(row,1);
4214 section = MSI_RecordGetString(row,4);
4215 key = MSI_RecordGetString(row,5);
4216 value = MSI_RecordGetString(row,6);
4217 action = MSI_RecordGetInteger(row,7);
4219 deformat_string(package,section,&deformated_section);
4220 deformat_string(package,key,&deformated_key);
4221 deformat_string(package,value,&deformated_value);
4223 fullname = get_ini_file_name(package, row);
4225 if (action == 0)
4227 TRACE("Adding value %s to section %s in %s\n",
4228 debugstr_w(deformated_key), debugstr_w(deformated_section),
4229 debugstr_w(fullname));
4230 WritePrivateProfileStringW(deformated_section, deformated_key,
4231 deformated_value, fullname);
4233 else if (action == 1)
4235 WCHAR returned[10];
4236 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4237 returned, 10, fullname);
4238 if (returned[0] == 0)
4240 TRACE("Adding value %s to section %s in %s\n",
4241 debugstr_w(deformated_key), debugstr_w(deformated_section),
4242 debugstr_w(fullname));
4244 WritePrivateProfileStringW(deformated_section, deformated_key,
4245 deformated_value, fullname);
4248 else if (action == 3)
4249 FIXME("Append to existing section not yet implemented\n");
4251 uirow = MSI_CreateRecord(4);
4252 MSI_RecordSetStringW(uirow,1,identifier);
4253 MSI_RecordSetStringW(uirow,2,deformated_section);
4254 MSI_RecordSetStringW(uirow,3,deformated_key);
4255 MSI_RecordSetStringW(uirow,4,deformated_value);
4256 msi_ui_actiondata( package, szWriteIniValues, uirow );
4257 msiobj_release( &uirow->hdr );
4259 msi_free(fullname);
4260 msi_free(deformated_key);
4261 msi_free(deformated_value);
4262 msi_free(deformated_section);
4263 return ERROR_SUCCESS;
4266 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4268 static const WCHAR query[] = {
4269 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4270 '`','I','n','i','F','i','l','e','`',0};
4271 MSIQUERY *view;
4272 UINT rc;
4274 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4275 if (rc != ERROR_SUCCESS)
4276 return ERROR_SUCCESS;
4278 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4279 msiobj_release(&view->hdr);
4280 return rc;
4283 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4285 MSIPACKAGE *package = param;
4286 LPCWSTR component, section, key, value, identifier;
4287 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4288 MSICOMPONENT *comp;
4289 MSIRECORD *uirow;
4290 INT action;
4292 component = MSI_RecordGetString( row, 8 );
4293 comp = msi_get_loaded_component( package, component );
4294 if (!comp)
4295 return ERROR_SUCCESS;
4297 comp->Action = msi_get_component_action( package, comp );
4298 if (comp->Action != INSTALLSTATE_ABSENT)
4300 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4301 return ERROR_SUCCESS;
4304 identifier = MSI_RecordGetString( row, 1 );
4305 section = MSI_RecordGetString( row, 4 );
4306 key = MSI_RecordGetString( row, 5 );
4307 value = MSI_RecordGetString( row, 6 );
4308 action = MSI_RecordGetInteger( row, 7 );
4310 deformat_string( package, section, &deformated_section );
4311 deformat_string( package, key, &deformated_key );
4312 deformat_string( package, value, &deformated_value );
4314 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4316 filename = get_ini_file_name( package, row );
4318 TRACE("Removing key %s from section %s in %s\n",
4319 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4321 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4323 WARN("Unable to remove key %u\n", GetLastError());
4325 msi_free( filename );
4327 else
4328 FIXME("Unsupported action %d\n", action);
4331 uirow = MSI_CreateRecord( 4 );
4332 MSI_RecordSetStringW( uirow, 1, identifier );
4333 MSI_RecordSetStringW( uirow, 2, deformated_section );
4334 MSI_RecordSetStringW( uirow, 3, deformated_key );
4335 MSI_RecordSetStringW( uirow, 4, deformated_value );
4336 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4337 msiobj_release( &uirow->hdr );
4339 msi_free( deformated_key );
4340 msi_free( deformated_value );
4341 msi_free( deformated_section );
4342 return ERROR_SUCCESS;
4345 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4347 MSIPACKAGE *package = param;
4348 LPCWSTR component, section, key, value, identifier;
4349 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4350 MSICOMPONENT *comp;
4351 MSIRECORD *uirow;
4352 INT action;
4354 component = MSI_RecordGetString( row, 8 );
4355 comp = msi_get_loaded_component( package, component );
4356 if (!comp)
4357 return ERROR_SUCCESS;
4359 comp->Action = msi_get_component_action( package, comp );
4360 if (comp->Action != INSTALLSTATE_LOCAL)
4362 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4363 return ERROR_SUCCESS;
4366 identifier = MSI_RecordGetString( row, 1 );
4367 section = MSI_RecordGetString( row, 4 );
4368 key = MSI_RecordGetString( row, 5 );
4369 value = MSI_RecordGetString( row, 6 );
4370 action = MSI_RecordGetInteger( row, 7 );
4372 deformat_string( package, section, &deformated_section );
4373 deformat_string( package, key, &deformated_key );
4374 deformat_string( package, value, &deformated_value );
4376 if (action == msidbIniFileActionRemoveLine)
4378 filename = get_ini_file_name( package, row );
4380 TRACE("Removing key %s from section %s in %s\n",
4381 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4383 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4385 WARN("Unable to remove key %u\n", GetLastError());
4387 msi_free( filename );
4389 else
4390 FIXME("Unsupported action %d\n", action);
4392 uirow = MSI_CreateRecord( 4 );
4393 MSI_RecordSetStringW( uirow, 1, identifier );
4394 MSI_RecordSetStringW( uirow, 2, deformated_section );
4395 MSI_RecordSetStringW( uirow, 3, deformated_key );
4396 MSI_RecordSetStringW( uirow, 4, deformated_value );
4397 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4398 msiobj_release( &uirow->hdr );
4400 msi_free( deformated_key );
4401 msi_free( deformated_value );
4402 msi_free( deformated_section );
4403 return ERROR_SUCCESS;
4406 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4408 static const WCHAR query[] = {
4409 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4410 '`','I','n','i','F','i','l','e','`',0};
4411 static const WCHAR remove_query[] = {
4412 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4413 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4414 MSIQUERY *view;
4415 UINT rc;
4417 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4418 if (rc == ERROR_SUCCESS)
4420 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4421 msiobj_release( &view->hdr );
4422 if (rc != ERROR_SUCCESS)
4423 return rc;
4425 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4426 if (rc == ERROR_SUCCESS)
4428 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4429 msiobj_release( &view->hdr );
4430 if (rc != ERROR_SUCCESS)
4431 return rc;
4433 return ERROR_SUCCESS;
4436 static void register_dll( const WCHAR *dll, BOOL unregister )
4438 HMODULE hmod;
4440 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4441 if (hmod)
4443 HRESULT (WINAPI *func_ptr)( void );
4444 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4446 func_ptr = (void *)GetProcAddress( hmod, func );
4447 if (func_ptr)
4449 HRESULT hr = func_ptr();
4450 if (FAILED( hr ))
4451 WARN("failed to register dll 0x%08x\n", hr);
4453 else
4454 WARN("entry point %s not found\n", func);
4455 FreeLibrary( hmod );
4456 return;
4458 WARN("failed to load library %u\n", GetLastError());
4461 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4463 MSIPACKAGE *package = param;
4464 LPCWSTR filename;
4465 MSIFILE *file;
4466 MSIRECORD *uirow;
4468 filename = MSI_RecordGetString(row,1);
4469 file = msi_get_loaded_file( package, filename );
4470 if (!file)
4472 WARN("unable to find file %s\n", debugstr_w(filename));
4473 return ERROR_SUCCESS;
4475 file->Component->Action = msi_get_component_action( package, file->Component );
4476 if (file->Component->Action != INSTALLSTATE_LOCAL)
4478 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4479 return ERROR_SUCCESS;
4482 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4483 register_dll( file->TargetPath, FALSE );
4485 uirow = MSI_CreateRecord( 2 );
4486 MSI_RecordSetStringW( uirow, 1, filename );
4487 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4488 msi_ui_actiondata( package, szSelfRegModules, uirow );
4489 msiobj_release( &uirow->hdr );
4491 return ERROR_SUCCESS;
4494 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4496 static const WCHAR query[] = {
4497 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4498 '`','S','e','l','f','R','e','g','`',0};
4499 MSIQUERY *view;
4500 UINT rc;
4502 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4503 if (rc != ERROR_SUCCESS)
4504 return ERROR_SUCCESS;
4506 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4507 msiobj_release(&view->hdr);
4508 return rc;
4511 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4513 MSIPACKAGE *package = param;
4514 LPCWSTR filename;
4515 MSIFILE *file;
4516 MSIRECORD *uirow;
4518 filename = MSI_RecordGetString( row, 1 );
4519 file = msi_get_loaded_file( package, filename );
4520 if (!file)
4522 WARN("unable to find file %s\n", debugstr_w(filename));
4523 return ERROR_SUCCESS;
4525 file->Component->Action = msi_get_component_action( package, file->Component );
4526 if (file->Component->Action != INSTALLSTATE_ABSENT)
4528 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4529 return ERROR_SUCCESS;
4532 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4533 register_dll( file->TargetPath, TRUE );
4535 uirow = MSI_CreateRecord( 2 );
4536 MSI_RecordSetStringW( uirow, 1, filename );
4537 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4538 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4539 msiobj_release( &uirow->hdr );
4541 return ERROR_SUCCESS;
4544 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4546 static const WCHAR query[] = {
4547 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4548 '`','S','e','l','f','R','e','g','`',0};
4549 MSIQUERY *view;
4550 UINT rc;
4552 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4553 if (rc != ERROR_SUCCESS)
4554 return ERROR_SUCCESS;
4556 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4557 msiobj_release( &view->hdr );
4558 return rc;
4561 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4563 MSIFEATURE *feature;
4564 UINT rc;
4565 HKEY hkey = NULL, userdata = NULL;
4567 if (!msi_check_publish(package))
4568 return ERROR_SUCCESS;
4570 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4571 &hkey, TRUE);
4572 if (rc != ERROR_SUCCESS)
4573 goto end;
4575 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4576 &userdata, TRUE);
4577 if (rc != ERROR_SUCCESS)
4578 goto end;
4580 /* here the guids are base 85 encoded */
4581 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4583 ComponentList *cl;
4584 LPWSTR data = NULL;
4585 GUID clsid;
4586 INT size;
4587 BOOL absent = FALSE;
4588 MSIRECORD *uirow;
4590 if (feature->Action != INSTALLSTATE_LOCAL &&
4591 feature->Action != INSTALLSTATE_SOURCE &&
4592 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4594 size = 1;
4595 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4597 size += 21;
4599 if (feature->Feature_Parent)
4600 size += strlenW( feature->Feature_Parent )+2;
4602 data = msi_alloc(size * sizeof(WCHAR));
4604 data[0] = 0;
4605 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4607 MSICOMPONENT* component = cl->component;
4608 WCHAR buf[21];
4610 buf[0] = 0;
4611 if (component->ComponentId)
4613 TRACE("From %s\n",debugstr_w(component->ComponentId));
4614 CLSIDFromString(component->ComponentId, &clsid);
4615 encode_base85_guid(&clsid,buf);
4616 TRACE("to %s\n",debugstr_w(buf));
4617 strcatW(data,buf);
4621 if (feature->Feature_Parent)
4623 static const WCHAR sep[] = {'\2',0};
4624 strcatW(data,sep);
4625 strcatW(data,feature->Feature_Parent);
4628 msi_reg_set_val_str( userdata, feature->Feature, data );
4629 msi_free(data);
4631 size = 0;
4632 if (feature->Feature_Parent)
4633 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4634 if (!absent)
4636 size += sizeof(WCHAR);
4637 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4638 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4640 else
4642 size += 2*sizeof(WCHAR);
4643 data = msi_alloc(size);
4644 data[0] = 0x6;
4645 data[1] = 0;
4646 if (feature->Feature_Parent)
4647 strcpyW( &data[1], feature->Feature_Parent );
4648 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4649 (LPBYTE)data,size);
4650 msi_free(data);
4653 /* the UI chunk */
4654 uirow = MSI_CreateRecord( 1 );
4655 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4656 msi_ui_actiondata( package, szPublishFeatures, uirow );
4657 msiobj_release( &uirow->hdr );
4658 /* FIXME: call msi_ui_progress? */
4661 end:
4662 RegCloseKey(hkey);
4663 RegCloseKey(userdata);
4664 return rc;
4667 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4669 UINT r;
4670 HKEY hkey;
4671 MSIRECORD *uirow;
4673 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4675 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4676 &hkey, FALSE);
4677 if (r == ERROR_SUCCESS)
4679 RegDeleteValueW(hkey, feature->Feature);
4680 RegCloseKey(hkey);
4683 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4684 &hkey, FALSE);
4685 if (r == ERROR_SUCCESS)
4687 RegDeleteValueW(hkey, feature->Feature);
4688 RegCloseKey(hkey);
4691 uirow = MSI_CreateRecord( 1 );
4692 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4693 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4694 msiobj_release( &uirow->hdr );
4696 return ERROR_SUCCESS;
4699 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4701 MSIFEATURE *feature;
4703 if (!msi_check_unpublish(package))
4704 return ERROR_SUCCESS;
4706 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4708 msi_unpublish_feature(package, feature);
4711 return ERROR_SUCCESS;
4714 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4716 SYSTEMTIME systime;
4717 DWORD size, langid;
4718 WCHAR date[9], *val, *buffer;
4719 const WCHAR *prop, *key;
4721 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4722 static const WCHAR modpath_fmt[] =
4723 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4724 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4725 static const WCHAR szModifyPath[] =
4726 {'M','o','d','i','f','y','P','a','t','h',0};
4727 static const WCHAR szUninstallString[] =
4728 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4729 static const WCHAR szEstimatedSize[] =
4730 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4731 static const WCHAR szDisplayVersion[] =
4732 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4733 static const WCHAR szInstallSource[] =
4734 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4735 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4736 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4737 static const WCHAR szAuthorizedCDFPrefix[] =
4738 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4739 static const WCHAR szARPCONTACT[] =
4740 {'A','R','P','C','O','N','T','A','C','T',0};
4741 static const WCHAR szContact[] =
4742 {'C','o','n','t','a','c','t',0};
4743 static const WCHAR szARPCOMMENTS[] =
4744 {'A','R','P','C','O','M','M','E','N','T','S',0};
4745 static const WCHAR szComments[] =
4746 {'C','o','m','m','e','n','t','s',0};
4747 static const WCHAR szProductName[] =
4748 {'P','r','o','d','u','c','t','N','a','m','e',0};
4749 static const WCHAR szDisplayName[] =
4750 {'D','i','s','p','l','a','y','N','a','m','e',0};
4751 static const WCHAR szARPHELPLINK[] =
4752 {'A','R','P','H','E','L','P','L','I','N','K',0};
4753 static const WCHAR szHelpLink[] =
4754 {'H','e','l','p','L','i','n','k',0};
4755 static const WCHAR szARPHELPTELEPHONE[] =
4756 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4757 static const WCHAR szHelpTelephone[] =
4758 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4759 static const WCHAR szARPINSTALLLOCATION[] =
4760 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4761 static const WCHAR szInstallLocation[] =
4762 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4763 static const WCHAR szManufacturer[] =
4764 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4765 static const WCHAR szPublisher[] =
4766 {'P','u','b','l','i','s','h','e','r',0};
4767 static const WCHAR szARPREADME[] =
4768 {'A','R','P','R','E','A','D','M','E',0};
4769 static const WCHAR szReadme[] =
4770 {'R','e','a','d','M','e',0};
4771 static const WCHAR szARPSIZE[] =
4772 {'A','R','P','S','I','Z','E',0};
4773 static const WCHAR szSize[] =
4774 {'S','i','z','e',0};
4775 static const WCHAR szARPURLINFOABOUT[] =
4776 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4777 static const WCHAR szURLInfoAbout[] =
4778 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4779 static const WCHAR szARPURLUPDATEINFO[] =
4780 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4781 static const WCHAR szURLUpdateInfo[] =
4782 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4783 static const WCHAR szARPSYSTEMCOMPONENT[] =
4784 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4785 static const WCHAR szSystemComponent[] =
4786 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4788 static const WCHAR *propval[] = {
4789 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4790 szARPCONTACT, szContact,
4791 szARPCOMMENTS, szComments,
4792 szProductName, szDisplayName,
4793 szARPHELPLINK, szHelpLink,
4794 szARPHELPTELEPHONE, szHelpTelephone,
4795 szARPINSTALLLOCATION, szInstallLocation,
4796 szSourceDir, szInstallSource,
4797 szManufacturer, szPublisher,
4798 szARPREADME, szReadme,
4799 szARPSIZE, szSize,
4800 szARPURLINFOABOUT, szURLInfoAbout,
4801 szARPURLUPDATEINFO, szURLUpdateInfo,
4802 NULL
4804 const WCHAR **p = propval;
4806 while (*p)
4808 prop = *p++;
4809 key = *p++;
4810 val = msi_dup_property(package->db, prop);
4811 msi_reg_set_val_str(hkey, key, val);
4812 msi_free(val);
4815 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4816 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4818 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4820 size = deformat_string(package, modpath_fmt, &buffer);
4821 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4822 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4823 msi_free(buffer);
4825 /* FIXME: Write real Estimated Size when we have it */
4826 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4828 GetLocalTime(&systime);
4829 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4830 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4832 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4833 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4835 buffer = msi_dup_property(package->db, szProductVersion);
4836 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4837 if (buffer)
4839 DWORD verdword = msi_version_str_to_dword(buffer);
4841 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4842 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4843 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4844 msi_free(buffer);
4847 return ERROR_SUCCESS;
4850 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4852 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4853 MSIRECORD *uirow;
4854 LPWSTR upgrade_code;
4855 HKEY hkey, props, upgrade_key;
4856 UINT rc;
4858 /* FIXME: also need to publish if the product is in advertise mode */
4859 if (!msi_check_publish(package))
4860 return ERROR_SUCCESS;
4862 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4863 if (rc != ERROR_SUCCESS)
4864 return rc;
4866 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4867 if (rc != ERROR_SUCCESS)
4868 goto done;
4870 rc = msi_publish_install_properties(package, hkey);
4871 if (rc != ERROR_SUCCESS)
4872 goto done;
4874 rc = msi_publish_install_properties(package, props);
4875 if (rc != ERROR_SUCCESS)
4876 goto done;
4878 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4879 if (upgrade_code)
4881 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4882 if (rc == ERROR_SUCCESS)
4884 squash_guid( package->ProductCode, squashed_pc );
4885 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4886 RegCloseKey( upgrade_key );
4888 msi_free( upgrade_code );
4890 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4891 package->delete_on_close = FALSE;
4893 done:
4894 uirow = MSI_CreateRecord( 1 );
4895 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4896 msi_ui_actiondata( package, szRegisterProduct, uirow );
4897 msiobj_release( &uirow->hdr );
4899 RegCloseKey(hkey);
4900 return ERROR_SUCCESS;
4903 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4905 return execute_script(package,INSTALL_SCRIPT);
4908 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4910 MSIPACKAGE *package = param;
4911 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4912 WCHAR *p, *icon_path;
4914 if (!icon) return ERROR_SUCCESS;
4915 if ((icon_path = msi_build_icon_path( package, icon )))
4917 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4918 DeleteFileW( icon_path );
4919 if ((p = strrchrW( icon_path, '\\' )))
4921 *p = 0;
4922 RemoveDirectoryW( icon_path );
4924 msi_free( icon_path );
4926 return ERROR_SUCCESS;
4929 static UINT msi_unpublish_icons( MSIPACKAGE *package )
4931 static const WCHAR query[]= {
4932 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
4933 MSIQUERY *view;
4934 UINT r;
4936 r = MSI_DatabaseOpenViewW( package->db, query, &view );
4937 if (r == ERROR_SUCCESS)
4939 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4940 msiobj_release( &view->hdr );
4941 if (r != ERROR_SUCCESS)
4942 return r;
4944 return ERROR_SUCCESS;
4947 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4949 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4950 WCHAR *upgrade, **features;
4951 BOOL full_uninstall = TRUE;
4952 MSIFEATURE *feature;
4953 MSIPATCHINFO *patch;
4954 UINT i;
4956 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4958 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4960 features = msi_split_string( remove, ',' );
4961 for (i = 0; features && features[i]; i++)
4963 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4965 msi_free(features);
4967 if (!full_uninstall)
4968 return ERROR_SUCCESS;
4970 MSIREG_DeleteProductKey(package->ProductCode);
4971 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4972 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4974 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4975 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4976 MSIREG_DeleteUserProductKey(package->ProductCode);
4977 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4979 upgrade = msi_dup_property(package->db, szUpgradeCode);
4980 if (upgrade)
4982 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4983 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4984 msi_free(upgrade);
4987 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4989 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4990 if (!strcmpW( package->ProductCode, patch->products ))
4992 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
4993 patch->delete_on_close = TRUE;
4995 /* FIXME: remove local patch package if this is the last product */
4997 TRACE("removing local package %s\n", debugstr_w(package->localfile));
4998 package->delete_on_close = TRUE;
5000 msi_unpublish_icons( package );
5001 return ERROR_SUCCESS;
5004 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5006 UINT rc;
5007 WCHAR *remove;
5009 /* turn off scheduling */
5010 package->script->CurrentlyScripting= FALSE;
5012 /* first do the same as an InstallExecute */
5013 rc = ACTION_InstallExecute(package);
5014 if (rc != ERROR_SUCCESS)
5015 return rc;
5017 /* then handle Commit Actions */
5018 rc = execute_script(package,COMMIT_SCRIPT);
5019 if (rc != ERROR_SUCCESS)
5020 return rc;
5022 remove = msi_dup_property(package->db, szRemove);
5023 rc = msi_unpublish_product(package, remove);
5024 msi_free(remove);
5025 return rc;
5028 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5030 static const WCHAR RunOnce[] = {
5031 'S','o','f','t','w','a','r','e','\\',
5032 'M','i','c','r','o','s','o','f','t','\\',
5033 'W','i','n','d','o','w','s','\\',
5034 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5035 'R','u','n','O','n','c','e',0};
5036 static const WCHAR InstallRunOnce[] = {
5037 'S','o','f','t','w','a','r','e','\\',
5038 'M','i','c','r','o','s','o','f','t','\\',
5039 'W','i','n','d','o','w','s','\\',
5040 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5041 'I','n','s','t','a','l','l','e','r','\\',
5042 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5044 static const WCHAR msiexec_fmt[] = {
5045 '%','s',
5046 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5047 '\"','%','s','\"',0};
5048 static const WCHAR install_fmt[] = {
5049 '/','I',' ','\"','%','s','\"',' ',
5050 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5051 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5052 WCHAR buffer[256], sysdir[MAX_PATH];
5053 HKEY hkey;
5054 WCHAR squished_pc[100];
5056 squash_guid(package->ProductCode,squished_pc);
5058 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5059 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5060 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5061 squished_pc);
5063 msi_reg_set_val_str( hkey, squished_pc, buffer );
5064 RegCloseKey(hkey);
5066 TRACE("Reboot command %s\n",debugstr_w(buffer));
5068 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5069 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5071 msi_reg_set_val_str( hkey, squished_pc, buffer );
5072 RegCloseKey(hkey);
5074 return ERROR_INSTALL_SUSPEND;
5077 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5079 static const WCHAR query[] =
5080 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5081 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5082 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5083 MSIRECORD *rec, *row;
5084 DWORD i, size = 0;
5085 va_list va;
5086 const WCHAR *str;
5087 WCHAR *data;
5089 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5091 rec = MSI_CreateRecord( count + 2 );
5092 str = MSI_RecordGetString( row, 1 );
5093 MSI_RecordSetStringW( rec, 0, str );
5094 msiobj_release( &row->hdr );
5095 MSI_RecordSetInteger( rec, 1, error );
5097 va_start( va, count );
5098 for (i = 0; i < count; i++)
5100 str = va_arg( va, const WCHAR *);
5101 MSI_RecordSetStringW( rec, i + 2, str );
5103 va_end( va );
5105 MSI_FormatRecordW( package, rec, NULL, &size );
5106 size++;
5107 data = msi_alloc( size * sizeof(WCHAR) );
5108 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5109 else data[0] = 0;
5110 msiobj_release( &rec->hdr );
5111 return data;
5114 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5116 DWORD attrib;
5117 UINT rc;
5120 * We are currently doing what should be done here in the top level Install
5121 * however for Administrative and uninstalls this step will be needed
5123 if (!package->PackagePath)
5124 return ERROR_SUCCESS;
5126 msi_set_sourcedir_props(package, TRUE);
5128 attrib = GetFileAttributesW(package->db->path);
5129 if (attrib == INVALID_FILE_ATTRIBUTES)
5131 LPWSTR prompt, msg;
5132 DWORD size = 0;
5134 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5135 package->Context, MSICODE_PRODUCT,
5136 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5137 if (rc == ERROR_MORE_DATA)
5139 prompt = msi_alloc(size * sizeof(WCHAR));
5140 MsiSourceListGetInfoW(package->ProductCode, NULL,
5141 package->Context, MSICODE_PRODUCT,
5142 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5144 else
5145 prompt = strdupW(package->db->path);
5147 msg = msi_build_error_string(package, 1302, 1, prompt);
5148 msi_free(prompt);
5149 while(attrib == INVALID_FILE_ATTRIBUTES)
5151 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5152 if (rc == IDCANCEL)
5154 msi_free(msg);
5155 return ERROR_INSTALL_USEREXIT;
5157 attrib = GetFileAttributesW(package->db->path);
5159 msi_free(msg);
5160 rc = ERROR_SUCCESS;
5162 else
5163 return ERROR_SUCCESS;
5165 return rc;
5168 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5170 HKEY hkey = 0;
5171 LPWSTR buffer, productid = NULL;
5172 UINT i, rc = ERROR_SUCCESS;
5173 MSIRECORD *uirow;
5175 static const WCHAR szPropKeys[][80] =
5177 {'P','r','o','d','u','c','t','I','D',0},
5178 {'U','S','E','R','N','A','M','E',0},
5179 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5180 {0},
5183 static const WCHAR szRegKeys[][80] =
5185 {'P','r','o','d','u','c','t','I','D',0},
5186 {'R','e','g','O','w','n','e','r',0},
5187 {'R','e','g','C','o','m','p','a','n','y',0},
5188 {0},
5191 if (msi_check_unpublish(package))
5193 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5194 goto end;
5197 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5198 if (!productid)
5199 goto end;
5201 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5202 NULL, &hkey, TRUE);
5203 if (rc != ERROR_SUCCESS)
5204 goto end;
5206 for( i = 0; szPropKeys[i][0]; i++ )
5208 buffer = msi_dup_property( package->db, szPropKeys[i] );
5209 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5210 msi_free( buffer );
5213 end:
5214 uirow = MSI_CreateRecord( 1 );
5215 MSI_RecordSetStringW( uirow, 1, productid );
5216 msi_ui_actiondata( package, szRegisterUser, uirow );
5217 msiobj_release( &uirow->hdr );
5219 msi_free(productid);
5220 RegCloseKey(hkey);
5221 return rc;
5225 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5227 UINT rc;
5229 package->script->InWhatSequence |= SEQUENCE_EXEC;
5230 rc = ACTION_ProcessExecSequence(package,FALSE);
5231 return rc;
5234 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5236 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5237 WCHAR productid_85[21], component_85[21], *ret;
5238 GUID clsid;
5239 DWORD sz;
5241 /* > is used if there is a component GUID and < if not. */
5243 productid_85[0] = 0;
5244 component_85[0] = 0;
5245 CLSIDFromString( package->ProductCode, &clsid );
5247 encode_base85_guid( &clsid, productid_85 );
5248 if (component)
5250 CLSIDFromString( component->ComponentId, &clsid );
5251 encode_base85_guid( &clsid, component_85 );
5254 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5255 debugstr_w(component_85));
5257 sz = 20 + strlenW( feature ) + 20 + 3;
5258 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5259 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5260 return ret;
5263 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5265 MSIPACKAGE *package = param;
5266 LPCWSTR compgroupid, component, feature, qualifier, text;
5267 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5268 HKEY hkey = NULL;
5269 UINT rc;
5270 MSICOMPONENT *comp;
5271 MSIFEATURE *feat;
5272 DWORD sz;
5273 MSIRECORD *uirow;
5274 int len;
5276 feature = MSI_RecordGetString(rec, 5);
5277 feat = msi_get_loaded_feature(package, feature);
5278 if (!feat)
5279 return ERROR_SUCCESS;
5281 feat->Action = msi_get_feature_action( package, feat );
5282 if (feat->Action != INSTALLSTATE_LOCAL &&
5283 feat->Action != INSTALLSTATE_SOURCE &&
5284 feat->Action != INSTALLSTATE_ADVERTISED)
5286 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5287 return ERROR_SUCCESS;
5290 component = MSI_RecordGetString(rec, 3);
5291 comp = msi_get_loaded_component(package, component);
5292 if (!comp)
5293 return ERROR_SUCCESS;
5295 compgroupid = MSI_RecordGetString(rec,1);
5296 qualifier = MSI_RecordGetString(rec,2);
5298 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5299 if (rc != ERROR_SUCCESS)
5300 goto end;
5302 advertise = msi_create_component_advertise_string( package, comp, feature );
5303 text = MSI_RecordGetString( rec, 4 );
5304 if (text)
5306 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5307 strcpyW( p, advertise );
5308 strcatW( p, text );
5309 msi_free( advertise );
5310 advertise = p;
5312 existing = msi_reg_get_val_str( hkey, qualifier );
5314 sz = strlenW( advertise ) + 1;
5315 if (existing)
5317 for (p = existing; *p; p += len)
5319 len = strlenW( p ) + 1;
5320 if (strcmpW( advertise, p )) sz += len;
5323 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5325 rc = ERROR_OUTOFMEMORY;
5326 goto end;
5328 q = output;
5329 if (existing)
5331 for (p = existing; *p; p += len)
5333 len = strlenW( p ) + 1;
5334 if (strcmpW( advertise, p ))
5336 memcpy( q, p, len * sizeof(WCHAR) );
5337 q += len;
5341 strcpyW( q, advertise );
5342 q[strlenW( q ) + 1] = 0;
5344 msi_reg_set_val_multi_str( hkey, qualifier, output );
5346 end:
5347 RegCloseKey(hkey);
5348 msi_free( output );
5349 msi_free( advertise );
5350 msi_free( existing );
5352 /* the UI chunk */
5353 uirow = MSI_CreateRecord( 2 );
5354 MSI_RecordSetStringW( uirow, 1, compgroupid );
5355 MSI_RecordSetStringW( uirow, 2, qualifier);
5356 msi_ui_actiondata( package, szPublishComponents, uirow );
5357 msiobj_release( &uirow->hdr );
5358 /* FIXME: call ui_progress? */
5360 return rc;
5364 * At present I am ignorning the advertised components part of this and only
5365 * focusing on the qualified component sets
5367 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5369 static const WCHAR query[] = {
5370 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5371 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5372 MSIQUERY *view;
5373 UINT rc;
5375 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5376 if (rc != ERROR_SUCCESS)
5377 return ERROR_SUCCESS;
5379 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5380 msiobj_release(&view->hdr);
5381 return rc;
5384 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5386 static const WCHAR szInstallerComponents[] = {
5387 'S','o','f','t','w','a','r','e','\\',
5388 'M','i','c','r','o','s','o','f','t','\\',
5389 'I','n','s','t','a','l','l','e','r','\\',
5390 'C','o','m','p','o','n','e','n','t','s','\\',0};
5392 MSIPACKAGE *package = param;
5393 LPCWSTR compgroupid, component, feature, qualifier;
5394 MSICOMPONENT *comp;
5395 MSIFEATURE *feat;
5396 MSIRECORD *uirow;
5397 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5398 LONG res;
5400 feature = MSI_RecordGetString( rec, 5 );
5401 feat = msi_get_loaded_feature( package, feature );
5402 if (!feat)
5403 return ERROR_SUCCESS;
5405 feat->Action = msi_get_feature_action( package, feat );
5406 if (feat->Action != INSTALLSTATE_ABSENT)
5408 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5409 return ERROR_SUCCESS;
5412 component = MSI_RecordGetString( rec, 3 );
5413 comp = msi_get_loaded_component( package, component );
5414 if (!comp)
5415 return ERROR_SUCCESS;
5417 compgroupid = MSI_RecordGetString( rec, 1 );
5418 qualifier = MSI_RecordGetString( rec, 2 );
5420 squash_guid( compgroupid, squashed );
5421 strcpyW( keypath, szInstallerComponents );
5422 strcatW( keypath, squashed );
5424 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5425 if (res != ERROR_SUCCESS)
5427 WARN("Unable to delete component key %d\n", res);
5430 uirow = MSI_CreateRecord( 2 );
5431 MSI_RecordSetStringW( uirow, 1, compgroupid );
5432 MSI_RecordSetStringW( uirow, 2, qualifier );
5433 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5434 msiobj_release( &uirow->hdr );
5436 return ERROR_SUCCESS;
5439 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5441 static const WCHAR query[] = {
5442 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5443 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5444 MSIQUERY *view;
5445 UINT rc;
5447 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5448 if (rc != ERROR_SUCCESS)
5449 return ERROR_SUCCESS;
5451 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5452 msiobj_release( &view->hdr );
5453 return rc;
5456 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5458 static const WCHAR query[] =
5459 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5460 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5461 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5462 MSIPACKAGE *package = param;
5463 MSICOMPONENT *component;
5464 MSIRECORD *row;
5465 MSIFILE *file;
5466 SC_HANDLE hscm = NULL, service = NULL;
5467 LPCWSTR comp, key;
5468 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5469 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5470 DWORD serv_type, start_type, err_control;
5471 SERVICE_DESCRIPTIONW sd = {NULL};
5473 comp = MSI_RecordGetString( rec, 12 );
5474 component = msi_get_loaded_component( package, comp );
5475 if (!component)
5477 WARN("service component not found\n");
5478 goto done;
5480 component->Action = msi_get_component_action( package, component );
5481 if (component->Action != INSTALLSTATE_LOCAL)
5483 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5484 goto done;
5486 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5487 if (!hscm)
5489 ERR("Failed to open the SC Manager!\n");
5490 goto done;
5493 start_type = MSI_RecordGetInteger(rec, 5);
5494 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5495 goto done;
5497 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5498 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5499 serv_type = MSI_RecordGetInteger(rec, 4);
5500 err_control = MSI_RecordGetInteger(rec, 6);
5501 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5502 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5503 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5504 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5505 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5506 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5508 /* fetch the service path */
5509 row = MSI_QueryGetRecord(package->db, query, comp);
5510 if (!row)
5512 ERR("Query failed\n");
5513 goto done;
5515 key = MSI_RecordGetString(row, 6);
5516 file = msi_get_loaded_file(package, key);
5517 msiobj_release(&row->hdr);
5518 if (!file)
5520 ERR("Failed to load the service file\n");
5521 goto done;
5524 if (!args || !args[0]) image_path = file->TargetPath;
5525 else
5527 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5528 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5529 return ERROR_OUTOFMEMORY;
5531 strcpyW(image_path, file->TargetPath);
5532 strcatW(image_path, szSpace);
5533 strcatW(image_path, args);
5535 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5536 start_type, err_control, image_path, load_order,
5537 NULL, depends, serv_name, pass);
5539 if (!service)
5541 if (GetLastError() != ERROR_SERVICE_EXISTS)
5542 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5544 else if (sd.lpDescription)
5546 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5547 WARN("failed to set service description %u\n", GetLastError());
5550 if (image_path != file->TargetPath) msi_free(image_path);
5551 done:
5552 CloseServiceHandle(service);
5553 CloseServiceHandle(hscm);
5554 msi_free(name);
5555 msi_free(disp);
5556 msi_free(sd.lpDescription);
5557 msi_free(load_order);
5558 msi_free(serv_name);
5559 msi_free(pass);
5560 msi_free(depends);
5561 msi_free(args);
5563 return ERROR_SUCCESS;
5566 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5568 static const WCHAR query[] = {
5569 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5570 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5571 MSIQUERY *view;
5572 UINT rc;
5574 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5575 if (rc != ERROR_SUCCESS)
5576 return ERROR_SUCCESS;
5578 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5579 msiobj_release(&view->hdr);
5580 return rc;
5583 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5584 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5586 LPCWSTR *vector, *temp_vector;
5587 LPWSTR p, q;
5588 DWORD sep_len;
5590 static const WCHAR separator[] = {'[','~',']',0};
5592 *numargs = 0;
5593 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5595 if (!args)
5596 return NULL;
5598 vector = msi_alloc(sizeof(LPWSTR));
5599 if (!vector)
5600 return NULL;
5602 p = args;
5605 (*numargs)++;
5606 vector[*numargs - 1] = p;
5608 if ((q = strstrW(p, separator)))
5610 *q = '\0';
5612 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5613 if (!temp_vector)
5615 msi_free(vector);
5616 return NULL;
5618 vector = temp_vector;
5620 p = q + sep_len;
5622 } while (q);
5624 return vector;
5627 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5629 MSIPACKAGE *package = param;
5630 MSICOMPONENT *comp;
5631 MSIRECORD *uirow;
5632 SC_HANDLE scm = NULL, service = NULL;
5633 LPCWSTR component, *vector = NULL;
5634 LPWSTR name, args, display_name = NULL;
5635 DWORD event, numargs, len;
5636 UINT r = ERROR_FUNCTION_FAILED;
5638 component = MSI_RecordGetString(rec, 6);
5639 comp = msi_get_loaded_component(package, component);
5640 if (!comp)
5641 return ERROR_SUCCESS;
5643 comp->Action = msi_get_component_action( package, comp );
5644 if (comp->Action != INSTALLSTATE_LOCAL)
5646 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5647 return ERROR_SUCCESS;
5650 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5651 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5652 event = MSI_RecordGetInteger(rec, 3);
5654 if (!(event & msidbServiceControlEventStart))
5656 r = ERROR_SUCCESS;
5657 goto done;
5660 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5661 if (!scm)
5663 ERR("Failed to open the service control manager\n");
5664 goto done;
5667 len = 0;
5668 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5669 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5671 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5672 GetServiceDisplayNameW( scm, name, display_name, &len );
5675 service = OpenServiceW(scm, name, SERVICE_START);
5676 if (!service)
5678 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5679 goto done;
5682 vector = msi_service_args_to_vector(args, &numargs);
5684 if (!StartServiceW(service, numargs, vector) &&
5685 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5687 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5688 goto done;
5691 r = ERROR_SUCCESS;
5693 done:
5694 uirow = MSI_CreateRecord( 2 );
5695 MSI_RecordSetStringW( uirow, 1, display_name );
5696 MSI_RecordSetStringW( uirow, 2, name );
5697 msi_ui_actiondata( package, szStartServices, uirow );
5698 msiobj_release( &uirow->hdr );
5700 CloseServiceHandle(service);
5701 CloseServiceHandle(scm);
5703 msi_free(name);
5704 msi_free(args);
5705 msi_free(vector);
5706 msi_free(display_name);
5707 return r;
5710 static UINT ACTION_StartServices( MSIPACKAGE *package )
5712 static const WCHAR query[] = {
5713 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5714 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5715 MSIQUERY *view;
5716 UINT rc;
5718 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5719 if (rc != ERROR_SUCCESS)
5720 return ERROR_SUCCESS;
5722 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5723 msiobj_release(&view->hdr);
5724 return rc;
5727 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5729 DWORD i, needed, count;
5730 ENUM_SERVICE_STATUSW *dependencies;
5731 SERVICE_STATUS ss;
5732 SC_HANDLE depserv;
5734 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5735 0, &needed, &count))
5736 return TRUE;
5738 if (GetLastError() != ERROR_MORE_DATA)
5739 return FALSE;
5741 dependencies = msi_alloc(needed);
5742 if (!dependencies)
5743 return FALSE;
5745 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5746 needed, &needed, &count))
5747 goto error;
5749 for (i = 0; i < count; i++)
5751 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5752 SERVICE_STOP | SERVICE_QUERY_STATUS);
5753 if (!depserv)
5754 goto error;
5756 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5757 goto error;
5760 return TRUE;
5762 error:
5763 msi_free(dependencies);
5764 return FALSE;
5767 static UINT stop_service( LPCWSTR name )
5769 SC_HANDLE scm = NULL, service = NULL;
5770 SERVICE_STATUS status;
5771 SERVICE_STATUS_PROCESS ssp;
5772 DWORD needed;
5774 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5775 if (!scm)
5777 WARN("Failed to open the SCM: %d\n", GetLastError());
5778 goto done;
5781 service = OpenServiceW(scm, name,
5782 SERVICE_STOP |
5783 SERVICE_QUERY_STATUS |
5784 SERVICE_ENUMERATE_DEPENDENTS);
5785 if (!service)
5787 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5788 goto done;
5791 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5792 sizeof(SERVICE_STATUS_PROCESS), &needed))
5794 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5795 goto done;
5798 if (ssp.dwCurrentState == SERVICE_STOPPED)
5799 goto done;
5801 stop_service_dependents(scm, service);
5803 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5804 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5806 done:
5807 CloseServiceHandle(service);
5808 CloseServiceHandle(scm);
5810 return ERROR_SUCCESS;
5813 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5815 MSIPACKAGE *package = param;
5816 MSICOMPONENT *comp;
5817 MSIRECORD *uirow;
5818 LPCWSTR component;
5819 LPWSTR name = NULL, display_name = NULL;
5820 DWORD event, len;
5821 SC_HANDLE scm;
5823 event = MSI_RecordGetInteger( rec, 3 );
5824 if (!(event & msidbServiceControlEventStop))
5825 return ERROR_SUCCESS;
5827 component = MSI_RecordGetString( rec, 6 );
5828 comp = msi_get_loaded_component( package, component );
5829 if (!comp)
5830 return ERROR_SUCCESS;
5832 comp->Action = msi_get_component_action( package, comp );
5833 if (comp->Action != INSTALLSTATE_ABSENT)
5835 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5836 return ERROR_SUCCESS;
5839 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5840 if (!scm)
5842 ERR("Failed to open the service control manager\n");
5843 goto done;
5846 len = 0;
5847 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5848 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5850 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5851 GetServiceDisplayNameW( scm, name, display_name, &len );
5853 CloseServiceHandle( scm );
5855 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5856 stop_service( name );
5858 done:
5859 uirow = MSI_CreateRecord( 2 );
5860 MSI_RecordSetStringW( uirow, 1, display_name );
5861 MSI_RecordSetStringW( uirow, 2, name );
5862 msi_ui_actiondata( package, szStopServices, uirow );
5863 msiobj_release( &uirow->hdr );
5865 msi_free( name );
5866 msi_free( display_name );
5867 return ERROR_SUCCESS;
5870 static UINT ACTION_StopServices( MSIPACKAGE *package )
5872 static const WCHAR query[] = {
5873 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5874 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5875 MSIQUERY *view;
5876 UINT rc;
5878 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5879 if (rc != ERROR_SUCCESS)
5880 return ERROR_SUCCESS;
5882 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5883 msiobj_release(&view->hdr);
5884 return rc;
5887 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5889 MSIPACKAGE *package = param;
5890 MSICOMPONENT *comp;
5891 MSIRECORD *uirow;
5892 LPCWSTR component;
5893 LPWSTR name = NULL, display_name = NULL;
5894 DWORD event, len;
5895 SC_HANDLE scm = NULL, service = NULL;
5897 event = MSI_RecordGetInteger( rec, 3 );
5898 if (!(event & msidbServiceControlEventDelete))
5899 return ERROR_SUCCESS;
5901 component = MSI_RecordGetString(rec, 6);
5902 comp = msi_get_loaded_component(package, component);
5903 if (!comp)
5904 return ERROR_SUCCESS;
5906 comp->Action = msi_get_component_action( package, comp );
5907 if (comp->Action != INSTALLSTATE_ABSENT)
5909 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5910 return ERROR_SUCCESS;
5913 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5914 stop_service( name );
5916 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5917 if (!scm)
5919 WARN("Failed to open the SCM: %d\n", GetLastError());
5920 goto done;
5923 len = 0;
5924 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5925 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5927 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5928 GetServiceDisplayNameW( scm, name, display_name, &len );
5931 service = OpenServiceW( scm, name, DELETE );
5932 if (!service)
5934 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5935 goto done;
5938 if (!DeleteService( service ))
5939 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5941 done:
5942 uirow = MSI_CreateRecord( 2 );
5943 MSI_RecordSetStringW( uirow, 1, display_name );
5944 MSI_RecordSetStringW( uirow, 2, name );
5945 msi_ui_actiondata( package, szDeleteServices, uirow );
5946 msiobj_release( &uirow->hdr );
5948 CloseServiceHandle( service );
5949 CloseServiceHandle( scm );
5950 msi_free( name );
5951 msi_free( display_name );
5953 return ERROR_SUCCESS;
5956 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5958 static const WCHAR query[] = {
5959 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5960 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5961 MSIQUERY *view;
5962 UINT rc;
5964 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5965 if (rc != ERROR_SUCCESS)
5966 return ERROR_SUCCESS;
5968 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5969 msiobj_release( &view->hdr );
5970 return rc;
5973 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5975 MSIPACKAGE *package = param;
5976 LPWSTR driver, driver_path, ptr;
5977 WCHAR outpath[MAX_PATH];
5978 MSIFILE *driver_file = NULL, *setup_file = NULL;
5979 MSICOMPONENT *comp;
5980 MSIRECORD *uirow;
5981 LPCWSTR desc, file_key, component;
5982 DWORD len, usage;
5983 UINT r = ERROR_SUCCESS;
5985 static const WCHAR driver_fmt[] = {
5986 'D','r','i','v','e','r','=','%','s',0};
5987 static const WCHAR setup_fmt[] = {
5988 'S','e','t','u','p','=','%','s',0};
5989 static const WCHAR usage_fmt[] = {
5990 'F','i','l','e','U','s','a','g','e','=','1',0};
5992 component = MSI_RecordGetString( rec, 2 );
5993 comp = msi_get_loaded_component( package, component );
5994 if (!comp)
5995 return ERROR_SUCCESS;
5997 comp->Action = msi_get_component_action( package, comp );
5998 if (comp->Action != INSTALLSTATE_LOCAL)
6000 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6001 return ERROR_SUCCESS;
6003 desc = MSI_RecordGetString(rec, 3);
6005 file_key = MSI_RecordGetString( rec, 4 );
6006 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6008 file_key = MSI_RecordGetString( rec, 5 );
6009 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6011 if (!driver_file)
6013 ERR("ODBC Driver entry not found!\n");
6014 return ERROR_FUNCTION_FAILED;
6017 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6018 if (setup_file)
6019 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6020 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6022 driver = msi_alloc(len * sizeof(WCHAR));
6023 if (!driver)
6024 return ERROR_OUTOFMEMORY;
6026 ptr = driver;
6027 lstrcpyW(ptr, desc);
6028 ptr += lstrlenW(ptr) + 1;
6030 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6031 ptr += len + 1;
6033 if (setup_file)
6035 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6036 ptr += len + 1;
6039 lstrcpyW(ptr, usage_fmt);
6040 ptr += lstrlenW(ptr) + 1;
6041 *ptr = '\0';
6043 driver_path = strdupW(driver_file->TargetPath);
6044 ptr = strrchrW(driver_path, '\\');
6045 if (ptr) *ptr = '\0';
6047 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6048 NULL, ODBC_INSTALL_COMPLETE, &usage))
6050 ERR("Failed to install SQL driver!\n");
6051 r = ERROR_FUNCTION_FAILED;
6054 uirow = MSI_CreateRecord( 5 );
6055 MSI_RecordSetStringW( uirow, 1, desc );
6056 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6057 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6058 msi_ui_actiondata( package, szInstallODBC, uirow );
6059 msiobj_release( &uirow->hdr );
6061 msi_free(driver);
6062 msi_free(driver_path);
6064 return r;
6067 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6069 MSIPACKAGE *package = param;
6070 LPWSTR translator, translator_path, ptr;
6071 WCHAR outpath[MAX_PATH];
6072 MSIFILE *translator_file = NULL, *setup_file = NULL;
6073 MSICOMPONENT *comp;
6074 MSIRECORD *uirow;
6075 LPCWSTR desc, file_key, component;
6076 DWORD len, usage;
6077 UINT r = ERROR_SUCCESS;
6079 static const WCHAR translator_fmt[] = {
6080 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6081 static const WCHAR setup_fmt[] = {
6082 'S','e','t','u','p','=','%','s',0};
6084 component = MSI_RecordGetString( rec, 2 );
6085 comp = msi_get_loaded_component( package, component );
6086 if (!comp)
6087 return ERROR_SUCCESS;
6089 comp->Action = msi_get_component_action( package, comp );
6090 if (comp->Action != INSTALLSTATE_LOCAL)
6092 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6093 return ERROR_SUCCESS;
6095 desc = MSI_RecordGetString(rec, 3);
6097 file_key = MSI_RecordGetString( rec, 4 );
6098 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6100 file_key = MSI_RecordGetString( rec, 5 );
6101 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6103 if (!translator_file)
6105 ERR("ODBC Translator entry not found!\n");
6106 return ERROR_FUNCTION_FAILED;
6109 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6110 if (setup_file)
6111 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6113 translator = msi_alloc(len * sizeof(WCHAR));
6114 if (!translator)
6115 return ERROR_OUTOFMEMORY;
6117 ptr = translator;
6118 lstrcpyW(ptr, desc);
6119 ptr += lstrlenW(ptr) + 1;
6121 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6122 ptr += len + 1;
6124 if (setup_file)
6126 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6127 ptr += len + 1;
6129 *ptr = '\0';
6131 translator_path = strdupW(translator_file->TargetPath);
6132 ptr = strrchrW(translator_path, '\\');
6133 if (ptr) *ptr = '\0';
6135 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6136 NULL, ODBC_INSTALL_COMPLETE, &usage))
6138 ERR("Failed to install SQL translator!\n");
6139 r = ERROR_FUNCTION_FAILED;
6142 uirow = MSI_CreateRecord( 5 );
6143 MSI_RecordSetStringW( uirow, 1, desc );
6144 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6145 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6146 msi_ui_actiondata( package, szInstallODBC, uirow );
6147 msiobj_release( &uirow->hdr );
6149 msi_free(translator);
6150 msi_free(translator_path);
6152 return r;
6155 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6157 MSIPACKAGE *package = param;
6158 MSICOMPONENT *comp;
6159 LPWSTR attrs;
6160 LPCWSTR desc, driver, component;
6161 WORD request = ODBC_ADD_SYS_DSN;
6162 INT registration;
6163 DWORD len;
6164 UINT r = ERROR_SUCCESS;
6165 MSIRECORD *uirow;
6167 static const WCHAR attrs_fmt[] = {
6168 'D','S','N','=','%','s',0 };
6170 component = MSI_RecordGetString( rec, 2 );
6171 comp = msi_get_loaded_component( package, component );
6172 if (!comp)
6173 return ERROR_SUCCESS;
6175 comp->Action = msi_get_component_action( package, comp );
6176 if (comp->Action != INSTALLSTATE_LOCAL)
6178 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6179 return ERROR_SUCCESS;
6182 desc = MSI_RecordGetString(rec, 3);
6183 driver = MSI_RecordGetString(rec, 4);
6184 registration = MSI_RecordGetInteger(rec, 5);
6186 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6187 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6189 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6190 attrs = msi_alloc(len * sizeof(WCHAR));
6191 if (!attrs)
6192 return ERROR_OUTOFMEMORY;
6194 len = sprintfW(attrs, attrs_fmt, desc);
6195 attrs[len + 1] = 0;
6197 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6199 ERR("Failed to install SQL data source!\n");
6200 r = ERROR_FUNCTION_FAILED;
6203 uirow = MSI_CreateRecord( 5 );
6204 MSI_RecordSetStringW( uirow, 1, desc );
6205 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6206 MSI_RecordSetInteger( uirow, 3, request );
6207 msi_ui_actiondata( package, szInstallODBC, uirow );
6208 msiobj_release( &uirow->hdr );
6210 msi_free(attrs);
6212 return r;
6215 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6217 static const WCHAR driver_query[] = {
6218 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6219 'O','D','B','C','D','r','i','v','e','r',0};
6220 static const WCHAR translator_query[] = {
6221 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6222 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6223 static const WCHAR source_query[] = {
6224 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6225 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6226 MSIQUERY *view;
6227 UINT rc;
6229 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6230 if (rc == ERROR_SUCCESS)
6232 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6233 msiobj_release(&view->hdr);
6234 if (rc != ERROR_SUCCESS)
6235 return rc;
6237 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6238 if (rc == ERROR_SUCCESS)
6240 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6241 msiobj_release(&view->hdr);
6242 if (rc != ERROR_SUCCESS)
6243 return rc;
6245 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6246 if (rc == ERROR_SUCCESS)
6248 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6249 msiobj_release(&view->hdr);
6250 if (rc != ERROR_SUCCESS)
6251 return rc;
6253 return ERROR_SUCCESS;
6256 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6258 MSIPACKAGE *package = param;
6259 MSICOMPONENT *comp;
6260 MSIRECORD *uirow;
6261 DWORD usage;
6262 LPCWSTR desc, component;
6264 component = MSI_RecordGetString( rec, 2 );
6265 comp = msi_get_loaded_component( package, component );
6266 if (!comp)
6267 return ERROR_SUCCESS;
6269 comp->Action = msi_get_component_action( package, comp );
6270 if (comp->Action != INSTALLSTATE_ABSENT)
6272 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6273 return ERROR_SUCCESS;
6276 desc = MSI_RecordGetString( rec, 3 );
6277 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6279 WARN("Failed to remove ODBC driver\n");
6281 else if (!usage)
6283 FIXME("Usage count reached 0\n");
6286 uirow = MSI_CreateRecord( 2 );
6287 MSI_RecordSetStringW( uirow, 1, desc );
6288 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6289 msi_ui_actiondata( package, szRemoveODBC, uirow );
6290 msiobj_release( &uirow->hdr );
6292 return ERROR_SUCCESS;
6295 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6297 MSIPACKAGE *package = param;
6298 MSICOMPONENT *comp;
6299 MSIRECORD *uirow;
6300 DWORD usage;
6301 LPCWSTR desc, component;
6303 component = MSI_RecordGetString( rec, 2 );
6304 comp = msi_get_loaded_component( package, component );
6305 if (!comp)
6306 return ERROR_SUCCESS;
6308 comp->Action = msi_get_component_action( package, comp );
6309 if (comp->Action != INSTALLSTATE_ABSENT)
6311 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6312 return ERROR_SUCCESS;
6315 desc = MSI_RecordGetString( rec, 3 );
6316 if (!SQLRemoveTranslatorW( desc, &usage ))
6318 WARN("Failed to remove ODBC translator\n");
6320 else if (!usage)
6322 FIXME("Usage count reached 0\n");
6325 uirow = MSI_CreateRecord( 2 );
6326 MSI_RecordSetStringW( uirow, 1, desc );
6327 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6328 msi_ui_actiondata( package, szRemoveODBC, uirow );
6329 msiobj_release( &uirow->hdr );
6331 return ERROR_SUCCESS;
6334 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6336 MSIPACKAGE *package = param;
6337 MSICOMPONENT *comp;
6338 MSIRECORD *uirow;
6339 LPWSTR attrs;
6340 LPCWSTR desc, driver, component;
6341 WORD request = ODBC_REMOVE_SYS_DSN;
6342 INT registration;
6343 DWORD len;
6345 static const WCHAR attrs_fmt[] = {
6346 'D','S','N','=','%','s',0 };
6348 component = MSI_RecordGetString( rec, 2 );
6349 comp = msi_get_loaded_component( package, component );
6350 if (!comp)
6351 return ERROR_SUCCESS;
6353 comp->Action = msi_get_component_action( package, comp );
6354 if (comp->Action != INSTALLSTATE_ABSENT)
6356 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6357 return ERROR_SUCCESS;
6360 desc = MSI_RecordGetString( rec, 3 );
6361 driver = MSI_RecordGetString( rec, 4 );
6362 registration = MSI_RecordGetInteger( rec, 5 );
6364 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6365 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6367 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6368 attrs = msi_alloc( len * sizeof(WCHAR) );
6369 if (!attrs)
6370 return ERROR_OUTOFMEMORY;
6372 FIXME("Use ODBCSourceAttribute table\n");
6374 len = sprintfW( attrs, attrs_fmt, desc );
6375 attrs[len + 1] = 0;
6377 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6379 WARN("Failed to remove ODBC data source\n");
6381 msi_free( attrs );
6383 uirow = MSI_CreateRecord( 3 );
6384 MSI_RecordSetStringW( uirow, 1, desc );
6385 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6386 MSI_RecordSetInteger( uirow, 3, request );
6387 msi_ui_actiondata( package, szRemoveODBC, uirow );
6388 msiobj_release( &uirow->hdr );
6390 return ERROR_SUCCESS;
6393 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6395 static const WCHAR driver_query[] = {
6396 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6397 'O','D','B','C','D','r','i','v','e','r',0};
6398 static const WCHAR translator_query[] = {
6399 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6400 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6401 static const WCHAR source_query[] = {
6402 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6403 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6404 MSIQUERY *view;
6405 UINT rc;
6407 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6408 if (rc == ERROR_SUCCESS)
6410 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6411 msiobj_release( &view->hdr );
6412 if (rc != ERROR_SUCCESS)
6413 return rc;
6415 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6416 if (rc == ERROR_SUCCESS)
6418 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6419 msiobj_release( &view->hdr );
6420 if (rc != ERROR_SUCCESS)
6421 return rc;
6423 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6424 if (rc == ERROR_SUCCESS)
6426 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6427 msiobj_release( &view->hdr );
6428 if (rc != ERROR_SUCCESS)
6429 return rc;
6431 return ERROR_SUCCESS;
6434 #define ENV_ACT_SETALWAYS 0x1
6435 #define ENV_ACT_SETABSENT 0x2
6436 #define ENV_ACT_REMOVE 0x4
6437 #define ENV_ACT_REMOVEMATCH 0x8
6439 #define ENV_MOD_MACHINE 0x20000000
6440 #define ENV_MOD_APPEND 0x40000000
6441 #define ENV_MOD_PREFIX 0x80000000
6442 #define ENV_MOD_MASK 0xC0000000
6444 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6446 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6448 LPCWSTR cptr = *name;
6450 static const WCHAR prefix[] = {'[','~',']',0};
6451 static const int prefix_len = 3;
6453 *flags = 0;
6454 while (*cptr)
6456 if (*cptr == '=')
6457 *flags |= ENV_ACT_SETALWAYS;
6458 else if (*cptr == '+')
6459 *flags |= ENV_ACT_SETABSENT;
6460 else if (*cptr == '-')
6461 *flags |= ENV_ACT_REMOVE;
6462 else if (*cptr == '!')
6463 *flags |= ENV_ACT_REMOVEMATCH;
6464 else if (*cptr == '*')
6465 *flags |= ENV_MOD_MACHINE;
6466 else
6467 break;
6469 cptr++;
6470 (*name)++;
6473 if (!*cptr)
6475 ERR("Missing environment variable\n");
6476 return ERROR_FUNCTION_FAILED;
6479 if (*value)
6481 LPCWSTR ptr = *value;
6482 if (!strncmpW(ptr, prefix, prefix_len))
6484 if (ptr[prefix_len] == szSemiColon[0])
6486 *flags |= ENV_MOD_APPEND;
6487 *value += lstrlenW(prefix);
6489 else
6491 *value = NULL;
6494 else if (lstrlenW(*value) >= prefix_len)
6496 ptr += lstrlenW(ptr) - prefix_len;
6497 if (!strcmpW( ptr, prefix ))
6499 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6501 *flags |= ENV_MOD_PREFIX;
6502 /* the "[~]" will be removed by deformat_string */;
6504 else
6506 *value = NULL;
6512 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6513 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6514 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6515 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6517 ERR("Invalid flags: %08x\n", *flags);
6518 return ERROR_FUNCTION_FAILED;
6521 if (!*flags)
6522 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6524 return ERROR_SUCCESS;
6527 static UINT open_env_key( DWORD flags, HKEY *key )
6529 static const WCHAR user_env[] =
6530 {'E','n','v','i','r','o','n','m','e','n','t',0};
6531 static const WCHAR machine_env[] =
6532 {'S','y','s','t','e','m','\\',
6533 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6534 'C','o','n','t','r','o','l','\\',
6535 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6536 'E','n','v','i','r','o','n','m','e','n','t',0};
6537 const WCHAR *env;
6538 HKEY root;
6539 LONG res;
6541 if (flags & ENV_MOD_MACHINE)
6543 env = machine_env;
6544 root = HKEY_LOCAL_MACHINE;
6546 else
6548 env = user_env;
6549 root = HKEY_CURRENT_USER;
6552 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6553 if (res != ERROR_SUCCESS)
6555 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6556 return ERROR_FUNCTION_FAILED;
6559 return ERROR_SUCCESS;
6562 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6564 MSIPACKAGE *package = param;
6565 LPCWSTR name, value, component;
6566 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6567 DWORD flags, type, size;
6568 UINT res;
6569 HKEY env = NULL;
6570 MSICOMPONENT *comp;
6571 MSIRECORD *uirow;
6572 int action = 0;
6574 component = MSI_RecordGetString(rec, 4);
6575 comp = msi_get_loaded_component(package, component);
6576 if (!comp)
6577 return ERROR_SUCCESS;
6579 comp->Action = msi_get_component_action( package, comp );
6580 if (comp->Action != INSTALLSTATE_LOCAL)
6582 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6583 return ERROR_SUCCESS;
6585 name = MSI_RecordGetString(rec, 2);
6586 value = MSI_RecordGetString(rec, 3);
6588 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6590 res = env_parse_flags(&name, &value, &flags);
6591 if (res != ERROR_SUCCESS || !value)
6592 goto done;
6594 if (value && !deformat_string(package, value, &deformatted))
6596 res = ERROR_OUTOFMEMORY;
6597 goto done;
6600 value = deformatted;
6602 res = open_env_key( flags, &env );
6603 if (res != ERROR_SUCCESS)
6604 goto done;
6606 if (flags & ENV_MOD_MACHINE)
6607 action |= 0x20000000;
6609 size = 0;
6610 type = REG_SZ;
6611 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6612 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6613 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6614 goto done;
6616 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6618 action = 0x2;
6620 /* Nothing to do. */
6621 if (!value)
6623 res = ERROR_SUCCESS;
6624 goto done;
6627 /* If we are appending but the string was empty, strip ; */
6628 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6630 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6631 newval = strdupW(value);
6632 if (!newval)
6634 res = ERROR_OUTOFMEMORY;
6635 goto done;
6638 else
6640 action = 0x1;
6642 /* Contrary to MSDN, +-variable to [~];path works */
6643 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6645 res = ERROR_SUCCESS;
6646 goto done;
6649 data = msi_alloc(size);
6650 if (!data)
6652 RegCloseKey(env);
6653 return ERROR_OUTOFMEMORY;
6656 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6657 if (res != ERROR_SUCCESS)
6658 goto done;
6660 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6662 action = 0x4;
6663 res = RegDeleteValueW(env, name);
6664 if (res != ERROR_SUCCESS)
6665 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6666 goto done;
6669 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6670 if (flags & ENV_MOD_MASK)
6672 DWORD mod_size;
6673 int multiplier = 0;
6674 if (flags & ENV_MOD_APPEND) multiplier++;
6675 if (flags & ENV_MOD_PREFIX) multiplier++;
6676 mod_size = lstrlenW(value) * multiplier;
6677 size += mod_size * sizeof(WCHAR);
6680 newval = msi_alloc(size);
6681 ptr = newval;
6682 if (!newval)
6684 res = ERROR_OUTOFMEMORY;
6685 goto done;
6688 if (flags & ENV_MOD_PREFIX)
6690 lstrcpyW(newval, value);
6691 ptr = newval + lstrlenW(value);
6692 action |= 0x80000000;
6695 lstrcpyW(ptr, data);
6697 if (flags & ENV_MOD_APPEND)
6699 lstrcatW(newval, value);
6700 action |= 0x40000000;
6703 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6704 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6705 if (res)
6707 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6710 done:
6711 uirow = MSI_CreateRecord( 3 );
6712 MSI_RecordSetStringW( uirow, 1, name );
6713 MSI_RecordSetStringW( uirow, 2, newval );
6714 MSI_RecordSetInteger( uirow, 3, action );
6715 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6716 msiobj_release( &uirow->hdr );
6718 if (env) RegCloseKey(env);
6719 msi_free(deformatted);
6720 msi_free(data);
6721 msi_free(newval);
6722 return res;
6725 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6727 static const WCHAR query[] = {
6728 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6729 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6730 MSIQUERY *view;
6731 UINT rc;
6733 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6734 if (rc != ERROR_SUCCESS)
6735 return ERROR_SUCCESS;
6737 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6738 msiobj_release(&view->hdr);
6739 return rc;
6742 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6744 MSIPACKAGE *package = param;
6745 LPCWSTR name, value, component;
6746 LPWSTR deformatted = NULL;
6747 DWORD flags;
6748 HKEY env;
6749 MSICOMPONENT *comp;
6750 MSIRECORD *uirow;
6751 int action = 0;
6752 LONG res;
6753 UINT r;
6755 component = MSI_RecordGetString( rec, 4 );
6756 comp = msi_get_loaded_component( package, component );
6757 if (!comp)
6758 return ERROR_SUCCESS;
6760 comp->Action = msi_get_component_action( package, comp );
6761 if (comp->Action != INSTALLSTATE_ABSENT)
6763 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6764 return ERROR_SUCCESS;
6766 name = MSI_RecordGetString( rec, 2 );
6767 value = MSI_RecordGetString( rec, 3 );
6769 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6771 r = env_parse_flags( &name, &value, &flags );
6772 if (r != ERROR_SUCCESS)
6773 return r;
6775 if (!(flags & ENV_ACT_REMOVE))
6777 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6778 return ERROR_SUCCESS;
6781 if (value && !deformat_string( package, value, &deformatted ))
6782 return ERROR_OUTOFMEMORY;
6784 value = deformatted;
6786 r = open_env_key( flags, &env );
6787 if (r != ERROR_SUCCESS)
6789 r = ERROR_SUCCESS;
6790 goto done;
6793 if (flags & ENV_MOD_MACHINE)
6794 action |= 0x20000000;
6796 TRACE("Removing %s\n", debugstr_w(name));
6798 res = RegDeleteValueW( env, name );
6799 if (res != ERROR_SUCCESS)
6801 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6802 r = ERROR_SUCCESS;
6805 done:
6806 uirow = MSI_CreateRecord( 3 );
6807 MSI_RecordSetStringW( uirow, 1, name );
6808 MSI_RecordSetStringW( uirow, 2, value );
6809 MSI_RecordSetInteger( uirow, 3, action );
6810 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6811 msiobj_release( &uirow->hdr );
6813 if (env) RegCloseKey( env );
6814 msi_free( deformatted );
6815 return r;
6818 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6820 static const WCHAR query[] = {
6821 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6822 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6823 MSIQUERY *view;
6824 UINT rc;
6826 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6827 if (rc != ERROR_SUCCESS)
6828 return ERROR_SUCCESS;
6830 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6831 msiobj_release( &view->hdr );
6832 return rc;
6835 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6837 LPWSTR key, template, id;
6838 UINT r = ERROR_SUCCESS;
6840 id = msi_dup_property( package->db, szProductID );
6841 if (id)
6843 msi_free( id );
6844 return ERROR_SUCCESS;
6846 template = msi_dup_property( package->db, szPIDTemplate );
6847 key = msi_dup_property( package->db, szPIDKEY );
6849 if (key && template)
6851 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6852 r = msi_set_property( package->db, szProductID, key );
6854 msi_free( template );
6855 msi_free( key );
6856 return r;
6859 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6861 TRACE("\n");
6862 package->need_reboot = 1;
6863 return ERROR_SUCCESS;
6866 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6868 static const WCHAR szAvailableFreeReg[] =
6869 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6870 MSIRECORD *uirow;
6871 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6873 TRACE("%p %d kilobytes\n", package, space);
6875 uirow = MSI_CreateRecord( 1 );
6876 MSI_RecordSetInteger( uirow, 1, space );
6877 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6878 msiobj_release( &uirow->hdr );
6880 return ERROR_SUCCESS;
6883 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6885 TRACE("%p\n", package);
6887 msi_set_property( package->db, szRollbackDisabled, szOne );
6888 return ERROR_SUCCESS;
6891 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6893 FIXME("%p\n", package);
6894 return ERROR_SUCCESS;
6897 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6899 static const WCHAR driver_query[] = {
6900 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6901 'O','D','B','C','D','r','i','v','e','r',0};
6902 static const WCHAR translator_query[] = {
6903 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6904 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6905 MSIQUERY *view;
6906 UINT r, count;
6908 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6909 if (r == ERROR_SUCCESS)
6911 count = 0;
6912 r = MSI_IterateRecords( view, &count, NULL, package );
6913 msiobj_release( &view->hdr );
6914 if (r != ERROR_SUCCESS)
6915 return r;
6916 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6918 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6919 if (r == ERROR_SUCCESS)
6921 count = 0;
6922 r = MSI_IterateRecords( view, &count, NULL, package );
6923 msiobj_release( &view->hdr );
6924 if (r != ERROR_SUCCESS)
6925 return r;
6926 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6928 return ERROR_SUCCESS;
6931 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6933 MSIPACKAGE *package = param;
6934 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6935 WCHAR *value;
6937 if ((value = msi_dup_property( package->db, property )))
6939 FIXME("remove %s\n", debugstr_w(value));
6940 msi_free( value );
6942 return ERROR_SUCCESS;
6945 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6947 static const WCHAR query[] = {
6948 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
6949 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
6950 MSIQUERY *view;
6951 UINT r;
6953 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6954 if (r == ERROR_SUCCESS)
6956 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
6957 msiobj_release( &view->hdr );
6958 if (r != ERROR_SUCCESS)
6959 return r;
6961 return ERROR_SUCCESS;
6964 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
6966 MSIPACKAGE *package = param;
6967 int attributes = MSI_RecordGetInteger( rec, 5 );
6969 if (attributes & msidbUpgradeAttributesMigrateFeatures)
6971 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
6972 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
6973 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
6974 const WCHAR *language = MSI_RecordGetString( rec, 4 );
6975 HKEY hkey;
6976 UINT r;
6978 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
6980 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6981 if (r != ERROR_SUCCESS)
6982 return ERROR_SUCCESS;
6984 else
6986 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6987 if (r != ERROR_SUCCESS)
6988 return ERROR_SUCCESS;
6990 RegCloseKey( hkey );
6992 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
6993 debugstr_w(upgrade_code), debugstr_w(version_min),
6994 debugstr_w(version_max), debugstr_w(language));
6996 return ERROR_SUCCESS;
6999 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7001 static const WCHAR query[] = {
7002 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7003 'U','p','g','r','a','d','e',0};
7004 MSIQUERY *view;
7005 UINT r;
7007 if (msi_get_property_int( package->db, szInstalled, 0 ))
7009 TRACE("product is installed, skipping action\n");
7010 return ERROR_SUCCESS;
7012 if (msi_get_property_int( package->db, szPreselected, 0 ))
7014 TRACE("Preselected property is set, not migrating feature states\n");
7015 return ERROR_SUCCESS;
7017 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7018 if (r == ERROR_SUCCESS)
7020 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7021 msiobj_release( &view->hdr );
7022 if (r != ERROR_SUCCESS)
7023 return r;
7025 return ERROR_SUCCESS;
7028 static void bind_image( const char *filename, const char *path )
7030 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7032 WARN("failed to bind image %u\n", GetLastError());
7036 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7038 UINT i;
7039 MSIFILE *file;
7040 MSIPACKAGE *package = param;
7041 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7042 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7043 char *filenameA, *pathA;
7044 WCHAR *pathW, **path_list;
7046 if (!(file = msi_get_loaded_file( package, key )))
7048 WARN("file %s not found\n", debugstr_w(key));
7049 return ERROR_SUCCESS;
7051 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7052 path_list = msi_split_string( paths, ';' );
7053 if (!path_list) bind_image( filenameA, NULL );
7054 else
7056 for (i = 0; path_list[i] && path_list[i][0]; i++)
7058 deformat_string( package, path_list[i], &pathW );
7059 if ((pathA = strdupWtoA( pathW )))
7061 bind_image( filenameA, pathA );
7062 msi_free( pathA );
7064 msi_free( pathW );
7067 msi_free( path_list );
7068 msi_free( filenameA );
7069 return ERROR_SUCCESS;
7072 static UINT ACTION_BindImage( MSIPACKAGE *package )
7074 static const WCHAR query[] = {
7075 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7076 'B','i','n','d','I','m','a','g','e',0};
7077 MSIQUERY *view;
7078 UINT r;
7080 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7081 if (r == ERROR_SUCCESS)
7083 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7084 msiobj_release( &view->hdr );
7085 if (r != ERROR_SUCCESS)
7086 return r;
7088 return ERROR_SUCCESS;
7091 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7093 static const WCHAR query[] = {
7094 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7095 MSIQUERY *view;
7096 DWORD count = 0;
7097 UINT r;
7099 r = MSI_OpenQuery( package->db, &view, query, table );
7100 if (r == ERROR_SUCCESS)
7102 r = MSI_IterateRecords(view, &count, NULL, package);
7103 msiobj_release(&view->hdr);
7104 if (r != ERROR_SUCCESS)
7105 return r;
7107 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7108 return ERROR_SUCCESS;
7111 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7113 static const WCHAR table[] = {
7114 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7115 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7118 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7120 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7121 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7124 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7126 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7127 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7130 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7132 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7133 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7136 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7138 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7139 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7142 static const struct
7144 const WCHAR *action;
7145 UINT (*handler)(MSIPACKAGE *);
7146 const WCHAR *action_rollback;
7148 StandardActions[] =
7150 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7151 { szAppSearch, ACTION_AppSearch, NULL },
7152 { szBindImage, ACTION_BindImage, NULL },
7153 { szCCPSearch, ACTION_CCPSearch, NULL },
7154 { szCostFinalize, ACTION_CostFinalize, NULL },
7155 { szCostInitialize, ACTION_CostInitialize, NULL },
7156 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7157 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7158 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7159 { szDisableRollback, ACTION_DisableRollback, NULL },
7160 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7161 { szExecuteAction, ACTION_ExecuteAction, NULL },
7162 { szFileCost, ACTION_FileCost, NULL },
7163 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7164 { szForceReboot, ACTION_ForceReboot, NULL },
7165 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7166 { szInstallExecute, ACTION_InstallExecute, NULL },
7167 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7168 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7169 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7170 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7171 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7172 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7173 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7174 { szInstallValidate, ACTION_InstallValidate, NULL },
7175 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7176 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7177 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7178 { szMoveFiles, ACTION_MoveFiles, NULL },
7179 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7180 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7181 { szPatchFiles, ACTION_PatchFiles, NULL },
7182 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7183 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7184 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7185 { szPublishProduct, ACTION_PublishProduct, NULL },
7186 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7187 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7188 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7189 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7190 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7191 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7192 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7193 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7194 { szRegisterUser, ACTION_RegisterUser, NULL },
7195 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7196 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7197 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7198 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7199 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7200 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7201 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7202 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7203 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7204 { szResolveSource, ACTION_ResolveSource, NULL },
7205 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7206 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7207 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7208 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7209 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7210 { szStartServices, ACTION_StartServices, szStopServices },
7211 { szStopServices, ACTION_StopServices, szStartServices },
7212 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7213 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7214 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7215 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7216 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7217 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7218 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7219 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7220 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7221 { szValidateProductID, ACTION_ValidateProductID, NULL },
7222 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7223 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7224 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7225 { NULL, NULL, NULL }
7228 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7230 BOOL ret = FALSE;
7231 UINT i;
7233 i = 0;
7234 while (StandardActions[i].action != NULL)
7236 if (!strcmpW( StandardActions[i].action, action ))
7238 ui_actionstart( package, action );
7239 if (StandardActions[i].handler)
7241 ui_actioninfo( package, action, TRUE, 0 );
7242 *rc = StandardActions[i].handler( package );
7243 ui_actioninfo( package, action, FALSE, *rc );
7245 if (StandardActions[i].action_rollback && !package->need_rollback)
7247 TRACE("scheduling rollback action\n");
7248 msi_schedule_action( package, ROLLBACK_SCRIPT, StandardActions[i].action_rollback );
7251 else
7253 FIXME("unhandled standard action %s\n", debugstr_w(action));
7254 *rc = ERROR_SUCCESS;
7256 ret = TRUE;
7257 break;
7259 i++;
7261 return ret;
7264 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7266 UINT rc = ERROR_SUCCESS;
7267 BOOL handled;
7269 TRACE("Performing action (%s)\n", debugstr_w(action));
7271 handled = ACTION_HandleStandardAction(package, action, &rc);
7273 if (!handled)
7274 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7276 if (!handled)
7278 WARN("unhandled msi action %s\n", debugstr_w(action));
7279 rc = ERROR_FUNCTION_NOT_CALLED;
7282 return rc;
7285 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7287 UINT rc = ERROR_SUCCESS;
7288 BOOL handled = FALSE;
7290 TRACE("Performing action (%s)\n", debugstr_w(action));
7292 handled = ACTION_HandleStandardAction(package, action, &rc);
7294 if (!handled)
7295 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7297 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7298 handled = TRUE;
7300 if (!handled)
7302 WARN("unhandled msi action %s\n", debugstr_w(action));
7303 rc = ERROR_FUNCTION_NOT_CALLED;
7306 return rc;
7309 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7311 UINT rc = ERROR_SUCCESS;
7312 MSIRECORD *row;
7314 static const WCHAR query[] =
7315 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7316 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7317 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7318 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7319 static const WCHAR ui_query[] =
7320 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7321 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7322 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7323 ' ', '=',' ','%','i',0};
7325 if (needs_ui_sequence(package))
7326 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7327 else
7328 row = MSI_QueryGetRecord(package->db, query, seq);
7330 if (row)
7332 LPCWSTR action, cond;
7334 TRACE("Running the actions\n");
7336 /* check conditions */
7337 cond = MSI_RecordGetString(row, 2);
7339 /* this is a hack to skip errors in the condition code */
7340 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7342 msiobj_release(&row->hdr);
7343 return ERROR_SUCCESS;
7346 action = MSI_RecordGetString(row, 1);
7347 if (!action)
7349 ERR("failed to fetch action\n");
7350 msiobj_release(&row->hdr);
7351 return ERROR_FUNCTION_FAILED;
7354 if (needs_ui_sequence(package))
7355 rc = ACTION_PerformUIAction(package, action, -1);
7356 else
7357 rc = ACTION_PerformAction(package, action, -1);
7359 msiobj_release(&row->hdr);
7362 return rc;
7365 /****************************************************
7366 * TOP level entry points
7367 *****************************************************/
7369 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7370 LPCWSTR szCommandLine )
7372 UINT rc;
7373 BOOL ui_exists;
7374 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7375 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7376 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7378 msi_set_property( package->db, szAction, szInstall );
7380 package->script->InWhatSequence = SEQUENCE_INSTALL;
7382 if (szPackagePath)
7384 LPWSTR p, dir;
7385 LPCWSTR file;
7387 dir = strdupW(szPackagePath);
7388 p = strrchrW(dir, '\\');
7389 if (p)
7391 *(++p) = 0;
7392 file = szPackagePath + (p - dir);
7394 else
7396 msi_free(dir);
7397 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7398 GetCurrentDirectoryW(MAX_PATH, dir);
7399 lstrcatW(dir, szBackSlash);
7400 file = szPackagePath;
7403 msi_free( package->PackagePath );
7404 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7405 if (!package->PackagePath)
7407 msi_free(dir);
7408 return ERROR_OUTOFMEMORY;
7411 lstrcpyW(package->PackagePath, dir);
7412 lstrcatW(package->PackagePath, file);
7413 msi_free(dir);
7415 msi_set_sourcedir_props(package, FALSE);
7418 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7419 if (rc != ERROR_SUCCESS)
7420 return rc;
7422 msi_apply_transforms( package );
7423 msi_apply_patches( package );
7425 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7427 TRACE("setting reinstall property\n");
7428 msi_set_property( package->db, szReinstall, szAll );
7431 /* properties may have been added by a transform */
7432 msi_clone_properties( package );
7434 msi_parse_command_line( package, szCommandLine, FALSE );
7435 msi_adjust_privilege_properties( package );
7436 msi_set_context( package );
7438 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7440 TRACE("disabling rollback\n");
7441 msi_set_property( package->db, szRollbackDisabled, szOne );
7444 if (needs_ui_sequence( package))
7446 package->script->InWhatSequence |= SEQUENCE_UI;
7447 rc = ACTION_ProcessUISequence(package);
7448 ui_exists = ui_sequence_exists(package);
7449 if (rc == ERROR_SUCCESS || !ui_exists)
7451 package->script->InWhatSequence |= SEQUENCE_EXEC;
7452 rc = ACTION_ProcessExecSequence(package, ui_exists);
7455 else
7456 rc = ACTION_ProcessExecSequence(package, FALSE);
7458 package->script->CurrentlyScripting = FALSE;
7460 /* process the ending type action */
7461 if (rc == ERROR_SUCCESS)
7462 ACTION_PerformActionSequence(package, -1);
7463 else if (rc == ERROR_INSTALL_USEREXIT)
7464 ACTION_PerformActionSequence(package, -2);
7465 else if (rc == ERROR_INSTALL_SUSPEND)
7466 ACTION_PerformActionSequence(package, -4);
7467 else /* failed */
7469 ACTION_PerformActionSequence(package, -3);
7470 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7472 package->need_rollback = TRUE;
7476 /* finish up running custom actions */
7477 ACTION_FinishCustomActions(package);
7479 if (package->need_rollback)
7481 WARN("installation failed, running rollback script\n");
7482 execute_script( package, ROLLBACK_SCRIPT );
7485 if (rc == ERROR_SUCCESS && package->need_reboot)
7486 return ERROR_SUCCESS_REBOOT_REQUIRED;
7488 return rc;