msxml3: Fix attributes formatting.
[wine/multimedia.git] / dlls / msi / action.c
blobfa926531d28e34277c73f9cc0948a2d6847e98aa
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 ERR("unknown component %s\n", debugstr_w(component));
1052 return ERROR_FUNCTION_FAILED;
1055 add_feature_component( ilfs->feature, comp );
1056 comp->Enabled = TRUE;
1058 return ERROR_SUCCESS;
1061 static UINT load_feature(MSIRECORD * row, LPVOID param)
1063 static const WCHAR query[] = {
1064 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
1065 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1066 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
1067 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1068 MSIPACKAGE *package = param;
1069 MSIFEATURE *feature;
1070 MSIQUERY *view;
1071 _ilfs ilfs;
1072 UINT rc;
1074 /* fill in the data */
1076 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1077 if (!feature)
1078 return ERROR_NOT_ENOUGH_MEMORY;
1080 list_init( &feature->Children );
1081 list_init( &feature->Components );
1083 feature->Feature = msi_dup_record_field( row, 1 );
1085 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1087 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1088 feature->Title = msi_dup_record_field( row, 3 );
1089 feature->Description = msi_dup_record_field( row, 4 );
1091 if (!MSI_RecordIsNull(row,5))
1092 feature->Display = MSI_RecordGetInteger(row,5);
1094 feature->Level= MSI_RecordGetInteger(row,6);
1095 feature->Directory = msi_dup_record_field( row, 7 );
1096 feature->Attributes = MSI_RecordGetInteger(row,8);
1098 feature->Installed = INSTALLSTATE_UNKNOWN;
1099 feature->Action = INSTALLSTATE_UNKNOWN;
1100 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1102 list_add_tail( &package->features, &feature->entry );
1104 /* load feature components */
1106 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1107 if (rc != ERROR_SUCCESS)
1108 return ERROR_SUCCESS;
1110 ilfs.package = package;
1111 ilfs.feature = feature;
1113 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1114 msiobj_release(&view->hdr);
1115 return rc;
1118 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1120 MSIPACKAGE *package = param;
1121 MSIFEATURE *parent, *child;
1123 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1124 if (!child)
1125 return ERROR_FUNCTION_FAILED;
1127 if (!child->Feature_Parent)
1128 return ERROR_SUCCESS;
1130 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1131 if (!parent)
1132 return ERROR_FUNCTION_FAILED;
1134 add_feature_child( parent, child );
1135 return ERROR_SUCCESS;
1138 UINT msi_load_all_features( MSIPACKAGE *package )
1140 static const WCHAR query[] = {
1141 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1142 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
1143 '`','D','i','s','p','l','a','y','`',0};
1144 MSIQUERY *view;
1145 UINT r;
1147 if (!list_empty(&package->features))
1148 return ERROR_SUCCESS;
1150 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1151 if (r != ERROR_SUCCESS)
1152 return r;
1154 r = MSI_IterateRecords( view, NULL, load_feature, package );
1155 if (r != ERROR_SUCCESS)
1157 msiobj_release( &view->hdr );
1158 return r;
1160 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1161 msiobj_release( &view->hdr );
1162 return r;
1165 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1167 if (!p)
1168 return p;
1169 p = strchrW(p, ch);
1170 if (!p)
1171 return p;
1172 *p = 0;
1173 return p+1;
1176 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1178 static const WCHAR query[] = {
1179 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1180 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1181 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1182 MSIQUERY *view = NULL;
1183 MSIRECORD *row = NULL;
1184 UINT r;
1186 TRACE("%s\n", debugstr_w(file->File));
1188 r = MSI_OpenQuery(package->db, &view, query, file->File);
1189 if (r != ERROR_SUCCESS)
1190 goto done;
1192 r = MSI_ViewExecute(view, NULL);
1193 if (r != ERROR_SUCCESS)
1194 goto done;
1196 r = MSI_ViewFetch(view, &row);
1197 if (r != ERROR_SUCCESS)
1198 goto done;
1200 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1201 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1202 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1203 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1204 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1206 done:
1207 if (view) msiobj_release(&view->hdr);
1208 if (row) msiobj_release(&row->hdr);
1209 return r;
1212 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1214 MSIRECORD *row;
1215 static const WCHAR query[] = {
1216 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1217 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1218 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1220 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1221 if (!row)
1223 WARN("query failed\n");
1224 return ERROR_FUNCTION_FAILED;
1227 file->disk_id = MSI_RecordGetInteger( row, 1 );
1228 msiobj_release( &row->hdr );
1229 return ERROR_SUCCESS;
1232 static UINT load_file(MSIRECORD *row, LPVOID param)
1234 MSIPACKAGE* package = param;
1235 LPCWSTR component;
1236 MSIFILE *file;
1238 /* fill in the data */
1240 file = msi_alloc_zero( sizeof (MSIFILE) );
1241 if (!file)
1242 return ERROR_NOT_ENOUGH_MEMORY;
1244 file->File = msi_dup_record_field( row, 1 );
1246 component = MSI_RecordGetString( row, 2 );
1247 file->Component = msi_get_loaded_component( package, component );
1249 if (!file->Component)
1251 WARN("Component not found: %s\n", debugstr_w(component));
1252 msi_free(file->File);
1253 msi_free(file);
1254 return ERROR_SUCCESS;
1257 file->FileName = msi_dup_record_field( row, 3 );
1258 msi_reduce_to_long_filename( file->FileName );
1260 file->ShortName = msi_dup_record_field( row, 3 );
1261 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1263 file->FileSize = MSI_RecordGetInteger( row, 4 );
1264 file->Version = msi_dup_record_field( row, 5 );
1265 file->Language = msi_dup_record_field( row, 6 );
1266 file->Attributes = MSI_RecordGetInteger( row, 7 );
1267 file->Sequence = MSI_RecordGetInteger( row, 8 );
1269 file->state = msifs_invalid;
1271 /* if the compressed bits are not set in the file attributes,
1272 * then read the information from the package word count property
1274 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1276 file->IsCompressed = FALSE;
1278 else if (file->Attributes &
1279 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1281 file->IsCompressed = TRUE;
1283 else if (file->Attributes & msidbFileAttributesNoncompressed)
1285 file->IsCompressed = FALSE;
1287 else
1289 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1292 load_file_hash(package, file);
1293 load_file_disk_id(package, file);
1295 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1297 list_add_tail( &package->files, &file->entry );
1299 return ERROR_SUCCESS;
1302 static UINT load_all_files(MSIPACKAGE *package)
1304 static const WCHAR query[] = {
1305 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1306 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1307 '`','S','e','q','u','e','n','c','e','`', 0};
1308 MSIQUERY *view;
1309 UINT rc;
1311 if (!list_empty(&package->files))
1312 return ERROR_SUCCESS;
1314 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1315 if (rc != ERROR_SUCCESS)
1316 return ERROR_SUCCESS;
1318 rc = MSI_IterateRecords(view, NULL, load_file, package);
1319 msiobj_release(&view->hdr);
1320 return rc;
1323 static UINT load_media( MSIRECORD *row, LPVOID param )
1325 MSIPACKAGE *package = param;
1326 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1327 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1329 /* FIXME: load external cabinets and directory sources too */
1330 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1331 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1332 return ERROR_SUCCESS;
1335 static UINT load_all_media( MSIPACKAGE *package )
1337 static const WCHAR query[] = {
1338 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
1339 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
1340 '`','D','i','s','k','I','d','`',0};
1341 MSIQUERY *view;
1342 UINT r;
1344 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1345 if (r != ERROR_SUCCESS)
1346 return ERROR_SUCCESS;
1348 r = MSI_IterateRecords( view, NULL, load_media, package );
1349 msiobj_release( &view->hdr );
1350 return r;
1353 static UINT load_patch(MSIRECORD *row, LPVOID param)
1355 MSIPACKAGE *package = param;
1356 MSIFILEPATCH *patch;
1357 LPWSTR file_key;
1359 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1360 if (!patch)
1361 return ERROR_NOT_ENOUGH_MEMORY;
1363 file_key = msi_dup_record_field( row, 1 );
1364 patch->File = msi_get_loaded_file( package, file_key );
1365 msi_free(file_key);
1367 if( !patch->File )
1369 ERR("Failed to find target for patch in File table\n");
1370 msi_free(patch);
1371 return ERROR_FUNCTION_FAILED;
1374 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1376 /* FIXME: The database should be properly transformed */
1377 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1379 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1380 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1381 patch->IsApplied = FALSE;
1383 /* FIXME:
1384 * Header field - for patch validation.
1385 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1388 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1390 list_add_tail( &package->filepatches, &patch->entry );
1392 return ERROR_SUCCESS;
1395 static UINT load_all_patches(MSIPACKAGE *package)
1397 static const WCHAR query[] = {
1398 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1399 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1400 '`','S','e','q','u','e','n','c','e','`',0};
1401 MSIQUERY *view;
1402 UINT rc;
1404 if (!list_empty(&package->filepatches))
1405 return ERROR_SUCCESS;
1407 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1408 if (rc != ERROR_SUCCESS)
1409 return ERROR_SUCCESS;
1411 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1412 msiobj_release(&view->hdr);
1413 return rc;
1416 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1418 static const WCHAR query[] = {
1419 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1420 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1421 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1422 MSIQUERY *view;
1424 folder->persistent = FALSE;
1425 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1427 if (!MSI_ViewExecute( view, NULL ))
1429 MSIRECORD *rec;
1430 if (!MSI_ViewFetch( view, &rec ))
1432 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1433 folder->persistent = TRUE;
1434 msiobj_release( &rec->hdr );
1437 msiobj_release( &view->hdr );
1439 return ERROR_SUCCESS;
1442 static UINT load_folder( MSIRECORD *row, LPVOID param )
1444 MSIPACKAGE *package = param;
1445 static WCHAR szEmpty[] = { 0 };
1446 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1447 MSIFOLDER *folder;
1449 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1450 list_init( &folder->children );
1451 folder->Directory = msi_dup_record_field( row, 1 );
1452 folder->Parent = msi_dup_record_field( row, 2 );
1453 p = msi_dup_record_field(row, 3);
1455 TRACE("%s\n", debugstr_w(folder->Directory));
1457 /* split src and target dir */
1458 tgt_short = p;
1459 src_short = folder_split_path( p, ':' );
1461 /* split the long and short paths */
1462 tgt_long = folder_split_path( tgt_short, '|' );
1463 src_long = folder_split_path( src_short, '|' );
1465 /* check for no-op dirs */
1466 if (tgt_short && !strcmpW( szDot, tgt_short ))
1467 tgt_short = szEmpty;
1468 if (src_short && !strcmpW( szDot, src_short ))
1469 src_short = szEmpty;
1471 if (!tgt_long)
1472 tgt_long = tgt_short;
1474 if (!src_short) {
1475 src_short = tgt_short;
1476 src_long = tgt_long;
1479 if (!src_long)
1480 src_long = src_short;
1482 /* FIXME: use the target short path too */
1483 folder->TargetDefault = strdupW(tgt_long);
1484 folder->SourceShortPath = strdupW(src_short);
1485 folder->SourceLongPath = strdupW(src_long);
1486 msi_free(p);
1488 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1489 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1490 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1492 load_folder_persistence( package, folder );
1494 list_add_tail( &package->folders, &folder->entry );
1495 return ERROR_SUCCESS;
1498 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1500 FolderList *fl;
1502 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1503 fl->folder = child;
1504 list_add_tail( &parent->children, &fl->entry );
1505 return ERROR_SUCCESS;
1508 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1510 MSIPACKAGE *package = param;
1511 MSIFOLDER *parent, *child;
1513 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1514 return ERROR_FUNCTION_FAILED;
1516 if (!child->Parent) return ERROR_SUCCESS;
1518 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1519 return ERROR_FUNCTION_FAILED;
1521 return add_folder_child( parent, child );
1524 static UINT load_all_folders( MSIPACKAGE *package )
1526 static const WCHAR query[] = {
1527 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1528 '`','D','i','r','e','c','t','o','r','y','`',0};
1529 MSIQUERY *view;
1530 UINT r;
1532 if (!list_empty(&package->folders))
1533 return ERROR_SUCCESS;
1535 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1536 if (r != ERROR_SUCCESS)
1537 return r;
1539 r = MSI_IterateRecords( view, NULL, load_folder, package );
1540 if (r != ERROR_SUCCESS)
1542 msiobj_release( &view->hdr );
1543 return r;
1545 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1546 msiobj_release( &view->hdr );
1547 return r;
1550 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1552 msi_set_property( package->db, szCostingComplete, szZero );
1553 msi_set_property( package->db, szRootDrive, szCRoot );
1555 load_all_folders( package );
1556 msi_load_all_components( package );
1557 msi_load_all_features( package );
1558 load_all_files( package );
1559 load_all_patches( package );
1560 load_all_media( package );
1562 return ERROR_SUCCESS;
1565 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1567 const WCHAR *action = package->script->Actions[script][index];
1568 ui_actionstart( package, action );
1569 TRACE("executing %s\n", debugstr_w(action));
1570 return ACTION_PerformAction( package, action, script );
1573 static UINT execute_script( MSIPACKAGE *package, UINT script )
1575 UINT i, rc = ERROR_SUCCESS;
1577 TRACE("executing script %u\n", script);
1579 if (!package->script)
1581 ERR("no script!\n");
1582 return ERROR_FUNCTION_FAILED;
1584 if (script == ROLLBACK_SCRIPT)
1586 for (i = package->script->ActionCount[script]; i > 0; i--)
1588 rc = execute_script_action( package, script, i - 1 );
1589 if (rc != ERROR_SUCCESS) break;
1592 else
1594 for (i = 0; i < package->script->ActionCount[script]; i++)
1596 rc = execute_script_action( package, script, i );
1597 if (rc != ERROR_SUCCESS) break;
1600 msi_free_action_script(package, script);
1601 return rc;
1604 static UINT ACTION_FileCost(MSIPACKAGE *package)
1606 return ERROR_SUCCESS;
1609 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1611 MSICOMPONENT *comp;
1612 UINT r;
1614 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1616 if (!comp->ComponentId) continue;
1618 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1619 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1620 &comp->Installed );
1621 if (r != ERROR_SUCCESS)
1622 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1623 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1624 &comp->Installed );
1625 if (r != ERROR_SUCCESS)
1626 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1627 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1628 &comp->Installed );
1629 if (r != ERROR_SUCCESS)
1630 comp->Installed = INSTALLSTATE_ABSENT;
1634 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1636 MSIFEATURE *feature;
1638 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1640 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1642 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1643 feature->Installed = INSTALLSTATE_ABSENT;
1644 else
1645 feature->Installed = state;
1649 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1651 return (feature->Level > 0 && feature->Level <= level);
1654 static BOOL process_state_property(MSIPACKAGE* package, int level,
1655 LPCWSTR property, INSTALLSTATE state)
1657 LPWSTR override;
1658 MSIFEATURE *feature;
1660 override = msi_dup_property( package->db, property );
1661 if (!override)
1662 return FALSE;
1664 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1666 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1667 continue;
1669 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1671 if (!strcmpiW( override, szAll ))
1673 if (feature->Installed != state)
1675 feature->Action = state;
1676 feature->ActionRequest = state;
1679 else
1681 LPWSTR ptr = override;
1682 LPWSTR ptr2 = strchrW(override,',');
1684 while (ptr)
1686 int len = ptr2 - ptr;
1688 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1689 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1691 if (feature->Installed != state)
1693 feature->Action = state;
1694 feature->ActionRequest = state;
1696 break;
1698 if (ptr2)
1700 ptr=ptr2+1;
1701 ptr2 = strchrW(ptr,',');
1703 else
1704 break;
1708 msi_free(override);
1709 return TRUE;
1712 static BOOL process_overrides( MSIPACKAGE *package, int level )
1714 static const WCHAR szAddLocal[] =
1715 {'A','D','D','L','O','C','A','L',0};
1716 static const WCHAR szAddSource[] =
1717 {'A','D','D','S','O','U','R','C','E',0};
1718 static const WCHAR szAdvertise[] =
1719 {'A','D','V','E','R','T','I','S','E',0};
1720 BOOL ret = FALSE;
1722 /* all these activation/deactivation things happen in order and things
1723 * later on the list override things earlier on the list.
1725 * 0 INSTALLLEVEL processing
1726 * 1 ADDLOCAL
1727 * 2 REMOVE
1728 * 3 ADDSOURCE
1729 * 4 ADDDEFAULT
1730 * 5 REINSTALL
1731 * 6 ADVERTISE
1732 * 7 COMPADDLOCAL
1733 * 8 COMPADDSOURCE
1734 * 9 FILEADDLOCAL
1735 * 10 FILEADDSOURCE
1736 * 11 FILEADDDEFAULT
1738 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1739 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1740 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1741 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1742 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1744 if (ret)
1745 msi_set_property( package->db, szPreselected, szOne );
1747 return ret;
1750 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1752 int level;
1753 MSICOMPONENT* component;
1754 MSIFEATURE *feature;
1756 TRACE("Checking Install Level\n");
1758 level = msi_get_property_int(package->db, szInstallLevel, 1);
1760 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1762 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1764 if (!is_feature_selected( feature, level )) continue;
1766 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1768 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1770 feature->Action = INSTALLSTATE_SOURCE;
1771 feature->ActionRequest = INSTALLSTATE_SOURCE;
1773 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1775 feature->Action = INSTALLSTATE_ADVERTISED;
1776 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1778 else
1780 feature->Action = INSTALLSTATE_LOCAL;
1781 feature->ActionRequest = INSTALLSTATE_LOCAL;
1785 /* disable child features of unselected parent or follow parent */
1786 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1788 FeatureList *fl;
1790 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1792 if (!is_feature_selected( feature, level ))
1794 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1795 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1797 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1799 fl->feature->Action = feature->Action;
1800 fl->feature->ActionRequest = feature->ActionRequest;
1805 else /* preselected */
1807 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1809 if (!is_feature_selected( feature, level )) continue;
1811 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1813 if (feature->Installed == INSTALLSTATE_ABSENT)
1815 feature->Action = INSTALLSTATE_UNKNOWN;
1816 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1818 else
1820 feature->Action = feature->Installed;
1821 feature->ActionRequest = feature->Installed;
1825 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1827 FeatureList *fl;
1829 if (!is_feature_selected( feature, level )) continue;
1831 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1833 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1835 fl->feature->Action = feature->Action;
1836 fl->feature->ActionRequest = feature->ActionRequest;
1842 /* now we want to set component state based based on feature state */
1843 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1845 ComponentList *cl;
1847 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1848 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1849 feature->ActionRequest, feature->Action);
1851 if (!is_feature_selected( feature, level )) continue;
1853 /* features with components that have compressed files are made local */
1854 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1856 if (cl->component->ForceLocalState &&
1857 feature->ActionRequest == INSTALLSTATE_SOURCE)
1859 feature->Action = INSTALLSTATE_LOCAL;
1860 feature->ActionRequest = INSTALLSTATE_LOCAL;
1861 break;
1865 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1867 component = cl->component;
1869 switch (feature->ActionRequest)
1871 case INSTALLSTATE_ABSENT:
1872 component->anyAbsent = 1;
1873 break;
1874 case INSTALLSTATE_ADVERTISED:
1875 component->hasAdvertiseFeature = 1;
1876 break;
1877 case INSTALLSTATE_SOURCE:
1878 component->hasSourceFeature = 1;
1879 break;
1880 case INSTALLSTATE_LOCAL:
1881 component->hasLocalFeature = 1;
1882 break;
1883 case INSTALLSTATE_DEFAULT:
1884 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1885 component->hasAdvertiseFeature = 1;
1886 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1887 component->hasSourceFeature = 1;
1888 else
1889 component->hasLocalFeature = 1;
1890 break;
1891 default:
1892 break;
1897 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1899 /* check if it's local or source */
1900 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1901 (component->hasLocalFeature || component->hasSourceFeature))
1903 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1904 !component->ForceLocalState)
1906 component->Action = INSTALLSTATE_SOURCE;
1907 component->ActionRequest = INSTALLSTATE_SOURCE;
1909 else
1911 component->Action = INSTALLSTATE_LOCAL;
1912 component->ActionRequest = INSTALLSTATE_LOCAL;
1914 continue;
1917 /* if any feature is local, the component must be local too */
1918 if (component->hasLocalFeature)
1920 component->Action = INSTALLSTATE_LOCAL;
1921 component->ActionRequest = INSTALLSTATE_LOCAL;
1922 continue;
1924 if (component->hasSourceFeature)
1926 component->Action = INSTALLSTATE_SOURCE;
1927 component->ActionRequest = INSTALLSTATE_SOURCE;
1928 continue;
1930 if (component->hasAdvertiseFeature)
1932 component->Action = INSTALLSTATE_ADVERTISED;
1933 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1934 continue;
1936 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1937 if (component->anyAbsent &&
1938 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1940 component->Action = INSTALLSTATE_ABSENT;
1941 component->ActionRequest = INSTALLSTATE_ABSENT;
1945 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1947 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1949 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1950 component->Action = INSTALLSTATE_LOCAL;
1951 component->ActionRequest = INSTALLSTATE_LOCAL;
1954 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1955 component->Installed == INSTALLSTATE_SOURCE &&
1956 component->hasSourceFeature)
1958 component->Action = INSTALLSTATE_UNKNOWN;
1959 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1962 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
1963 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1966 return ERROR_SUCCESS;
1969 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1971 MSIPACKAGE *package = param;
1972 LPCWSTR name;
1973 MSIFEATURE *feature;
1975 name = MSI_RecordGetString( row, 1 );
1977 feature = msi_get_loaded_feature( package, name );
1978 if (!feature)
1979 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1980 else
1982 LPCWSTR Condition;
1983 Condition = MSI_RecordGetString(row,3);
1985 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1987 int level = MSI_RecordGetInteger(row,2);
1988 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1989 feature->Level = level;
1992 return ERROR_SUCCESS;
1995 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
1997 static const WCHAR name[] = {'\\',0};
1998 VS_FIXEDFILEINFO *ptr, *ret;
1999 LPVOID version;
2000 DWORD versize, handle;
2001 UINT sz;
2003 versize = GetFileVersionInfoSizeW( filename, &handle );
2004 if (!versize)
2005 return NULL;
2007 version = msi_alloc( versize );
2008 if (!version)
2009 return NULL;
2011 GetFileVersionInfoW( filename, 0, versize, version );
2013 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2015 msi_free( version );
2016 return NULL;
2019 ret = msi_alloc( sz );
2020 memcpy( ret, ptr, sz );
2022 msi_free( version );
2023 return ret;
2026 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2028 DWORD ms, ls;
2030 msi_parse_version_string( version, &ms, &ls );
2032 if (fi->dwFileVersionMS > ms) return 1;
2033 else if (fi->dwFileVersionMS < ms) return -1;
2034 else if (fi->dwFileVersionLS > ls) return 1;
2035 else if (fi->dwFileVersionLS < ls) return -1;
2036 return 0;
2039 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2041 DWORD ms1, ms2;
2043 msi_parse_version_string( ver1, &ms1, NULL );
2044 msi_parse_version_string( ver2, &ms2, NULL );
2046 if (ms1 > ms2) return 1;
2047 else if (ms1 < ms2) return -1;
2048 return 0;
2051 DWORD msi_get_disk_file_size( LPCWSTR filename )
2053 HANDLE file;
2054 DWORD size;
2056 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2057 if (file == INVALID_HANDLE_VALUE)
2058 return INVALID_FILE_SIZE;
2060 size = GetFileSize( file, NULL );
2061 TRACE("size is %u\n", size);
2062 CloseHandle( file );
2063 return size;
2066 BOOL msi_file_hash_matches( MSIFILE *file )
2068 UINT r;
2069 MSIFILEHASHINFO hash;
2071 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2072 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2073 if (r != ERROR_SUCCESS)
2074 return FALSE;
2076 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2079 static WCHAR *get_temp_dir( void )
2081 static UINT id;
2082 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2084 GetTempPathW( MAX_PATH, tmp );
2085 for (;;)
2087 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2088 if (CreateDirectoryW( dir, NULL )) break;
2090 return strdupW( dir );
2094 * msi_build_directory_name()
2096 * This function is to save messing round with directory names
2097 * It handles adding backslashes between path segments,
2098 * and can add \ at the end of the directory name if told to.
2100 * It takes a variable number of arguments.
2101 * It always allocates a new string for the result, so make sure
2102 * to free the return value when finished with it.
2104 * The first arg is the number of path segments that follow.
2105 * The arguments following count are a list of path segments.
2106 * A path segment may be NULL.
2108 * Path segments will be added with a \ separating them.
2109 * A \ will not be added after the last segment, however if the
2110 * last segment is NULL, then the last character will be a \
2112 WCHAR *msi_build_directory_name( DWORD count, ... )
2114 DWORD sz = 1, i;
2115 WCHAR *dir;
2116 va_list va;
2118 va_start( va, count );
2119 for (i = 0; i < count; i++)
2121 const WCHAR *str = va_arg( va, const WCHAR * );
2122 if (str) sz += strlenW( str ) + 1;
2124 va_end( va );
2126 dir = msi_alloc( sz * sizeof(WCHAR) );
2127 dir[0] = 0;
2129 va_start( va, count );
2130 for (i = 0; i < count; i++)
2132 const WCHAR *str = va_arg( va, const WCHAR * );
2133 if (!str) continue;
2134 strcatW( dir, str );
2135 if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2137 va_end( va );
2138 return dir;
2141 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2143 MSIASSEMBLY *assembly = file->Component->assembly;
2145 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2147 msi_free( file->TargetPath );
2148 if (assembly && !assembly->application)
2150 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2151 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2152 msi_track_tempfile( package, file->TargetPath );
2154 else
2156 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2157 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2160 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2163 static UINT calculate_file_cost( MSIPACKAGE *package )
2165 VS_FIXEDFILEINFO *file_version;
2166 WCHAR *font_version;
2167 MSIFILE *file;
2169 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2171 MSICOMPONENT *comp = file->Component;
2172 DWORD file_size;
2174 if (!comp->Enabled) continue;
2176 if (file->IsCompressed)
2177 comp->ForceLocalState = TRUE;
2179 set_target_path( package, file );
2181 if ((comp->assembly && !comp->assembly->installed) ||
2182 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2184 comp->Cost += file->FileSize;
2185 continue;
2187 file_size = msi_get_disk_file_size( file->TargetPath );
2189 if (file->Version)
2191 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2193 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2195 comp->Cost += file->FileSize - file_size;
2197 msi_free( file_version );
2198 continue;
2200 else if ((font_version = font_version_from_file( file->TargetPath )))
2202 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2204 comp->Cost += file->FileSize - file_size;
2206 msi_free( font_version );
2207 continue;
2210 if (file_size != file->FileSize)
2212 comp->Cost += file->FileSize - file_size;
2215 return ERROR_SUCCESS;
2218 void msi_clean_path( WCHAR *p )
2220 WCHAR *q = p;
2221 int n, len = 0;
2223 while (1)
2225 /* copy until the end of the string or a space */
2226 while (*p != ' ' && (*q = *p))
2228 p++, len++;
2229 /* reduce many backslashes to one */
2230 if (*p != '\\' || *q != '\\')
2231 q++;
2234 /* quit at the end of the string */
2235 if (!*p)
2236 break;
2238 /* count the number of spaces */
2239 n = 0;
2240 while (p[n] == ' ')
2241 n++;
2243 /* if it's leading or trailing space, skip it */
2244 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2245 p += n;
2246 else /* copy n spaces */
2247 while (n && (*q++ = *p++)) n--;
2251 static WCHAR *get_target_dir_property( MSIDATABASE *db )
2253 int len;
2254 WCHAR *path, *target_dir = msi_dup_property( db, szTargetDir );
2256 if (!target_dir) return NULL;
2258 len = strlenW( target_dir );
2259 if (target_dir[len - 1] == '\\') return target_dir;
2260 if ((path = msi_alloc( (len + 2) * sizeof(WCHAR) )))
2262 strcpyW( path, target_dir );
2263 path[len] = '\\';
2264 path[len + 1] = 0;
2266 msi_free( target_dir );
2267 return path;
2270 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2272 FolderList *fl;
2273 MSIFOLDER *folder, *parent, *child;
2274 WCHAR *path;
2276 TRACE("resolving %s\n", debugstr_w(name));
2278 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2280 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2282 if (!load_prop || !(path = get_target_dir_property( package->db )))
2284 path = msi_dup_property( package->db, szRootDrive );
2287 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2289 parent = msi_get_loaded_folder( package, folder->Parent );
2290 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2292 msi_clean_path( path );
2293 if (folder->ResolvedTarget && !strcmpiW( path, folder->ResolvedTarget ))
2295 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2296 msi_free( path );
2297 return;
2299 msi_set_property( package->db, folder->Directory, path );
2300 msi_free( folder->ResolvedTarget );
2301 folder->ResolvedTarget = path;
2303 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2305 child = fl->folder;
2306 msi_resolve_target_folder( package, child->Directory, load_prop );
2308 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2311 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2313 static const WCHAR query[] = {
2314 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2315 '`','C','o','n','d','i','t','i','o','n','`',0};
2316 static const WCHAR szOutOfDiskSpace[] = {
2317 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2318 MSICOMPONENT *comp;
2319 MSIQUERY *view;
2320 LPWSTR level;
2321 UINT rc;
2323 TRACE("Building directory properties\n");
2324 msi_resolve_target_folder( package, szTargetDir, TRUE );
2326 TRACE("Evaluating component conditions\n");
2327 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2329 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2331 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2332 comp->Enabled = FALSE;
2334 else
2335 comp->Enabled = TRUE;
2338 /* read components states from the registry */
2339 ACTION_GetComponentInstallStates(package);
2340 ACTION_GetFeatureInstallStates(package);
2342 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2344 TRACE("Evaluating feature conditions\n");
2346 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2347 if (rc == ERROR_SUCCESS)
2349 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2350 msiobj_release( &view->hdr );
2351 if (rc != ERROR_SUCCESS)
2352 return rc;
2356 TRACE("Calculating file cost\n");
2357 calculate_file_cost( package );
2359 msi_set_property( package->db, szCostingComplete, szOne );
2360 /* set default run level if not set */
2361 level = msi_dup_property( package->db, szInstallLevel );
2362 if (!level)
2363 msi_set_property( package->db, szInstallLevel, szOne );
2364 msi_free(level);
2366 /* FIXME: check volume disk space */
2367 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2369 return MSI_SetFeatureStates(package);
2372 /* OK this value is "interpreted" and then formatted based on the
2373 first few characters */
2374 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2375 DWORD *size)
2377 LPSTR data = NULL;
2379 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2381 if (value[1]=='x')
2383 LPWSTR ptr;
2384 CHAR byte[5];
2385 LPWSTR deformated = NULL;
2386 int count;
2388 deformat_string(package, &value[2], &deformated);
2390 /* binary value type */
2391 ptr = deformated;
2392 *type = REG_BINARY;
2393 if (strlenW(ptr)%2)
2394 *size = (strlenW(ptr)/2)+1;
2395 else
2396 *size = strlenW(ptr)/2;
2398 data = msi_alloc(*size);
2400 byte[0] = '0';
2401 byte[1] = 'x';
2402 byte[4] = 0;
2403 count = 0;
2404 /* if uneven pad with a zero in front */
2405 if (strlenW(ptr)%2)
2407 byte[2]= '0';
2408 byte[3]= *ptr;
2409 ptr++;
2410 data[count] = (BYTE)strtol(byte,NULL,0);
2411 count ++;
2412 TRACE("Uneven byte count\n");
2414 while (*ptr)
2416 byte[2]= *ptr;
2417 ptr++;
2418 byte[3]= *ptr;
2419 ptr++;
2420 data[count] = (BYTE)strtol(byte,NULL,0);
2421 count ++;
2423 msi_free(deformated);
2425 TRACE("Data %i bytes(%i)\n",*size,count);
2427 else
2429 LPWSTR deformated;
2430 LPWSTR p;
2431 DWORD d = 0;
2432 deformat_string(package, &value[1], &deformated);
2434 *type=REG_DWORD;
2435 *size = sizeof(DWORD);
2436 data = msi_alloc(*size);
2437 p = deformated;
2438 if (*p == '-')
2439 p++;
2440 while (*p)
2442 if ( (*p < '0') || (*p > '9') )
2443 break;
2444 d *= 10;
2445 d += (*p - '0');
2446 p++;
2448 if (deformated[0] == '-')
2449 d = -d;
2450 *(LPDWORD)data = d;
2451 TRACE("DWORD %i\n",*(LPDWORD)data);
2453 msi_free(deformated);
2456 else
2458 static const WCHAR szMulti[] = {'[','~',']',0};
2459 LPCWSTR ptr;
2460 *type=REG_SZ;
2462 if (value[0]=='#')
2464 if (value[1]=='%')
2466 ptr = &value[2];
2467 *type=REG_EXPAND_SZ;
2469 else
2470 ptr = &value[1];
2472 else
2473 ptr=value;
2475 if (strstrW(value, szMulti))
2476 *type = REG_MULTI_SZ;
2478 /* remove initial delimiter */
2479 if (!strncmpW(value, szMulti, 3))
2480 ptr = value + 3;
2482 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2484 /* add double NULL terminator */
2485 if (*type == REG_MULTI_SZ)
2487 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2488 data = msi_realloc_zero(data, *size);
2491 return data;
2494 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2496 const WCHAR *ret;
2498 switch (root)
2500 case -1:
2501 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2503 *root_key = HKEY_LOCAL_MACHINE;
2504 ret = szHLM;
2506 else
2508 *root_key = HKEY_CURRENT_USER;
2509 ret = szHCU;
2511 break;
2512 case 0:
2513 *root_key = HKEY_CLASSES_ROOT;
2514 ret = szHCR;
2515 break;
2516 case 1:
2517 *root_key = HKEY_CURRENT_USER;
2518 ret = szHCU;
2519 break;
2520 case 2:
2521 *root_key = HKEY_LOCAL_MACHINE;
2522 ret = szHLM;
2523 break;
2524 case 3:
2525 *root_key = HKEY_USERS;
2526 ret = szHU;
2527 break;
2528 default:
2529 ERR("Unknown root %i\n", root);
2530 return NULL;
2533 return ret;
2536 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2538 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2539 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2541 if (is_64bit && package->platform == PLATFORM_INTEL &&
2542 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2544 UINT size;
2545 WCHAR *path_32node;
2547 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2548 if (!(path_32node = msi_alloc( size ))) return NULL;
2550 memcpy( path_32node, path, len * sizeof(WCHAR) );
2551 strcpyW( path_32node + len, szWow6432Node );
2552 strcatW( path_32node, szBackSlash );
2553 strcatW( path_32node, path + len );
2554 return path_32node;
2557 return strdupW( path );
2560 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2562 MSIPACKAGE *package = param;
2563 LPSTR value_data = NULL;
2564 HKEY root_key, hkey;
2565 DWORD type,size;
2566 LPWSTR deformated, uikey, keypath;
2567 LPCWSTR szRoot, component, name, key, value;
2568 MSICOMPONENT *comp;
2569 MSIRECORD * uirow;
2570 INT root;
2571 BOOL check_first = FALSE;
2572 UINT rc;
2574 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2576 component = MSI_RecordGetString(row, 6);
2577 comp = msi_get_loaded_component(package,component);
2578 if (!comp)
2579 return ERROR_SUCCESS;
2581 comp->Action = msi_get_component_action( package, comp );
2582 if (comp->Action != INSTALLSTATE_LOCAL)
2584 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2585 return ERROR_SUCCESS;
2588 name = MSI_RecordGetString(row, 4);
2589 if( MSI_RecordIsNull(row,5) && name )
2591 /* null values can have special meanings */
2592 if (name[0]=='-' && name[1] == 0)
2593 return ERROR_SUCCESS;
2594 else if ((name[0]=='+' && name[1] == 0) ||
2595 (name[0] == '*' && name[1] == 0))
2596 name = NULL;
2597 check_first = TRUE;
2600 root = MSI_RecordGetInteger(row,2);
2601 key = MSI_RecordGetString(row, 3);
2603 szRoot = get_root_key( package, root, &root_key );
2604 if (!szRoot)
2605 return ERROR_SUCCESS;
2607 deformat_string(package, key , &deformated);
2608 size = strlenW(deformated) + strlenW(szRoot) + 1;
2609 uikey = msi_alloc(size*sizeof(WCHAR));
2610 strcpyW(uikey,szRoot);
2611 strcatW(uikey,deformated);
2613 keypath = get_keypath( package, root_key, deformated );
2614 msi_free( deformated );
2615 if (RegCreateKeyW( root_key, keypath, &hkey ))
2617 ERR("Could not create key %s\n", debugstr_w(keypath));
2618 msi_free(uikey);
2619 msi_free(keypath);
2620 return ERROR_SUCCESS;
2623 value = MSI_RecordGetString(row,5);
2624 if (value)
2625 value_data = parse_value(package, value, &type, &size);
2626 else
2628 value_data = (LPSTR)strdupW(szEmpty);
2629 size = sizeof(szEmpty);
2630 type = REG_SZ;
2633 deformat_string(package, name, &deformated);
2635 if (!check_first)
2637 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2638 debugstr_w(uikey));
2639 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2641 else
2643 DWORD sz = 0;
2644 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2645 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2647 TRACE("value %s of %s checked already exists\n",
2648 debugstr_w(deformated), debugstr_w(uikey));
2650 else
2652 TRACE("Checked and setting value %s of %s\n",
2653 debugstr_w(deformated), debugstr_w(uikey));
2654 if (deformated || size)
2655 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2658 RegCloseKey(hkey);
2660 uirow = MSI_CreateRecord(3);
2661 MSI_RecordSetStringW(uirow,2,deformated);
2662 MSI_RecordSetStringW(uirow,1,uikey);
2663 if (type == REG_SZ || type == REG_EXPAND_SZ)
2664 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2665 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2666 msiobj_release( &uirow->hdr );
2668 msi_free(value_data);
2669 msi_free(deformated);
2670 msi_free(uikey);
2671 msi_free(keypath);
2673 return ERROR_SUCCESS;
2676 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2678 static const WCHAR query[] = {
2679 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2680 '`','R','e','g','i','s','t','r','y','`',0};
2681 MSIQUERY *view;
2682 UINT rc;
2684 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2685 if (rc != ERROR_SUCCESS)
2686 return ERROR_SUCCESS;
2688 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2689 msiobj_release(&view->hdr);
2690 return rc;
2693 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2695 LONG res;
2696 HKEY hkey;
2697 DWORD num_subkeys, num_values;
2699 if (delete_key)
2701 if ((res = RegDeleteTreeW( hkey_root, key )))
2703 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2705 return;
2708 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2710 if ((res = RegDeleteValueW( hkey, value )))
2712 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2714 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2715 NULL, NULL, NULL, NULL );
2716 RegCloseKey( hkey );
2717 if (!res && !num_subkeys && !num_values)
2719 TRACE("Removing empty key %s\n", debugstr_w(key));
2720 RegDeleteKeyW( hkey_root, key );
2722 return;
2724 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2728 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2730 MSIPACKAGE *package = param;
2731 LPCWSTR component, name, key_str, root_key_str;
2732 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2733 MSICOMPONENT *comp;
2734 MSIRECORD *uirow;
2735 BOOL delete_key = FALSE;
2736 HKEY hkey_root;
2737 UINT size;
2738 INT root;
2740 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2742 component = MSI_RecordGetString( row, 6 );
2743 comp = msi_get_loaded_component( package, component );
2744 if (!comp)
2745 return ERROR_SUCCESS;
2747 comp->Action = msi_get_component_action( package, comp );
2748 if (comp->Action != INSTALLSTATE_ABSENT)
2750 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2751 return ERROR_SUCCESS;
2754 name = MSI_RecordGetString( row, 4 );
2755 if (MSI_RecordIsNull( row, 5 ) && name )
2757 if (name[0] == '+' && !name[1])
2758 return ERROR_SUCCESS;
2759 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2761 delete_key = TRUE;
2762 name = NULL;
2766 root = MSI_RecordGetInteger( row, 2 );
2767 key_str = MSI_RecordGetString( row, 3 );
2769 root_key_str = get_root_key( package, root, &hkey_root );
2770 if (!root_key_str)
2771 return ERROR_SUCCESS;
2773 deformat_string( package, key_str, &deformated_key );
2774 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2775 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2776 strcpyW( ui_key_str, root_key_str );
2777 strcatW( ui_key_str, deformated_key );
2779 deformat_string( package, name, &deformated_name );
2781 keypath = get_keypath( package, hkey_root, deformated_key );
2782 msi_free( deformated_key );
2783 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2784 msi_free( keypath );
2786 uirow = MSI_CreateRecord( 2 );
2787 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2788 MSI_RecordSetStringW( uirow, 2, deformated_name );
2789 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2790 msiobj_release( &uirow->hdr );
2792 msi_free( ui_key_str );
2793 msi_free( deformated_name );
2794 return ERROR_SUCCESS;
2797 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2799 MSIPACKAGE *package = param;
2800 LPCWSTR component, name, key_str, root_key_str;
2801 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2802 MSICOMPONENT *comp;
2803 MSIRECORD *uirow;
2804 BOOL delete_key = FALSE;
2805 HKEY hkey_root;
2806 UINT size;
2807 INT root;
2809 component = MSI_RecordGetString( row, 5 );
2810 comp = msi_get_loaded_component( package, component );
2811 if (!comp)
2812 return ERROR_SUCCESS;
2814 comp->Action = msi_get_component_action( package, comp );
2815 if (comp->Action != INSTALLSTATE_LOCAL)
2817 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2818 return ERROR_SUCCESS;
2821 if ((name = MSI_RecordGetString( row, 4 )))
2823 if (name[0] == '-' && !name[1])
2825 delete_key = TRUE;
2826 name = NULL;
2830 root = MSI_RecordGetInteger( row, 2 );
2831 key_str = MSI_RecordGetString( row, 3 );
2833 root_key_str = get_root_key( package, root, &hkey_root );
2834 if (!root_key_str)
2835 return ERROR_SUCCESS;
2837 deformat_string( package, key_str, &deformated_key );
2838 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2839 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2840 strcpyW( ui_key_str, root_key_str );
2841 strcatW( ui_key_str, deformated_key );
2843 deformat_string( package, name, &deformated_name );
2845 keypath = get_keypath( package, hkey_root, deformated_key );
2846 msi_free( deformated_key );
2847 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2848 msi_free( keypath );
2850 uirow = MSI_CreateRecord( 2 );
2851 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2852 MSI_RecordSetStringW( uirow, 2, deformated_name );
2853 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2854 msiobj_release( &uirow->hdr );
2856 msi_free( ui_key_str );
2857 msi_free( deformated_name );
2858 return ERROR_SUCCESS;
2861 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2863 static const WCHAR registry_query[] = {
2864 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2865 '`','R','e','g','i','s','t','r','y','`',0};
2866 static const WCHAR remove_registry_query[] = {
2867 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2868 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2869 MSIQUERY *view;
2870 UINT rc;
2872 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2873 if (rc == ERROR_SUCCESS)
2875 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2876 msiobj_release( &view->hdr );
2877 if (rc != ERROR_SUCCESS)
2878 return rc;
2880 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2881 if (rc == ERROR_SUCCESS)
2883 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2884 msiobj_release( &view->hdr );
2885 if (rc != ERROR_SUCCESS)
2886 return rc;
2888 return ERROR_SUCCESS;
2891 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2893 package->script->CurrentlyScripting = TRUE;
2895 return ERROR_SUCCESS;
2899 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2901 static const WCHAR query[]= {
2902 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2903 '`','R','e','g','i','s','t','r','y','`',0};
2904 MSICOMPONENT *comp;
2905 DWORD total = 0, count = 0;
2906 MSIQUERY *view;
2907 MSIFEATURE *feature;
2908 MSIFILE *file;
2909 UINT rc;
2911 TRACE("InstallValidate\n");
2913 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2914 if (rc == ERROR_SUCCESS)
2916 rc = MSI_IterateRecords( view, &count, NULL, package );
2917 msiobj_release( &view->hdr );
2918 if (rc != ERROR_SUCCESS)
2919 return rc;
2920 total += count * REG_PROGRESS_VALUE;
2922 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2923 total += COMPONENT_PROGRESS_VALUE;
2925 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2926 total += file->FileSize;
2928 msi_ui_progress( package, 0, total, 0, 0 );
2930 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2932 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2933 debugstr_w(feature->Feature), feature->Installed,
2934 feature->ActionRequest, feature->Action);
2936 return ERROR_SUCCESS;
2939 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2941 MSIPACKAGE* package = param;
2942 LPCWSTR cond = NULL;
2943 LPCWSTR message = NULL;
2944 UINT r;
2946 static const WCHAR title[]=
2947 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2949 cond = MSI_RecordGetString(row,1);
2951 r = MSI_EvaluateConditionW(package,cond);
2952 if (r == MSICONDITION_FALSE)
2954 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2956 LPWSTR deformated;
2957 message = MSI_RecordGetString(row,2);
2958 deformat_string(package,message,&deformated);
2959 MessageBoxW(NULL,deformated,title,MB_OK);
2960 msi_free(deformated);
2963 return ERROR_INSTALL_FAILURE;
2966 return ERROR_SUCCESS;
2969 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2971 static const WCHAR query[] = {
2972 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2973 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2974 MSIQUERY *view;
2975 UINT rc;
2977 TRACE("Checking launch conditions\n");
2979 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2980 if (rc != ERROR_SUCCESS)
2981 return ERROR_SUCCESS;
2983 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2984 msiobj_release(&view->hdr);
2985 return rc;
2988 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2991 if (!cmp->KeyPath)
2992 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
2994 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2996 static const WCHAR query[] = {
2997 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2998 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
2999 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3000 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3001 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3002 MSIRECORD *row;
3003 UINT root, len;
3004 LPWSTR deformated, buffer, deformated_name;
3005 LPCWSTR key, name;
3007 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3008 if (!row)
3009 return NULL;
3011 root = MSI_RecordGetInteger(row,2);
3012 key = MSI_RecordGetString(row, 3);
3013 name = MSI_RecordGetString(row, 4);
3014 deformat_string(package, key , &deformated);
3015 deformat_string(package, name, &deformated_name);
3017 len = strlenW(deformated) + 6;
3018 if (deformated_name)
3019 len+=strlenW(deformated_name);
3021 buffer = msi_alloc( len *sizeof(WCHAR));
3023 if (deformated_name)
3024 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3025 else
3026 sprintfW(buffer,fmt,root,deformated);
3028 msi_free(deformated);
3029 msi_free(deformated_name);
3030 msiobj_release(&row->hdr);
3032 return buffer;
3034 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3036 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3037 return NULL;
3039 else
3041 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3043 if (file)
3044 return strdupW( file->TargetPath );
3046 return NULL;
3049 static HKEY openSharedDLLsKey(void)
3051 HKEY hkey=0;
3052 static const WCHAR path[] =
3053 {'S','o','f','t','w','a','r','e','\\',
3054 'M','i','c','r','o','s','o','f','t','\\',
3055 'W','i','n','d','o','w','s','\\',
3056 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3057 'S','h','a','r','e','d','D','L','L','s',0};
3059 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3060 return hkey;
3063 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3065 HKEY hkey;
3066 DWORD count=0;
3067 DWORD type;
3068 DWORD sz = sizeof(count);
3069 DWORD rc;
3071 hkey = openSharedDLLsKey();
3072 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3073 if (rc != ERROR_SUCCESS)
3074 count = 0;
3075 RegCloseKey(hkey);
3076 return count;
3079 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3081 HKEY hkey;
3083 hkey = openSharedDLLsKey();
3084 if (count > 0)
3085 msi_reg_set_val_dword( hkey, path, count );
3086 else
3087 RegDeleteValueW(hkey,path);
3088 RegCloseKey(hkey);
3089 return count;
3092 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3094 MSIFEATURE *feature;
3095 INT count = 0;
3096 BOOL write = FALSE;
3098 /* only refcount DLLs */
3099 if (comp->KeyPath == NULL ||
3100 comp->assembly ||
3101 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3102 comp->Attributes & msidbComponentAttributesODBCDataSource)
3103 write = FALSE;
3104 else
3106 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3107 write = (count > 0);
3109 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3110 write = TRUE;
3113 /* increment counts */
3114 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3116 ComponentList *cl;
3118 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3119 continue;
3121 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3123 if ( cl->component == comp )
3124 count++;
3128 /* decrement counts */
3129 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3131 ComponentList *cl;
3133 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3134 continue;
3136 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3138 if ( cl->component == comp )
3139 count--;
3143 /* ref count all the files in the component */
3144 if (write)
3146 MSIFILE *file;
3148 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3150 if (file->Component == comp)
3151 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3155 /* add a count for permanent */
3156 if (comp->Attributes & msidbComponentAttributesPermanent)
3157 count ++;
3159 comp->RefCount = count;
3161 if (write)
3162 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3165 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3167 if (comp->assembly)
3169 const WCHAR prefixW[] = {'<','\\',0};
3170 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3171 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3173 if (keypath)
3175 strcpyW( keypath, prefixW );
3176 strcatW( keypath, comp->assembly->display_name );
3178 return keypath;
3180 return resolve_keypath( package, comp );
3183 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3185 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3186 UINT rc;
3187 MSICOMPONENT *comp;
3188 HKEY hkey;
3190 TRACE("\n");
3192 squash_guid(package->ProductCode,squished_pc);
3193 msi_set_sourcedir_props(package, FALSE);
3195 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3197 MSIRECORD *uirow;
3198 INSTALLSTATE action;
3200 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3201 if (!comp->ComponentId)
3202 continue;
3204 squash_guid( comp->ComponentId, squished_cc );
3205 msi_free( comp->FullKeypath );
3206 comp->FullKeypath = build_full_keypath( package, comp );
3208 ACTION_RefCountComponent( package, comp );
3210 if (package->need_rollback) action = comp->Installed;
3211 else action = comp->ActionRequest;
3213 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3214 debugstr_w(comp->Component), debugstr_w(squished_cc),
3215 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3217 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3219 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3220 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3221 else
3222 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3224 if (rc != ERROR_SUCCESS)
3225 continue;
3227 if (comp->Attributes & msidbComponentAttributesPermanent)
3229 static const WCHAR szPermKey[] =
3230 { '0','0','0','0','0','0','0','0','0','0','0','0',
3231 '0','0','0','0','0','0','0','0','0','0','0','0',
3232 '0','0','0','0','0','0','0','0',0 };
3234 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3236 if (action == INSTALLSTATE_LOCAL)
3237 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3238 else
3240 MSIFILE *file;
3241 MSIRECORD *row;
3242 LPWSTR ptr, ptr2;
3243 WCHAR source[MAX_PATH];
3244 WCHAR base[MAX_PATH];
3245 LPWSTR sourcepath;
3247 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3248 static const WCHAR query[] = {
3249 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3250 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3251 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3252 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3253 '`','D','i','s','k','I','d','`',0};
3255 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3256 continue;
3258 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3259 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3260 ptr2 = strrchrW(source, '\\') + 1;
3261 msiobj_release(&row->hdr);
3263 lstrcpyW(base, package->PackagePath);
3264 ptr = strrchrW(base, '\\');
3265 *(ptr + 1) = '\0';
3267 sourcepath = msi_resolve_file_source(package, file);
3268 ptr = sourcepath + lstrlenW(base);
3269 lstrcpyW(ptr2, ptr);
3270 msi_free(sourcepath);
3272 msi_reg_set_val_str(hkey, squished_pc, source);
3274 RegCloseKey(hkey);
3276 else if (action == INSTALLSTATE_ABSENT)
3278 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3279 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3280 else
3281 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3284 /* UI stuff */
3285 uirow = MSI_CreateRecord(3);
3286 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3287 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3288 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3289 msi_ui_actiondata( package, szProcessComponents, uirow );
3290 msiobj_release( &uirow->hdr );
3292 return ERROR_SUCCESS;
3295 typedef struct {
3296 CLSID clsid;
3297 LPWSTR source;
3299 LPWSTR path;
3300 ITypeLib *ptLib;
3301 } typelib_struct;
3303 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3304 LPWSTR lpszName, LONG_PTR lParam)
3306 TLIBATTR *attr;
3307 typelib_struct *tl_struct = (typelib_struct*) lParam;
3308 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3309 int sz;
3310 HRESULT res;
3312 if (!IS_INTRESOURCE(lpszName))
3314 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3315 return TRUE;
3318 sz = strlenW(tl_struct->source)+4;
3319 sz *= sizeof(WCHAR);
3321 if ((INT_PTR)lpszName == 1)
3322 tl_struct->path = strdupW(tl_struct->source);
3323 else
3325 tl_struct->path = msi_alloc(sz);
3326 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3329 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3330 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3331 if (FAILED(res))
3333 msi_free(tl_struct->path);
3334 tl_struct->path = NULL;
3336 return TRUE;
3339 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3340 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3342 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3343 return FALSE;
3346 msi_free(tl_struct->path);
3347 tl_struct->path = NULL;
3349 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3350 ITypeLib_Release(tl_struct->ptLib);
3352 return TRUE;
3355 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3357 MSIPACKAGE* package = param;
3358 LPCWSTR component;
3359 MSICOMPONENT *comp;
3360 MSIFILE *file;
3361 typelib_struct tl_struct;
3362 ITypeLib *tlib;
3363 HMODULE module;
3364 HRESULT hr;
3366 component = MSI_RecordGetString(row,3);
3367 comp = msi_get_loaded_component(package,component);
3368 if (!comp)
3369 return ERROR_SUCCESS;
3371 comp->Action = msi_get_component_action( package, comp );
3372 if (comp->Action != INSTALLSTATE_LOCAL)
3374 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3375 return ERROR_SUCCESS;
3378 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3380 TRACE("component has no key path\n");
3381 return ERROR_SUCCESS;
3383 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3385 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3386 if (module)
3388 LPCWSTR guid;
3389 guid = MSI_RecordGetString(row,1);
3390 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3391 tl_struct.source = strdupW( file->TargetPath );
3392 tl_struct.path = NULL;
3394 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3395 (LONG_PTR)&tl_struct);
3397 if (tl_struct.path)
3399 LPCWSTR helpid, help_path = NULL;
3400 HRESULT res;
3402 helpid = MSI_RecordGetString(row,6);
3404 if (helpid) help_path = msi_get_target_folder( package, helpid );
3405 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3407 if (FAILED(res))
3408 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3409 else
3410 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3412 ITypeLib_Release(tl_struct.ptLib);
3413 msi_free(tl_struct.path);
3415 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3417 FreeLibrary(module);
3418 msi_free(tl_struct.source);
3420 else
3422 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3423 if (FAILED(hr))
3425 ERR("Failed to load type library: %08x\n", hr);
3426 return ERROR_INSTALL_FAILURE;
3429 ITypeLib_Release(tlib);
3432 return ERROR_SUCCESS;
3435 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3437 static const WCHAR query[] = {
3438 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3439 '`','T','y','p','e','L','i','b','`',0};
3440 MSIQUERY *view;
3441 UINT rc;
3443 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3444 if (rc != ERROR_SUCCESS)
3445 return ERROR_SUCCESS;
3447 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3448 msiobj_release(&view->hdr);
3449 return rc;
3452 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3454 MSIPACKAGE *package = param;
3455 LPCWSTR component, guid;
3456 MSICOMPONENT *comp;
3457 GUID libid;
3458 UINT version;
3459 LCID language;
3460 SYSKIND syskind;
3461 HRESULT hr;
3463 component = MSI_RecordGetString( row, 3 );
3464 comp = msi_get_loaded_component( package, component );
3465 if (!comp)
3466 return ERROR_SUCCESS;
3468 comp->Action = msi_get_component_action( package, comp );
3469 if (comp->Action != INSTALLSTATE_ABSENT)
3471 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3472 return ERROR_SUCCESS;
3474 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3476 guid = MSI_RecordGetString( row, 1 );
3477 CLSIDFromString( (LPCWSTR)guid, &libid );
3478 version = MSI_RecordGetInteger( row, 4 );
3479 language = MSI_RecordGetInteger( row, 2 );
3481 #ifdef _WIN64
3482 syskind = SYS_WIN64;
3483 #else
3484 syskind = SYS_WIN32;
3485 #endif
3487 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3488 if (FAILED(hr))
3490 WARN("Failed to unregister typelib: %08x\n", hr);
3493 return ERROR_SUCCESS;
3496 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3498 static const WCHAR query[] = {
3499 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3500 '`','T','y','p','e','L','i','b','`',0};
3501 MSIQUERY *view;
3502 UINT rc;
3504 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3505 if (rc != ERROR_SUCCESS)
3506 return ERROR_SUCCESS;
3508 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3509 msiobj_release( &view->hdr );
3510 return rc;
3513 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3515 static const WCHAR szlnk[] = {'.','l','n','k',0};
3516 LPCWSTR directory, extension, link_folder;
3517 LPWSTR link_file, filename;
3519 directory = MSI_RecordGetString( row, 2 );
3520 link_folder = msi_get_target_folder( package, directory );
3521 if (!link_folder)
3523 /* some installers use a separate root */
3524 MSIFOLDER *folder = msi_get_loaded_folder( package, directory );
3525 while (folder->Parent && strcmpW( folder->Parent, folder->Directory ))
3527 folder = msi_get_loaded_folder( package, folder->Parent );
3529 msi_resolve_target_folder( package, folder->Directory, TRUE );
3530 link_folder = msi_get_target_folder( package, directory );
3532 /* may be needed because of a bug somewhere else */
3533 msi_create_full_path( link_folder );
3535 filename = msi_dup_record_field( row, 3 );
3536 msi_reduce_to_long_filename( filename );
3538 extension = strchrW( filename, '.' );
3539 if (!extension || strcmpiW( extension, szlnk ))
3541 int len = strlenW( filename );
3542 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3543 memcpy( filename + len, szlnk, sizeof(szlnk) );
3545 link_file = msi_build_directory_name( 2, link_folder, filename );
3546 msi_free( filename );
3548 return link_file;
3551 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3553 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3554 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3555 WCHAR *folder, *dest, *path;
3557 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3558 folder = msi_dup_property( package->db, szWindowsFolder );
3559 else
3561 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3562 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3563 msi_free( appdata );
3565 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3566 msi_create_full_path( dest );
3567 path = msi_build_directory_name( 2, dest, icon_name );
3568 msi_free( folder );
3569 msi_free( dest );
3570 return path;
3573 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3575 MSIPACKAGE *package = param;
3576 LPWSTR link_file, deformated, path;
3577 LPCWSTR component, target;
3578 MSICOMPONENT *comp;
3579 IShellLinkW *sl = NULL;
3580 IPersistFile *pf = NULL;
3581 HRESULT res;
3583 component = MSI_RecordGetString(row, 4);
3584 comp = msi_get_loaded_component(package, component);
3585 if (!comp)
3586 return ERROR_SUCCESS;
3588 comp->Action = msi_get_component_action( package, comp );
3589 if (comp->Action != INSTALLSTATE_LOCAL)
3591 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3592 return ERROR_SUCCESS;
3594 msi_ui_actiondata( package, szCreateShortcuts, row );
3596 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3597 &IID_IShellLinkW, (LPVOID *) &sl );
3599 if (FAILED( res ))
3601 ERR("CLSID_ShellLink not available\n");
3602 goto err;
3605 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3606 if (FAILED( res ))
3608 ERR("QueryInterface(IID_IPersistFile) failed\n");
3609 goto err;
3612 target = MSI_RecordGetString(row, 5);
3613 if (strchrW(target, '['))
3615 deformat_string(package, target, &deformated);
3616 IShellLinkW_SetPath(sl,deformated);
3617 msi_free(deformated);
3619 else
3621 FIXME("poorly handled shortcut format, advertised shortcut\n");
3622 IShellLinkW_SetPath(sl,comp->FullKeypath);
3625 if (!MSI_RecordIsNull(row,6))
3627 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3628 deformat_string(package, arguments, &deformated);
3629 IShellLinkW_SetArguments(sl,deformated);
3630 msi_free(deformated);
3633 if (!MSI_RecordIsNull(row,7))
3635 LPCWSTR description = MSI_RecordGetString(row, 7);
3636 IShellLinkW_SetDescription(sl, description);
3639 if (!MSI_RecordIsNull(row,8))
3640 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3642 if (!MSI_RecordIsNull(row,9))
3644 INT index;
3645 LPCWSTR icon = MSI_RecordGetString(row, 9);
3647 path = msi_build_icon_path(package, icon);
3648 index = MSI_RecordGetInteger(row,10);
3650 /* no value means 0 */
3651 if (index == MSI_NULL_INTEGER)
3652 index = 0;
3654 IShellLinkW_SetIconLocation(sl, path, index);
3655 msi_free(path);
3658 if (!MSI_RecordIsNull(row,11))
3659 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3661 if (!MSI_RecordIsNull(row,12))
3663 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3664 full_path = msi_get_target_folder( package, wkdir );
3665 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3667 link_file = get_link_file(package, row);
3669 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3670 IPersistFile_Save(pf, link_file, FALSE);
3671 msi_free(link_file);
3673 err:
3674 if (pf)
3675 IPersistFile_Release( pf );
3676 if (sl)
3677 IShellLinkW_Release( sl );
3679 return ERROR_SUCCESS;
3682 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3684 static const WCHAR query[] = {
3685 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3686 '`','S','h','o','r','t','c','u','t','`',0};
3687 MSIQUERY *view;
3688 HRESULT res;
3689 UINT rc;
3691 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3692 if (rc != ERROR_SUCCESS)
3693 return ERROR_SUCCESS;
3695 res = CoInitialize( NULL );
3697 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3698 msiobj_release(&view->hdr);
3700 if (SUCCEEDED(res)) CoUninitialize();
3701 return rc;
3704 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3706 MSIPACKAGE *package = param;
3707 LPWSTR link_file;
3708 LPCWSTR component;
3709 MSICOMPONENT *comp;
3711 component = MSI_RecordGetString( row, 4 );
3712 comp = msi_get_loaded_component( package, component );
3713 if (!comp)
3714 return ERROR_SUCCESS;
3716 comp->Action = msi_get_component_action( package, comp );
3717 if (comp->Action != INSTALLSTATE_ABSENT)
3719 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3720 return ERROR_SUCCESS;
3722 msi_ui_actiondata( package, szRemoveShortcuts, row );
3724 link_file = get_link_file( package, row );
3726 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3727 if (!DeleteFileW( link_file ))
3729 WARN("Failed to remove shortcut file %u\n", GetLastError());
3731 msi_free( link_file );
3733 return ERROR_SUCCESS;
3736 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3738 static const WCHAR query[] = {
3739 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3740 '`','S','h','o','r','t','c','u','t','`',0};
3741 MSIQUERY *view;
3742 UINT rc;
3744 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3745 if (rc != ERROR_SUCCESS)
3746 return ERROR_SUCCESS;
3748 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3749 msiobj_release( &view->hdr );
3750 return rc;
3753 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3755 MSIPACKAGE* package = param;
3756 HANDLE the_file;
3757 LPWSTR FilePath;
3758 LPCWSTR FileName;
3759 CHAR buffer[1024];
3760 DWORD sz;
3761 UINT rc;
3763 FileName = MSI_RecordGetString(row,1);
3764 if (!FileName)
3766 ERR("Unable to get FileName\n");
3767 return ERROR_SUCCESS;
3770 FilePath = msi_build_icon_path(package, FileName);
3772 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3774 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3775 FILE_ATTRIBUTE_NORMAL, NULL);
3777 if (the_file == INVALID_HANDLE_VALUE)
3779 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3780 msi_free(FilePath);
3781 return ERROR_SUCCESS;
3786 DWORD write;
3787 sz = 1024;
3788 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3789 if (rc != ERROR_SUCCESS)
3791 ERR("Failed to get stream\n");
3792 CloseHandle(the_file);
3793 DeleteFileW(FilePath);
3794 break;
3796 WriteFile(the_file,buffer,sz,&write,NULL);
3797 } while (sz == 1024);
3799 msi_free(FilePath);
3800 CloseHandle(the_file);
3802 return ERROR_SUCCESS;
3805 static UINT msi_publish_icons(MSIPACKAGE *package)
3807 static const WCHAR query[]= {
3808 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3809 '`','I','c','o','n','`',0};
3810 MSIQUERY *view;
3811 UINT r;
3813 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3814 if (r == ERROR_SUCCESS)
3816 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3817 msiobj_release(&view->hdr);
3818 if (r != ERROR_SUCCESS)
3819 return r;
3821 return ERROR_SUCCESS;
3824 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3826 UINT r;
3827 HKEY source;
3828 LPWSTR buffer;
3829 MSIMEDIADISK *disk;
3830 MSISOURCELISTINFO *info;
3832 r = RegCreateKeyW(hkey, szSourceList, &source);
3833 if (r != ERROR_SUCCESS)
3834 return r;
3836 RegCloseKey(source);
3838 buffer = strrchrW(package->PackagePath, '\\') + 1;
3839 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3840 package->Context, MSICODE_PRODUCT,
3841 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3842 if (r != ERROR_SUCCESS)
3843 return r;
3845 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3846 package->Context, MSICODE_PRODUCT,
3847 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3848 if (r != ERROR_SUCCESS)
3849 return r;
3851 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3852 package->Context, MSICODE_PRODUCT,
3853 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3854 if (r != ERROR_SUCCESS)
3855 return r;
3857 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3859 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3860 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3861 info->options, info->value);
3862 else
3863 MsiSourceListSetInfoW(package->ProductCode, NULL,
3864 info->context, info->options,
3865 info->property, info->value);
3868 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3870 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3871 disk->context, disk->options,
3872 disk->disk_id, disk->volume_label, disk->disk_prompt);
3875 return ERROR_SUCCESS;
3878 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3880 MSIHANDLE hdb, suminfo;
3881 WCHAR guids[MAX_PATH];
3882 WCHAR packcode[SQUISH_GUID_SIZE];
3883 LPWSTR buffer;
3884 LPWSTR ptr;
3885 DWORD langid;
3886 DWORD size;
3887 UINT r;
3889 static const WCHAR szARPProductIcon[] =
3890 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3891 static const WCHAR szAssignment[] =
3892 {'A','s','s','i','g','n','m','e','n','t',0};
3893 static const WCHAR szAdvertiseFlags[] =
3894 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3895 static const WCHAR szClients[] =
3896 {'C','l','i','e','n','t','s',0};
3897 static const WCHAR szColon[] = {':',0};
3899 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3900 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3901 msi_free(buffer);
3903 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3904 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3906 /* FIXME */
3907 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3909 buffer = msi_dup_property(package->db, szARPProductIcon);
3910 if (buffer)
3912 LPWSTR path = msi_build_icon_path(package, buffer);
3913 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3914 msi_free(path);
3915 msi_free(buffer);
3918 buffer = msi_dup_property(package->db, szProductVersion);
3919 if (buffer)
3921 DWORD verdword = msi_version_str_to_dword(buffer);
3922 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3923 msi_free(buffer);
3926 msi_reg_set_val_dword(hkey, szAssignment, 0);
3927 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3928 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3929 msi_reg_set_val_str(hkey, szClients, szColon);
3931 hdb = alloc_msihandle(&package->db->hdr);
3932 if (!hdb)
3933 return ERROR_NOT_ENOUGH_MEMORY;
3935 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3936 MsiCloseHandle(hdb);
3937 if (r != ERROR_SUCCESS)
3938 goto done;
3940 size = MAX_PATH;
3941 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3942 NULL, guids, &size);
3943 if (r != ERROR_SUCCESS)
3944 goto done;
3946 ptr = strchrW(guids, ';');
3947 if (ptr) *ptr = 0;
3948 squash_guid(guids, packcode);
3949 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3951 done:
3952 MsiCloseHandle(suminfo);
3953 return ERROR_SUCCESS;
3956 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3958 UINT r;
3959 HKEY hkey;
3960 LPWSTR upgrade;
3961 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3963 upgrade = msi_dup_property(package->db, szUpgradeCode);
3964 if (!upgrade)
3965 return ERROR_SUCCESS;
3967 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3968 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3969 else
3970 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3972 if (r != ERROR_SUCCESS)
3974 WARN("failed to open upgrade code key\n");
3975 msi_free(upgrade);
3976 return ERROR_SUCCESS;
3978 squash_guid(package->ProductCode, squashed_pc);
3979 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3980 RegCloseKey(hkey);
3981 msi_free(upgrade);
3982 return ERROR_SUCCESS;
3985 static BOOL msi_check_publish(MSIPACKAGE *package)
3987 MSIFEATURE *feature;
3989 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3991 feature->Action = msi_get_feature_action( package, feature );
3992 if (feature->Action == INSTALLSTATE_LOCAL)
3993 return TRUE;
3996 return FALSE;
3999 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4001 MSIFEATURE *feature;
4003 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4005 feature->Action = msi_get_feature_action( package, feature );
4006 if (feature->Action != INSTALLSTATE_ABSENT)
4007 return FALSE;
4010 return TRUE;
4013 static UINT msi_publish_patches( MSIPACKAGE *package )
4015 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4016 WCHAR patch_squashed[GUID_SIZE];
4017 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4018 LONG res;
4019 MSIPATCHINFO *patch;
4020 UINT r;
4021 WCHAR *p, *all_patches = NULL;
4022 DWORD len = 0;
4024 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4025 if (r != ERROR_SUCCESS)
4026 return ERROR_FUNCTION_FAILED;
4028 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4029 if (res != ERROR_SUCCESS)
4031 r = ERROR_FUNCTION_FAILED;
4032 goto done;
4035 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4036 if (r != ERROR_SUCCESS)
4037 goto done;
4039 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4041 squash_guid( patch->patchcode, patch_squashed );
4042 len += strlenW( patch_squashed ) + 1;
4045 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4046 if (!all_patches)
4047 goto done;
4049 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4051 HKEY patch_key;
4053 squash_guid( patch->patchcode, p );
4054 p += strlenW( p ) + 1;
4056 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4057 (const BYTE *)patch->transforms,
4058 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4059 if (res != ERROR_SUCCESS)
4060 goto done;
4062 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4063 if (r != ERROR_SUCCESS)
4064 goto done;
4066 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4067 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4068 RegCloseKey( patch_key );
4069 if (res != ERROR_SUCCESS)
4070 goto done;
4072 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4074 res = GetLastError();
4075 ERR("Unable to copy patch package %d\n", res);
4076 goto done;
4078 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4079 if (res != ERROR_SUCCESS)
4080 goto done;
4082 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4083 RegCloseKey( patch_key );
4084 if (res != ERROR_SUCCESS)
4085 goto done;
4088 all_patches[len] = 0;
4089 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4090 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4091 if (res != ERROR_SUCCESS)
4092 goto done;
4094 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4095 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4096 if (res != ERROR_SUCCESS)
4097 r = ERROR_FUNCTION_FAILED;
4099 done:
4100 RegCloseKey( product_patches_key );
4101 RegCloseKey( patches_key );
4102 RegCloseKey( product_key );
4103 msi_free( all_patches );
4104 return r;
4107 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4109 UINT rc;
4110 HKEY hukey = NULL, hudkey = NULL;
4111 MSIRECORD *uirow;
4113 if (!list_empty(&package->patches))
4115 rc = msi_publish_patches(package);
4116 if (rc != ERROR_SUCCESS)
4117 goto end;
4120 /* FIXME: also need to publish if the product is in advertise mode */
4121 if (!msi_check_publish(package))
4122 return ERROR_SUCCESS;
4124 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4125 &hukey, TRUE);
4126 if (rc != ERROR_SUCCESS)
4127 goto end;
4129 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4130 NULL, &hudkey, TRUE);
4131 if (rc != ERROR_SUCCESS)
4132 goto end;
4134 rc = msi_publish_upgrade_code(package);
4135 if (rc != ERROR_SUCCESS)
4136 goto end;
4138 rc = msi_publish_product_properties(package, hukey);
4139 if (rc != ERROR_SUCCESS)
4140 goto end;
4142 rc = msi_publish_sourcelist(package, hukey);
4143 if (rc != ERROR_SUCCESS)
4144 goto end;
4146 rc = msi_publish_icons(package);
4148 end:
4149 uirow = MSI_CreateRecord( 1 );
4150 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4151 msi_ui_actiondata( package, szPublishProduct, uirow );
4152 msiobj_release( &uirow->hdr );
4154 RegCloseKey(hukey);
4155 RegCloseKey(hudkey);
4156 return rc;
4159 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4161 WCHAR *filename, *ptr, *folder, *ret;
4162 const WCHAR *dirprop;
4164 filename = msi_dup_record_field( row, 2 );
4165 if (filename && (ptr = strchrW( filename, '|' )))
4166 ptr++;
4167 else
4168 ptr = filename;
4170 dirprop = MSI_RecordGetString( row, 3 );
4171 if (dirprop)
4173 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4174 if (!folder) folder = msi_dup_property( package->db, dirprop );
4176 else
4177 folder = msi_dup_property( package->db, szWindowsFolder );
4179 if (!folder)
4181 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4182 msi_free( filename );
4183 return NULL;
4186 ret = msi_build_directory_name( 2, folder, ptr );
4188 msi_free( filename );
4189 msi_free( folder );
4190 return ret;
4193 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4195 MSIPACKAGE *package = param;
4196 LPCWSTR component, section, key, value, identifier;
4197 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4198 MSIRECORD * uirow;
4199 INT action;
4200 MSICOMPONENT *comp;
4202 component = MSI_RecordGetString(row, 8);
4203 comp = msi_get_loaded_component(package,component);
4204 if (!comp)
4205 return ERROR_SUCCESS;
4207 comp->Action = msi_get_component_action( package, comp );
4208 if (comp->Action != INSTALLSTATE_LOCAL)
4210 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4211 return ERROR_SUCCESS;
4214 identifier = MSI_RecordGetString(row,1);
4215 section = MSI_RecordGetString(row,4);
4216 key = MSI_RecordGetString(row,5);
4217 value = MSI_RecordGetString(row,6);
4218 action = MSI_RecordGetInteger(row,7);
4220 deformat_string(package,section,&deformated_section);
4221 deformat_string(package,key,&deformated_key);
4222 deformat_string(package,value,&deformated_value);
4224 fullname = get_ini_file_name(package, row);
4226 if (action == 0)
4228 TRACE("Adding value %s to section %s in %s\n",
4229 debugstr_w(deformated_key), debugstr_w(deformated_section),
4230 debugstr_w(fullname));
4231 WritePrivateProfileStringW(deformated_section, deformated_key,
4232 deformated_value, fullname);
4234 else if (action == 1)
4236 WCHAR returned[10];
4237 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4238 returned, 10, fullname);
4239 if (returned[0] == 0)
4241 TRACE("Adding value %s to section %s in %s\n",
4242 debugstr_w(deformated_key), debugstr_w(deformated_section),
4243 debugstr_w(fullname));
4245 WritePrivateProfileStringW(deformated_section, deformated_key,
4246 deformated_value, fullname);
4249 else if (action == 3)
4250 FIXME("Append to existing section not yet implemented\n");
4252 uirow = MSI_CreateRecord(4);
4253 MSI_RecordSetStringW(uirow,1,identifier);
4254 MSI_RecordSetStringW(uirow,2,deformated_section);
4255 MSI_RecordSetStringW(uirow,3,deformated_key);
4256 MSI_RecordSetStringW(uirow,4,deformated_value);
4257 msi_ui_actiondata( package, szWriteIniValues, uirow );
4258 msiobj_release( &uirow->hdr );
4260 msi_free(fullname);
4261 msi_free(deformated_key);
4262 msi_free(deformated_value);
4263 msi_free(deformated_section);
4264 return ERROR_SUCCESS;
4267 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4269 static const WCHAR query[] = {
4270 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4271 '`','I','n','i','F','i','l','e','`',0};
4272 MSIQUERY *view;
4273 UINT rc;
4275 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4276 if (rc != ERROR_SUCCESS)
4277 return ERROR_SUCCESS;
4279 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4280 msiobj_release(&view->hdr);
4281 return rc;
4284 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4286 MSIPACKAGE *package = param;
4287 LPCWSTR component, section, key, value, identifier;
4288 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4289 MSICOMPONENT *comp;
4290 MSIRECORD *uirow;
4291 INT action;
4293 component = MSI_RecordGetString( row, 8 );
4294 comp = msi_get_loaded_component( package, component );
4295 if (!comp)
4296 return ERROR_SUCCESS;
4298 comp->Action = msi_get_component_action( package, comp );
4299 if (comp->Action != INSTALLSTATE_ABSENT)
4301 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4302 return ERROR_SUCCESS;
4305 identifier = MSI_RecordGetString( row, 1 );
4306 section = MSI_RecordGetString( row, 4 );
4307 key = MSI_RecordGetString( row, 5 );
4308 value = MSI_RecordGetString( row, 6 );
4309 action = MSI_RecordGetInteger( row, 7 );
4311 deformat_string( package, section, &deformated_section );
4312 deformat_string( package, key, &deformated_key );
4313 deformat_string( package, value, &deformated_value );
4315 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4317 filename = get_ini_file_name( package, row );
4319 TRACE("Removing key %s from section %s in %s\n",
4320 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4322 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4324 WARN("Unable to remove key %u\n", GetLastError());
4326 msi_free( filename );
4328 else
4329 FIXME("Unsupported action %d\n", action);
4332 uirow = MSI_CreateRecord( 4 );
4333 MSI_RecordSetStringW( uirow, 1, identifier );
4334 MSI_RecordSetStringW( uirow, 2, deformated_section );
4335 MSI_RecordSetStringW( uirow, 3, deformated_key );
4336 MSI_RecordSetStringW( uirow, 4, deformated_value );
4337 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4338 msiobj_release( &uirow->hdr );
4340 msi_free( deformated_key );
4341 msi_free( deformated_value );
4342 msi_free( deformated_section );
4343 return ERROR_SUCCESS;
4346 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4348 MSIPACKAGE *package = param;
4349 LPCWSTR component, section, key, value, identifier;
4350 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4351 MSICOMPONENT *comp;
4352 MSIRECORD *uirow;
4353 INT action;
4355 component = MSI_RecordGetString( row, 8 );
4356 comp = msi_get_loaded_component( package, component );
4357 if (!comp)
4358 return ERROR_SUCCESS;
4360 comp->Action = msi_get_component_action( package, comp );
4361 if (comp->Action != INSTALLSTATE_LOCAL)
4363 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4364 return ERROR_SUCCESS;
4367 identifier = MSI_RecordGetString( row, 1 );
4368 section = MSI_RecordGetString( row, 4 );
4369 key = MSI_RecordGetString( row, 5 );
4370 value = MSI_RecordGetString( row, 6 );
4371 action = MSI_RecordGetInteger( row, 7 );
4373 deformat_string( package, section, &deformated_section );
4374 deformat_string( package, key, &deformated_key );
4375 deformat_string( package, value, &deformated_value );
4377 if (action == msidbIniFileActionRemoveLine)
4379 filename = get_ini_file_name( package, row );
4381 TRACE("Removing key %s from section %s in %s\n",
4382 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4384 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4386 WARN("Unable to remove key %u\n", GetLastError());
4388 msi_free( filename );
4390 else
4391 FIXME("Unsupported action %d\n", action);
4393 uirow = MSI_CreateRecord( 4 );
4394 MSI_RecordSetStringW( uirow, 1, identifier );
4395 MSI_RecordSetStringW( uirow, 2, deformated_section );
4396 MSI_RecordSetStringW( uirow, 3, deformated_key );
4397 MSI_RecordSetStringW( uirow, 4, deformated_value );
4398 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4399 msiobj_release( &uirow->hdr );
4401 msi_free( deformated_key );
4402 msi_free( deformated_value );
4403 msi_free( deformated_section );
4404 return ERROR_SUCCESS;
4407 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4409 static const WCHAR query[] = {
4410 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4411 '`','I','n','i','F','i','l','e','`',0};
4412 static const WCHAR remove_query[] = {
4413 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4414 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4415 MSIQUERY *view;
4416 UINT rc;
4418 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4419 if (rc == ERROR_SUCCESS)
4421 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4422 msiobj_release( &view->hdr );
4423 if (rc != ERROR_SUCCESS)
4424 return rc;
4426 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4427 if (rc == ERROR_SUCCESS)
4429 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4430 msiobj_release( &view->hdr );
4431 if (rc != ERROR_SUCCESS)
4432 return rc;
4434 return ERROR_SUCCESS;
4437 static void register_dll( const WCHAR *dll, BOOL unregister )
4439 HMODULE hmod;
4441 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4442 if (hmod)
4444 HRESULT (WINAPI *func_ptr)( void );
4445 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4447 func_ptr = (void *)GetProcAddress( hmod, func );
4448 if (func_ptr)
4450 HRESULT hr = func_ptr();
4451 if (FAILED( hr ))
4452 WARN("failed to register dll 0x%08x\n", hr);
4454 else
4455 WARN("entry point %s not found\n", func);
4456 FreeLibrary( hmod );
4457 return;
4459 WARN("failed to load library %u\n", GetLastError());
4462 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4464 MSIPACKAGE *package = param;
4465 LPCWSTR filename;
4466 MSIFILE *file;
4467 MSIRECORD *uirow;
4469 filename = MSI_RecordGetString(row,1);
4470 file = msi_get_loaded_file( package, filename );
4471 if (!file)
4473 WARN("unable to find file %s\n", debugstr_w(filename));
4474 return ERROR_SUCCESS;
4476 file->Component->Action = msi_get_component_action( package, file->Component );
4477 if (file->Component->Action != INSTALLSTATE_LOCAL)
4479 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4480 return ERROR_SUCCESS;
4483 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4484 register_dll( file->TargetPath, FALSE );
4486 uirow = MSI_CreateRecord( 2 );
4487 MSI_RecordSetStringW( uirow, 1, filename );
4488 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4489 msi_ui_actiondata( package, szSelfRegModules, uirow );
4490 msiobj_release( &uirow->hdr );
4492 return ERROR_SUCCESS;
4495 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4497 static const WCHAR query[] = {
4498 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4499 '`','S','e','l','f','R','e','g','`',0};
4500 MSIQUERY *view;
4501 UINT rc;
4503 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4504 if (rc != ERROR_SUCCESS)
4505 return ERROR_SUCCESS;
4507 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4508 msiobj_release(&view->hdr);
4509 return rc;
4512 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4514 MSIPACKAGE *package = param;
4515 LPCWSTR filename;
4516 MSIFILE *file;
4517 MSIRECORD *uirow;
4519 filename = MSI_RecordGetString( row, 1 );
4520 file = msi_get_loaded_file( package, filename );
4521 if (!file)
4523 WARN("unable to find file %s\n", debugstr_w(filename));
4524 return ERROR_SUCCESS;
4526 file->Component->Action = msi_get_component_action( package, file->Component );
4527 if (file->Component->Action != INSTALLSTATE_ABSENT)
4529 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4530 return ERROR_SUCCESS;
4533 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4534 register_dll( file->TargetPath, TRUE );
4536 uirow = MSI_CreateRecord( 2 );
4537 MSI_RecordSetStringW( uirow, 1, filename );
4538 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4539 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4540 msiobj_release( &uirow->hdr );
4542 return ERROR_SUCCESS;
4545 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4547 static const WCHAR query[] = {
4548 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4549 '`','S','e','l','f','R','e','g','`',0};
4550 MSIQUERY *view;
4551 UINT rc;
4553 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4554 if (rc != ERROR_SUCCESS)
4555 return ERROR_SUCCESS;
4557 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4558 msiobj_release( &view->hdr );
4559 return rc;
4562 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4564 MSIFEATURE *feature;
4565 UINT rc;
4566 HKEY hkey = NULL, userdata = NULL;
4568 if (!msi_check_publish(package))
4569 return ERROR_SUCCESS;
4571 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4572 &hkey, TRUE);
4573 if (rc != ERROR_SUCCESS)
4574 goto end;
4576 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4577 &userdata, TRUE);
4578 if (rc != ERROR_SUCCESS)
4579 goto end;
4581 /* here the guids are base 85 encoded */
4582 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4584 ComponentList *cl;
4585 LPWSTR data = NULL;
4586 GUID clsid;
4587 INT size;
4588 BOOL absent = FALSE;
4589 MSIRECORD *uirow;
4591 if (feature->Action != INSTALLSTATE_LOCAL &&
4592 feature->Action != INSTALLSTATE_SOURCE &&
4593 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4595 size = 1;
4596 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4598 size += 21;
4600 if (feature->Feature_Parent)
4601 size += strlenW( feature->Feature_Parent )+2;
4603 data = msi_alloc(size * sizeof(WCHAR));
4605 data[0] = 0;
4606 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4608 MSICOMPONENT* component = cl->component;
4609 WCHAR buf[21];
4611 buf[0] = 0;
4612 if (component->ComponentId)
4614 TRACE("From %s\n",debugstr_w(component->ComponentId));
4615 CLSIDFromString(component->ComponentId, &clsid);
4616 encode_base85_guid(&clsid,buf);
4617 TRACE("to %s\n",debugstr_w(buf));
4618 strcatW(data,buf);
4622 if (feature->Feature_Parent)
4624 static const WCHAR sep[] = {'\2',0};
4625 strcatW(data,sep);
4626 strcatW(data,feature->Feature_Parent);
4629 msi_reg_set_val_str( userdata, feature->Feature, data );
4630 msi_free(data);
4632 size = 0;
4633 if (feature->Feature_Parent)
4634 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4635 if (!absent)
4637 size += sizeof(WCHAR);
4638 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4639 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4641 else
4643 size += 2*sizeof(WCHAR);
4644 data = msi_alloc(size);
4645 data[0] = 0x6;
4646 data[1] = 0;
4647 if (feature->Feature_Parent)
4648 strcpyW( &data[1], feature->Feature_Parent );
4649 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4650 (LPBYTE)data,size);
4651 msi_free(data);
4654 /* the UI chunk */
4655 uirow = MSI_CreateRecord( 1 );
4656 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4657 msi_ui_actiondata( package, szPublishFeatures, uirow );
4658 msiobj_release( &uirow->hdr );
4659 /* FIXME: call msi_ui_progress? */
4662 end:
4663 RegCloseKey(hkey);
4664 RegCloseKey(userdata);
4665 return rc;
4668 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4670 UINT r;
4671 HKEY hkey;
4672 MSIRECORD *uirow;
4674 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4676 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4677 &hkey, FALSE);
4678 if (r == ERROR_SUCCESS)
4680 RegDeleteValueW(hkey, feature->Feature);
4681 RegCloseKey(hkey);
4684 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4685 &hkey, FALSE);
4686 if (r == ERROR_SUCCESS)
4688 RegDeleteValueW(hkey, feature->Feature);
4689 RegCloseKey(hkey);
4692 uirow = MSI_CreateRecord( 1 );
4693 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4694 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4695 msiobj_release( &uirow->hdr );
4697 return ERROR_SUCCESS;
4700 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4702 MSIFEATURE *feature;
4704 if (!msi_check_unpublish(package))
4705 return ERROR_SUCCESS;
4707 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4709 msi_unpublish_feature(package, feature);
4712 return ERROR_SUCCESS;
4715 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4717 SYSTEMTIME systime;
4718 DWORD size, langid;
4719 WCHAR date[9], *val, *buffer;
4720 const WCHAR *prop, *key;
4722 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4723 static const WCHAR modpath_fmt[] =
4724 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4725 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4726 static const WCHAR szModifyPath[] =
4727 {'M','o','d','i','f','y','P','a','t','h',0};
4728 static const WCHAR szUninstallString[] =
4729 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4730 static const WCHAR szEstimatedSize[] =
4731 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4732 static const WCHAR szDisplayVersion[] =
4733 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4734 static const WCHAR szInstallSource[] =
4735 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4736 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4737 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4738 static const WCHAR szAuthorizedCDFPrefix[] =
4739 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4740 static const WCHAR szARPCONTACT[] =
4741 {'A','R','P','C','O','N','T','A','C','T',0};
4742 static const WCHAR szContact[] =
4743 {'C','o','n','t','a','c','t',0};
4744 static const WCHAR szARPCOMMENTS[] =
4745 {'A','R','P','C','O','M','M','E','N','T','S',0};
4746 static const WCHAR szComments[] =
4747 {'C','o','m','m','e','n','t','s',0};
4748 static const WCHAR szProductName[] =
4749 {'P','r','o','d','u','c','t','N','a','m','e',0};
4750 static const WCHAR szDisplayName[] =
4751 {'D','i','s','p','l','a','y','N','a','m','e',0};
4752 static const WCHAR szARPHELPLINK[] =
4753 {'A','R','P','H','E','L','P','L','I','N','K',0};
4754 static const WCHAR szHelpLink[] =
4755 {'H','e','l','p','L','i','n','k',0};
4756 static const WCHAR szARPHELPTELEPHONE[] =
4757 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4758 static const WCHAR szHelpTelephone[] =
4759 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4760 static const WCHAR szARPINSTALLLOCATION[] =
4761 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4762 static const WCHAR szInstallLocation[] =
4763 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4764 static const WCHAR szManufacturer[] =
4765 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4766 static const WCHAR szPublisher[] =
4767 {'P','u','b','l','i','s','h','e','r',0};
4768 static const WCHAR szARPREADME[] =
4769 {'A','R','P','R','E','A','D','M','E',0};
4770 static const WCHAR szReadme[] =
4771 {'R','e','a','d','M','e',0};
4772 static const WCHAR szARPSIZE[] =
4773 {'A','R','P','S','I','Z','E',0};
4774 static const WCHAR szSize[] =
4775 {'S','i','z','e',0};
4776 static const WCHAR szARPURLINFOABOUT[] =
4777 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4778 static const WCHAR szURLInfoAbout[] =
4779 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4780 static const WCHAR szARPURLUPDATEINFO[] =
4781 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4782 static const WCHAR szURLUpdateInfo[] =
4783 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4784 static const WCHAR szARPSYSTEMCOMPONENT[] =
4785 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4786 static const WCHAR szSystemComponent[] =
4787 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4789 static const WCHAR *propval[] = {
4790 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4791 szARPCONTACT, szContact,
4792 szARPCOMMENTS, szComments,
4793 szProductName, szDisplayName,
4794 szARPHELPLINK, szHelpLink,
4795 szARPHELPTELEPHONE, szHelpTelephone,
4796 szARPINSTALLLOCATION, szInstallLocation,
4797 szSourceDir, szInstallSource,
4798 szManufacturer, szPublisher,
4799 szARPREADME, szReadme,
4800 szARPSIZE, szSize,
4801 szARPURLINFOABOUT, szURLInfoAbout,
4802 szARPURLUPDATEINFO, szURLUpdateInfo,
4803 NULL
4805 const WCHAR **p = propval;
4807 while (*p)
4809 prop = *p++;
4810 key = *p++;
4811 val = msi_dup_property(package->db, prop);
4812 msi_reg_set_val_str(hkey, key, val);
4813 msi_free(val);
4816 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4817 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4819 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4821 size = deformat_string(package, modpath_fmt, &buffer);
4822 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4823 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4824 msi_free(buffer);
4826 /* FIXME: Write real Estimated Size when we have it */
4827 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4829 GetLocalTime(&systime);
4830 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4831 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4833 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4834 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4836 buffer = msi_dup_property(package->db, szProductVersion);
4837 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4838 if (buffer)
4840 DWORD verdword = msi_version_str_to_dword(buffer);
4842 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4843 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4844 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4845 msi_free(buffer);
4848 return ERROR_SUCCESS;
4851 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4853 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4854 MSIRECORD *uirow;
4855 LPWSTR upgrade_code;
4856 HKEY hkey, props, upgrade_key;
4857 UINT rc;
4859 /* FIXME: also need to publish if the product is in advertise mode */
4860 if (!msi_check_publish(package))
4861 return ERROR_SUCCESS;
4863 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4864 if (rc != ERROR_SUCCESS)
4865 return rc;
4867 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4868 if (rc != ERROR_SUCCESS)
4869 goto done;
4871 rc = msi_publish_install_properties(package, hkey);
4872 if (rc != ERROR_SUCCESS)
4873 goto done;
4875 rc = msi_publish_install_properties(package, props);
4876 if (rc != ERROR_SUCCESS)
4877 goto done;
4879 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4880 if (upgrade_code)
4882 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4883 if (rc == ERROR_SUCCESS)
4885 squash_guid( package->ProductCode, squashed_pc );
4886 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4887 RegCloseKey( upgrade_key );
4889 msi_free( upgrade_code );
4891 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4892 package->delete_on_close = FALSE;
4894 done:
4895 uirow = MSI_CreateRecord( 1 );
4896 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4897 msi_ui_actiondata( package, szRegisterProduct, uirow );
4898 msiobj_release( &uirow->hdr );
4900 RegCloseKey(hkey);
4901 return ERROR_SUCCESS;
4904 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4906 return execute_script(package,INSTALL_SCRIPT);
4909 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4911 MSIPACKAGE *package = param;
4912 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4913 WCHAR *p, *icon_path;
4915 if (!icon) return ERROR_SUCCESS;
4916 if ((icon_path = msi_build_icon_path( package, icon )))
4918 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4919 DeleteFileW( icon_path );
4920 if ((p = strrchrW( icon_path, '\\' )))
4922 *p = 0;
4923 RemoveDirectoryW( icon_path );
4925 msi_free( icon_path );
4927 return ERROR_SUCCESS;
4930 static UINT msi_unpublish_icons( MSIPACKAGE *package )
4932 static const WCHAR query[]= {
4933 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
4934 MSIQUERY *view;
4935 UINT r;
4937 r = MSI_DatabaseOpenViewW( package->db, query, &view );
4938 if (r == ERROR_SUCCESS)
4940 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4941 msiobj_release( &view->hdr );
4942 if (r != ERROR_SUCCESS)
4943 return r;
4945 return ERROR_SUCCESS;
4948 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4950 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4951 WCHAR *upgrade, **features;
4952 BOOL full_uninstall = TRUE;
4953 MSIFEATURE *feature;
4954 MSIPATCHINFO *patch;
4955 UINT i;
4957 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4959 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4961 features = msi_split_string( remove, ',' );
4962 for (i = 0; features && features[i]; i++)
4964 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4966 msi_free(features);
4968 if (!full_uninstall)
4969 return ERROR_SUCCESS;
4971 MSIREG_DeleteProductKey(package->ProductCode);
4972 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4973 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4975 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4976 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4977 MSIREG_DeleteUserProductKey(package->ProductCode);
4978 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4980 upgrade = msi_dup_property(package->db, szUpgradeCode);
4981 if (upgrade)
4983 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4984 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4985 msi_free(upgrade);
4988 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4990 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4991 if (!strcmpW( package->ProductCode, patch->products ))
4993 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
4994 patch->delete_on_close = TRUE;
4996 /* FIXME: remove local patch package if this is the last product */
4998 TRACE("removing local package %s\n", debugstr_w(package->localfile));
4999 package->delete_on_close = TRUE;
5001 msi_unpublish_icons( package );
5002 return ERROR_SUCCESS;
5005 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5007 UINT rc;
5008 WCHAR *remove;
5010 /* turn off scheduling */
5011 package->script->CurrentlyScripting= FALSE;
5013 /* first do the same as an InstallExecute */
5014 rc = ACTION_InstallExecute(package);
5015 if (rc != ERROR_SUCCESS)
5016 return rc;
5018 /* then handle Commit Actions */
5019 rc = execute_script(package,COMMIT_SCRIPT);
5020 if (rc != ERROR_SUCCESS)
5021 return rc;
5023 remove = msi_dup_property(package->db, szRemove);
5024 rc = msi_unpublish_product(package, remove);
5025 msi_free(remove);
5026 return rc;
5029 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5031 static const WCHAR RunOnce[] = {
5032 'S','o','f','t','w','a','r','e','\\',
5033 'M','i','c','r','o','s','o','f','t','\\',
5034 'W','i','n','d','o','w','s','\\',
5035 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5036 'R','u','n','O','n','c','e',0};
5037 static const WCHAR InstallRunOnce[] = {
5038 'S','o','f','t','w','a','r','e','\\',
5039 'M','i','c','r','o','s','o','f','t','\\',
5040 'W','i','n','d','o','w','s','\\',
5041 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5042 'I','n','s','t','a','l','l','e','r','\\',
5043 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5045 static const WCHAR msiexec_fmt[] = {
5046 '%','s',
5047 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5048 '\"','%','s','\"',0};
5049 static const WCHAR install_fmt[] = {
5050 '/','I',' ','\"','%','s','\"',' ',
5051 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5052 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5053 WCHAR buffer[256], sysdir[MAX_PATH];
5054 HKEY hkey;
5055 WCHAR squished_pc[100];
5057 squash_guid(package->ProductCode,squished_pc);
5059 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5060 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5061 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5062 squished_pc);
5064 msi_reg_set_val_str( hkey, squished_pc, buffer );
5065 RegCloseKey(hkey);
5067 TRACE("Reboot command %s\n",debugstr_w(buffer));
5069 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5070 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5072 msi_reg_set_val_str( hkey, squished_pc, buffer );
5073 RegCloseKey(hkey);
5075 return ERROR_INSTALL_SUSPEND;
5078 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5080 static const WCHAR query[] =
5081 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5082 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5083 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5084 MSIRECORD *rec, *row;
5085 DWORD i, size = 0;
5086 va_list va;
5087 const WCHAR *str;
5088 WCHAR *data;
5090 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5092 rec = MSI_CreateRecord( count + 2 );
5093 str = MSI_RecordGetString( row, 1 );
5094 MSI_RecordSetStringW( rec, 0, str );
5095 msiobj_release( &row->hdr );
5096 MSI_RecordSetInteger( rec, 1, error );
5098 va_start( va, count );
5099 for (i = 0; i < count; i++)
5101 str = va_arg( va, const WCHAR *);
5102 MSI_RecordSetStringW( rec, i + 2, str );
5104 va_end( va );
5106 MSI_FormatRecordW( package, rec, NULL, &size );
5107 size++;
5108 data = msi_alloc( size * sizeof(WCHAR) );
5109 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5110 else data[0] = 0;
5111 msiobj_release( &rec->hdr );
5112 return data;
5115 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5117 DWORD attrib;
5118 UINT rc;
5121 * We are currently doing what should be done here in the top level Install
5122 * however for Administrative and uninstalls this step will be needed
5124 if (!package->PackagePath)
5125 return ERROR_SUCCESS;
5127 msi_set_sourcedir_props(package, TRUE);
5129 attrib = GetFileAttributesW(package->db->path);
5130 if (attrib == INVALID_FILE_ATTRIBUTES)
5132 LPWSTR prompt;
5133 LPWSTR msg;
5134 DWORD size = 0;
5136 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5137 package->Context, MSICODE_PRODUCT,
5138 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5139 if (rc == ERROR_MORE_DATA)
5141 prompt = msi_alloc(size * sizeof(WCHAR));
5142 MsiSourceListGetInfoW(package->ProductCode, NULL,
5143 package->Context, MSICODE_PRODUCT,
5144 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5146 else
5147 prompt = strdupW(package->db->path);
5149 msg = msi_build_error_string(package, 1302, 1, prompt);
5150 while(attrib == INVALID_FILE_ATTRIBUTES)
5152 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5153 if (rc == IDCANCEL)
5155 rc = ERROR_INSTALL_USEREXIT;
5156 break;
5158 attrib = GetFileAttributesW(package->db->path);
5160 msi_free(prompt);
5161 rc = ERROR_SUCCESS;
5163 else
5164 return ERROR_SUCCESS;
5166 return rc;
5169 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5171 HKEY hkey = 0;
5172 LPWSTR buffer, productid = NULL;
5173 UINT i, rc = ERROR_SUCCESS;
5174 MSIRECORD *uirow;
5176 static const WCHAR szPropKeys[][80] =
5178 {'P','r','o','d','u','c','t','I','D',0},
5179 {'U','S','E','R','N','A','M','E',0},
5180 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5181 {0},
5184 static const WCHAR szRegKeys[][80] =
5186 {'P','r','o','d','u','c','t','I','D',0},
5187 {'R','e','g','O','w','n','e','r',0},
5188 {'R','e','g','C','o','m','p','a','n','y',0},
5189 {0},
5192 if (msi_check_unpublish(package))
5194 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5195 goto end;
5198 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5199 if (!productid)
5200 goto end;
5202 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5203 NULL, &hkey, TRUE);
5204 if (rc != ERROR_SUCCESS)
5205 goto end;
5207 for( i = 0; szPropKeys[i][0]; i++ )
5209 buffer = msi_dup_property( package->db, szPropKeys[i] );
5210 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5211 msi_free( buffer );
5214 end:
5215 uirow = MSI_CreateRecord( 1 );
5216 MSI_RecordSetStringW( uirow, 1, productid );
5217 msi_ui_actiondata( package, szRegisterUser, uirow );
5218 msiobj_release( &uirow->hdr );
5220 msi_free(productid);
5221 RegCloseKey(hkey);
5222 return rc;
5226 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5228 UINT rc;
5230 package->script->InWhatSequence |= SEQUENCE_EXEC;
5231 rc = ACTION_ProcessExecSequence(package,FALSE);
5232 return rc;
5235 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5237 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5238 WCHAR productid_85[21], component_85[21], *ret;
5239 GUID clsid;
5240 DWORD sz;
5242 /* > is used if there is a component GUID and < if not. */
5244 productid_85[0] = 0;
5245 component_85[0] = 0;
5246 CLSIDFromString( package->ProductCode, &clsid );
5248 encode_base85_guid( &clsid, productid_85 );
5249 if (component)
5251 CLSIDFromString( component->ComponentId, &clsid );
5252 encode_base85_guid( &clsid, component_85 );
5255 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5256 debugstr_w(component_85));
5258 sz = 20 + strlenW( feature ) + 20 + 3;
5259 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5260 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5261 return ret;
5264 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5266 MSIPACKAGE *package = param;
5267 LPCWSTR compgroupid, component, feature, qualifier, text;
5268 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5269 HKEY hkey = NULL;
5270 UINT rc;
5271 MSICOMPONENT *comp;
5272 MSIFEATURE *feat;
5273 DWORD sz;
5274 MSIRECORD *uirow;
5275 int len;
5277 feature = MSI_RecordGetString(rec, 5);
5278 feat = msi_get_loaded_feature(package, feature);
5279 if (!feat)
5280 return ERROR_SUCCESS;
5282 feat->Action = msi_get_feature_action( package, feat );
5283 if (feat->Action != INSTALLSTATE_LOCAL &&
5284 feat->Action != INSTALLSTATE_SOURCE &&
5285 feat->Action != INSTALLSTATE_ADVERTISED)
5287 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5288 return ERROR_SUCCESS;
5291 component = MSI_RecordGetString(rec, 3);
5292 comp = msi_get_loaded_component(package, component);
5293 if (!comp)
5294 return ERROR_SUCCESS;
5296 compgroupid = MSI_RecordGetString(rec,1);
5297 qualifier = MSI_RecordGetString(rec,2);
5299 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5300 if (rc != ERROR_SUCCESS)
5301 goto end;
5303 advertise = msi_create_component_advertise_string( package, comp, feature );
5304 text = MSI_RecordGetString( rec, 4 );
5305 if (text)
5307 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5308 strcpyW( p, advertise );
5309 strcatW( p, text );
5310 msi_free( advertise );
5311 advertise = p;
5313 existing = msi_reg_get_val_str( hkey, qualifier );
5315 sz = strlenW( advertise ) + 1;
5316 if (existing)
5318 for (p = existing; *p; p += len)
5320 len = strlenW( p ) + 1;
5321 if (strcmpW( advertise, p )) sz += len;
5324 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5326 rc = ERROR_OUTOFMEMORY;
5327 goto end;
5329 q = output;
5330 if (existing)
5332 for (p = existing; *p; p += len)
5334 len = strlenW( p ) + 1;
5335 if (strcmpW( advertise, p ))
5337 memcpy( q, p, len * sizeof(WCHAR) );
5338 q += len;
5342 strcpyW( q, advertise );
5343 q[strlenW( q ) + 1] = 0;
5345 msi_reg_set_val_multi_str( hkey, qualifier, output );
5347 end:
5348 RegCloseKey(hkey);
5349 msi_free( output );
5350 msi_free( advertise );
5351 msi_free( existing );
5353 /* the UI chunk */
5354 uirow = MSI_CreateRecord( 2 );
5355 MSI_RecordSetStringW( uirow, 1, compgroupid );
5356 MSI_RecordSetStringW( uirow, 2, qualifier);
5357 msi_ui_actiondata( package, szPublishComponents, uirow );
5358 msiobj_release( &uirow->hdr );
5359 /* FIXME: call ui_progress? */
5361 return rc;
5365 * At present I am ignorning the advertised components part of this and only
5366 * focusing on the qualified component sets
5368 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5370 static const WCHAR query[] = {
5371 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5372 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5373 MSIQUERY *view;
5374 UINT rc;
5376 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5377 if (rc != ERROR_SUCCESS)
5378 return ERROR_SUCCESS;
5380 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5381 msiobj_release(&view->hdr);
5382 return rc;
5385 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5387 static const WCHAR szInstallerComponents[] = {
5388 'S','o','f','t','w','a','r','e','\\',
5389 'M','i','c','r','o','s','o','f','t','\\',
5390 'I','n','s','t','a','l','l','e','r','\\',
5391 'C','o','m','p','o','n','e','n','t','s','\\',0};
5393 MSIPACKAGE *package = param;
5394 LPCWSTR compgroupid, component, feature, qualifier;
5395 MSICOMPONENT *comp;
5396 MSIFEATURE *feat;
5397 MSIRECORD *uirow;
5398 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5399 LONG res;
5401 feature = MSI_RecordGetString( rec, 5 );
5402 feat = msi_get_loaded_feature( package, feature );
5403 if (!feat)
5404 return ERROR_SUCCESS;
5406 feat->Action = msi_get_feature_action( package, feat );
5407 if (feat->Action != INSTALLSTATE_ABSENT)
5409 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5410 return ERROR_SUCCESS;
5413 component = MSI_RecordGetString( rec, 3 );
5414 comp = msi_get_loaded_component( package, component );
5415 if (!comp)
5416 return ERROR_SUCCESS;
5418 compgroupid = MSI_RecordGetString( rec, 1 );
5419 qualifier = MSI_RecordGetString( rec, 2 );
5421 squash_guid( compgroupid, squashed );
5422 strcpyW( keypath, szInstallerComponents );
5423 strcatW( keypath, squashed );
5425 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5426 if (res != ERROR_SUCCESS)
5428 WARN("Unable to delete component key %d\n", res);
5431 uirow = MSI_CreateRecord( 2 );
5432 MSI_RecordSetStringW( uirow, 1, compgroupid );
5433 MSI_RecordSetStringW( uirow, 2, qualifier );
5434 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5435 msiobj_release( &uirow->hdr );
5437 return ERROR_SUCCESS;
5440 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5442 static const WCHAR query[] = {
5443 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5444 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5445 MSIQUERY *view;
5446 UINT rc;
5448 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5449 if (rc != ERROR_SUCCESS)
5450 return ERROR_SUCCESS;
5452 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5453 msiobj_release( &view->hdr );
5454 return rc;
5457 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5459 static const WCHAR query[] =
5460 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5461 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5462 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5463 MSIPACKAGE *package = param;
5464 MSICOMPONENT *component;
5465 MSIRECORD *row;
5466 MSIFILE *file;
5467 SC_HANDLE hscm = NULL, service = NULL;
5468 LPCWSTR comp, key;
5469 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5470 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5471 DWORD serv_type, start_type, err_control;
5472 SERVICE_DESCRIPTIONW sd = {NULL};
5474 comp = MSI_RecordGetString( rec, 12 );
5475 component = msi_get_loaded_component( package, comp );
5476 if (!component)
5478 WARN("service component not found\n");
5479 goto done;
5481 component->Action = msi_get_component_action( package, component );
5482 if (component->Action != INSTALLSTATE_LOCAL)
5484 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5485 goto done;
5487 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5488 if (!hscm)
5490 ERR("Failed to open the SC Manager!\n");
5491 goto done;
5494 start_type = MSI_RecordGetInteger(rec, 5);
5495 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5496 goto done;
5498 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5499 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5500 serv_type = MSI_RecordGetInteger(rec, 4);
5501 err_control = MSI_RecordGetInteger(rec, 6);
5502 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5503 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5504 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5505 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5506 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5507 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5509 /* fetch the service path */
5510 row = MSI_QueryGetRecord(package->db, query, comp);
5511 if (!row)
5513 ERR("Query failed\n");
5514 goto done;
5516 key = MSI_RecordGetString(row, 6);
5517 file = msi_get_loaded_file(package, key);
5518 msiobj_release(&row->hdr);
5519 if (!file)
5521 ERR("Failed to load the service file\n");
5522 goto done;
5525 if (!args || !args[0]) image_path = file->TargetPath;
5526 else
5528 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5529 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5530 return ERROR_OUTOFMEMORY;
5532 strcpyW(image_path, file->TargetPath);
5533 strcatW(image_path, szSpace);
5534 strcatW(image_path, args);
5536 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5537 start_type, err_control, image_path, load_order,
5538 NULL, depends, serv_name, pass);
5540 if (!service)
5542 if (GetLastError() != ERROR_SERVICE_EXISTS)
5543 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5545 else if (sd.lpDescription)
5547 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5548 WARN("failed to set service description %u\n", GetLastError());
5551 if (image_path != file->TargetPath) msi_free(image_path);
5552 done:
5553 CloseServiceHandle(service);
5554 CloseServiceHandle(hscm);
5555 msi_free(name);
5556 msi_free(disp);
5557 msi_free(sd.lpDescription);
5558 msi_free(load_order);
5559 msi_free(serv_name);
5560 msi_free(pass);
5561 msi_free(depends);
5562 msi_free(args);
5564 return ERROR_SUCCESS;
5567 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5569 static const WCHAR query[] = {
5570 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5571 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5572 MSIQUERY *view;
5573 UINT rc;
5575 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5576 if (rc != ERROR_SUCCESS)
5577 return ERROR_SUCCESS;
5579 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5580 msiobj_release(&view->hdr);
5581 return rc;
5584 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5585 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5587 LPCWSTR *vector, *temp_vector;
5588 LPWSTR p, q;
5589 DWORD sep_len;
5591 static const WCHAR separator[] = {'[','~',']',0};
5593 *numargs = 0;
5594 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5596 if (!args)
5597 return NULL;
5599 vector = msi_alloc(sizeof(LPWSTR));
5600 if (!vector)
5601 return NULL;
5603 p = args;
5606 (*numargs)++;
5607 vector[*numargs - 1] = p;
5609 if ((q = strstrW(p, separator)))
5611 *q = '\0';
5613 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5614 if (!temp_vector)
5616 msi_free(vector);
5617 return NULL;
5619 vector = temp_vector;
5621 p = q + sep_len;
5623 } while (q);
5625 return vector;
5628 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5630 MSIPACKAGE *package = param;
5631 MSICOMPONENT *comp;
5632 MSIRECORD *uirow;
5633 SC_HANDLE scm = NULL, service = NULL;
5634 LPCWSTR component, *vector = NULL;
5635 LPWSTR name, args, display_name = NULL;
5636 DWORD event, numargs, len;
5637 UINT r = ERROR_FUNCTION_FAILED;
5639 component = MSI_RecordGetString(rec, 6);
5640 comp = msi_get_loaded_component(package, component);
5641 if (!comp)
5642 return ERROR_SUCCESS;
5644 comp->Action = msi_get_component_action( package, comp );
5645 if (comp->Action != INSTALLSTATE_LOCAL)
5647 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5648 return ERROR_SUCCESS;
5651 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5652 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5653 event = MSI_RecordGetInteger(rec, 3);
5655 if (!(event & msidbServiceControlEventStart))
5657 r = ERROR_SUCCESS;
5658 goto done;
5661 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5662 if (!scm)
5664 ERR("Failed to open the service control manager\n");
5665 goto done;
5668 len = 0;
5669 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5670 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5672 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5673 GetServiceDisplayNameW( scm, name, display_name, &len );
5676 service = OpenServiceW(scm, name, SERVICE_START);
5677 if (!service)
5679 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5680 goto done;
5683 vector = msi_service_args_to_vector(args, &numargs);
5685 if (!StartServiceW(service, numargs, vector) &&
5686 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5688 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5689 goto done;
5692 r = ERROR_SUCCESS;
5694 done:
5695 uirow = MSI_CreateRecord( 2 );
5696 MSI_RecordSetStringW( uirow, 1, display_name );
5697 MSI_RecordSetStringW( uirow, 2, name );
5698 msi_ui_actiondata( package, szStartServices, uirow );
5699 msiobj_release( &uirow->hdr );
5701 CloseServiceHandle(service);
5702 CloseServiceHandle(scm);
5704 msi_free(name);
5705 msi_free(args);
5706 msi_free(vector);
5707 msi_free(display_name);
5708 return r;
5711 static UINT ACTION_StartServices( MSIPACKAGE *package )
5713 static const WCHAR query[] = {
5714 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5715 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5716 MSIQUERY *view;
5717 UINT rc;
5719 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5720 if (rc != ERROR_SUCCESS)
5721 return ERROR_SUCCESS;
5723 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5724 msiobj_release(&view->hdr);
5725 return rc;
5728 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5730 DWORD i, needed, count;
5731 ENUM_SERVICE_STATUSW *dependencies;
5732 SERVICE_STATUS ss;
5733 SC_HANDLE depserv;
5735 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5736 0, &needed, &count))
5737 return TRUE;
5739 if (GetLastError() != ERROR_MORE_DATA)
5740 return FALSE;
5742 dependencies = msi_alloc(needed);
5743 if (!dependencies)
5744 return FALSE;
5746 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5747 needed, &needed, &count))
5748 goto error;
5750 for (i = 0; i < count; i++)
5752 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5753 SERVICE_STOP | SERVICE_QUERY_STATUS);
5754 if (!depserv)
5755 goto error;
5757 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5758 goto error;
5761 return TRUE;
5763 error:
5764 msi_free(dependencies);
5765 return FALSE;
5768 static UINT stop_service( LPCWSTR name )
5770 SC_HANDLE scm = NULL, service = NULL;
5771 SERVICE_STATUS status;
5772 SERVICE_STATUS_PROCESS ssp;
5773 DWORD needed;
5775 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5776 if (!scm)
5778 WARN("Failed to open the SCM: %d\n", GetLastError());
5779 goto done;
5782 service = OpenServiceW(scm, name,
5783 SERVICE_STOP |
5784 SERVICE_QUERY_STATUS |
5785 SERVICE_ENUMERATE_DEPENDENTS);
5786 if (!service)
5788 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5789 goto done;
5792 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5793 sizeof(SERVICE_STATUS_PROCESS), &needed))
5795 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5796 goto done;
5799 if (ssp.dwCurrentState == SERVICE_STOPPED)
5800 goto done;
5802 stop_service_dependents(scm, service);
5804 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5805 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5807 done:
5808 CloseServiceHandle(service);
5809 CloseServiceHandle(scm);
5811 return ERROR_SUCCESS;
5814 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5816 MSIPACKAGE *package = param;
5817 MSICOMPONENT *comp;
5818 MSIRECORD *uirow;
5819 LPCWSTR component;
5820 LPWSTR name = NULL, display_name = NULL;
5821 DWORD event, len;
5822 SC_HANDLE scm;
5824 event = MSI_RecordGetInteger( rec, 3 );
5825 if (!(event & msidbServiceControlEventStop))
5826 return ERROR_SUCCESS;
5828 component = MSI_RecordGetString( rec, 6 );
5829 comp = msi_get_loaded_component( package, component );
5830 if (!comp)
5831 return ERROR_SUCCESS;
5833 comp->Action = msi_get_component_action( package, comp );
5834 if (comp->Action != INSTALLSTATE_ABSENT)
5836 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5837 return ERROR_SUCCESS;
5840 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5841 if (!scm)
5843 ERR("Failed to open the service control manager\n");
5844 goto done;
5847 len = 0;
5848 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5849 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5851 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5852 GetServiceDisplayNameW( scm, name, display_name, &len );
5854 CloseServiceHandle( scm );
5856 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5857 stop_service( name );
5859 done:
5860 uirow = MSI_CreateRecord( 2 );
5861 MSI_RecordSetStringW( uirow, 1, display_name );
5862 MSI_RecordSetStringW( uirow, 2, name );
5863 msi_ui_actiondata( package, szStopServices, uirow );
5864 msiobj_release( &uirow->hdr );
5866 msi_free( name );
5867 msi_free( display_name );
5868 return ERROR_SUCCESS;
5871 static UINT ACTION_StopServices( MSIPACKAGE *package )
5873 static const WCHAR query[] = {
5874 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5875 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5876 MSIQUERY *view;
5877 UINT rc;
5879 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5880 if (rc != ERROR_SUCCESS)
5881 return ERROR_SUCCESS;
5883 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5884 msiobj_release(&view->hdr);
5885 return rc;
5888 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5890 MSIPACKAGE *package = param;
5891 MSICOMPONENT *comp;
5892 MSIRECORD *uirow;
5893 LPCWSTR component;
5894 LPWSTR name = NULL, display_name = NULL;
5895 DWORD event, len;
5896 SC_HANDLE scm = NULL, service = NULL;
5898 event = MSI_RecordGetInteger( rec, 3 );
5899 if (!(event & msidbServiceControlEventDelete))
5900 return ERROR_SUCCESS;
5902 component = MSI_RecordGetString(rec, 6);
5903 comp = msi_get_loaded_component(package, component);
5904 if (!comp)
5905 return ERROR_SUCCESS;
5907 comp->Action = msi_get_component_action( package, comp );
5908 if (comp->Action != INSTALLSTATE_ABSENT)
5910 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5911 return ERROR_SUCCESS;
5914 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5915 stop_service( name );
5917 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5918 if (!scm)
5920 WARN("Failed to open the SCM: %d\n", GetLastError());
5921 goto done;
5924 len = 0;
5925 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5926 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5928 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5929 GetServiceDisplayNameW( scm, name, display_name, &len );
5932 service = OpenServiceW( scm, name, DELETE );
5933 if (!service)
5935 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5936 goto done;
5939 if (!DeleteService( service ))
5940 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5942 done:
5943 uirow = MSI_CreateRecord( 2 );
5944 MSI_RecordSetStringW( uirow, 1, display_name );
5945 MSI_RecordSetStringW( uirow, 2, name );
5946 msi_ui_actiondata( package, szDeleteServices, uirow );
5947 msiobj_release( &uirow->hdr );
5949 CloseServiceHandle( service );
5950 CloseServiceHandle( scm );
5951 msi_free( name );
5952 msi_free( display_name );
5954 return ERROR_SUCCESS;
5957 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5959 static const WCHAR query[] = {
5960 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5961 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5962 MSIQUERY *view;
5963 UINT rc;
5965 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5966 if (rc != ERROR_SUCCESS)
5967 return ERROR_SUCCESS;
5969 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5970 msiobj_release( &view->hdr );
5971 return rc;
5974 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5976 MSIPACKAGE *package = param;
5977 LPWSTR driver, driver_path, ptr;
5978 WCHAR outpath[MAX_PATH];
5979 MSIFILE *driver_file = NULL, *setup_file = NULL;
5980 MSICOMPONENT *comp;
5981 MSIRECORD *uirow;
5982 LPCWSTR desc, file_key, component;
5983 DWORD len, usage;
5984 UINT r = ERROR_SUCCESS;
5986 static const WCHAR driver_fmt[] = {
5987 'D','r','i','v','e','r','=','%','s',0};
5988 static const WCHAR setup_fmt[] = {
5989 'S','e','t','u','p','=','%','s',0};
5990 static const WCHAR usage_fmt[] = {
5991 'F','i','l','e','U','s','a','g','e','=','1',0};
5993 component = MSI_RecordGetString( rec, 2 );
5994 comp = msi_get_loaded_component( package, component );
5995 if (!comp)
5996 return ERROR_SUCCESS;
5998 comp->Action = msi_get_component_action( package, comp );
5999 if (comp->Action != INSTALLSTATE_LOCAL)
6001 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6002 return ERROR_SUCCESS;
6004 desc = MSI_RecordGetString(rec, 3);
6006 file_key = MSI_RecordGetString( rec, 4 );
6007 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6009 file_key = MSI_RecordGetString( rec, 5 );
6010 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6012 if (!driver_file)
6014 ERR("ODBC Driver entry not found!\n");
6015 return ERROR_FUNCTION_FAILED;
6018 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6019 if (setup_file)
6020 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6021 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6023 driver = msi_alloc(len * sizeof(WCHAR));
6024 if (!driver)
6025 return ERROR_OUTOFMEMORY;
6027 ptr = driver;
6028 lstrcpyW(ptr, desc);
6029 ptr += lstrlenW(ptr) + 1;
6031 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6032 ptr += len + 1;
6034 if (setup_file)
6036 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6037 ptr += len + 1;
6040 lstrcpyW(ptr, usage_fmt);
6041 ptr += lstrlenW(ptr) + 1;
6042 *ptr = '\0';
6044 driver_path = strdupW(driver_file->TargetPath);
6045 ptr = strrchrW(driver_path, '\\');
6046 if (ptr) *ptr = '\0';
6048 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6049 NULL, ODBC_INSTALL_COMPLETE, &usage))
6051 ERR("Failed to install SQL driver!\n");
6052 r = ERROR_FUNCTION_FAILED;
6055 uirow = MSI_CreateRecord( 5 );
6056 MSI_RecordSetStringW( uirow, 1, desc );
6057 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6058 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6059 msi_ui_actiondata( package, szInstallODBC, uirow );
6060 msiobj_release( &uirow->hdr );
6062 msi_free(driver);
6063 msi_free(driver_path);
6065 return r;
6068 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6070 MSIPACKAGE *package = param;
6071 LPWSTR translator, translator_path, ptr;
6072 WCHAR outpath[MAX_PATH];
6073 MSIFILE *translator_file = NULL, *setup_file = NULL;
6074 MSICOMPONENT *comp;
6075 MSIRECORD *uirow;
6076 LPCWSTR desc, file_key, component;
6077 DWORD len, usage;
6078 UINT r = ERROR_SUCCESS;
6080 static const WCHAR translator_fmt[] = {
6081 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6082 static const WCHAR setup_fmt[] = {
6083 'S','e','t','u','p','=','%','s',0};
6085 component = MSI_RecordGetString( rec, 2 );
6086 comp = msi_get_loaded_component( package, component );
6087 if (!comp)
6088 return ERROR_SUCCESS;
6090 comp->Action = msi_get_component_action( package, comp );
6091 if (comp->Action != INSTALLSTATE_LOCAL)
6093 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6094 return ERROR_SUCCESS;
6096 desc = MSI_RecordGetString(rec, 3);
6098 file_key = MSI_RecordGetString( rec, 4 );
6099 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6101 file_key = MSI_RecordGetString( rec, 5 );
6102 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6104 if (!translator_file)
6106 ERR("ODBC Translator entry not found!\n");
6107 return ERROR_FUNCTION_FAILED;
6110 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6111 if (setup_file)
6112 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6114 translator = msi_alloc(len * sizeof(WCHAR));
6115 if (!translator)
6116 return ERROR_OUTOFMEMORY;
6118 ptr = translator;
6119 lstrcpyW(ptr, desc);
6120 ptr += lstrlenW(ptr) + 1;
6122 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6123 ptr += len + 1;
6125 if (setup_file)
6127 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6128 ptr += len + 1;
6130 *ptr = '\0';
6132 translator_path = strdupW(translator_file->TargetPath);
6133 ptr = strrchrW(translator_path, '\\');
6134 if (ptr) *ptr = '\0';
6136 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6137 NULL, ODBC_INSTALL_COMPLETE, &usage))
6139 ERR("Failed to install SQL translator!\n");
6140 r = ERROR_FUNCTION_FAILED;
6143 uirow = MSI_CreateRecord( 5 );
6144 MSI_RecordSetStringW( uirow, 1, desc );
6145 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6146 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6147 msi_ui_actiondata( package, szInstallODBC, uirow );
6148 msiobj_release( &uirow->hdr );
6150 msi_free(translator);
6151 msi_free(translator_path);
6153 return r;
6156 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6158 MSIPACKAGE *package = param;
6159 MSICOMPONENT *comp;
6160 LPWSTR attrs;
6161 LPCWSTR desc, driver, component;
6162 WORD request = ODBC_ADD_SYS_DSN;
6163 INT registration;
6164 DWORD len;
6165 UINT r = ERROR_SUCCESS;
6166 MSIRECORD *uirow;
6168 static const WCHAR attrs_fmt[] = {
6169 'D','S','N','=','%','s',0 };
6171 component = MSI_RecordGetString( rec, 2 );
6172 comp = msi_get_loaded_component( package, component );
6173 if (!comp)
6174 return ERROR_SUCCESS;
6176 comp->Action = msi_get_component_action( package, comp );
6177 if (comp->Action != INSTALLSTATE_LOCAL)
6179 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6180 return ERROR_SUCCESS;
6183 desc = MSI_RecordGetString(rec, 3);
6184 driver = MSI_RecordGetString(rec, 4);
6185 registration = MSI_RecordGetInteger(rec, 5);
6187 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6188 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6190 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6191 attrs = msi_alloc(len * sizeof(WCHAR));
6192 if (!attrs)
6193 return ERROR_OUTOFMEMORY;
6195 len = sprintfW(attrs, attrs_fmt, desc);
6196 attrs[len + 1] = 0;
6198 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6200 ERR("Failed to install SQL data source!\n");
6201 r = ERROR_FUNCTION_FAILED;
6204 uirow = MSI_CreateRecord( 5 );
6205 MSI_RecordSetStringW( uirow, 1, desc );
6206 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6207 MSI_RecordSetInteger( uirow, 3, request );
6208 msi_ui_actiondata( package, szInstallODBC, uirow );
6209 msiobj_release( &uirow->hdr );
6211 msi_free(attrs);
6213 return r;
6216 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6218 static const WCHAR driver_query[] = {
6219 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6220 'O','D','B','C','D','r','i','v','e','r',0};
6221 static const WCHAR translator_query[] = {
6222 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6223 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6224 static const WCHAR source_query[] = {
6225 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6226 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6227 MSIQUERY *view;
6228 UINT rc;
6230 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6231 if (rc == ERROR_SUCCESS)
6233 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6234 msiobj_release(&view->hdr);
6235 if (rc != ERROR_SUCCESS)
6236 return rc;
6238 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6239 if (rc == ERROR_SUCCESS)
6241 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6242 msiobj_release(&view->hdr);
6243 if (rc != ERROR_SUCCESS)
6244 return rc;
6246 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6247 if (rc == ERROR_SUCCESS)
6249 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6250 msiobj_release(&view->hdr);
6251 if (rc != ERROR_SUCCESS)
6252 return rc;
6254 return ERROR_SUCCESS;
6257 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6259 MSIPACKAGE *package = param;
6260 MSICOMPONENT *comp;
6261 MSIRECORD *uirow;
6262 DWORD usage;
6263 LPCWSTR desc, component;
6265 component = MSI_RecordGetString( rec, 2 );
6266 comp = msi_get_loaded_component( package, component );
6267 if (!comp)
6268 return ERROR_SUCCESS;
6270 comp->Action = msi_get_component_action( package, comp );
6271 if (comp->Action != INSTALLSTATE_ABSENT)
6273 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6274 return ERROR_SUCCESS;
6277 desc = MSI_RecordGetString( rec, 3 );
6278 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6280 WARN("Failed to remove ODBC driver\n");
6282 else if (!usage)
6284 FIXME("Usage count reached 0\n");
6287 uirow = MSI_CreateRecord( 2 );
6288 MSI_RecordSetStringW( uirow, 1, desc );
6289 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6290 msi_ui_actiondata( package, szRemoveODBC, uirow );
6291 msiobj_release( &uirow->hdr );
6293 return ERROR_SUCCESS;
6296 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6298 MSIPACKAGE *package = param;
6299 MSICOMPONENT *comp;
6300 MSIRECORD *uirow;
6301 DWORD usage;
6302 LPCWSTR desc, component;
6304 component = MSI_RecordGetString( rec, 2 );
6305 comp = msi_get_loaded_component( package, component );
6306 if (!comp)
6307 return ERROR_SUCCESS;
6309 comp->Action = msi_get_component_action( package, comp );
6310 if (comp->Action != INSTALLSTATE_ABSENT)
6312 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6313 return ERROR_SUCCESS;
6316 desc = MSI_RecordGetString( rec, 3 );
6317 if (!SQLRemoveTranslatorW( desc, &usage ))
6319 WARN("Failed to remove ODBC translator\n");
6321 else if (!usage)
6323 FIXME("Usage count reached 0\n");
6326 uirow = MSI_CreateRecord( 2 );
6327 MSI_RecordSetStringW( uirow, 1, desc );
6328 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6329 msi_ui_actiondata( package, szRemoveODBC, uirow );
6330 msiobj_release( &uirow->hdr );
6332 return ERROR_SUCCESS;
6335 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6337 MSIPACKAGE *package = param;
6338 MSICOMPONENT *comp;
6339 MSIRECORD *uirow;
6340 LPWSTR attrs;
6341 LPCWSTR desc, driver, component;
6342 WORD request = ODBC_REMOVE_SYS_DSN;
6343 INT registration;
6344 DWORD len;
6346 static const WCHAR attrs_fmt[] = {
6347 'D','S','N','=','%','s',0 };
6349 component = MSI_RecordGetString( rec, 2 );
6350 comp = msi_get_loaded_component( package, component );
6351 if (!comp)
6352 return ERROR_SUCCESS;
6354 comp->Action = msi_get_component_action( package, comp );
6355 if (comp->Action != INSTALLSTATE_ABSENT)
6357 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6358 return ERROR_SUCCESS;
6361 desc = MSI_RecordGetString( rec, 3 );
6362 driver = MSI_RecordGetString( rec, 4 );
6363 registration = MSI_RecordGetInteger( rec, 5 );
6365 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6366 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6368 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6369 attrs = msi_alloc( len * sizeof(WCHAR) );
6370 if (!attrs)
6371 return ERROR_OUTOFMEMORY;
6373 FIXME("Use ODBCSourceAttribute table\n");
6375 len = sprintfW( attrs, attrs_fmt, desc );
6376 attrs[len + 1] = 0;
6378 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6380 WARN("Failed to remove ODBC data source\n");
6382 msi_free( attrs );
6384 uirow = MSI_CreateRecord( 3 );
6385 MSI_RecordSetStringW( uirow, 1, desc );
6386 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6387 MSI_RecordSetInteger( uirow, 3, request );
6388 msi_ui_actiondata( package, szRemoveODBC, uirow );
6389 msiobj_release( &uirow->hdr );
6391 return ERROR_SUCCESS;
6394 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6396 static const WCHAR driver_query[] = {
6397 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6398 'O','D','B','C','D','r','i','v','e','r',0};
6399 static const WCHAR translator_query[] = {
6400 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6401 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6402 static const WCHAR source_query[] = {
6403 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6404 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6405 MSIQUERY *view;
6406 UINT rc;
6408 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6409 if (rc == ERROR_SUCCESS)
6411 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6412 msiobj_release( &view->hdr );
6413 if (rc != ERROR_SUCCESS)
6414 return rc;
6416 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6417 if (rc == ERROR_SUCCESS)
6419 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6420 msiobj_release( &view->hdr );
6421 if (rc != ERROR_SUCCESS)
6422 return rc;
6424 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6425 if (rc == ERROR_SUCCESS)
6427 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6428 msiobj_release( &view->hdr );
6429 if (rc != ERROR_SUCCESS)
6430 return rc;
6432 return ERROR_SUCCESS;
6435 #define ENV_ACT_SETALWAYS 0x1
6436 #define ENV_ACT_SETABSENT 0x2
6437 #define ENV_ACT_REMOVE 0x4
6438 #define ENV_ACT_REMOVEMATCH 0x8
6440 #define ENV_MOD_MACHINE 0x20000000
6441 #define ENV_MOD_APPEND 0x40000000
6442 #define ENV_MOD_PREFIX 0x80000000
6443 #define ENV_MOD_MASK 0xC0000000
6445 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6447 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6449 LPCWSTR cptr = *name;
6451 static const WCHAR prefix[] = {'[','~',']',0};
6452 static const int prefix_len = 3;
6454 *flags = 0;
6455 while (*cptr)
6457 if (*cptr == '=')
6458 *flags |= ENV_ACT_SETALWAYS;
6459 else if (*cptr == '+')
6460 *flags |= ENV_ACT_SETABSENT;
6461 else if (*cptr == '-')
6462 *flags |= ENV_ACT_REMOVE;
6463 else if (*cptr == '!')
6464 *flags |= ENV_ACT_REMOVEMATCH;
6465 else if (*cptr == '*')
6466 *flags |= ENV_MOD_MACHINE;
6467 else
6468 break;
6470 cptr++;
6471 (*name)++;
6474 if (!*cptr)
6476 ERR("Missing environment variable\n");
6477 return ERROR_FUNCTION_FAILED;
6480 if (*value)
6482 LPCWSTR ptr = *value;
6483 if (!strncmpW(ptr, prefix, prefix_len))
6485 if (ptr[prefix_len] == szSemiColon[0])
6487 *flags |= ENV_MOD_APPEND;
6488 *value += lstrlenW(prefix);
6490 else
6492 *value = NULL;
6495 else if (lstrlenW(*value) >= prefix_len)
6497 ptr += lstrlenW(ptr) - prefix_len;
6498 if (!strcmpW( ptr, prefix ))
6500 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6502 *flags |= ENV_MOD_PREFIX;
6503 /* the "[~]" will be removed by deformat_string */;
6505 else
6507 *value = NULL;
6513 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6514 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6515 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6516 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6518 ERR("Invalid flags: %08x\n", *flags);
6519 return ERROR_FUNCTION_FAILED;
6522 if (!*flags)
6523 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6525 return ERROR_SUCCESS;
6528 static UINT open_env_key( DWORD flags, HKEY *key )
6530 static const WCHAR user_env[] =
6531 {'E','n','v','i','r','o','n','m','e','n','t',0};
6532 static const WCHAR machine_env[] =
6533 {'S','y','s','t','e','m','\\',
6534 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6535 'C','o','n','t','r','o','l','\\',
6536 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6537 'E','n','v','i','r','o','n','m','e','n','t',0};
6538 const WCHAR *env;
6539 HKEY root;
6540 LONG res;
6542 if (flags & ENV_MOD_MACHINE)
6544 env = machine_env;
6545 root = HKEY_LOCAL_MACHINE;
6547 else
6549 env = user_env;
6550 root = HKEY_CURRENT_USER;
6553 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6554 if (res != ERROR_SUCCESS)
6556 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6557 return ERROR_FUNCTION_FAILED;
6560 return ERROR_SUCCESS;
6563 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6565 MSIPACKAGE *package = param;
6566 LPCWSTR name, value, component;
6567 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6568 DWORD flags, type, size;
6569 UINT res;
6570 HKEY env = NULL;
6571 MSICOMPONENT *comp;
6572 MSIRECORD *uirow;
6573 int action = 0;
6575 component = MSI_RecordGetString(rec, 4);
6576 comp = msi_get_loaded_component(package, component);
6577 if (!comp)
6578 return ERROR_SUCCESS;
6580 comp->Action = msi_get_component_action( package, comp );
6581 if (comp->Action != INSTALLSTATE_LOCAL)
6583 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6584 return ERROR_SUCCESS;
6586 name = MSI_RecordGetString(rec, 2);
6587 value = MSI_RecordGetString(rec, 3);
6589 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6591 res = env_parse_flags(&name, &value, &flags);
6592 if (res != ERROR_SUCCESS || !value)
6593 goto done;
6595 if (value && !deformat_string(package, value, &deformatted))
6597 res = ERROR_OUTOFMEMORY;
6598 goto done;
6601 value = deformatted;
6603 res = open_env_key( flags, &env );
6604 if (res != ERROR_SUCCESS)
6605 goto done;
6607 if (flags & ENV_MOD_MACHINE)
6608 action |= 0x20000000;
6610 size = 0;
6611 type = REG_SZ;
6612 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6613 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6614 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6615 goto done;
6617 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6619 action = 0x2;
6621 /* Nothing to do. */
6622 if (!value)
6624 res = ERROR_SUCCESS;
6625 goto done;
6628 /* If we are appending but the string was empty, strip ; */
6629 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6631 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6632 newval = strdupW(value);
6633 if (!newval)
6635 res = ERROR_OUTOFMEMORY;
6636 goto done;
6639 else
6641 action = 0x1;
6643 /* Contrary to MSDN, +-variable to [~];path works */
6644 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6646 res = ERROR_SUCCESS;
6647 goto done;
6650 data = msi_alloc(size);
6651 if (!data)
6653 RegCloseKey(env);
6654 return ERROR_OUTOFMEMORY;
6657 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6658 if (res != ERROR_SUCCESS)
6659 goto done;
6661 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6663 action = 0x4;
6664 res = RegDeleteValueW(env, name);
6665 if (res != ERROR_SUCCESS)
6666 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6667 goto done;
6670 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6671 if (flags & ENV_MOD_MASK)
6673 DWORD mod_size;
6674 int multiplier = 0;
6675 if (flags & ENV_MOD_APPEND) multiplier++;
6676 if (flags & ENV_MOD_PREFIX) multiplier++;
6677 mod_size = lstrlenW(value) * multiplier;
6678 size += mod_size * sizeof(WCHAR);
6681 newval = msi_alloc(size);
6682 ptr = newval;
6683 if (!newval)
6685 res = ERROR_OUTOFMEMORY;
6686 goto done;
6689 if (flags & ENV_MOD_PREFIX)
6691 lstrcpyW(newval, value);
6692 ptr = newval + lstrlenW(value);
6693 action |= 0x80000000;
6696 lstrcpyW(ptr, data);
6698 if (flags & ENV_MOD_APPEND)
6700 lstrcatW(newval, value);
6701 action |= 0x40000000;
6704 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6705 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6706 if (res)
6708 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6711 done:
6712 uirow = MSI_CreateRecord( 3 );
6713 MSI_RecordSetStringW( uirow, 1, name );
6714 MSI_RecordSetStringW( uirow, 2, newval );
6715 MSI_RecordSetInteger( uirow, 3, action );
6716 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6717 msiobj_release( &uirow->hdr );
6719 if (env) RegCloseKey(env);
6720 msi_free(deformatted);
6721 msi_free(data);
6722 msi_free(newval);
6723 return res;
6726 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6728 static const WCHAR query[] = {
6729 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6730 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6731 MSIQUERY *view;
6732 UINT rc;
6734 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6735 if (rc != ERROR_SUCCESS)
6736 return ERROR_SUCCESS;
6738 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6739 msiobj_release(&view->hdr);
6740 return rc;
6743 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6745 MSIPACKAGE *package = param;
6746 LPCWSTR name, value, component;
6747 LPWSTR deformatted = NULL;
6748 DWORD flags;
6749 HKEY env;
6750 MSICOMPONENT *comp;
6751 MSIRECORD *uirow;
6752 int action = 0;
6753 LONG res;
6754 UINT r;
6756 component = MSI_RecordGetString( rec, 4 );
6757 comp = msi_get_loaded_component( package, component );
6758 if (!comp)
6759 return ERROR_SUCCESS;
6761 comp->Action = msi_get_component_action( package, comp );
6762 if (comp->Action != INSTALLSTATE_ABSENT)
6764 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6765 return ERROR_SUCCESS;
6767 name = MSI_RecordGetString( rec, 2 );
6768 value = MSI_RecordGetString( rec, 3 );
6770 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6772 r = env_parse_flags( &name, &value, &flags );
6773 if (r != ERROR_SUCCESS)
6774 return r;
6776 if (!(flags & ENV_ACT_REMOVE))
6778 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6779 return ERROR_SUCCESS;
6782 if (value && !deformat_string( package, value, &deformatted ))
6783 return ERROR_OUTOFMEMORY;
6785 value = deformatted;
6787 r = open_env_key( flags, &env );
6788 if (r != ERROR_SUCCESS)
6790 r = ERROR_SUCCESS;
6791 goto done;
6794 if (flags & ENV_MOD_MACHINE)
6795 action |= 0x20000000;
6797 TRACE("Removing %s\n", debugstr_w(name));
6799 res = RegDeleteValueW( env, name );
6800 if (res != ERROR_SUCCESS)
6802 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6803 r = ERROR_SUCCESS;
6806 done:
6807 uirow = MSI_CreateRecord( 3 );
6808 MSI_RecordSetStringW( uirow, 1, name );
6809 MSI_RecordSetStringW( uirow, 2, value );
6810 MSI_RecordSetInteger( uirow, 3, action );
6811 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6812 msiobj_release( &uirow->hdr );
6814 if (env) RegCloseKey( env );
6815 msi_free( deformatted );
6816 return r;
6819 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6821 static const WCHAR query[] = {
6822 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6823 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6824 MSIQUERY *view;
6825 UINT rc;
6827 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6828 if (rc != ERROR_SUCCESS)
6829 return ERROR_SUCCESS;
6831 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6832 msiobj_release( &view->hdr );
6833 return rc;
6836 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6838 LPWSTR key, template, id;
6839 UINT r = ERROR_SUCCESS;
6841 id = msi_dup_property( package->db, szProductID );
6842 if (id)
6844 msi_free( id );
6845 return ERROR_SUCCESS;
6847 template = msi_dup_property( package->db, szPIDTemplate );
6848 key = msi_dup_property( package->db, szPIDKEY );
6850 if (key && template)
6852 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6853 r = msi_set_property( package->db, szProductID, key );
6855 msi_free( template );
6856 msi_free( key );
6857 return r;
6860 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6862 TRACE("\n");
6863 package->need_reboot = 1;
6864 return ERROR_SUCCESS;
6867 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6869 static const WCHAR szAvailableFreeReg[] =
6870 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6871 MSIRECORD *uirow;
6872 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6874 TRACE("%p %d kilobytes\n", package, space);
6876 uirow = MSI_CreateRecord( 1 );
6877 MSI_RecordSetInteger( uirow, 1, space );
6878 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6879 msiobj_release( &uirow->hdr );
6881 return ERROR_SUCCESS;
6884 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6886 TRACE("%p\n", package);
6888 msi_set_property( package->db, szRollbackDisabled, szOne );
6889 return ERROR_SUCCESS;
6892 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6894 FIXME("%p\n", package);
6895 return ERROR_SUCCESS;
6898 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6900 static const WCHAR driver_query[] = {
6901 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6902 'O','D','B','C','D','r','i','v','e','r',0};
6903 static const WCHAR translator_query[] = {
6904 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6905 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6906 MSIQUERY *view;
6907 UINT r, count;
6909 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6910 if (r == ERROR_SUCCESS)
6912 count = 0;
6913 r = MSI_IterateRecords( view, &count, NULL, package );
6914 msiobj_release( &view->hdr );
6915 if (r != ERROR_SUCCESS)
6916 return r;
6917 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6919 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6920 if (r == ERROR_SUCCESS)
6922 count = 0;
6923 r = MSI_IterateRecords( view, &count, NULL, package );
6924 msiobj_release( &view->hdr );
6925 if (r != ERROR_SUCCESS)
6926 return r;
6927 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6929 return ERROR_SUCCESS;
6932 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6934 MSIPACKAGE *package = param;
6935 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6936 WCHAR *value;
6938 if ((value = msi_dup_property( package->db, property )))
6940 FIXME("remove %s\n", debugstr_w(value));
6941 msi_free( value );
6943 return ERROR_SUCCESS;
6946 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6948 static const WCHAR query[] = {
6949 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
6950 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
6951 MSIQUERY *view;
6952 UINT r;
6954 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6955 if (r == ERROR_SUCCESS)
6957 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
6958 msiobj_release( &view->hdr );
6959 if (r != ERROR_SUCCESS)
6960 return r;
6962 return ERROR_SUCCESS;
6965 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
6967 MSIPACKAGE *package = param;
6968 int attributes = MSI_RecordGetInteger( rec, 5 );
6970 if (attributes & msidbUpgradeAttributesMigrateFeatures)
6972 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
6973 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
6974 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
6975 const WCHAR *language = MSI_RecordGetString( rec, 4 );
6976 HKEY hkey;
6977 UINT r;
6979 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
6981 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6982 if (r != ERROR_SUCCESS)
6983 return ERROR_SUCCESS;
6985 else
6987 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6988 if (r != ERROR_SUCCESS)
6989 return ERROR_SUCCESS;
6991 RegCloseKey( hkey );
6993 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
6994 debugstr_w(upgrade_code), debugstr_w(version_min),
6995 debugstr_w(version_max), debugstr_w(language));
6997 return ERROR_SUCCESS;
7000 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7002 static const WCHAR query[] = {
7003 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7004 'U','p','g','r','a','d','e',0};
7005 MSIQUERY *view;
7006 UINT r;
7008 if (msi_get_property_int( package->db, szInstalled, 0 ))
7010 TRACE("product is installed, skipping action\n");
7011 return ERROR_SUCCESS;
7013 if (msi_get_property_int( package->db, szPreselected, 0 ))
7015 TRACE("Preselected property is set, not migrating feature states\n");
7016 return ERROR_SUCCESS;
7018 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7019 if (r == ERROR_SUCCESS)
7021 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7022 msiobj_release( &view->hdr );
7023 if (r != ERROR_SUCCESS)
7024 return r;
7026 return ERROR_SUCCESS;
7029 static void bind_image( const char *filename, const char *path )
7031 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7033 WARN("failed to bind image %u\n", GetLastError());
7037 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7039 UINT i;
7040 MSIFILE *file;
7041 MSIPACKAGE *package = param;
7042 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7043 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7044 char *filenameA, *pathA;
7045 WCHAR *pathW, **path_list;
7047 if (!(file = msi_get_loaded_file( package, key )))
7049 WARN("file %s not found\n", debugstr_w(key));
7050 return ERROR_SUCCESS;
7052 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7053 path_list = msi_split_string( paths, ';' );
7054 if (!path_list) bind_image( filenameA, NULL );
7055 else
7057 for (i = 0; path_list[i] && path_list[i][0]; i++)
7059 deformat_string( package, path_list[i], &pathW );
7060 if ((pathA = strdupWtoA( pathW )))
7062 bind_image( filenameA, pathA );
7063 msi_free( pathA );
7065 msi_free( pathW );
7068 msi_free( path_list );
7069 msi_free( filenameA );
7070 return ERROR_SUCCESS;
7073 static UINT ACTION_BindImage( MSIPACKAGE *package )
7075 static const WCHAR query[] = {
7076 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7077 'B','i','n','d','I','m','a','g','e',0};
7078 MSIQUERY *view;
7079 UINT r;
7081 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7082 if (r == ERROR_SUCCESS)
7084 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7085 msiobj_release( &view->hdr );
7086 if (r != ERROR_SUCCESS)
7087 return r;
7089 return ERROR_SUCCESS;
7092 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7094 static const WCHAR query[] = {
7095 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7096 MSIQUERY *view;
7097 DWORD count = 0;
7098 UINT r;
7100 r = MSI_OpenQuery( package->db, &view, query, table );
7101 if (r == ERROR_SUCCESS)
7103 r = MSI_IterateRecords(view, &count, NULL, package);
7104 msiobj_release(&view->hdr);
7105 if (r != ERROR_SUCCESS)
7106 return r;
7108 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7109 return ERROR_SUCCESS;
7112 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7114 static const WCHAR table[] = {
7115 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7116 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7119 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7121 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7122 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7125 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7127 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7128 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7131 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7133 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7134 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7137 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7139 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7140 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7143 static const struct
7145 const WCHAR *action;
7146 UINT (*handler)(MSIPACKAGE *);
7147 const WCHAR *action_rollback;
7149 StandardActions[] =
7151 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7152 { szAppSearch, ACTION_AppSearch, NULL },
7153 { szBindImage, ACTION_BindImage, NULL },
7154 { szCCPSearch, ACTION_CCPSearch, NULL },
7155 { szCostFinalize, ACTION_CostFinalize, NULL },
7156 { szCostInitialize, ACTION_CostInitialize, NULL },
7157 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7158 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7159 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7160 { szDisableRollback, ACTION_DisableRollback, NULL },
7161 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7162 { szExecuteAction, ACTION_ExecuteAction, NULL },
7163 { szFileCost, ACTION_FileCost, NULL },
7164 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7165 { szForceReboot, ACTION_ForceReboot, NULL },
7166 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7167 { szInstallExecute, ACTION_InstallExecute, NULL },
7168 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7169 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7170 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7171 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7172 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7173 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7174 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7175 { szInstallValidate, ACTION_InstallValidate, NULL },
7176 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7177 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7178 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7179 { szMoveFiles, ACTION_MoveFiles, NULL },
7180 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7181 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7182 { szPatchFiles, ACTION_PatchFiles, NULL },
7183 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7184 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7185 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7186 { szPublishProduct, ACTION_PublishProduct, NULL },
7187 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7188 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7189 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7190 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7191 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7192 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7193 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7194 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7195 { szRegisterUser, ACTION_RegisterUser, NULL },
7196 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7197 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7198 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7199 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7200 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7201 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7202 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7203 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7204 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7205 { szResolveSource, ACTION_ResolveSource, NULL },
7206 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7207 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7208 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7209 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfUnregModules },
7210 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7211 { szStartServices, ACTION_StartServices, szStopServices },
7212 { szStopServices, ACTION_StopServices, szStartServices },
7213 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7214 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7215 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7216 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7217 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7218 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7219 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7220 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7221 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7222 { szValidateProductID, ACTION_ValidateProductID, NULL },
7223 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7224 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7225 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7226 { NULL, NULL, NULL }
7229 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7231 BOOL ret = FALSE;
7232 UINT i;
7234 i = 0;
7235 while (StandardActions[i].action != NULL)
7237 if (!strcmpW( StandardActions[i].action, action ))
7239 ui_actionstart( package, action );
7240 if (StandardActions[i].handler)
7242 ui_actioninfo( package, action, TRUE, 0 );
7243 *rc = StandardActions[i].handler( package );
7244 ui_actioninfo( package, action, FALSE, *rc );
7246 if (StandardActions[i].action_rollback && !package->need_rollback)
7248 TRACE("scheduling rollback action\n");
7249 msi_schedule_action( package, ROLLBACK_SCRIPT, StandardActions[i].action_rollback );
7252 else
7254 FIXME("unhandled standard action %s\n", debugstr_w(action));
7255 *rc = ERROR_SUCCESS;
7257 ret = TRUE;
7258 break;
7260 i++;
7262 return ret;
7265 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7267 UINT rc = ERROR_SUCCESS;
7268 BOOL handled;
7270 TRACE("Performing action (%s)\n", debugstr_w(action));
7272 handled = ACTION_HandleStandardAction(package, action, &rc);
7274 if (!handled)
7275 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7277 if (!handled)
7279 WARN("unhandled msi action %s\n", debugstr_w(action));
7280 rc = ERROR_FUNCTION_NOT_CALLED;
7283 return rc;
7286 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7288 UINT rc = ERROR_SUCCESS;
7289 BOOL handled = FALSE;
7291 TRACE("Performing action (%s)\n", debugstr_w(action));
7293 handled = ACTION_HandleStandardAction(package, action, &rc);
7295 if (!handled)
7296 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7298 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7299 handled = TRUE;
7301 if (!handled)
7303 WARN("unhandled msi action %s\n", debugstr_w(action));
7304 rc = ERROR_FUNCTION_NOT_CALLED;
7307 return rc;
7310 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7312 UINT rc = ERROR_SUCCESS;
7313 MSIRECORD *row;
7315 static const WCHAR query[] =
7316 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7317 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7318 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7319 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7320 static const WCHAR ui_query[] =
7321 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7322 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7323 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7324 ' ', '=',' ','%','i',0};
7326 if (needs_ui_sequence(package))
7327 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7328 else
7329 row = MSI_QueryGetRecord(package->db, query, seq);
7331 if (row)
7333 LPCWSTR action, cond;
7335 TRACE("Running the actions\n");
7337 /* check conditions */
7338 cond = MSI_RecordGetString(row, 2);
7340 /* this is a hack to skip errors in the condition code */
7341 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7343 msiobj_release(&row->hdr);
7344 return ERROR_SUCCESS;
7347 action = MSI_RecordGetString(row, 1);
7348 if (!action)
7350 ERR("failed to fetch action\n");
7351 msiobj_release(&row->hdr);
7352 return ERROR_FUNCTION_FAILED;
7355 if (needs_ui_sequence(package))
7356 rc = ACTION_PerformUIAction(package, action, -1);
7357 else
7358 rc = ACTION_PerformAction(package, action, -1);
7360 msiobj_release(&row->hdr);
7363 return rc;
7366 /****************************************************
7367 * TOP level entry points
7368 *****************************************************/
7370 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7371 LPCWSTR szCommandLine )
7373 UINT rc;
7374 BOOL ui_exists;
7375 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7376 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7377 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7379 msi_set_property( package->db, szAction, szInstall );
7381 package->script->InWhatSequence = SEQUENCE_INSTALL;
7383 if (szPackagePath)
7385 LPWSTR p, dir;
7386 LPCWSTR file;
7388 dir = strdupW(szPackagePath);
7389 p = strrchrW(dir, '\\');
7390 if (p)
7392 *(++p) = 0;
7393 file = szPackagePath + (p - dir);
7395 else
7397 msi_free(dir);
7398 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7399 GetCurrentDirectoryW(MAX_PATH, dir);
7400 lstrcatW(dir, szBackSlash);
7401 file = szPackagePath;
7404 msi_free( package->PackagePath );
7405 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7406 if (!package->PackagePath)
7408 msi_free(dir);
7409 return ERROR_OUTOFMEMORY;
7412 lstrcpyW(package->PackagePath, dir);
7413 lstrcatW(package->PackagePath, file);
7414 msi_free(dir);
7416 msi_set_sourcedir_props(package, FALSE);
7419 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7420 if (rc != ERROR_SUCCESS)
7421 return rc;
7423 msi_apply_transforms( package );
7424 msi_apply_patches( package );
7426 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7428 TRACE("setting reinstall property\n");
7429 msi_set_property( package->db, szReinstall, szAll );
7432 /* properties may have been added by a transform */
7433 msi_clone_properties( package );
7435 msi_parse_command_line( package, szCommandLine, FALSE );
7436 msi_adjust_privilege_properties( package );
7437 msi_set_context( package );
7439 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7441 TRACE("disabling rollback\n");
7442 msi_set_property( package->db, szRollbackDisabled, szOne );
7445 if (needs_ui_sequence( package))
7447 package->script->InWhatSequence |= SEQUENCE_UI;
7448 rc = ACTION_ProcessUISequence(package);
7449 ui_exists = ui_sequence_exists(package);
7450 if (rc == ERROR_SUCCESS || !ui_exists)
7452 package->script->InWhatSequence |= SEQUENCE_EXEC;
7453 rc = ACTION_ProcessExecSequence(package, ui_exists);
7456 else
7457 rc = ACTION_ProcessExecSequence(package, FALSE);
7459 package->script->CurrentlyScripting = FALSE;
7461 /* process the ending type action */
7462 if (rc == ERROR_SUCCESS)
7463 ACTION_PerformActionSequence(package, -1);
7464 else if (rc == ERROR_INSTALL_USEREXIT)
7465 ACTION_PerformActionSequence(package, -2);
7466 else if (rc == ERROR_INSTALL_SUSPEND)
7467 ACTION_PerformActionSequence(package, -4);
7468 else /* failed */
7470 ACTION_PerformActionSequence(package, -3);
7471 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7473 package->need_rollback = TRUE;
7477 /* finish up running custom actions */
7478 ACTION_FinishCustomActions(package);
7480 if (package->need_rollback)
7482 WARN("installation failed, running rollback script\n");
7483 execute_script( package, ROLLBACK_SCRIPT );
7486 if (rc == ERROR_SUCCESS && package->need_reboot)
7487 return ERROR_SUCCESS_REBOOT_REQUIRED;
7489 return rc;