1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
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"
42
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
45
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
47
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};
156
157 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
158 {
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;
165
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);
171 }
172
173 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
174 UINT rc)
175 {
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];
188
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);
194
195 row = MSI_CreateRecord(1);
196 MSI_RecordSetStringW(row,1,message);
197
198 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
199 msiobj_release(&row->hdr);
200 }
201
202 enum parse_state
203 {
204 state_whitespace,
205 state_token,
206 state_quote
207 };
208
209 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
210 {
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;
215
216 for (p = str; *p; p++)
217 {
218 ignore = 0;
219 switch (state)
220 {
221 case state_whitespace:
222 switch (*p)
223 {
224 case ' ':
225 in_quotes = 1;
226 ignore = 1;
227 len++;
228 break;
229 case '"':
230 state = state_quote;
231 if (in_quotes && p[1] != '\"') count--;
232 else count++;
233 break;
234 default:
235 state = state_token;
236 in_quotes = 1;
237 len++;
238 break;
239 }
240 break;
241
242 case state_token:
243 switch (*p)
244 {
245 case '"':
246 state = state_quote;
247 if (in_quotes) count--;
248 else count++;
249 break;
250 case ' ':
251 state = state_whitespace;
252 if (!count) goto done;
253 in_quotes = 1;
254 len++;
255 break;
256 default:
257 if (!count) in_quotes = 0;
258 else in_quotes = 1;
259 len++;
260 break;
261 }
262 break;
263
264 case state_quote:
265 switch (*p)
266 {
267 case '"':
268 if (in_quotes && p[1] != '\"') count--;
269 else count++;
270 break;
271 case ' ':
272 state = state_whitespace;
273 if (!count || (count > 1 && !len)) goto done;
274 in_quotes = 1;
275 len++;
276 break;
277 default:
278 state = state_token;
279 if (!count) in_quotes = 0;
280 else in_quotes = 1;
281 len++;
282 break;
283 }
284 break;
285
286 default: break;
287 }
288 if (!ignore) *out++ = *p;
289 }
290
291 done:
292 if (!len) *value = 0;
293 else *out = 0;
294
295 *quotes = count;
296 return p - str;
297 }
298
299 static void remove_quotes( WCHAR *str )
300 {
301 WCHAR *p = str;
302 int len = strlenW( str );
303
304 while ((p = strchrW( p, '"' )))
305 {
306 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
307 p++;
308 }
309 }
310
311 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
312 BOOL preserve_case )
313 {
314 LPCWSTR ptr, ptr2;
315 int num_quotes;
316 DWORD len;
317 WCHAR *prop, *val;
318 UINT r;
319
320 if (!szCommandLine)
321 return ERROR_SUCCESS;
322
323 ptr = szCommandLine;
324 while (*ptr)
325 {
326 while (*ptr == ' ') ptr++;
327 if (!*ptr) break;
328
329 ptr2 = strchrW( ptr, '=' );
330 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
331
332 len = ptr2 - ptr;
333 if (!len) return ERROR_INVALID_COMMAND_LINE;
334
335 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
336 memcpy( prop, ptr, len * sizeof(WCHAR) );
337 prop[len] = 0;
338 if (!preserve_case) struprW( prop );
339
340 ptr2++;
341 while (*ptr2 == ' ') ptr2++;
342
343 num_quotes = 0;
344 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
345 len = parse_prop( ptr2, val, &num_quotes );
346 if (num_quotes % 2)
347 {
348 WARN("unbalanced quotes\n");
349 msi_free( val );
350 msi_free( prop );
351 return ERROR_INVALID_COMMAND_LINE;
352 }
353 remove_quotes( val );
354 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
355
356 r = msi_set_property( package->db, prop, val );
357 if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
358 msi_reset_folders( package, TRUE );
359
360 msi_free( val );
361 msi_free( prop );
362
363 ptr = ptr2 + len;
364 }
365
366 return ERROR_SUCCESS;
367 }
368
369 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
370 {
371 LPCWSTR pc;
372 LPWSTR p, *ret = NULL;
373 UINT count = 0;
374
375 if (!str)
376 return ret;
377
378 /* count the number of substrings */
379 for ( pc = str, count = 0; pc; count++ )
380 {
381 pc = strchrW( pc, sep );
382 if (pc)
383 pc++;
384 }
385
386 /* allocate space for an array of substring pointers and the substrings */
387 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
388 (lstrlenW(str)+1) * sizeof(WCHAR) );
389 if (!ret)
390 return ret;
391
392 /* copy the string and set the pointers */
393 p = (LPWSTR) &ret[count+1];
394 lstrcpyW( p, str );
395 for( count = 0; (ret[count] = p); count++ )
396 {
397 p = strchrW( p, sep );
398 if (p)
399 *p++ = 0;
400 }
401
402 return ret;
403 }
404
405 static BOOL ui_sequence_exists( MSIPACKAGE *package )
406 {
407 static const WCHAR query [] = {
408 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
409 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
410 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','',' ',
411 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
412 MSIQUERY *view;
413 UINT rc;
414
415 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
416 if (rc == ERROR_SUCCESS)
417 {
418 msiobj_release(&view->hdr);
419 return TRUE;
420 }
421 return FALSE;
422 }
423
424 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
425 {
426 LPWSTR source, check;
427
428 if (msi_get_property_int( package->db, szInstalled, 0 ))
429 {
430 HKEY hkey;
431
432 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
433 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
434 RegCloseKey( hkey );
435 }
436 else
437 {
438 LPWSTR p, db;
439 DWORD len;
440
441 db = msi_dup_property( package->db, szOriginalDatabase );
442 if (!db)
443 return ERROR_OUTOFMEMORY;
444
445 p = strrchrW( db, '\\' );
446 if (!p)
447 {
448 p = strrchrW( db, '/' );
449 if (!p)
450 {
451 msi_free(db);
452 return ERROR_SUCCESS;
453 }
454 }
455
456 len = p - db + 2;
457 source = msi_alloc( len * sizeof(WCHAR) );
458 lstrcpynW( source, db, len );
459 msi_free( db );
460 }
461
462 check = msi_dup_property( package->db, szSourceDir );
463 if (!check || replace)
464 {
465 UINT r = msi_set_property( package->db, szSourceDir, source );
466 if (r == ERROR_SUCCESS)
467 msi_reset_folders( package, TRUE );
468 }
469 msi_free( check );
470
471 check = msi_dup_property( package->db, szSOURCEDIR );
472 if (!check || replace)
473 msi_set_property( package->db, szSOURCEDIR, source );
474
475 msi_free( check );
476 msi_free( source );
477
478 return ERROR_SUCCESS;
479 }
480
481 static BOOL needs_ui_sequence(MSIPACKAGE *package)
482 {
483 return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
484 }
485
486 UINT msi_set_context(MSIPACKAGE *package)
487 {
488 UINT r = msi_locate_product( package->ProductCode, &package->Context );
489 if (r != ERROR_SUCCESS)
490 {
491 int num = msi_get_property_int( package->db, szAllUsers, 0 );
492 if (num == 1 || num == 2)
493 package->Context = MSIINSTALLCONTEXT_MACHINE;
494 else
495 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
496 }
497 return ERROR_SUCCESS;
498 }
499
500 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
501 {
502 UINT rc;
503 LPCWSTR cond, action;
504 MSIPACKAGE *package = param;
505
506 action = MSI_RecordGetString(row,1);
507 if (!action)
508 {
509 ERR("Error is retrieving action name\n");
510 return ERROR_FUNCTION_FAILED;
511 }
512
513 /* check conditions */
514 cond = MSI_RecordGetString(row,2);
515
516 /* this is a hack to skip errors in the condition code */
517 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
518 {
519 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
520 return ERROR_SUCCESS;
521 }
522
523 if (needs_ui_sequence(package))
524 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
525 else
526 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
527
528 msi_dialog_check_messages( NULL );
529
530 if (package->CurrentInstallState != ERROR_SUCCESS)
531 rc = package->CurrentInstallState;
532
533 if (rc == ERROR_FUNCTION_NOT_CALLED)
534 rc = ERROR_SUCCESS;
535
536 if (rc != ERROR_SUCCESS)
537 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
538
539 if (package->need_reboot_now)
540 {
541 TRACE("action %s asked for immediate reboot, suspending installation\n",
542 debugstr_w(action));
543 rc = ACTION_ForceReboot( package );
544 }
545 return rc;
546 }
547
548 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
549 {
550 static const WCHAR query[] = {
551 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
552 ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
553 '>',' ','',' ','O','R','D','E','R',' ','B','Y',' ',
554 '`','S','e','q','u','e','n','c','e','`',0};
555 MSIQUERY *view;
556 UINT r;
557
558 TRACE("%p %s\n", package, debugstr_w(table));
559
560 r = MSI_OpenQuery( package->db, &view, query, table );
561 if (r == ERROR_SUCCESS)
562 {
563 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
564 msiobj_release(&view->hdr);
565 }
566 return r;
567 }
568
569 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
570 {
571 static const WCHAR query[] = {
572 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
573 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
574 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
575 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
576 'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
577 static const WCHAR query_validate[] = {
578 'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
579 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
580 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
581 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
582 ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
583 MSIQUERY *view;
584 INT seq = 0;
585 UINT rc;
586
587 if (package->script->ExecuteSequenceRun)
588 {
589 TRACE("Execute Sequence already Run\n");
590 return ERROR_SUCCESS;
591 }
592
593 package->script->ExecuteSequenceRun = TRUE;
594
595 /* get the sequence number */
596 if (UIran)
597 {
598 MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
599 if (!row) return ERROR_FUNCTION_FAILED;
600 seq = MSI_RecordGetInteger(row,1);
601 msiobj_release(&row->hdr);
602 }
603 rc = MSI_OpenQuery(package->db, &view, query, seq);
604 if (rc == ERROR_SUCCESS)
605 {
606 TRACE("Running the actions\n");
607
608 msi_set_property(package->db, szSourceDir, NULL);
609 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
610 msiobj_release(&view->hdr);
611 }
612 return rc;
613 }
614
615 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
616 {
617 static const WCHAR query[] = {
618 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
619 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
620 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','',' ',
621 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
622 MSIQUERY *view;
623 UINT rc;
624
625 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
626 if (rc == ERROR_SUCCESS)
627 {
628 TRACE("Running the actions\n");
629 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
630 msiobj_release(&view->hdr);
631 }
632 return rc;
633 }
634
635 /********************************************************
636 * ACTION helper functions and functions that perform the actions
637 *******************************************************/
638 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
639 UINT* rc, UINT script, BOOL force )
640 {
641 BOOL ret=FALSE;
642 UINT arc;
643
644 arc = ACTION_CustomAction(package, action, script, force);
645
646 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
647 {
648 *rc = arc;
649 ret = TRUE;
650 }
651 return ret;
652 }
653
654 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
655 {
656 MSICOMPONENT *comp;
657
658 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
659 {
660 if (!strcmpW( Component, comp->Component )) return comp;
661 }
662 return NULL;
663 }
664
665 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
666 {
667 MSIFEATURE *feature;
668
669 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
670 {
671 if (!strcmpW( Feature, feature->Feature )) return feature;
672 }
673 return NULL;
674 }
675
676 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
677 {
678 MSIFILE *file;
679
680 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
681 {
682 if (!strcmpW( key, file->File )) return file;
683 }
684 return NULL;
685 }
686
687 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
688 {
689 MSIFILEPATCH *patch;
690
691 /* FIXME: There might be more than one patch */
692 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
693 {
694 if (!strcmpW( key, patch->File->File )) return patch;
695 }
696 return NULL;
697 }
698
699 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
700 {
701 MSIFOLDER *folder;
702
703 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
704 {
705 if (!strcmpW( dir, folder->Directory )) return folder;
706 }
707 return NULL;
708 }
709
710 /*
711 * Recursively create all directories in the path.
712 * shamelessly stolen from setupapi/queue.c
713 */
714 BOOL msi_create_full_path( const WCHAR *path )
715 {
716 BOOL ret = TRUE;
717 WCHAR *new_path;
718 int len;
719
720 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
721 strcpyW( new_path, path );
722
723 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
724 new_path[len - 1] = 0;
725
726 while (!CreateDirectoryW( new_path, NULL ))
727 {
728 WCHAR *slash;
729 DWORD last_error = GetLastError();
730 if (last_error == ERROR_ALREADY_EXISTS) break;
731 if (last_error != ERROR_PATH_NOT_FOUND)
732 {
733 ret = FALSE;
734 break;
735 }
736 if (!(slash = strrchrW( new_path, '\\' )))
737 {
738 ret = FALSE;
739 break;
740 }
741 len = slash - new_path;
742 new_path[len] = 0;
743 if (!msi_create_full_path( new_path ))
744 {
745 ret = FALSE;
746 break;
747 }
748 new_path[len] = '\\';
749 }
750 msi_free( new_path );
751 return ret;
752 }
753
754 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
755 {
756 MSIRECORD *row;
757
758 row = MSI_CreateRecord( 4 );
759 MSI_RecordSetInteger( row, 1, a );
760 MSI_RecordSetInteger( row, 2, b );
761 MSI_RecordSetInteger( row, 3, c );
762 MSI_RecordSetInteger( row, 4, d );
763 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
764 msiobj_release( &row->hdr );
765
766 msi_dialog_check_messages( NULL );
767 }
768
769 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
770 {
771 static const WCHAR query[] =
772 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
773 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
774 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
775 WCHAR message[1024];
776 MSIRECORD *row = 0;
777 DWORD size;
778
779 if (!package->LastAction || strcmpW( package->LastAction, action ))
780 {
781 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
782
783 if (MSI_RecordIsNull( row, 3 ))
784 {
785 msiobj_release( &row->hdr );
786 return;
787 }
788 /* update the cached action format */
789 msi_free( package->ActionFormat );
790 package->ActionFormat = msi_dup_record_field( row, 3 );
791 msi_free( package->LastAction );
792 package->LastAction = strdupW( action );
793 msiobj_release( &row->hdr );
794 }
795 size = 1024;
796 MSI_RecordSetStringW( record, 0, package->ActionFormat );
797 MSI_FormatRecordW( package, record, message, &size );
798 row = MSI_CreateRecord( 1 );
799 MSI_RecordSetStringW( row, 1, message );
800 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
801 msiobj_release( &row->hdr );
802 }
803
804 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
805 {
806 if (!comp->Enabled)
807 {
808 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
809 return INSTALLSTATE_UNKNOWN;
810 }
811 if (package->need_rollback) return comp->Installed;
812 return comp->ActionRequest;
813 }
814
815 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
816 {
817 if (package->need_rollback) return feature->Installed;
818 return feature->ActionRequest;
819 }
820
821 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
822 {
823 MSIPACKAGE *package = param;
824 LPCWSTR dir, component, full_path;
825 MSIRECORD *uirow;
826 MSIFOLDER *folder;
827 MSICOMPONENT *comp;
828
829 component = MSI_RecordGetString(row, 2);
830 if (!component)
831 return ERROR_SUCCESS;
832
833 comp = msi_get_loaded_component(package, component);
834 if (!comp)
835 return ERROR_SUCCESS;
836
837 comp->Action = msi_get_component_action( package, comp );
838 if (comp->Action != INSTALLSTATE_LOCAL)
839 {
840 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
841 return ERROR_SUCCESS;
842 }
843
844 dir = MSI_RecordGetString(row,1);
845 if (!dir)
846 {
847 ERR("Unable to get folder id\n");
848 return ERROR_SUCCESS;
849 }
850
851 uirow = MSI_CreateRecord(1);
852 MSI_RecordSetStringW(uirow, 1, dir);
853 msi_ui_actiondata(package, szCreateFolders, uirow);
854 msiobj_release(&uirow->hdr);
855
856 full_path = msi_get_target_folder( package, dir );
857 if (!full_path)
858 {
859 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
860 return ERROR_SUCCESS;
861 }
862 TRACE("folder is %s\n", debugstr_w(full_path));
863
864 folder = msi_get_loaded_folder( package, dir );
865 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
866 folder->State = FOLDER_STATE_CREATED;
867 return ERROR_SUCCESS;
868 }
869
870 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
871 {
872 static const WCHAR query[] = {
873 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
874 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
875 MSIQUERY *view;
876 UINT rc;
877
878 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
879 if (rc != ERROR_SUCCESS)
880 return ERROR_SUCCESS;
881
882 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
883 msiobj_release(&view->hdr);
884 return rc;
885 }
886
887 static void remove_persistent_folder( MSIFOLDER *folder )
888 {
889 FolderList *fl;
890
891 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
892 {
893 remove_persistent_folder( fl->folder );
894 }
895 if (folder->persistent && folder->State != FOLDER_STATE_REMOVED)
896 {
897 if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED;
898 }
899 }
900
901 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
902 {
903 MSIPACKAGE *package = param;
904 LPCWSTR dir, component, full_path;
905 MSIRECORD *uirow;
906 MSIFOLDER *folder;
907 MSICOMPONENT *comp;
908
909 component = MSI_RecordGetString(row, 2);
910 if (!component)
911 return ERROR_SUCCESS;
912
913 comp = msi_get_loaded_component(package, component);
914 if (!comp)
915 return ERROR_SUCCESS;
916
917 comp->Action = msi_get_component_action( package, comp );
918 if (comp->Action != INSTALLSTATE_ABSENT)
919 {
920 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
921 return ERROR_SUCCESS;
922 }
923
924 dir = MSI_RecordGetString( row, 1 );
925 if (!dir)
926 {
927 ERR("Unable to get folder id\n");
928 return ERROR_SUCCESS;
929 }
930
931 full_path = msi_get_target_folder( package, dir );
932 if (!full_path)
933 {
934 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
935 return ERROR_SUCCESS;
936 }
937 TRACE("folder is %s\n", debugstr_w(full_path));
938
939 uirow = MSI_CreateRecord( 1 );
940 MSI_RecordSetStringW( uirow, 1, dir );
941 msi_ui_actiondata( package, szRemoveFolders, uirow );
942 msiobj_release( &uirow->hdr );
943
944 folder = msi_get_loaded_folder( package, dir );
945 remove_persistent_folder( folder );
946 return ERROR_SUCCESS;
947 }
948
949 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
950 {
951 static const WCHAR query[] = {
952 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
953 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
954 MSIQUERY *view;
955 UINT rc;
956
957 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
958 if (rc != ERROR_SUCCESS)
959 return ERROR_SUCCESS;
960
961 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
962 msiobj_release( &view->hdr );
963 return rc;
964 }
965
966 static UINT load_component( MSIRECORD *row, LPVOID param )
967 {
968 MSIPACKAGE *package = param;
969 MSICOMPONENT *comp;
970
971 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
972 if (!comp)
973 return ERROR_FUNCTION_FAILED;
974
975 list_add_tail( &package->components, &comp->entry );
976
977 /* fill in the data */
978 comp->Component = msi_dup_record_field( row, 1 );
979
980 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
981
982 comp->ComponentId = msi_dup_record_field( row, 2 );
983 comp->Directory = msi_dup_record_field( row, 3 );
984 comp->Attributes = MSI_RecordGetInteger(row,4);
985 comp->Condition = msi_dup_record_field( row, 5 );
986 comp->KeyPath = msi_dup_record_field( row, 6 );
987
988 comp->Installed = INSTALLSTATE_UNKNOWN;
989 comp->Action = INSTALLSTATE_UNKNOWN;
990 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
991
992 comp->assembly = msi_load_assembly( package, comp );
993 return ERROR_SUCCESS;
994 }
995
996 UINT msi_load_all_components( MSIPACKAGE *package )
997 {
998 static const WCHAR query[] = {
999 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1000 '`','C','o','m','p','o','n','e','n','t','`',0};
1001 MSIQUERY *view;
1002 UINT r;
1003
1004 if (!list_empty(&package->components))
1005 return ERROR_SUCCESS;
1006
1007 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1008 if (r != ERROR_SUCCESS)
1009 return r;
1010
1011 if (!msi_init_assembly_caches( package ))
1012 {
1013 ERR("can't initialize assembly caches\n");
1014 msiobj_release( &view->hdr );
1015 return ERROR_FUNCTION_FAILED;
1016 }
1017
1018 r = MSI_IterateRecords(view, NULL, load_component, package);
1019 msiobj_release(&view->hdr);
1020 msi_destroy_assembly_caches( package );
1021 return r;
1022 }
1023
1024 typedef struct {
1025 MSIPACKAGE *package;
1026 MSIFEATURE *feature;
1027 } _ilfs;
1028
1029 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1030 {
1031 ComponentList *cl;
1032
1033 cl = msi_alloc( sizeof (*cl) );
1034 if ( !cl )
1035 return ERROR_NOT_ENOUGH_MEMORY;
1036 cl->component = comp;
1037 list_add_tail( &feature->Components, &cl->entry );
1038
1039 return ERROR_SUCCESS;
1040 }
1041
1042 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1043 {
1044 FeatureList *fl;
1045
1046 fl = msi_alloc( sizeof(*fl) );
1047 if ( !fl )
1048 return ERROR_NOT_ENOUGH_MEMORY;
1049 fl->feature = child;
1050 list_add_tail( &parent->Children, &fl->entry );
1051
1052 return ERROR_SUCCESS;
1053 }
1054
1055 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1056 {
1057 _ilfs* ilfs = param;
1058 LPCWSTR component;
1059 MSICOMPONENT *comp;
1060
1061 component = MSI_RecordGetString(row,1);
1062
1063 /* check to see if the component is already loaded */
1064 comp = msi_get_loaded_component( ilfs->package, component );
1065 if (!comp)
1066 {
1067 WARN("ignoring unknown component %s\n", debugstr_w(component));
1068 return ERROR_SUCCESS;
1069 }
1070 add_feature_component( ilfs->feature, comp );
1071 comp->Enabled = TRUE;
1072
1073 return ERROR_SUCCESS;
1074 }
1075
1076 static UINT load_feature(MSIRECORD * row, LPVOID param)
1077 {
1078 static const WCHAR query[] = {
1079 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
1080 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1081 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
1082 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1083 MSIPACKAGE *package = param;
1084 MSIFEATURE *feature;
1085 MSIQUERY *view;
1086 _ilfs ilfs;
1087 UINT rc;
1088
1089 /* fill in the data */
1090
1091 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1092 if (!feature)
1093 return ERROR_NOT_ENOUGH_MEMORY;
1094
1095 list_init( &feature->Children );
1096 list_init( &feature->Components );
1097
1098 feature->Feature = msi_dup_record_field( row, 1 );
1099
1100 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1101
1102 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1103 feature->Title = msi_dup_record_field( row, 3 );
1104 feature->Description = msi_dup_record_field( row, 4 );
1105
1106 if (!MSI_RecordIsNull(row,5))
1107 feature->Display = MSI_RecordGetInteger(row,5);
1108
1109 feature->Level= MSI_RecordGetInteger(row,6);
1110 feature->Directory = msi_dup_record_field( row, 7 );
1111 feature->Attributes = MSI_RecordGetInteger(row,8);
1112
1113 feature->Installed = INSTALLSTATE_UNKNOWN;
1114 feature->Action = INSTALLSTATE_UNKNOWN;
1115 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1116
1117 list_add_tail( &package->features, &feature->entry );
1118
1119 /* load feature components */
1120
1121 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1122 if (rc != ERROR_SUCCESS)
1123 return ERROR_SUCCESS;
1124
1125 ilfs.package = package;
1126 ilfs.feature = feature;
1127
1128 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1129 msiobj_release(&view->hdr);
1130 return rc;
1131 }
1132
1133 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1134 {
1135 MSIPACKAGE *package = param;
1136 MSIFEATURE *parent, *child;
1137
1138 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1139 if (!child)
1140 return ERROR_FUNCTION_FAILED;
1141
1142 if (!child->Feature_Parent)
1143 return ERROR_SUCCESS;
1144
1145 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1146 if (!parent)
1147 return ERROR_FUNCTION_FAILED;
1148
1149 add_feature_child( parent, child );
1150 return ERROR_SUCCESS;
1151 }
1152
1153 UINT msi_load_all_features( MSIPACKAGE *package )
1154 {
1155 static const WCHAR query[] = {
1156 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1157 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
1158 '`','D','i','s','p','l','a','y','`',0};
1159 MSIQUERY *view;
1160 UINT r;
1161
1162 if (!list_empty(&package->features))
1163 return ERROR_SUCCESS;
1164
1165 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1166 if (r != ERROR_SUCCESS)
1167 return r;
1168
1169 r = MSI_IterateRecords( view, NULL, load_feature, package );
1170 if (r != ERROR_SUCCESS)
1171 {
1172 msiobj_release( &view->hdr );
1173 return r;
1174 }
1175 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1176 msiobj_release( &view->hdr );
1177 return r;
1178 }
1179
1180 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1181 {
1182 if (!p)
1183 return p;
1184 p = strchrW(p, ch);
1185 if (!p)
1186 return p;
1187 *p = 0;
1188 return p+1;
1189 }
1190
1191 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1192 {
1193 static const WCHAR query[] = {
1194 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1195 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1196 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1197 MSIQUERY *view = NULL;
1198 MSIRECORD *row = NULL;
1199 UINT r;
1200
1201 TRACE("%s\n", debugstr_w(file->File));
1202
1203 r = MSI_OpenQuery(package->db, &view, query, file->File);
1204 if (r != ERROR_SUCCESS)
1205 goto done;
1206
1207 r = MSI_ViewExecute(view, NULL);
1208 if (r != ERROR_SUCCESS)
1209 goto done;
1210
1211 r = MSI_ViewFetch(view, &row);
1212 if (r != ERROR_SUCCESS)
1213 goto done;
1214
1215 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1216 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1217 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1218 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1219 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1220
1221 done:
1222 if (view) msiobj_release(&view->hdr);
1223 if (row) msiobj_release(&row->hdr);
1224 return r;
1225 }
1226
1227 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1228 {
1229 MSIRECORD *row;
1230 static const WCHAR query[] = {
1231 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1232 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1233 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1234
1235 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1236 if (!row)
1237 {
1238 WARN("query failed\n");
1239 return ERROR_FUNCTION_FAILED;
1240 }
1241
1242 file->disk_id = MSI_RecordGetInteger( row, 1 );
1243 msiobj_release( &row->hdr );
1244 return ERROR_SUCCESS;
1245 }
1246
1247 static UINT load_file(MSIRECORD *row, LPVOID param)
1248 {
1249 MSIPACKAGE* package = param;
1250 LPCWSTR component;
1251 MSIFILE *file;
1252
1253 /* fill in the data */
1254
1255 file = msi_alloc_zero( sizeof (MSIFILE) );
1256 if (!file)
1257 return ERROR_NOT_ENOUGH_MEMORY;
1258
1259 file->File = msi_dup_record_field( row, 1 );
1260
1261 component = MSI_RecordGetString( row, 2 );
1262 file->Component = msi_get_loaded_component( package, component );
1263
1264 if (!file->Component)
1265 {
1266 WARN("Component not found: %s\n", debugstr_w(component));
1267 msi_free(file->File);
1268 msi_free(file);
1269 return ERROR_SUCCESS;
1270 }
1271
1272 file->FileName = msi_dup_record_field( row, 3 );
1273 msi_reduce_to_long_filename( file->FileName );
1274
1275 file->ShortName = msi_dup_record_field( row, 3 );
1276 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1277
1278 file->FileSize = MSI_RecordGetInteger( row, 4 );
1279 file->Version = msi_dup_record_field( row, 5 );
1280 file->Language = msi_dup_record_field( row, 6 );
1281 file->Attributes = MSI_RecordGetInteger( row, 7 );
1282 file->Sequence = MSI_RecordGetInteger( row, 8 );
1283
1284 file->state = msifs_invalid;
1285
1286 /* if the compressed bits are not set in the file attributes,
1287 * then read the information from the package word count property
1288 */
1289 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1290 {
1291 file->IsCompressed = FALSE;
1292 }
1293 else if (file->Attributes &
1294 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1295 {
1296 file->IsCompressed = TRUE;
1297 }
1298 else if (file->Attributes & msidbFileAttributesNoncompressed)
1299 {
1300 file->IsCompressed = FALSE;
1301 }
1302 else
1303 {
1304 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1305 }
1306
1307 load_file_hash(package, file);
1308 load_file_disk_id(package, file);
1309
1310 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1311
1312 list_add_tail( &package->files, &file->entry );
1313
1314 return ERROR_SUCCESS;
1315 }
1316
1317 static UINT load_all_files(MSIPACKAGE *package)
1318 {
1319 static const WCHAR query[] = {
1320 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1321 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1322 '`','S','e','q','u','e','n','c','e','`', 0};
1323 MSIQUERY *view;
1324 UINT rc;
1325
1326 if (!list_empty(&package->files))
1327 return ERROR_SUCCESS;
1328
1329 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1330 if (rc != ERROR_SUCCESS)
1331 return ERROR_SUCCESS;
1332
1333 rc = MSI_IterateRecords(view, NULL, load_file, package);
1334 msiobj_release(&view->hdr);
1335 return rc;
1336 }
1337
1338 static UINT load_media( MSIRECORD *row, LPVOID param )
1339 {
1340 MSIPACKAGE *package = param;
1341 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1342 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1343
1344 /* FIXME: load external cabinets and directory sources too */
1345 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1346 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1347 return ERROR_SUCCESS;
1348 }
1349
1350 static UINT load_all_media( MSIPACKAGE *package )
1351 {
1352 static const WCHAR query[] = {
1353 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
1354 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
1355 '`','D','i','s','k','I','d','`',0};
1356 MSIQUERY *view;
1357 UINT r;
1358
1359 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1360 if (r != ERROR_SUCCESS)
1361 return ERROR_SUCCESS;
1362
1363 r = MSI_IterateRecords( view, NULL, load_media, package );
1364 msiobj_release( &view->hdr );
1365 return r;
1366 }
1367
1368 static UINT load_patch(MSIRECORD *row, LPVOID param)
1369 {
1370 MSIPACKAGE *package = param;
1371 MSIFILEPATCH *patch;
1372 LPWSTR file_key;
1373
1374 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1375 if (!patch)
1376 return ERROR_NOT_ENOUGH_MEMORY;
1377
1378 file_key = msi_dup_record_field( row, 1 );
1379 patch->File = msi_get_loaded_file( package, file_key );
1380 msi_free(file_key);
1381
1382 if( !patch->File )
1383 {
1384 ERR("Failed to find target for patch in File table\n");
1385 msi_free(patch);
1386 return ERROR_FUNCTION_FAILED;
1387 }
1388
1389 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1390
1391 /* FIXME: The database should be properly transformed */
1392 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1393
1394 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1395 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1396 patch->IsApplied = FALSE;
1397
1398 /* FIXME:
1399 * Header field - for patch validation.
1400 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1401 */
1402
1403 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1404
1405 list_add_tail( &package->filepatches, &patch->entry );
1406
1407 return ERROR_SUCCESS;
1408 }
1409
1410 static UINT load_all_patches(MSIPACKAGE *package)
1411 {
1412 static const WCHAR query[] = {
1413 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1414 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1415 '`','S','e','q','u','e','n','c','e','`',0};
1416 MSIQUERY *view;
1417 UINT rc;
1418
1419 if (!list_empty(&package->filepatches))
1420 return ERROR_SUCCESS;
1421
1422 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1423 if (rc != ERROR_SUCCESS)
1424 return ERROR_SUCCESS;
1425
1426 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1427 msiobj_release(&view->hdr);
1428 return rc;
1429 }
1430
1431 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1432 {
1433 static const WCHAR query[] = {
1434 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1435 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1436 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1437 MSIQUERY *view;
1438
1439 folder->persistent = FALSE;
1440 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1441 {
1442 if (!MSI_ViewExecute( view, NULL ))
1443 {
1444 MSIRECORD *rec;
1445 if (!MSI_ViewFetch( view, &rec ))
1446 {
1447 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1448 folder->persistent = TRUE;
1449 msiobj_release( &rec->hdr );
1450 }
1451 }
1452 msiobj_release( &view->hdr );
1453 }
1454 return ERROR_SUCCESS;
1455 }
1456
1457 static UINT load_folder( MSIRECORD *row, LPVOID param )
1458 {
1459 MSIPACKAGE *package = param;
1460 static WCHAR szEmpty[] = { 0 };
1461 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1462 MSIFOLDER *folder;
1463
1464 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1465 list_init( &folder->children );
1466 folder->Directory = msi_dup_record_field( row, 1 );
1467 folder->Parent = msi_dup_record_field( row, 2 );
1468 p = msi_dup_record_field(row, 3);
1469
1470 TRACE("%s\n", debugstr_w(folder->Directory));
1471
1472 /* split src and target dir */
1473 tgt_short = p;
1474 src_short = folder_split_path( p, ':' );
1475
1476 /* split the long and short paths */
1477 tgt_long = folder_split_path( tgt_short, '|' );
1478 src_long = folder_split_path( src_short, '|' );
1479
1480 /* check for no-op dirs */
1481 if (tgt_short && !strcmpW( szDot, tgt_short ))
1482 tgt_short = szEmpty;
1483 if (src_short && !strcmpW( szDot, src_short ))
1484 src_short = szEmpty;
1485
1486 if (!tgt_long)
1487 tgt_long = tgt_short;
1488
1489 if (!src_short) {
1490 src_short = tgt_short;
1491 src_long = tgt_long;
1492 }
1493
1494 if (!src_long)
1495 src_long = src_short;
1496
1497 /* FIXME: use the target short path too */
1498 folder->TargetDefault = strdupW(tgt_long);
1499 folder->SourceShortPath = strdupW(src_short);
1500 folder->SourceLongPath = strdupW(src_long);
1501 msi_free(p);
1502
1503 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1504 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1505 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1506
1507 load_folder_persistence( package, folder );
1508
1509 list_add_tail( &package->folders, &folder->entry );
1510 return ERROR_SUCCESS;
1511 }
1512
1513 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1514 {
1515 FolderList *fl;
1516
1517 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1518 fl->folder = child;
1519 list_add_tail( &parent->children, &fl->entry );
1520 return ERROR_SUCCESS;
1521 }
1522
1523 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1524 {
1525 MSIPACKAGE *package = param;
1526 MSIFOLDER *parent, *child;
1527
1528 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1529 return ERROR_FUNCTION_FAILED;
1530
1531 if (!child->Parent) return ERROR_SUCCESS;
1532
1533 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1534 return ERROR_FUNCTION_FAILED;
1535
1536 return add_folder_child( parent, child );
1537 }
1538
1539 static UINT load_all_folders( MSIPACKAGE *package )
1540 {
1541 static const WCHAR query[] = {
1542 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1543 '`','D','i','r','e','c','t','o','r','y','`',0};
1544 MSIQUERY *view;
1545 UINT r;
1546
1547 if (!list_empty(&package->folders))
1548 return ERROR_SUCCESS;
1549
1550 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1551 if (r != ERROR_SUCCESS)
1552 return r;
1553
1554 r = MSI_IterateRecords( view, NULL, load_folder, package );
1555 if (r != ERROR_SUCCESS)
1556 {
1557 msiobj_release( &view->hdr );
1558 return r;
1559 }
1560 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1561 msiobj_release( &view->hdr );
1562 return r;
1563 }
1564
1565 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1566 {
1567 msi_set_property( package->db, szCostingComplete, szZero );
1568 msi_set_property( package->db, szRootDrive, szCRoot );
1569
1570 load_all_folders( package );
1571 msi_load_all_components( package );
1572 msi_load_all_features( package );
1573 load_all_files( package );
1574 load_all_patches( package );
1575 load_all_media( package );
1576
1577 return ERROR_SUCCESS;
1578 }
1579
1580 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1581 {
1582 const WCHAR *action = package->script->Actions[script][index];
1583 ui_actionstart( package, action );
1584 TRACE("executing %s\n", debugstr_w(action));
1585 return ACTION_PerformAction( package, action, script );
1586 }
1587
1588 static UINT execute_script( MSIPACKAGE *package, UINT script )
1589 {
1590 UINT i, rc = ERROR_SUCCESS;
1591
1592 TRACE("executing script %u\n", script);
1593
1594 if (!package->script)
1595 {
1596 ERR("no script!\n");
1597 return ERROR_FUNCTION_FAILED;
1598 }
1599 if (script == SCRIPT_ROLLBACK)
1600 {
1601 for (i = package->script->ActionCount[script]; i > 0; i--)
1602 {
1603 rc = execute_script_action( package, script, i - 1 );
1604 if (rc != ERROR_SUCCESS) break;
1605 }
1606 }
1607 else
1608 {
1609 for (i = 0; i < package->script->ActionCount[script]; i++)
1610 {
1611 rc = execute_script_action( package, script, i );
1612 if (rc != ERROR_SUCCESS) break;
1613 }
1614 }
1615 msi_free_action_script(package, script);
1616 return rc;
1617 }
1618
1619 static UINT ACTION_FileCost(MSIPACKAGE *package)
1620 {
1621 return ERROR_SUCCESS;
1622 }
1623
1624 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1625 {
1626 MSICOMPONENT *comp;
1627 UINT r;
1628
1629 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1630 {
1631 if (!comp->ComponentId) continue;
1632
1633 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1634 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1635 &comp->Installed );
1636 if (r == ERROR_SUCCESS) continue;
1637
1638 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1639 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1640 &comp->Installed );
1641 if (r == ERROR_SUCCESS) continue;
1642
1643 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1644 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1645 &comp->Installed );
1646 if (r == ERROR_SUCCESS) continue;
1647
1648 comp->Installed = INSTALLSTATE_ABSENT;
1649 }
1650 }
1651
1652 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1653 {
1654 MSIFEATURE *feature;
1655
1656 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1657 {
1658 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1659
1660 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1661 feature->Installed = INSTALLSTATE_ABSENT;
1662 else
1663 feature->Installed = state;
1664 }
1665 }
1666
1667 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1668 {
1669 return (feature->Level > 0 && feature->Level <= level);
1670 }
1671
1672 static BOOL process_state_property(MSIPACKAGE* package, int level,
1673 LPCWSTR property, INSTALLSTATE state)
1674 {
1675 LPWSTR override;
1676 MSIFEATURE *feature;
1677
1678 override = msi_dup_property( package->db, property );
1679 if (!override)
1680 return FALSE;
1681
1682 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1683 {
1684 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1685 continue;
1686
1687 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1688
1689 if (!strcmpiW( override, szAll ))
1690 {
1691 if (feature->Installed != state)
1692 {
1693 feature->Action = state;
1694 feature->ActionRequest = state;
1695 }
1696 }
1697 else
1698 {
1699 LPWSTR ptr = override;
1700 LPWSTR ptr2 = strchrW(override,',');
1701
1702 while (ptr)
1703 {
1704 int len = ptr2 - ptr;
1705
1706 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1707 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1708 {
1709 if (feature->Installed != state)
1710 {
1711 feature->Action = state;
1712 feature->ActionRequest = state;
1713 }
1714 break;
1715 }
1716 if (ptr2)
1717 {
1718 ptr=ptr2+1;
1719 ptr2 = strchrW(ptr,',');
1720 }
1721 else
1722 break;
1723 }
1724 }
1725 }
1726 msi_free(override);
1727 return TRUE;
1728 }
1729
1730 static BOOL process_overrides( MSIPACKAGE *package, int level )
1731 {
1732 static const WCHAR szAddLocal[] =
1733 {'A','D','D','L','O','C','A','L',0};
1734 static const WCHAR szAddSource[] =
1735 {'A','D','D','S','O','U','R','C','E',0};
1736 static const WCHAR szAdvertise[] =
1737 {'A','D','V','E','R','T','I','S','E',0};
1738 BOOL ret = FALSE;
1739
1740 /* all these activation/deactivation things happen in order and things
1741 * later on the list override things earlier on the list.
1742 *
1743 * 0 INSTALLLEVEL processing
1744 * 1 ADDLOCAL
1745 * 2 REMOVE
1746 * 3 ADDSOURCE
1747 * 4 ADDDEFAULT
1748 * 5 REINSTALL
1749 * 6 ADVERTISE
1750 * 7 COMPADDLOCAL
1751 * 8 COMPADDSOURCE
1752 * 9 FILEADDLOCAL
1753 * 10 FILEADDSOURCE
1754 * 11 FILEADDDEFAULT
1755 */
1756 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1757 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1758 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1759 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1760 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1761
1762 if (ret)
1763 msi_set_property( package->db, szPreselected, szOne );
1764
1765 return ret;
1766 }
1767
1768 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1769 {
1770 int level;
1771 MSICOMPONENT* component;
1772 MSIFEATURE *feature;
1773
1774 TRACE("Checking Install Level\n");
1775
1776 level = msi_get_property_int(package->db, szInstallLevel, 1);
1777
1778 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1779 {
1780 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1781 {
1782 if (!is_feature_selected( feature, level )) continue;
1783
1784 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1785 {
1786 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1787 {
1788 feature->Action = INSTALLSTATE_SOURCE;
1789 feature->ActionRequest = INSTALLSTATE_SOURCE;
1790 }
1791 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1792 {
1793 feature->Action = INSTALLSTATE_ADVERTISED;
1794 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1795 }
1796 else
1797 {
1798 feature->Action = INSTALLSTATE_LOCAL;
1799 feature->ActionRequest = INSTALLSTATE_LOCAL;
1800 }
1801 }
1802 }
1803 /* disable child features of unselected parent or follow parent */
1804 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1805 {
1806 FeatureList *fl;
1807
1808 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1809 {
1810 if (!is_feature_selected( feature, level ))
1811 {
1812 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1813 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1814 }
1815 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1816 {
1817 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1818 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1819 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1820 fl->feature->Action = feature->Action;
1821 fl->feature->ActionRequest = feature->ActionRequest;
1822 }
1823 }
1824 }
1825 }
1826 else /* preselected */
1827 {
1828 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1829 {
1830 if (!is_feature_selected( feature, level )) continue;
1831
1832 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1833 {
1834 if (feature->Installed == INSTALLSTATE_ABSENT)
1835 {
1836 feature->Action = INSTALLSTATE_UNKNOWN;
1837 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1838 }
1839 else
1840 {
1841 feature->Action = feature->Installed;
1842 feature->ActionRequest = feature->Installed;
1843 }
1844 }
1845 }
1846 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1847 {
1848 FeatureList *fl;
1849
1850 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1851 {
1852 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent &&
1853 (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise)))
1854 {
1855 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n",
1856 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1857 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1858 fl->feature->Action = feature->Action;
1859 fl->feature->ActionRequest = feature->ActionRequest;
1860 }
1861 }
1862 }
1863 }
1864
1865 /* now we want to set component state based based on feature state */
1866 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1867 {
1868 ComponentList *cl;
1869
1870 TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
1871 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1872 feature->ActionRequest, feature->Action);
1873
1874 if (!is_feature_selected( feature, level )) continue;
1875
1876 /* features with components that have compressed files are made local */
1877 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1878 {
1879 if (cl->component->ForceLocalState &&
1880 feature->ActionRequest == INSTALLSTATE_SOURCE)
1881 {
1882 feature->Action = INSTALLSTATE_LOCAL;
1883 feature->ActionRequest = INSTALLSTATE_LOCAL;
1884 break;
1885 }
1886 }
1887
1888 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1889 {
1890 component = cl->component;
1891
1892 switch (feature->ActionRequest)
1893 {
1894 case INSTALLSTATE_ABSENT:
1895 component->anyAbsent = 1;
1896 break;
1897 case INSTALLSTATE_ADVERTISED:
1898 component->hasAdvertiseFeature = 1;
1899 break;
1900 case INSTALLSTATE_SOURCE:
1901 component->hasSourceFeature = 1;
1902 break;
1903 case INSTALLSTATE_LOCAL:
1904 component->hasLocalFeature = 1;
1905 break;
1906 case INSTALLSTATE_DEFAULT:
1907 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1908 component->hasAdvertiseFeature = 1;
1909 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1910 component->hasSourceFeature = 1;
1911 else
1912 component->hasLocalFeature = 1;
1913 break;
1914 default:
1915 break;
1916 }
1917 }
1918 }
1919
1920 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1921 {
1922 /* check if it's local or source */
1923 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1924 (component->hasLocalFeature || component->hasSourceFeature))
1925 {
1926 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1927 !component->ForceLocalState)
1928 {
1929 component->Action = INSTALLSTATE_SOURCE;
1930 component->ActionRequest = INSTALLSTATE_SOURCE;
1931 }
1932 else
1933 {
1934 component->Action = INSTALLSTATE_LOCAL;
1935 component->ActionRequest = INSTALLSTATE_LOCAL;
1936 }
1937 continue;
1938 }
1939
1940 /* if any feature is local, the component must be local too */
1941 if (component->hasLocalFeature)
1942 {
1943 component->Action = INSTALLSTATE_LOCAL;
1944 component->ActionRequest = INSTALLSTATE_LOCAL;
1945 continue;
1946 }
1947 if (component->hasSourceFeature)
1948 {
1949 component->Action = INSTALLSTATE_SOURCE;
1950 component->ActionRequest = INSTALLSTATE_SOURCE;
1951 continue;
1952 }
1953 if (component->hasAdvertiseFeature)
1954 {
1955 component->Action = INSTALLSTATE_ADVERTISED;
1956 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1957 continue;
1958 }
1959 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1960 if (component->anyAbsent &&
1961 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1962 {
1963 component->Action = INSTALLSTATE_ABSENT;
1964 component->ActionRequest = INSTALLSTATE_ABSENT;
1965 }
1966 }
1967
1968 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1969 {
1970 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1971 {
1972 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1973 component->Action = INSTALLSTATE_LOCAL;
1974 component->ActionRequest = INSTALLSTATE_LOCAL;
1975 }
1976
1977 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1978 component->Installed == INSTALLSTATE_SOURCE &&
1979 component->hasSourceFeature)
1980 {
1981 component->Action = INSTALLSTATE_UNKNOWN;
1982 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1983 }
1984
1985 TRACE("component %s (installed %d request %d action %d)\n",
1986 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1987 }
1988
1989 return ERROR_SUCCESS;
1990 }
1991
1992 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1993 {
1994 MSIPACKAGE *package = param;
1995 LPCWSTR name;
1996 MSIFEATURE *feature;
1997
1998 name = MSI_RecordGetString( row, 1 );
1999
2000 feature = msi_get_loaded_feature( package, name );
2001 if (!feature)
2002 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2003 else
2004 {
2005 LPCWSTR Condition;
2006 Condition = MSI_RecordGetString(row,3);
2007
2008 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2009 {
2010 int level = MSI_RecordGetInteger(row,2);
2011 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2012 feature->Level = level;
2013 }
2014 }
2015 return ERROR_SUCCESS;
2016 }
2017
2018 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2019 {
2020 static const WCHAR name[] = {'\\',0};
2021 VS_FIXEDFILEINFO *ptr, *ret;
2022 LPVOID version;
2023 DWORD versize, handle;
2024 UINT sz;
2025
2026 versize = GetFileVersionInfoSizeW( filename, &handle );
2027 if (!versize)
2028 return NULL;
2029
2030 version = msi_alloc( versize );
2031 if (!version)
2032 return NULL;
2033
2034 GetFileVersionInfoW( filename, 0, versize, version );
2035
2036 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2037 {
2038 msi_free( version );
2039 return NULL;
2040 }
2041
2042 ret = msi_alloc( sz );
2043 memcpy( ret, ptr, sz );
2044
2045 msi_free( version );
2046 return ret;
2047 }
2048
2049 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2050 {
2051 DWORD ms, ls;
2052
2053 msi_parse_version_string( version, &ms, &ls );
2054
2055 if (fi->dwFileVersionMS > ms) return 1;
2056 else if (fi->dwFileVersionMS < ms) return -1;
2057 else if (fi->dwFileVersionLS > ls) return 1;
2058 else if (fi->dwFileVersionLS < ls) return -1;
2059 return 0;
2060 }
2061
2062 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2063 {
2064 DWORD ms1, ms2;
2065
2066 msi_parse_version_string( ver1, &ms1, NULL );
2067 msi_parse_version_string( ver2, &ms2, NULL );
2068
2069 if (ms1 > ms2) return 1;
2070 else if (ms1 < ms2) return -1;
2071 return 0;
2072 }
2073
2074 DWORD msi_get_disk_file_size( LPCWSTR filename )
2075 {
2076 HANDLE file;
2077 DWORD size;
2078
2079 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2080 if (file == INVALID_HANDLE_VALUE)
2081 return INVALID_FILE_SIZE;
2082
2083 size = GetFileSize( file, NULL );
2084 TRACE("size is %u\n", size);
2085 CloseHandle( file );
2086 return size;
2087 }
2088
2089 BOOL msi_file_hash_matches( MSIFILE *file )
2090 {
2091 UINT r;
2092 MSIFILEHASHINFO hash;
2093
2094 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2095 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2096 if (r != ERROR_SUCCESS)
2097 return FALSE;
2098
2099 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2100 }
2101
2102 static WCHAR *get_temp_dir( void )
2103 {
2104 static UINT id;
2105 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2106
2107 GetTempPathW( MAX_PATH, tmp );
2108 for (;;)
2109 {
2110 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2111 if (CreateDirectoryW( dir, NULL )) break;
2112 }
2113 return strdupW( dir );
2114 }
2115
2116 /*
2117 * msi_build_directory_name()
2118 *
2119 * This function is to save messing round with directory names
2120 * It handles adding backslashes between path segments,
2121 * and can add \ at the end of the directory name if told to.
2122 *
2123 * It takes a variable number of arguments.
2124 * It always allocates a new string for the result, so make sure
2125 * to free the return value when finished with it.
2126 *
2127 * The first arg is the number of path segments that follow.
2128 * The arguments following count are a list of path segments.
2129 * A path segment may be NULL.
2130 *
2131 * Path segments will be added with a \ separating them.
2132 * A \ will not be added after the last segment, however if the
2133 * last segment is NULL, then the last character will be a \
2134 */
2135 WCHAR *msi_build_directory_name( DWORD count, ... )
2136 {
2137 DWORD sz = 1, i;
2138 WCHAR *dir;
2139 va_list va;
2140
2141 va_start( va, count );
2142 for (i = 0; i < count; i++)
2143 {
2144 const WCHAR *str = va_arg( va, const WCHAR * );
2145 if (str) sz += strlenW( str ) + 1;
2146 }
2147 va_end( va );
2148
2149 dir = msi_alloc( sz * sizeof(WCHAR) );
2150 dir[0] = 0;
2151
2152 va_start( va, count );
2153 for (i = 0; i < count; i++)
2154 {
2155 const WCHAR *str = va_arg( va, const WCHAR * );
2156 if (!str) continue;
2157 strcatW( dir, str );
2158 if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2159 }
2160 va_end( va );
2161 return dir;
2162 }
2163
2164 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2165 {
2166 MSIASSEMBLY *assembly = file->Component->assembly;
2167
2168 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2169
2170 msi_free( file->TargetPath );
2171 if (assembly && !assembly->application)
2172 {
2173 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2174 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2175 msi_track_tempfile( package, file->TargetPath );
2176 }
2177 else
2178 {
2179 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2180 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2181 }
2182
2183 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2184 }
2185
2186 static UINT calculate_file_cost( MSIPACKAGE *package )
2187 {
2188 VS_FIXEDFILEINFO *file_version;
2189 WCHAR *font_version;
2190 MSIFILE *file;
2191
2192 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2193 {
2194 MSICOMPONENT *comp = file->Component;
2195 DWORD file_size;
2196
2197 if (!comp->Enabled) continue;
2198
2199 if (file->IsCompressed)
2200 comp->ForceLocalState = TRUE;
2201
2202 set_target_path( package, file );
2203
2204 if ((comp->assembly && !comp->assembly->installed) ||
2205 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2206 {
2207 comp->Cost += file->FileSize;
2208 continue;
2209 }
2210 file_size = msi_get_disk_file_size( file->TargetPath );
2211
2212 if (file->Version)
2213 {
2214 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2215 {
2216 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2217 {
2218 comp->Cost += file->FileSize - file_size;
2219 }
2220 msi_free( file_version );
2221 continue;
2222 }
2223 else if ((font_version = msi_font_version_from_file( file->TargetPath )))
2224 {
2225 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2226 {
2227 comp->Cost += file->FileSize - file_size;
2228 }
2229 msi_free( font_version );
2230 continue;
2231 }
2232 }
2233 if (file_size != file->FileSize)
2234 {
2235 comp->Cost += file->FileSize - file_size;
2236 }
2237 }
2238 return ERROR_SUCCESS;
2239 }
2240
2241 WCHAR *msi_normalize_path( const WCHAR *in )
2242 {
2243 const WCHAR *p = in;
2244 WCHAR *q, *ret;
2245 int n, len = strlenW( in ) + 2;
2246
2247 if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
2248
2249 len = 0;
2250 while (1)
2251 {
2252 /* copy until the end of the string or a space */
2253 while (*p != ' ' && (*q = *p))
2254 {
2255 p++, len++;
2256 /* reduce many backslashes to one */
2257 if (*p != '\\' || *q != '\\')
2258 q++;
2259 }
2260
2261 /* quit at the end of the string */
2262 if (!*p)
2263 break;
2264
2265 /* count the number of spaces */
2266 n = 0;
2267 while (p[n] == ' ')
2268 n++;
2269
2270 /* if it's leading or trailing space, skip it */
2271 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2272 p += n;
2273 else /* copy n spaces */
2274 while (n && (*q++ = *p++)) n--;
2275 }
2276 while (q - ret > 0 && q[-1] == ' ') q--;
2277 if (q - ret > 0 && q[-1] != '\\')
2278 {
2279 q[0] = '\\';
2280 q[1] = 0;
2281 }
2282 return ret;
2283 }
2284
2285 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2286 {
2287 FolderList *fl;
2288 MSIFOLDER *folder, *parent, *child;
2289 WCHAR *path, *normalized_path;
2290
2291 TRACE("resolving %s\n", debugstr_w(name));
2292
2293 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2294
2295 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2296 {
2297 if (!load_prop || !(path = msi_dup_property( package->db, szTargetDir )))
2298 {
2299 path = msi_dup_property( package->db, szRootDrive );
2300 }
2301 }
2302 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2303 {
2304 if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
2305 {
2306 parent = msi_get_loaded_folder( package, folder->Parent );
2307 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2308 }
2309 else
2310 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2311 }
2312 normalized_path = msi_normalize_path( path );
2313 msi_free( path );
2314 if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
2315 {
2316 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2317 msi_free( normalized_path );
2318 return;
2319 }
2320 msi_set_property( package->db, folder->Directory, normalized_path );
2321 msi_free( folder->ResolvedTarget );
2322 folder->ResolvedTarget = normalized_path;
2323
2324 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2325 {
2326 child = fl->folder;
2327 msi_resolve_target_folder( package, child->Directory, load_prop );
2328 }
2329 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2330 }
2331
2332 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2333 {
2334 static const WCHAR query[] = {
2335 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2336 '`','C','o','n','d','i','t','i','o','n','`',0};
2337 static const WCHAR szOutOfDiskSpace[] = {
2338 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2339 MSICOMPONENT *comp;
2340 MSIQUERY *view;
2341 LPWSTR level;
2342 UINT rc;
2343
2344 TRACE("Building directory properties\n");
2345 msi_resolve_target_folder( package, szTargetDir, TRUE );
2346
2347 TRACE("Evaluating component conditions\n");
2348 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2349 {
2350 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2351 {
2352 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2353 comp->Enabled = FALSE;
2354 }
2355 else
2356 comp->Enabled = TRUE;
2357 }
2358
2359 /* read components states from the registry */
2360 ACTION_GetComponentInstallStates(package);
2361 ACTION_GetFeatureInstallStates(package);
2362
2363 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2364 {
2365 TRACE("Evaluating feature conditions\n");
2366
2367 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2368 if (rc == ERROR_SUCCESS)
2369 {
2370 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2371 msiobj_release( &view->hdr );
2372 if (rc != ERROR_SUCCESS)
2373 return rc;
2374 }
2375 }
2376
2377 TRACE("Calculating file cost\n");
2378 calculate_file_cost( package );
2379
2380 msi_set_property( package->db, szCostingComplete, szOne );
2381 /* set default run level if not set */
2382 level = msi_dup_property( package->db, szInstallLevel );
2383 if (!level)
2384 msi_set_property( package->db, szInstallLevel, szOne );
2385 msi_free(level);
2386
2387 /* FIXME: check volume disk space */
2388 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2389
2390 return MSI_SetFeatureStates(package);
2391 }
2392
2393 /* OK this value is "interpreted" and then formatted based on the
2394 first few characters */
2395 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2396 DWORD *size)
2397 {
2398 LPSTR data = NULL;
2399
2400 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2401 {
2402 if (value[1]=='x')
2403 {
2404 LPWSTR ptr;
2405 CHAR byte[5];
2406 LPWSTR deformated = NULL;
2407 int count;
2408
2409 deformat_string(package, &value[2], &deformated);
2410
2411 /* binary value type */
2412 ptr = deformated;
2413 *type = REG_BINARY;
2414 if (strlenW(ptr)%2)
2415 *size = (strlenW(ptr)/2)+1;
2416 else
2417 *size = strlenW(ptr)/2;
2418
2419 data = msi_alloc(*size);
2420
2421 byte[0] = '';
2422 byte[1] = 'x';
2423 byte[4] = 0;
2424 count = 0;
2425 /* if uneven pad with a zero in front */
2426 if (strlenW(ptr)%2)
2427 {
2428 byte[2]= '';
2429 byte[3]= *ptr;
2430 ptr++;
2431 data[count] = (BYTE)strtol(byte,NULL,0);
2432 count ++;
2433 TRACE("Uneven byte count\n");
2434 }
2435 while (*ptr)
2436 {
2437 byte[2]= *ptr;
2438 ptr++;
2439 byte[3]= *ptr;
2440 ptr++;
2441 data[count] = (BYTE)strtol(byte,NULL,0);
2442 count ++;
2443 }
2444 msi_free(deformated);
2445
2446 TRACE("Data %i bytes(%i)\n",*size,count);
2447 }
2448 else
2449 {
2450 LPWSTR deformated;
2451 LPWSTR p;
2452 DWORD d = 0;
2453 deformat_string(package, &value[1], &deformated);
2454
2455 *type=REG_DWORD;
2456 *size = sizeof(DWORD);
2457 data = msi_alloc(*size);
2458 p = deformated;
2459 if (*p == '-')
2460 p++;
2461 while (*p)
2462 {
2463 if ( (*p < '') || (*p > '9') )
2464 break;
2465 d *= 10;
2466 d += (*p - '');
2467 p++;
2468 }
2469 if (deformated[0] == '-')
2470 d = -d;
2471 *(LPDWORD)data = d;
2472 TRACE("DWORD %i\n",*(LPDWORD)data);
2473
2474 msi_free(deformated);
2475 }
2476 }
2477 else
2478 {
2479 static const WCHAR szMulti[] = {'[','~',']',0};
2480 LPCWSTR ptr;
2481 *type=REG_SZ;
2482
2483 if (value[0]=='#')
2484 {
2485 if (value[1]=='%')
2486 {
2487 ptr = &value[2];
2488 *type=REG_EXPAND_SZ;
2489 }
2490 else
2491 ptr = &value[1];
2492 }
2493 else
2494 ptr=value;
2495
2496 if (strstrW(value, szMulti))
2497 *type = REG_MULTI_SZ;
2498
2499 /* remove initial delimiter */
2500 if (!strncmpW(value, szMulti, 3))
2501 ptr = value + 3;
2502
2503 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2504
2505 /* add double NULL terminator */
2506 if (*type == REG_MULTI_SZ)
2507 {
2508 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2509 data = msi_realloc_zero(data, *size);
2510 }
2511 }
2512 return data;
2513 }
2514
2515 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2516 {
2517 const WCHAR *ret;
2518
2519 switch (root)
2520 {
2521 case -1:
2522 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2523 {
2524 *root_key = HKEY_LOCAL_MACHINE;
2525 ret = szHLM;
2526 }
2527 else
2528 {
2529 *root_key = HKEY_CURRENT_USER;
2530 ret = szHCU;
2531 }
2532 break;
2533 case 0:
2534 *root_key = HKEY_CLASSES_ROOT;
2535 ret = szHCR;
2536 break;
2537 case 1:
2538 *root_key = HKEY_CURRENT_USER;
2539 ret = szHCU;
2540 break;
2541 case 2:
2542 *root_key = HKEY_LOCAL_MACHINE;
2543 ret = szHLM;
2544 break;
2545 case 3:
2546 *root_key = HKEY_USERS;
2547 ret = szHU;
2548 break;
2549 default:
2550 ERR("Unknown root %i\n", root);
2551 return NULL;
2552 }
2553
2554 return ret;
2555 }
2556
2557 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2558 {
2559 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2560 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2561
2562 if (is_64bit && package->platform == PLATFORM_INTEL &&
2563 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2564 {
2565 UINT size;
2566 WCHAR *path_32node;
2567
2568 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2569 if (!(path_32node = msi_alloc( size ))) return NULL;
2570
2571 memcpy( path_32node, path, len * sizeof(WCHAR) );
2572 strcpyW( path_32node + len, szWow6432Node );
2573 strcatW( path_32node, szBackSlash );
2574 strcatW( path_32node, path + len );
2575 return path_32node;
2576 }
2577
2578 return strdupW( path );
2579 }
2580
2581 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2582 {
2583 MSIPACKAGE *package = param;
2584 LPSTR value_data = NULL;
2585 HKEY root_key, hkey;
2586 DWORD type,size;
2587 LPWSTR deformated, uikey, keypath;
2588 LPCWSTR szRoot, component, name, key, value;
2589 MSICOMPONENT *comp;
2590 MSIRECORD * uirow;
2591 INT root;
2592 BOOL check_first = FALSE;
2593 UINT rc;
2594
2595 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2596
2597 component = MSI_RecordGetString(row, 6);
2598 comp = msi_get_loaded_component(package,component);
2599 if (!comp)
2600 return ERROR_SUCCESS;
2601
2602 comp->Action = msi_get_component_action( package, comp );
2603 if (comp->Action != INSTALLSTATE_LOCAL)
2604 {
2605 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2606 return ERROR_SUCCESS;
2607 }
2608
2609 name = MSI_RecordGetString(row, 4);
2610 if( MSI_RecordIsNull(row,5) && name )
2611 {
2612 /* null values can have special meanings */
2613 if (name[0]=='-' && name[1] == 0)
2614 return ERROR_SUCCESS;
2615 else if ((name[0]=='+' && name[1] == 0) ||
2616 (name[0] == '*' && name[1] == 0))
2617 name = NULL;
2618 check_first = TRUE;
2619 }
2620
2621 root = MSI_RecordGetInteger(row,2);
2622 key = MSI_RecordGetString(row, 3);
2623
2624 szRoot = get_root_key( package, root, &root_key );
2625 if (!szRoot)
2626 return ERROR_SUCCESS;
2627
2628 deformat_string(package, key , &deformated);
2629 size = strlenW(deformated) + strlenW(szRoot) + 1;
2630 uikey = msi_alloc(size*sizeof(WCHAR));
2631 strcpyW(uikey,szRoot);
2632 strcatW(uikey,deformated);
2633
2634 keypath = get_keypath( package, root_key, deformated );
2635 msi_free( deformated );
2636 if (RegCreateKeyW( root_key, keypath, &hkey ))
2637 {
2638 ERR("Could not create key %s\n", debugstr_w(keypath));
2639 msi_free(uikey);
2640 msi_free(keypath);
2641 return ERROR_SUCCESS;
2642 }
2643
2644 value = MSI_RecordGetString(row,5);
2645 if (value)
2646 value_data = parse_value(package, value, &type, &size);
2647 else
2648 {
2649 value_data = (LPSTR)strdupW(szEmpty);
2650 size = sizeof(szEmpty);
2651 type = REG_SZ;
2652 }
2653
2654 deformat_string(package, name, &deformated);
2655
2656 if (!check_first)
2657 {
2658 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2659 debugstr_w(uikey));
2660 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2661 }
2662 else
2663 {
2664 DWORD sz = 0;
2665 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2666 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2667 {
2668 TRACE("value %s of %s checked already exists\n",
2669 debugstr_w(deformated), debugstr_w(uikey));
2670 }
2671 else
2672 {
2673 TRACE("Checked and setting value %s of %s\n",
2674 debugstr_w(deformated), debugstr_w(uikey));
2675 if (deformated || size)
2676 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2677 }
2678 }
2679 RegCloseKey(hkey);
2680
2681 uirow = MSI_CreateRecord(3);
2682 MSI_RecordSetStringW(uirow,2,deformated);
2683 MSI_RecordSetStringW(uirow,1,uikey);
2684 if (type == REG_SZ || type == REG_EXPAND_SZ)
2685 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2686 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2687 msiobj_release( &uirow->hdr );
2688
2689 msi_free(value_data);
2690 msi_free(deformated);
2691 msi_free(uikey);
2692 msi_free(keypath);
2693
2694 return ERROR_SUCCESS;
2695 }
2696
2697 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2698 {
2699 static const WCHAR query[] = {
2700 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2701 '`','R','e','g','i','s','t','r','y','`',0};
2702 MSIQUERY *view;
2703 UINT rc;
2704
2705 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2706 if (rc != ERROR_SUCCESS)
2707 return ERROR_SUCCESS;
2708
2709 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2710 msiobj_release(&view->hdr);
2711 return rc;
2712 }
2713
2714 static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *value )
2715 {
2716 LONG res;
2717 HKEY hkey;
2718 DWORD num_subkeys, num_values;
2719
2720 if (!(res = RegOpenKeyW( root, keypath, &hkey )))
2721 {
2722 if ((res = RegDeleteValueW( hkey, value )))
2723 {
2724 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2725 }
2726 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2727 NULL, NULL, NULL, NULL );
2728 RegCloseKey( hkey );
2729 if (!res && !num_subkeys && !num_values)
2730 {
2731 TRACE("removing empty key %s\n", debugstr_w(keypath));
2732 RegDeleteKeyW( root, keypath );
2733 }
2734 return;
2735 }
2736 TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
2737 }
2738
2739 static void delete_reg_key( HKEY root, const WCHAR *keypath )
2740 {
2741 LONG res = RegDeleteTreeW( root, keypath );
2742 if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res);
2743 }
2744
2745 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2746 {
2747 MSIPACKAGE *package = param;
2748 LPCWSTR component, name, key_str, root_key_str;
2749 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2750 MSICOMPONENT *comp;
2751 MSIRECORD *uirow;
2752 BOOL delete_key = FALSE;
2753 HKEY hkey_root;
2754 UINT size;
2755 INT root;
2756
2757 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2758
2759 component = MSI_RecordGetString( row, 6 );
2760 comp = msi_get_loaded_component( package, component );
2761 if (!comp)
2762 return ERROR_SUCCESS;
2763
2764 comp->Action = msi_get_component_action( package, comp );
2765 if (comp->Action != INSTALLSTATE_ABSENT)
2766 {
2767 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2768 return ERROR_SUCCESS;
2769 }
2770
2771 name = MSI_RecordGetString( row, 4 );
2772 if (MSI_RecordIsNull( row, 5 ) && name )
2773 {
2774 if (name[0] == '+' && !name[1])
2775 return ERROR_SUCCESS;
2776 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2777 {
2778 delete_key = TRUE;
2779 name = NULL;
2780 }
2781 }
2782
2783 root = MSI_RecordGetInteger( row, 2 );
2784 key_str = MSI_RecordGetString( row, 3 );
2785
2786 root_key_str = get_root_key( package, root, &hkey_root );
2787 if (!root_key_str)
2788 return ERROR_SUCCESS;
2789
2790 deformat_string( package, key_str, &deformated_key );
2791 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2792 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2793 strcpyW( ui_key_str, root_key_str );
2794 strcatW( ui_key_str, deformated_key );
2795
2796 deformat_string( package, name, &deformated_name );
2797
2798 keypath = get_keypath( package, hkey_root, deformated_key );
2799 msi_free( deformated_key );
2800 if (delete_key) delete_reg_key( hkey_root, keypath );
2801 else delete_reg_value( hkey_root, keypath, deformated_name );
2802 msi_free( keypath );
2803
2804 uirow = MSI_CreateRecord( 2 );
2805 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2806 MSI_RecordSetStringW( uirow, 2, deformated_name );
2807 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2808 msiobj_release( &uirow->hdr );
2809
2810 msi_free( ui_key_str );
2811 msi_free( deformated_name );
2812 return ERROR_SUCCESS;
2813 }
2814
2815 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2816 {
2817 MSIPACKAGE *package = param;
2818 LPCWSTR component, name, key_str, root_key_str;
2819 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2820 MSICOMPONENT *comp;
2821 MSIRECORD *uirow;
2822 BOOL delete_key = FALSE;
2823 HKEY hkey_root;
2824 UINT size;
2825 INT root;
2826
2827 component = MSI_RecordGetString( row, 5 );
2828 comp = msi_get_loaded_component( package, component );
2829 if (!comp)
2830 return ERROR_SUCCESS;
2831
2832 comp->Action = msi_get_component_action( package, comp );
2833 if (comp->Action != INSTALLSTATE_LOCAL)
2834 {
2835 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2836 return ERROR_SUCCESS;
2837 }
2838
2839 if ((name = MSI_RecordGetString( row, 4 )))
2840 {
2841 if (name[0] == '-' && !name[1])
2842 {
2843 delete_key = TRUE;
2844 name = NULL;
2845 }
2846 }
2847
2848 root = MSI_RecordGetInteger( row, 2 );
2849 key_str = MSI_RecordGetString( row, 3 );
2850
2851 root_key_str = get_root_key( package, root, &hkey_root );
2852 if (!root_key_str)
2853 return ERROR_SUCCESS;
2854
2855 deformat_string( package, key_str, &deformated_key );
2856 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2857 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2858 strcpyW( ui_key_str, root_key_str );
2859 strcatW( ui_key_str, deformated_key );
2860
2861 deformat_string( package, name, &deformated_name );
2862
2863 keypath = get_keypath( package, hkey_root, deformated_key );
2864 msi_free( deformated_key );
2865 if (delete_key) delete_reg_key( hkey_root, keypath );
2866 else delete_reg_value( hkey_root, keypath, deformated_name );
2867 msi_free( keypath );
2868
2869 uirow = MSI_CreateRecord( 2 );
2870 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2871 MSI_RecordSetStringW( uirow, 2, deformated_name );
2872 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2873 msiobj_release( &uirow->hdr );
2874
2875 msi_free( ui_key_str );
2876 msi_free( deformated_name );
2877 return ERROR_SUCCESS;
2878 }
2879
2880 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2881 {
2882 static const WCHAR registry_query[] = {
2883 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2884 '`','R','e','g','i','s','t','r','y','`',0};
2885 static const WCHAR remove_registry_query[] = {
2886 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2887 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2888 MSIQUERY *view;
2889 UINT rc;
2890
2891 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2892 if (rc == ERROR_SUCCESS)
2893 {
2894 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2895 msiobj_release( &view->hdr );
2896 if (rc != ERROR_SUCCESS)
2897 return rc;
2898 }
2899 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2900 if (rc == ERROR_SUCCESS)
2901 {
2902 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2903 msiobj_release( &view->hdr );
2904 if (rc != ERROR_SUCCESS)
2905 return rc;
2906 }
2907 return ERROR_SUCCESS;
2908 }
2909
2910 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2911 {
2912 package->script->CurrentlyScripting = TRUE;
2913
2914 return ERROR_SUCCESS;
2915 }
2916
2917
2918 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2919 {
2920 static const WCHAR query[]= {
2921 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2922 '`','R','e','g','i','s','t','r','y','`',0};
2923 MSICOMPONENT *comp;
2924 DWORD total = 0, count = 0;
2925 MSIQUERY *view;
2926 MSIFEATURE *feature;
2927 MSIFILE *file;
2928 UINT rc;
2929
2930 TRACE("InstallValidate\n");
2931
2932 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2933 if (rc == ERROR_SUCCESS)
2934 {
2935 rc = MSI_IterateRecords( view, &count, NULL, package );
2936 msiobj_release( &view->hdr );
2937 if (rc != ERROR_SUCCESS)
2938 return rc;
2939 total += count * REG_PROGRESS_VALUE;
2940 }
2941 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2942 total += COMPONENT_PROGRESS_VALUE;
2943
2944 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2945 total += file->FileSize;
2946
2947 msi_ui_progress( package, 0, total, 0, 0 );
2948
2949 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2950 {
2951 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2952 debugstr_w(feature->Feature), feature->Installed,
2953 feature->ActionRequest, feature->Action);
2954 }
2955 return ERROR_SUCCESS;
2956 }
2957
2958 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2959 {
2960 MSIPACKAGE* package = param;
2961 LPCWSTR cond = NULL;
2962 LPCWSTR message = NULL;
2963 UINT r;
2964
2965 static const WCHAR title[]=
2966 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2967
2968 cond = MSI_RecordGetString(row,1);
2969
2970 r = MSI_EvaluateConditionW(package,cond);
2971 if (r == MSICONDITION_FALSE)
2972 {
2973 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2974 {
2975 LPWSTR deformated;
2976 message = MSI_RecordGetString(row,2);
2977 deformat_string(package,message,&deformated);
2978 MessageBoxW(NULL,deformated,title,MB_OK);
2979 msi_free(deformated);
2980 }
2981
2982 return ERROR_INSTALL_FAILURE;
2983 }
2984
2985 return ERROR_SUCCESS;
2986 }
2987
2988 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2989 {
2990 static const WCHAR query[] = {
2991 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2992 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2993 MSIQUERY *view;
2994 UINT rc;
2995
2996 TRACE("Checking launch conditions\n");
2997
2998 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2999 if (rc != ERROR_SUCCESS)
3000 return ERROR_SUCCESS;
3001
3002 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3003 msiobj_release(&view->hdr);
3004 return rc;
3005 }
3006
3007 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3008 {
3009
3010 if (!cmp->KeyPath)
3011 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3012
3013 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3014 {
3015 static const WCHAR query[] = {
3016 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3017 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3018 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3019 static const WCHAR fmt[] = {'%','','2','i',':','\\','%','s','\\',0};
3020 static const WCHAR fmt2[]= {'%','','2','i',':','\\','%','s','\\','%','s',0};
3021 MSIRECORD *row;
3022 UINT root, len;
3023 LPWSTR deformated, buffer, deformated_name;
3024 LPCWSTR key, name;
3025
3026 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3027 if (!row)
3028 return NULL;
3029
3030 root = MSI_RecordGetInteger(row,2);
3031 key = MSI_RecordGetString(row, 3);
3032 name = MSI_RecordGetString(row, 4);
3033 deformat_string(package, key , &deformated);
3034 deformat_string(package, name, &deformated_name);
3035
3036 len = strlenW(deformated) + 6;
3037 if (deformated_name)
3038 len+=strlenW(deformated_name);
3039
3040 buffer = msi_alloc( len *sizeof(WCHAR));
3041
3042 if (deformated_name)
3043 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3044 else
3045 sprintfW(buffer,fmt,root,deformated);
3046
3047 msi_free(deformated);
3048 msi_free(deformated_name);
3049 msiobj_release(&row->hdr);
3050
3051 return buffer;
3052 }
3053 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3054 {
3055 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3056 return NULL;
3057 }
3058 else
3059 {
3060 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3061
3062 if (file)
3063 return strdupW( file->TargetPath );
3064 }
3065 return NULL;
3066 }
3067
3068 static HKEY openSharedDLLsKey(void)
3069 {
3070 HKEY hkey=0;
3071 static const WCHAR path[] =
3072 {'S','o','f','t','w','a','r','e','\\',
3073 'M','i','c','r','o','s','o','f','t','\\',
3074 'W','i','n','d','o','w','s','\\',
3075 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3076 'S','h','a','r','e','d','D','L','L','s',0};
3077
3078 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3079 return hkey;
3080 }
3081
3082 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3083 {
3084 HKEY hkey;
3085 DWORD count=0;
3086 DWORD type;
3087 DWORD sz = sizeof(count);
3088 DWORD rc;
3089
3090 hkey = openSharedDLLsKey();
3091 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3092 if (rc != ERROR_SUCCESS)
3093 count = 0;
3094 RegCloseKey(hkey);
3095 return count;
3096 }
3097
3098 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3099 {
3100 HKEY hkey;
3101
3102 hkey = openSharedDLLsKey();
3103 if (count > 0)
3104 msi_reg_set_val_dword( hkey, path, count );
3105 else
3106 RegDeleteValueW(hkey,path);
3107 RegCloseKey(hkey);
3108 return count;
3109 }
3110
3111 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3112 {
3113 MSIFEATURE *feature;
3114 INT count = 0;
3115 BOOL write = FALSE;
3116
3117 /* only refcount DLLs */
3118 if (comp->KeyPath == NULL ||
3119 comp->assembly ||
3120 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3121 comp->Attributes & msidbComponentAttributesODBCDataSource)
3122 write = FALSE;
3123 else
3124 {
3125 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3126 write = (count > 0);
3127
3128 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3129 write = TRUE;
3130 }
3131
3132 /* increment counts */
3133 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3134 {
3135 ComponentList *cl;
3136
3137 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3138 continue;
3139
3140 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3141 {
3142 if ( cl->component == comp )
3143 count++;
3144 }
3145 }
3146
3147 /* decrement counts */
3148 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3149 {
3150 ComponentList *cl;
3151
3152 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3153 continue;
3154
3155 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3156 {
3157 if ( cl->component == comp )
3158 count--;
3159 }
3160 }
3161
3162 /* ref count all the files in the component */
3163 if (write)
3164 {
3165 MSIFILE *file;
3166
3167 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3168 {
3169 if (file->Component == comp)
3170 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3171 }
3172 }
3173
3174 /* add a count for permanent */
3175 if (comp->Attributes & msidbComponentAttributesPermanent)
3176 count ++;
3177
3178 comp->RefCount = count;
3179
3180 if (write)
3181 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3182 }
3183
3184 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3185 {
3186 if (comp->assembly)
3187 {
3188 const WCHAR prefixW[] = {'<','\\',0};
3189 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3190 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3191
3192 if (keypath)
3193 {
3194 strcpyW( keypath, prefixW );
3195 strcatW( keypath, comp->assembly->display_name );
3196 }
3197 return keypath;
3198 }
3199 return resolve_keypath( package, comp );
3200 }
3201
3202 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3203 {
3204 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3205 UINT rc;
3206 MSICOMPONENT *comp;
3207 HKEY hkey;
3208
3209 TRACE("\n");
3210
3211 squash_guid(package->ProductCode,squished_pc);
3212 msi_set_sourcedir_props(package, FALSE);
3213
3214 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3215 {
3216 MSIRECORD *uirow;
3217 INSTALLSTATE action;
3218
3219 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3220 if (!comp->ComponentId)
3221 continue;
3222
3223 squash_guid( comp->ComponentId, squished_cc );
3224 msi_free( comp->FullKeypath );
3225 comp->FullKeypath = build_full_keypath( package, comp );
3226
3227 ACTION_RefCountComponent( package, comp );
3228
3229 if (package->need_rollback) action = comp->Installed;
3230 else action = comp->ActionRequest;
3231
3232 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3233 debugstr_w(comp->Component), debugstr_w(squished_cc),
3234 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3235
3236 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3237 {
3238 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3239 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3240 else
3241 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3242
3243 if (rc != ERROR_SUCCESS)
3244 continue;
3245
3246 if (comp->Attributes & msidbComponentAttributesPermanent)
3247 {
3248 static const WCHAR szPermKey[] =
3249 { '','','','','','','','','','','','',
3250 '','','','','','','','','','','','',
3251 '','','','','','','','',0 };
3252
3253 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3254 }
3255 if (action == INSTALLSTATE_LOCAL)
3256 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3257 else
3258 {
3259 MSIFILE *file;
3260 MSIRECORD *row;
3261 LPWSTR ptr, ptr2;
3262 WCHAR source[MAX_PATH];
3263 WCHAR base[MAX_PATH];
3264 LPWSTR sourcepath;
3265
3266 static const WCHAR fmt[] = {'%','','2','d','\\',0};
3267 static const WCHAR query[] = {
3268 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3269 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3270 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3271 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3272 '`','D','i','s','k','I','d','`',0};
3273
3274 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3275 continue;
3276
3277 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3278 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3279 ptr2 = strrchrW(source, '\\') + 1;
3280 msiobj_release(&row->hdr);
3281
3282 lstrcpyW(base, package->PackagePath);
3283 ptr = strrchrW(base, '\\');
3284 *(ptr + 1) = '\0';
3285
3286 sourcepath = msi_resolve_file_source(package, file);
3287 ptr = sourcepath + lstrlenW(base);
3288 lstrcpyW(ptr2, ptr);
3289 msi_free(sourcepath);
3290
3291 msi_reg_set_val_str(hkey, squished_pc, source);
3292 }
3293 RegCloseKey(hkey);
3294 }
3295 else if (action == INSTALLSTATE_ABSENT)
3296 {
3297 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3298 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3299 else
3300 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3301 }
3302
3303 /* UI stuff */
3304 uirow = MSI_CreateRecord(3);
3305 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3306 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3307 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3308 msi_ui_actiondata( package, szProcessComponents, uirow );
3309 msiobj_release( &uirow->hdr );
3310 }
3311 return ERROR_SUCCESS;
3312 }
3313
3314 typedef struct {
3315 CLSID clsid;
3316 LPWSTR source;
3317
3318 LPWSTR path;
3319 ITypeLib *ptLib;
3320 } typelib_struct;
3321
3322 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3323 LPWSTR lpszName, LONG_PTR lParam)
3324 {
3325 TLIBATTR *attr;
3326 typelib_struct *tl_struct = (typelib_struct*) lParam;
3327 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3328 int sz;
3329 HRESULT res;
3330
3331 if (!IS_INTRESOURCE(lpszName))
3332 {
3333 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3334 return TRUE;
3335 }
3336
3337 sz = strlenW(tl_struct->source)+4;
3338 sz *= sizeof(WCHAR);
3339
3340 if ((INT_PTR)lpszName == 1)
3341 tl_struct->path = strdupW(tl_struct->source);
3342 else
3343 {
3344 tl_struct->path = msi_alloc(sz);
3345 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3346 }
3347
3348 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3349 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3350 if (FAILED(res))
3351 {
3352 msi_free(tl_struct->path);
3353 tl_struct->path = NULL;
3354
3355 return TRUE;
3356 }
3357
3358 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3359 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3360 {
3361 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3362 return FALSE;
3363 }
3364
3365 msi_free(tl_struct->path);
3366 tl_struct->path = NULL;
3367
3368 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3369 ITypeLib_Release(tl_struct->ptLib);
3370
3371 return TRUE;
3372 }
3373
3374 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3375 {
3376 MSIPACKAGE* package = param;
3377 LPCWSTR component;
3378 MSICOMPONENT *comp;
3379 MSIFILE *file;
3380 typelib_struct tl_struct;
3381 ITypeLib *tlib;
3382 HMODULE module;
3383 HRESULT hr;
3384
3385 component = MSI_RecordGetString(row,3);
3386 comp = msi_get_loaded_component(package,component);
3387 if (!comp)
3388 return ERROR_SUCCESS;
3389
3390 comp->Action = msi_get_component_action( package, comp );
3391 if (comp->Action != INSTALLSTATE_LOCAL)
3392 {
3393 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3394 return ERROR_SUCCESS;
3395 }
3396
3397 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3398 {
3399 TRACE("component has no key path\n");
3400 return ERROR_SUCCESS;
3401 }
3402 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3403
3404 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3405 if (module)
3406 {
3407 LPCWSTR guid;
3408 guid = MSI_RecordGetString(row,1);
3409 CLSIDFromString( guid, &tl_struct.clsid);
3410 tl_struct.source = strdupW( file->TargetPath );
3411 tl_struct.path = NULL;
3412
3413 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3414 (LONG_PTR)&tl_struct);
3415
3416 if (tl_struct.path)
3417 {
3418 LPCWSTR helpid, help_path = NULL;
3419 HRESULT res;
3420
3421 helpid = MSI_RecordGetString(row,6);
3422
3423 if (helpid) help_path = msi_get_target_folder( package, helpid );
3424 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3425
3426 if (FAILED(res))
3427 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3428 else
3429 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3430
3431 ITypeLib_Release(tl_struct.ptLib);
3432 msi_free(tl_struct.path);
3433 }
3434 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3435
3436 FreeLibrary(module);
3437 msi_free(tl_struct.source);
3438 }
3439 else
3440 {
3441 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3442 if (FAILED(hr))
3443 {
3444 ERR("Failed to load type library: %08x\n", hr);
3445 return ERROR_INSTALL_FAILURE;
3446 }
3447
3448 ITypeLib_Release(tlib);
3449 }
3450
3451 return ERROR_SUCCESS;
3452 }
3453
3454 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3455 {
3456 static const WCHAR query[] = {
3457 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3458 '`','T','y','p','e','L','i','b','`',0};
3459 MSIQUERY *view;
3460 UINT rc;
3461
3462 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3463 if (rc != ERROR_SUCCESS)
3464 return ERROR_SUCCESS;
3465
3466 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3467 msiobj_release(&view->hdr);
3468 return rc;
3469 }
3470
3471 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3472 {
3473 MSIPACKAGE *package = param;
3474 LPCWSTR component, guid;
3475 MSICOMPONENT *comp;
3476 GUID libid;
3477 UINT version;
3478 LCID language;
3479 SYSKIND syskind;
3480 HRESULT hr;
3481
3482 component = MSI_RecordGetString( row, 3 );
3483 comp = msi_get_loaded_component( package, component );
3484 if (!comp)
3485 return ERROR_SUCCESS;
3486
3487 comp->Action = msi_get_component_action( package, comp );
3488 if (comp->Action != INSTALLSTATE_ABSENT)
3489 {
3490 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3491 return ERROR_SUCCESS;
3492 }
3493 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3494
3495 guid = MSI_RecordGetString( row, 1 );
3496 CLSIDFromString( guid, &libid );
3497 version = MSI_RecordGetInteger( row, 4 );
3498 language = MSI_RecordGetInteger( row, 2 );
3499
3500 #ifdef _WIN64
3501 syskind = SYS_WIN64;
3502 #else
3503 syskind = SYS_WIN32;
3504 #endif
3505
3506 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3507 if (FAILED(hr))
3508 {
3509 WARN("Failed to unregister typelib: %08x\n", hr);
3510 }
3511
3512 return ERROR_SUCCESS;
3513 }
3514
3515 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3516 {
3517 static const WCHAR query[] = {
3518 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3519 '`','T','y','p','e','L','i','b','`',0};
3520 MSIQUERY *view;
3521 UINT rc;
3522
3523 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3524 if (rc != ERROR_SUCCESS)
3525 return ERROR_SUCCESS;
3526
3527 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3528 msiobj_release( &view->hdr );
3529 return rc;
3530 }
3531
3532 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3533 {
3534 static const WCHAR szlnk[] = {'.','l','n','k',0};
3535 LPCWSTR directory, extension, link_folder;
3536 LPWSTR link_file, filename;
3537
3538 directory = MSI_RecordGetString( row, 2 );
3539 link_folder = msi_get_target_folder( package, directory );
3540 if (!link_folder)
3541 {
3542 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3543 return NULL;
3544 }
3545 /* may be needed because of a bug somewhere else */
3546 msi_create_full_path( link_folder );
3547
3548 filename = msi_dup_record_field( row, 3 );
3549 msi_reduce_to_long_filename( filename );
3550
3551 extension = strchrW( filename, '.' );
3552 if (!extension || strcmpiW( extension, szlnk ))
3553 {
3554 int len = strlenW( filename );
3555 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3556 memcpy( filename + len, szlnk, sizeof(szlnk) );
3557 }
3558 link_file = msi_build_directory_name( 2, link_folder, filename );
3559 msi_free( filename );
3560
3561 return link_file;
3562 }
3563
3564 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3565 {
3566 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3567 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3568 WCHAR *folder, *dest, *path;
3569
3570 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3571 folder = msi_dup_property( package->db, szWindowsFolder );
3572 else
3573 {
3574 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3575 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3576 msi_free( appdata );
3577 }
3578 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3579 msi_create_full_path( dest );
3580 path = msi_build_directory_name( 2, dest, icon_name );
3581 msi_free( folder );
3582 msi_free( dest );
3583 return path;
3584 }
3585
3586 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3587 {
3588 MSIPACKAGE *package = param;
3589 LPWSTR link_file, deformated, path;
3590 LPCWSTR component, target;
3591 MSICOMPONENT *comp;
3592 IShellLinkW *sl = NULL;
3593 IPersistFile *pf = NULL;
3594 HRESULT res;
3595
3596 component = MSI_RecordGetString(row, 4);
3597 comp = msi_get_loaded_component(package, component);
3598 if (!comp)
3599 return ERROR_SUCCESS;
3600
3601 comp->Action = msi_get_component_action( package, comp );
3602 if (comp->Action != INSTALLSTATE_LOCAL)
3603 {
3604 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3605 return ERROR_SUCCESS;
3606 }
3607 msi_ui_actiondata( package, szCreateShortcuts, row );
3608
3609 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3610 &IID_IShellLinkW, (LPVOID *) &sl );
3611
3612 if (FAILED( res ))
3613 {
3614 ERR("CLSID_ShellLink not available\n");
3615 goto err;
3616 }
3617
3618 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3619 if (FAILED( res ))
3620 {
3621 ERR("QueryInterface(IID_IPersistFile) failed\n");
3622 goto err;
3623 }
3624
3625 target = MSI_RecordGetString(row, 5);
3626 if (strchrW(target, '['))
3627 {
3628 deformat_string( package, target, &path );
3629 TRACE("target path is %s\n", debugstr_w(path));
3630 IShellLinkW_SetPath( sl, path );
3631 msi_free( path );
3632 }
3633 else
3634 {
3635 FIXME("poorly handled shortcut format, advertised shortcut\n");
3636 IShellLinkW_SetPath(sl,comp->FullKeypath);
3637 }
3638
3639 if (!MSI_RecordIsNull(row,6))
3640 {
3641 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3642 deformat_string(package, arguments, &deformated);
3643 IShellLinkW_SetArguments(sl,deformated);
3644 msi_free(deformated);
3645 }
3646
3647 if (!MSI_RecordIsNull(row,7))
3648 {
3649 LPCWSTR description = MSI_RecordGetString(row, 7);
3650 IShellLinkW_SetDescription(sl, description);
3651 }
3652
3653 if (!MSI_RecordIsNull(row,8))
3654 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3655
3656 if (!MSI_RecordIsNull(row,9))
3657 {
3658 INT index;
3659 LPCWSTR icon = MSI_RecordGetString(row, 9);
3660
3661 path = msi_build_icon_path(package, icon);
3662 index = MSI_RecordGetInteger(row,10);
3663
3664 /* no value means 0 */
3665 if (index == MSI_NULL_INTEGER)
3666 index = 0;
3667
3668 IShellLinkW_SetIconLocation(sl, path, index);
3669 msi_free(path);
3670 }
3671
3672 if (!MSI_RecordIsNull(row,11))
3673 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3674
3675 if (!MSI_RecordIsNull(row,12))
3676 {
3677 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3678 full_path = msi_get_target_folder( package, wkdir );
3679 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3680 }
3681 link_file = get_link_file(package, row);
3682
3683 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3684 IPersistFile_Save(pf, link_file, FALSE);
3685 msi_free(link_file);
3686
3687 err:
3688 if (pf)
3689 IPersistFile_Release( pf );
3690 if (sl)
3691 IShellLinkW_Release( sl );
3692
3693 return ERROR_SUCCESS;
3694 }
3695
3696 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3697 {
3698 static const WCHAR query[] = {
3699 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3700 '`','S','h','o','r','t','c','u','t','`',0};
3701 MSIQUERY *view;
3702 HRESULT res;
3703 UINT rc;
3704
3705 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3706 if (rc != ERROR_SUCCESS)
3707 return ERROR_SUCCESS;
3708
3709 res = CoInitialize( NULL );
3710
3711 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3712 msiobj_release(&view->hdr);
3713
3714 if (SUCCEEDED(res)) CoUninitialize();
3715 return rc;
3716 }
3717
3718 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3719 {
3720 MSIPACKAGE *package = param;
3721 LPWSTR link_file;
3722 LPCWSTR component;
3723 MSICOMPONENT *comp;
3724
3725 component = MSI_RecordGetString( row, 4 );
3726 comp = msi_get_loaded_component( package, component );
3727 if (!comp)
3728 return ERROR_SUCCESS;
3729
3730 comp->Action = msi_get_component_action( package, comp );
3731 if (comp->Action != INSTALLSTATE_ABSENT)
3732 {
3733 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3734 return ERROR_SUCCESS;
3735 }
3736 msi_ui_actiondata( package, szRemoveShortcuts, row );
3737
3738 link_file = get_link_file( package, row );
3739
3740 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3741 if (!DeleteFileW( link_file ))
3742 {
3743 WARN("Failed to remove shortcut file %u\n", GetLastError());
3744 }
3745 msi_free( link_file );
3746
3747 return ERROR_SUCCESS;
3748 }
3749
3750 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3751 {
3752 static const WCHAR query[] = {
3753 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3754 '`','S','h','o','r','t','c','u','t','`',0};
3755 MSIQUERY *view;
3756 UINT rc;
3757
3758 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3759 if (rc != ERROR_SUCCESS)
3760 return ERROR_SUCCESS;
3761
3762 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3763 msiobj_release( &view->hdr );
3764 return rc;
3765 }
3766
3767 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3768 {
3769 MSIPACKAGE* package = param;
3770 HANDLE the_file;
3771 LPWSTR FilePath;
3772 LPCWSTR FileName;
3773 CHAR buffer[1024];
3774 DWORD sz;
3775 UINT rc;
3776
3777 FileName = MSI_RecordGetString(row,1);
3778 if (!FileName)
3779 {
3780 ERR("Unable to get FileName\n");
3781 return ERROR_SUCCESS;
3782 }
3783
3784 FilePath = msi_build_icon_path(package, FileName);
3785
3786 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3787
3788 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3789 FILE_ATTRIBUTE_NORMAL, NULL);
3790
3791 if (the_file == INVALID_HANDLE_VALUE)
3792 {
3793 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3794 msi_free(FilePath);
3795 return ERROR_SUCCESS;
3796 }
3797
3798 do
3799 {
3800 DWORD write;
3801 sz = 1024;
3802 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3803 if (rc != ERROR_SUCCESS)
3804 {
3805 ERR("Failed to get stream\n");
3806 CloseHandle(the_file);
3807 DeleteFileW(FilePath);
3808 break;
3809 }
3810 WriteFile(the_file,buffer,sz,&write,NULL);
3811 } while (sz == 1024);
3812
3813 msi_free(FilePath);
3814 CloseHandle(the_file);
3815
3816 return ERROR_SUCCESS;
3817 }
3818
3819 static UINT msi_publish_icons(MSIPACKAGE *package)
3820 {
3821 static const WCHAR query[]= {
3822 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3823 '`','I','c','o','n','`',0};
3824 MSIQUERY *view;
3825 UINT r;
3826
3827 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3828 if (r == ERROR_SUCCESS)
3829 {
3830 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3831 msiobj_release(&view->hdr);
3832 if (r != ERROR_SUCCESS)
3833 return r;
3834 }
3835 return ERROR_SUCCESS;
3836 }
3837
3838 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3839 {
3840 UINT r;
3841 HKEY source;
3842 LPWSTR buffer;
3843 MSIMEDIADISK *disk;
3844 MSISOURCELISTINFO *info;
3845
3846 r = RegCreateKeyW(hkey, szSourceList, &source);
3847 if (r != ERROR_SUCCESS)
3848 return r;
3849
3850 RegCloseKey(source);
3851
3852 buffer = strrchrW(package->PackagePath, '\\') + 1;
3853 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3854 package->Context, MSICODE_PRODUCT,
3855 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3856 if (r != ERROR_SUCCESS)
3857 return r;
3858
3859 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3860 package->Context, MSICODE_PRODUCT,
3861 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3862 if (r != ERROR_SUCCESS)
3863 return r;
3864
3865 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3866 package->Context, MSICODE_PRODUCT,
3867 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3868 if (r != ERROR_SUCCESS)
3869 return r;
3870
3871 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3872 {
3873 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3874 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3875 info->options, info->value);
3876 else
3877 MsiSourceListSetInfoW(package->ProductCode, NULL,
3878 info->context, info->options,
3879 info->property, info->value);
3880 }
3881
3882 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3883 {
3884 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3885 disk->context, disk->options,
3886 disk->disk_id, disk->volume_label, disk->disk_prompt);
3887 }
3888
3889 return ERROR_SUCCESS;
3890 }
3891
3892 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3893 {
3894 MSIHANDLE hdb, suminfo;
3895 WCHAR guids[MAX_PATH];
3896 WCHAR packcode[SQUISH_GUID_SIZE];
3897 LPWSTR buffer;
3898 LPWSTR ptr;
3899 DWORD langid;
3900 DWORD size;
3901 UINT r;
3902
3903 static const WCHAR szARPProductIcon[] =
3904 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3905 static const WCHAR szAssignment[] =
3906 {'A','s','s','i','g','n','m','e','n','t',0};
3907 static const WCHAR szAdvertiseFlags[] =
3908 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3909 static const WCHAR szClients[] =
3910 {'C','l','i','e','n','t','s',0};
3911 static const WCHAR szColon[] = {':',0};
3912
3913 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3914 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3915 msi_free(buffer);
3916
3917 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3918 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3919
3920 /* FIXME */
3921 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3922
3923 buffer = msi_dup_property(package->db, szARPProductIcon);
3924 if (buffer)
3925 {
3926 LPWSTR path = msi_build_icon_path(package, buffer);
3927 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3928 msi_free(path);
3929 msi_free(buffer);
3930 }
3931
3932 buffer = msi_dup_property(package->db, szProductVersion);
3933 if (buffer)
3934 {
3935 DWORD verdword = msi_version_str_to_dword(buffer);
3936 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3937 msi_free(buffer);
3938 }
3939
3940 msi_reg_set_val_dword(hkey, szAssignment, 0);
3941 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3942 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3943 msi_reg_set_val_str(hkey, szClients, szColon);
3944
3945 hdb = alloc_msihandle(&package->db->hdr);
3946 if (!hdb)
3947 return ERROR_NOT_ENOUGH_MEMORY;
3948
3949 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3950 MsiCloseHandle(hdb);
3951 if (r != ERROR_SUCCESS)
3952 goto done;
3953
3954 size = MAX_PATH;
3955 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3956 NULL, guids, &size);
3957 if (r != ERROR_SUCCESS)
3958 goto done;
3959
3960 ptr = strchrW(guids, ';');
3961 if (ptr) *ptr = 0;
3962 squash_guid(guids, packcode);
3963 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3964
3965 done:
3966 MsiCloseHandle(suminfo);
3967 return ERROR_SUCCESS;
3968 }
3969
3970 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3971 {
3972 UINT r;
3973 HKEY hkey;
3974 LPWSTR upgrade;
3975 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3976
3977 upgrade = msi_dup_property(package->db, szUpgradeCode);
3978 if (!upgrade)
3979 return ERROR_SUCCESS;
3980
3981 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3982 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3983 else
3984 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3985
3986 if (r != ERROR_SUCCESS)
3987 {
3988 WARN("failed to open upgrade code key\n");
3989 msi_free(upgrade);
3990 return ERROR_SUCCESS;
3991 }
3992 squash_guid(package->ProductCode, squashed_pc);
3993 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3994 RegCloseKey(hkey);
3995 msi_free(upgrade);
3996 return ERROR_SUCCESS;
3997 }
3998
3999 static BOOL msi_check_publish(MSIPACKAGE *package)
4000 {
4001 MSIFEATURE *feature;
4002
4003 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4004 {
4005 feature->Action = msi_get_feature_action( package, feature );
4006 if (feature->Action == INSTALLSTATE_LOCAL)
4007 return TRUE;
4008 }
4009
4010 return FALSE;
4011 }
4012
4013 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4014 {
4015 MSIFEATURE *feature;
4016
4017 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4018 {
4019 feature->Action = msi_get_feature_action( package, feature );
4020 if (feature->Action != INSTALLSTATE_ABSENT)
4021 return FALSE;
4022 }
4023
4024 return TRUE;
4025 }
4026
4027 static UINT msi_publish_patches( MSIPACKAGE *package )
4028 {
4029 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4030 WCHAR patch_squashed[GUID_SIZE];
4031 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4032 LONG res;
4033 MSIPATCHINFO *patch;
4034 UINT r;
4035 WCHAR *p, *all_patches = NULL;
4036 DWORD len = 0;
4037
4038 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4039 if (r != ERROR_SUCCESS)
4040 return ERROR_FUNCTION_FAILED;
4041
4042 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4043 if (res != ERROR_SUCCESS)
4044 {
4045 r = ERROR_FUNCTION_FAILED;
4046 goto done;
4047 }
4048
4049 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4050 if (r != ERROR_SUCCESS)
4051 goto done;
4052
4053 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4054 {
4055 squash_guid( patch->patchcode, patch_squashed );
4056 len += strlenW( patch_squashed ) + 1;
4057 }
4058
4059 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4060 if (!all_patches)
4061 goto done;
4062
4063 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4064 {
4065 HKEY patch_key;
4066
4067 squash_guid( patch->patchcode, p );
4068 p += strlenW( p ) + 1;
4069
4070 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4071 (const BYTE *)patch->transforms,
4072 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4073 if (res != ERROR_SUCCESS)
4074 goto done;
4075
4076 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4077 if (r != ERROR_SUCCESS)
4078 goto done;
4079
4080 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4081 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4082 RegCloseKey( patch_key );
4083 if (res != ERROR_SUCCESS)
4084 goto done;
4085
4086 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4087 {
4088 res = GetLastError();
4089 ERR("Unable to copy patch package %d\n", res);
4090 goto done;
4091 }
4092 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4093 if (res != ERROR_SUCCESS)
4094 goto done;
4095
4096 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4097 RegCloseKey( patch_key );
4098 if (res != ERROR_SUCCESS)
4099 goto done;
4100 }
4101
4102 all_patches[len] = 0;
4103 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4104 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4105 if (res != ERROR_SUCCESS)
4106 goto done;
4107
4108 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4109 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4110 if (res != ERROR_SUCCESS)
4111 r = ERROR_FUNCTION_FAILED;
4112
4113 done:
4114 RegCloseKey( product_patches_key );
4115 RegCloseKey( patches_key );
4116 RegCloseKey( product_key );
4117 msi_free( all_patches );
4118 return r;
4119 }
4120
4121 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4122 {
4123 UINT rc;
4124 HKEY hukey = NULL, hudkey = NULL;
4125 MSIRECORD *uirow;
4126
4127 if (!list_empty(&package->patches))
4128 {
4129 rc = msi_publish_patches(package);
4130 if (rc != ERROR_SUCCESS)
4131 goto end;
4132 }
4133
4134 /* FIXME: also need to publish if the product is in advertise mode */
4135 if (!msi_check_publish(package))
4136 return ERROR_SUCCESS;
4137
4138 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4139 &hukey, TRUE);
4140 if (rc != ERROR_SUCCESS)
4141 goto end;
4142
4143 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4144 NULL, &hudkey, TRUE);
4145 if (rc != ERROR_SUCCESS)
4146 goto end;
4147
4148 rc = msi_publish_upgrade_code(package);
4149 if (rc != ERROR_SUCCESS)
4150 goto end;
4151
4152 rc = msi_publish_product_properties(package, hukey);
4153 if (rc != ERROR_SUCCESS)
4154 goto end;
4155
4156 rc = msi_publish_sourcelist(package, hukey);
4157 if (rc != ERROR_SUCCESS)
4158 goto end;
4159
4160 rc = msi_publish_icons(package);
4161
4162 end:
4163 uirow = MSI_CreateRecord( 1 );
4164 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4165 msi_ui_actiondata( package, szPublishProduct, uirow );
4166 msiobj_release( &uirow->hdr );
4167
4168 RegCloseKey(hukey);
4169 RegCloseKey(hudkey);
4170 return rc;
4171 }
4172
4173 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4174 {
4175 WCHAR *filename, *ptr, *folder, *ret;
4176 const WCHAR *dirprop;
4177
4178 filename = msi_dup_record_field( row, 2 );
4179 if (filename && (ptr = strchrW( filename, '|' )))
4180 ptr++;
4181 else
4182 ptr = filename;
4183
4184 dirprop = MSI_RecordGetString( row, 3 );
4185 if (dirprop)
4186 {
4187 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4188 if (!folder) folder = msi_dup_property( package->db, dirprop );
4189 }
4190 else
4191 folder = msi_dup_property( package->db, szWindowsFolder );
4192
4193 if (!folder)
4194 {
4195 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4196 msi_free( filename );
4197 return NULL;
4198 }
4199
4200 ret = msi_build_directory_name( 2, folder, ptr );
4201
4202 msi_free( filename );
4203 msi_free( folder );
4204 return ret;
4205 }
4206
4207 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4208 {
4209 MSIPACKAGE *package = param;
4210 LPCWSTR component, section, key, value, identifier;
4211 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4212 MSIRECORD * uirow;
4213 INT action;
4214 MSICOMPONENT *comp;
4215
4216 component = MSI_RecordGetString(row, 8);
4217 comp = msi_get_loaded_component(package,component);
4218 if (!comp)
4219 return ERROR_SUCCESS;
4220
4221 comp->Action = msi_get_component_action( package, comp );
4222 if (comp->Action != INSTALLSTATE_LOCAL)
4223 {
4224 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4225 return ERROR_SUCCESS;
4226 }
4227
4228 identifier = MSI_RecordGetString(row,1);
4229 section = MSI_RecordGetString(row,4);
4230 key = MSI_RecordGetString(row,5);
4231 value = MSI_RecordGetString(row,6);
4232 action = MSI_RecordGetInteger(row,7);
4233
4234 deformat_string(package,section,&deformated_section);
4235 deformat_string(package,key,&deformated_key);
4236 deformat_string(package,value,&deformated_value);
4237
4238 fullname = get_ini_file_name(package, row);
4239
4240 if (action == 0)
4241 {
4242 TRACE("Adding value %s to section %s in %s\n",
4243 debugstr_w(deformated_key), debugstr_w(deformated_section),
4244 debugstr_w(fullname));
4245 WritePrivateProfileStringW(deformated_section, deformated_key,
4246 deformated_value, fullname);
4247 }
4248 else if (action == 1)
4249 {
4250 WCHAR returned[10];
4251 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4252 returned, 10, fullname);
4253 if (returned[0] == 0)
4254 {
4255 TRACE("Adding value %s to section %s in %s\n",
4256 debugstr_w(deformated_key), debugstr_w(deformated_section),
4257 debugstr_w(fullname));
4258
4259 WritePrivateProfileStringW(deformated_section, deformated_key,
4260 deformated_value, fullname);
4261 }
4262 }
4263 else if (action == 3)
4264 FIXME("Append to existing section not yet implemented\n");
4265
4266 uirow = MSI_CreateRecord(4);
4267 MSI_RecordSetStringW(uirow,1,identifier);
4268 MSI_RecordSetStringW(uirow,2,deformated_section);
4269 MSI_RecordSetStringW(uirow,3,deformated_key);
4270 MSI_RecordSetStringW(uirow,4,deformated_value);
4271 msi_ui_actiondata( package, szWriteIniValues, uirow );
4272 msiobj_release( &uirow->hdr );
4273
4274 msi_free(fullname);
4275 msi_free(deformated_key);
4276 msi_free(deformated_value);
4277 msi_free(deformated_section);
4278 return ERROR_SUCCESS;
4279 }
4280
4281 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4282 {
4283 static const WCHAR query[] = {
4284 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4285 '`','I','n','i','F','i','l','e','`',0};
4286 MSIQUERY *view;
4287 UINT rc;
4288
4289 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4290 if (rc != ERROR_SUCCESS)
4291 return ERROR_SUCCESS;
4292
4293 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4294 msiobj_release(&view->hdr);
4295 return rc;
4296 }
4297
4298 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4299 {
4300 MSIPACKAGE *package = param;
4301 LPCWSTR component, section, key, value, identifier;
4302 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4303 MSICOMPONENT *comp;
4304 MSIRECORD *uirow;
4305 INT action;
4306
4307 component = MSI_RecordGetString( row, 8 );
4308 comp = msi_get_loaded_component( package, component );
4309 if (!comp)
4310 return ERROR_SUCCESS;
4311
4312 comp->Action = msi_get_component_action( package, comp );
4313 if (comp->Action != INSTALLSTATE_ABSENT)
4314 {
4315 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4316 return ERROR_SUCCESS;
4317 }
4318
4319 identifier = MSI_RecordGetString( row, 1 );
4320 section = MSI_RecordGetString( row, 4 );
4321 key = MSI_RecordGetString( row, 5 );
4322 value = MSI_RecordGetString( row, 6 );
4323 action = MSI_RecordGetInteger( row, 7 );
4324
4325 deformat_string( package, section, &deformated_section );
4326 deformat_string( package, key, &deformated_key );
4327 deformat_string( package, value, &deformated_value );
4328
4329 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4330 {
4331 filename = get_ini_file_name( package, row );
4332
4333 TRACE("Removing key %s from section %s in %s\n",
4334 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4335
4336 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4337 {
4338 WARN("Unable to remove key %u\n", GetLastError());
4339 }
4340 msi_free( filename );
4341 }
4342 else
4343 FIXME("Unsupported action %d\n", action);
4344
4345
4346 uirow = MSI_CreateRecord( 4 );
4347 MSI_RecordSetStringW( uirow, 1, identifier );
4348 MSI_RecordSetStringW( uirow, 2, deformated_section );
4349 MSI_RecordSetStringW( uirow, 3, deformated_key );
4350 MSI_RecordSetStringW( uirow, 4, deformated_value );
4351 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4352 msiobj_release( &uirow->hdr );
4353
4354 msi_free( deformated_key );
4355 msi_free( deformated_value );
4356 msi_free( deformated_section );
4357 return ERROR_SUCCESS;
4358 }
4359
4360 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4361 {
4362 MSIPACKAGE *package = param;
4363 LPCWSTR component, section, key, value, identifier;
4364 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4365 MSICOMPONENT *comp;
4366 MSIRECORD *uirow;
4367 INT action;
4368
4369 component = MSI_RecordGetString( row, 8 );
4370 comp = msi_get_loaded_component( package, component );
4371 if (!comp)
4372 return ERROR_SUCCESS;
4373
4374 comp->Action = msi_get_component_action( package, comp );
4375 if (comp->Action != INSTALLSTATE_LOCAL)
4376 {
4377 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4378 return ERROR_SUCCESS;
4379 }
4380
4381 identifier = MSI_RecordGetString( row, 1 );
4382 section = MSI_RecordGetString( row, 4 );
4383 key = MSI_RecordGetString( row, 5 );
4384 value = MSI_RecordGetString( row, 6 );
4385 action = MSI_RecordGetInteger( row, 7 );
4386
4387 deformat_string( package, section, &deformated_section );
4388 deformat_string( package, key, &deformated_key );
4389 deformat_string( package, value, &deformated_value );
4390
4391 if (action == msidbIniFileActionRemoveLine)
4392 {
4393 filename = get_ini_file_name( package, row );
4394
4395 TRACE("Removing key %s from section %s in %s\n",
4396 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4397
4398 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4399 {
4400 WARN("Unable to remove key %u\n", GetLastError());
4401 }
4402 msi_free( filename );
4403 }
4404 else
4405 FIXME("Unsupported action %d\n", action);
4406
4407 uirow = MSI_CreateRecord( 4 );
4408 MSI_RecordSetStringW( uirow, 1, identifier );
4409 MSI_RecordSetStringW( uirow, 2, deformated_section );
4410 MSI_RecordSetStringW( uirow, 3, deformated_key );
4411 MSI_RecordSetStringW( uirow, 4, deformated_value );
4412 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4413 msiobj_release( &uirow->hdr );
4414
4415 msi_free( deformated_key );
4416 msi_free( deformated_value );
4417 msi_free( deformated_section );
4418 return ERROR_SUCCESS;
4419 }
4420
4421 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4422 {
4423 static const WCHAR query[] = {
4424 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4425 '`','I','n','i','F','i','l','e','`',0};
4426 static const WCHAR remove_query[] = {
4427 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4428 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4429 MSIQUERY *view;
4430 UINT rc;
4431
4432 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4433 if (rc == ERROR_SUCCESS)
4434 {
4435 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4436 msiobj_release( &view->hdr );
4437 if (rc != ERROR_SUCCESS)
4438 return rc;
4439 }
4440 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4441 if (rc == ERROR_SUCCESS)
4442 {
4443 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4444 msiobj_release( &view->hdr );
4445 if (rc != ERROR_SUCCESS)
4446 return rc;
4447 }
4448 return ERROR_SUCCESS;
4449 }
4450
4451 static void register_dll( const WCHAR *dll, BOOL unregister )
4452 {
4453 HMODULE hmod;
4454
4455 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4456 if (hmod)
4457 {
4458 HRESULT (WINAPI *func_ptr)( void );
4459 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4460
4461 func_ptr = (void *)GetProcAddress( hmod, func );
4462 if (func_ptr)
4463 {
4464 HRESULT hr = func_ptr();
4465 if (FAILED( hr ))
4466 WARN("failed to register dll 0x%08x\n", hr);
4467 }
4468 else
4469 WARN("entry point %s not found\n", func);
4470 FreeLibrary( hmod );
4471 return;
4472 }
4473 WARN("failed to load library %u\n", GetLastError());
4474 }
4475
4476 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4477 {
4478 MSIPACKAGE *package = param;
4479 LPCWSTR filename;
4480 MSIFILE *file;
4481 MSIRECORD *uirow;
4482
4483 filename = MSI_RecordGetString( row, 1 );
4484 file = msi_get_loaded_file( package, filename );
4485 if (!file)
4486 {
4487 WARN("unable to find file %s\n", debugstr_w(filename));
4488 return ERROR_SUCCESS;
4489 }
4490 file->Component->Action = msi_get_component_action( package, file->Component );
4491 if (file->Component->Action != INSTALLSTATE_LOCAL)
4492 {
4493 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4494 return ERROR_SUCCESS;
4495 }
4496
4497 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4498 register_dll( file->TargetPath, FALSE );
4499
4500 uirow = MSI_CreateRecord( 2 );
4501 MSI_RecordSetStringW( uirow, 1, file->File );
4502 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4503 msi_ui_actiondata( package, szSelfRegModules, uirow );
4504 msiobj_release( &uirow->hdr );
4505
4506 return ERROR_SUCCESS;
4507 }
4508
4509 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4510 {
4511 static const WCHAR query[] = {
4512 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4513 '`','S','e','l','f','R','e','g','`',0};
4514 MSIQUERY *view;
4515 UINT rc;
4516
4517 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4518 if (rc != ERROR_SUCCESS)
4519 return ERROR_SUCCESS;
4520
4521 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4522 msiobj_release(&view->hdr);
4523 return rc;
4524 }
4525
4526 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4527 {
4528 MSIPACKAGE *package = param;
4529 LPCWSTR filename;
4530 MSIFILE *file;
4531 MSIRECORD *uirow;
4532
4533 filename = MSI_RecordGetString( row, 1 );
4534 file = msi_get_loaded_file( package, filename );
4535 if (!file)
4536 {
4537 WARN("unable to find file %s\n", debugstr_w(filename));
4538 return ERROR_SUCCESS;
4539 }
4540 file->Component->Action = msi_get_component_action( package, file->Component );
4541 if (file->Component->Action != INSTALLSTATE_ABSENT)
4542 {
4543 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4544 return ERROR_SUCCESS;
4545 }
4546
4547 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4548 register_dll( file->TargetPath, TRUE );
4549
4550 uirow = MSI_CreateRecord( 2 );
4551 MSI_RecordSetStringW( uirow, 1, file->File );
4552 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4553 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4554 msiobj_release( &uirow->hdr );
4555
4556 return ERROR_SUCCESS;
4557 }
4558
4559 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4560 {
4561 static const WCHAR query[] = {
4562 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4563 '`','S','e','l','f','R','e','g','`',0};
4564 MSIQUERY *view;
4565 UINT rc;
4566
4567 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4568 if (rc != ERROR_SUCCESS)
4569 return ERROR_SUCCESS;
4570
4571 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4572 msiobj_release( &view->hdr );
4573 return rc;
4574 }
4575
4576 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4577 {
4578 MSIFEATURE *feature;
4579 UINT rc;
4580 HKEY hkey = NULL, userdata = NULL;
4581
4582 if (!msi_check_publish(package))
4583 return ERROR_SUCCESS;
4584
4585 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4586 &hkey, TRUE);
4587 if (rc != ERROR_SUCCESS)
4588 goto end;
4589
4590 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4591 &userdata, TRUE);
4592 if (rc != ERROR_SUCCESS)
4593 goto end;
4594
4595 /* here the guids are base 85 encoded */
4596 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4597 {
4598 ComponentList *cl;
4599 LPWSTR data = NULL;
4600 GUID clsid;
4601 INT size;
4602 BOOL absent = FALSE;
4603 MSIRECORD *uirow;
4604
4605 if (feature->Action != INSTALLSTATE_LOCAL &&
4606 feature->Action != INSTALLSTATE_SOURCE &&
4607 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4608
4609 size = 1;
4610 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4611 {
4612 size += 21;
4613 }
4614 if (feature->Feature_Parent)
4615 size += strlenW( feature->Feature_Parent )+2;
4616
4617 data = msi_alloc(size * sizeof(WCHAR));
4618
4619 data[0] = 0;
4620 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4621 {
4622 MSICOMPONENT* component = cl->component;
4623 WCHAR buf[21];
4624
4625 buf[0] = 0;
4626 if (component->ComponentId)
4627 {
4628 TRACE("From %s\n",debugstr_w(component->ComponentId));
4629 CLSIDFromString(component->ComponentId, &clsid);
4630 encode_base85_guid(&clsid,buf);
4631 TRACE("to %s\n",debugstr_w(buf));
4632 strcatW(data,buf);
4633 }
4634 }
4635
4636 if (feature->Feature_Parent)
4637 {
4638 static const WCHAR sep[] = {'\2',0};
4639 strcatW(data,sep);
4640 strcatW(data,feature->Feature_Parent);
4641 }
4642
4643 msi_reg_set_val_str( userdata, feature->Feature, data );
4644 msi_free(data);
4645
4646 size = 0;
4647 if (feature->Feature_Parent)
4648 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4649 if (!absent)
4650 {
4651 size += sizeof(WCHAR);
4652 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4653 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4654 }
4655 else
4656 {
4657 size += 2*sizeof(WCHAR);
4658 data = msi_alloc(size);
4659 data[0] = 0x6;
4660 data[1] = 0;
4661 if (feature->Feature_Parent)
4662 strcpyW( &data[1], feature->Feature_Parent );
4663 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4664 (LPBYTE)data,size);
4665 msi_free(data);
4666 }
4667
4668 /* the UI chunk */
4669 uirow = MSI_CreateRecord( 1 );
4670 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4671 msi_ui_actiondata( package, szPublishFeatures, uirow );
4672 msiobj_release( &uirow->hdr );
4673 /* FIXME: call msi_ui_progress? */
4674 }
4675
4676 end:
4677 RegCloseKey(hkey);
4678 RegCloseKey(userdata);
4679 return rc;
4680 }
4681
4682 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4683 {
4684 UINT r;
4685 HKEY hkey;
4686 MSIRECORD *uirow;
4687
4688 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4689
4690 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4691 &hkey, FALSE);
4692 if (r == ERROR_SUCCESS)
4693 {
4694 RegDeleteValueW(hkey, feature->Feature);
4695 RegCloseKey(hkey);
4696 }
4697
4698 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4699 &hkey, FALSE);
4700 if (r == ERROR_SUCCESS)
4701 {
4702 RegDeleteValueW(hkey, feature->Feature);
4703 RegCloseKey(hkey);
4704 }
4705
4706 uirow = MSI_CreateRecord( 1 );
4707 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4708 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4709 msiobj_release( &uirow->hdr );
4710
4711 return ERROR_SUCCESS;
4712 }
4713
4714 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4715 {
4716 MSIFEATURE *feature;
4717
4718 if (!msi_check_unpublish(package))
4719 return ERROR_SUCCESS;
4720
4721 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4722 {
4723 msi_unpublish_feature(package, feature);
4724 }
4725
4726 return ERROR_SUCCESS;
4727 }
4728
4729 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4730 {
4731 SYSTEMTIME systime;
4732 DWORD size, langid;
4733 WCHAR date[9], *val, *buffer;
4734 const WCHAR *prop, *key;
4735
4736 static const WCHAR date_fmt[] = {'%','i','%','','2','i','%','','2','i',0};
4737 static const WCHAR modpath_fmt[] =
4738 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4739 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4740 static const WCHAR szModifyPath[] =
4741 {'M','o','d','i','f','y','P','a','t','h',0};
4742 static const WCHAR szUninstallString[] =
4743 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4744 static const WCHAR szEstimatedSize[] =
4745 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4746 static const WCHAR szDisplayVersion[] =
4747 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4748 static const WCHAR szInstallSource[] =
4749 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4750 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4751 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4752 static const WCHAR szAuthorizedCDFPrefix[] =
4753 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4754 static const WCHAR szARPCONTACT[] =
4755 {'A','R','P','C','O','N','T','A','C','T',0};
4756 static const WCHAR szContact[] =
4757 {'C','o','n','t','a','c','t',0};
4758 static const WCHAR szARPCOMMENTS[] =
4759 {'A','R','P','C','O','M','M','E','N','T','S',0};
4760 static const WCHAR szComments[] =
4761 {'C','o','m','m','e','n','t','s',0};
4762 static const WCHAR szProductName[] =
4763 {'P','r','o','d','u','c','t','N','a','m','e',0};
4764 static const WCHAR szDisplayName[] =
4765 {'D','i','s','p','l','a','y','N','a','m','e',0};
4766 static const WCHAR szARPHELPLINK[] =
4767 {'A','R','P','H','E','L','P','L','I','N','K',0};
4768 static const WCHAR szHelpLink[] =
4769 {'H','e','l','p','L','i','n','k',0};
4770 static const WCHAR szARPHELPTELEPHONE[] =
4771 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4772 static const WCHAR szHelpTelephone[] =
4773 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4774 static const WCHAR szARPINSTALLLOCATION[] =
4775 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4776 static const WCHAR szInstallLocation[] =
4777 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4778 static const WCHAR szManufacturer[] =
4779 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4780 static const WCHAR szPublisher[] =
4781 {'P','u','b','l','i','s','h','e','r',0};
4782 static const WCHAR szARPREADME[] =
4783 {'A','R','P','R','E','A','D','M','E',0};
4784 static const WCHAR szReadme[] =
4785 {'R','e','a','d','M','e',0};
4786 static const WCHAR szARPSIZE[] =
4787 {'A','R','P','S','I','Z','E',0};
4788 static const WCHAR szSize[] =
4789 {'S','i','z','e',0};
4790 static const WCHAR szARPURLINFOABOUT[] =
4791 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4792 static const WCHAR szURLInfoAbout[] =
4793 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4794 static const WCHAR szARPURLUPDATEINFO[] =
4795 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4796 static const WCHAR szURLUpdateInfo[] =
4797 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4798 static const WCHAR szARPSYSTEMCOMPONENT[] =
4799 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4800 static const WCHAR szSystemComponent[] =
4801 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4802
4803 static const WCHAR *propval[] = {
4804 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4805 szARPCONTACT, szContact,
4806 szARPCOMMENTS, szComments,
4807 szProductName, szDisplayName,
4808 szARPHELPLINK, szHelpLink,
4809 szARPHELPTELEPHONE, szHelpTelephone,
4810 szARPINSTALLLOCATION, szInstallLocation,
4811 szSourceDir, szInstallSource,
4812 szManufacturer, szPublisher,
4813 szARPREADME, szReadme,
4814 szARPSIZE, szSize,
4815 szARPURLINFOABOUT, szURLInfoAbout,
4816 szARPURLUPDATEINFO, szURLUpdateInfo,
4817 NULL
4818 };
4819 const WCHAR **p = propval;
4820
4821 while (*p)
4822 {
4823 prop = *p++;
4824 key = *p++;
4825 val = msi_dup_property(package->db, prop);
4826 msi_reg_set_val_str(hkey, key, val);
4827 msi_free(val);
4828 }
4829
4830 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4831 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4832 {
4833 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4834 }
4835 size = deformat_string(package, modpath_fmt, &buffer);
4836 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4837 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4838 msi_free(buffer);
4839
4840 /* FIXME: Write real Estimated Size when we have it */
4841 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4842
4843 GetLocalTime(&systime);
4844 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4845 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4846
4847 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4848 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4849
4850 buffer = msi_dup_property(package->db, szProductVersion);
4851 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4852 if (buffer)
4853 {
4854 DWORD verdword = msi_version_str_to_dword(buffer);
4855
4856 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4857 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4858 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4859 msi_free(buffer);
4860 }
4861
4862 return ERROR_SUCCESS;
4863 }
4864
4865 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4866 {
4867 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4868 MSIRECORD *uirow;
4869 LPWSTR upgrade_code;
4870 HKEY hkey, props, upgrade_key;
4871 UINT rc;
4872
4873 /* FIXME: also need to publish if the product is in advertise mode */
4874 if (!msi_check_publish(package))
4875 return ERROR_SUCCESS;
4876
4877 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4878 if (rc != ERROR_SUCCESS)
4879 return rc;
4880
4881 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4882 if (rc != ERROR_SUCCESS)
4883 goto done;
4884
4885 rc = msi_publish_install_properties(package, hkey);
4886 if (rc != ERROR_SUCCESS)
4887 goto done;
4888
4889 rc = msi_publish_install_properties(package, props);
4890 if (rc != ERROR_SUCCESS)
4891 goto done;
4892
4893 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4894 if (upgrade_code)
4895 {
4896 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4897 if (rc == ERROR_SUCCESS)
4898 {
4899 squash_guid( package->ProductCode, squashed_pc );
4900 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4901 RegCloseKey( upgrade_key );
4902 }
4903 msi_free( upgrade_code );
4904 }
4905 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4906 package->delete_on_close = FALSE;
4907
4908 done:
4909 uirow = MSI_CreateRecord( 1 );
4910 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4911 msi_ui_actiondata( package, szRegisterProduct, uirow );
4912 msiobj_release( &uirow->hdr );
4913
4914 RegCloseKey(hkey);
4915 return ERROR_SUCCESS;
4916 }
4917
4918 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4919 {
4920 return execute_script(package, SCRIPT_INSTALL);
4921 }
4922
4923 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4924 {
4925 MSIPACKAGE *package = param;
4926 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4927 WCHAR *p, *icon_path;
4928
4929 if (!icon) return ERROR_SUCCESS;
4930 if ((icon_path = msi_build_icon_path( package, icon )))
4931 {
4932 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4933 DeleteFileW( icon_path );
4934 if ((p = strrchrW( icon_path, '\\' )))
4935 {
4936 *p = 0;
4937 RemoveDirectoryW( icon_path );
4938 }
4939 msi_free( icon_path );
4940 }
4941 return ERROR_SUCCESS;
4942 }
4943
4944 static UINT msi_unpublish_icons( MSIPACKAGE *package )
4945 {
4946 static const WCHAR query[]= {
4947 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
4948 MSIQUERY *view;
4949 UINT r;
4950
4951 r = MSI_DatabaseOpenViewW( package->db, query, &view );
4952 if (r == ERROR_SUCCESS)
4953 {
4954 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4955 msiobj_release( &view->hdr );
4956 if (r != ERROR_SUCCESS)
4957 return r;
4958 }
4959 return ERROR_SUCCESS;
4960 }
4961
4962 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4963 {
4964 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4965 WCHAR *upgrade, **features;
4966 BOOL full_uninstall = TRUE;
4967 MSIFEATURE *feature;
4968 MSIPATCHINFO *patch;
4969 UINT i;
4970
4971 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4972 {
4973 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4974 }
4975 features = msi_split_string( remove, ',' );
4976 for (i = 0; features && features[i]; i++)
4977 {
4978 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4979 }
4980 msi_free(features);
4981
4982 if (!full_uninstall)
4983 return ERROR_SUCCESS;
4984
4985 MSIREG_DeleteProductKey(package->ProductCode);
4986 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4987 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4988
4989 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4990 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4991 MSIREG_DeleteUserProductKey(package->ProductCode);
4992 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4993
4994 upgrade = msi_dup_property(package->db, szUpgradeCode);
4995 if (upgrade)
4996 {
4997 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4998 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4999 msi_free(upgrade);
5000 }
5001
5002 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5003 {
5004 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5005 if (!strcmpW( package->ProductCode, patch->products ))
5006 {
5007 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5008 patch->delete_on_close = TRUE;
5009 }
5010 /* FIXME: remove local patch package if this is the last product */
5011 }
5012 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5013 package->delete_on_close = TRUE;
5014
5015 msi_unpublish_icons( package );
5016 return ERROR_SUCCESS;
5017 }
5018
5019 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5020 {
5021 UINT rc;
5022 WCHAR *remove;
5023
5024 /* turn off scheduling */
5025 package->script->CurrentlyScripting= FALSE;
5026
5027 /* first do the same as an InstallExecute */
5028 rc = ACTION_InstallExecute(package);
5029 if (rc != ERROR_SUCCESS)
5030 return rc;
5031
5032 /* then handle commit actions */
5033 rc = execute_script(package, SCRIPT_COMMIT);
5034 if (rc != ERROR_SUCCESS)
5035 return rc;
5036
5037 remove = msi_dup_property(package->db, szRemove);
5038 rc = msi_unpublish_product(package, remove);
5039 msi_free(remove);
5040 return rc;
5041 }
5042
5043 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5044 {
5045 static const WCHAR RunOnce[] = {
5046 'S','o','f','t','w','a','r','e','\\',
5047 'M','i','c','r','o','s','o','f','t','\\',
5048 'W','i','n','d','o','w','s','\\',
5049 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5050 'R','u','n','O','n','c','e',0};
5051 static const WCHAR InstallRunOnce[] = {
5052 'S','o','f','t','w','a','r','e','\\',
5053 'M','i','c','r','o','s','o','f','t','\\',
5054 'W','i','n','d','o','w','s','\\',
5055 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5056 'I','n','s','t','a','l','l','e','r','\\',
5057 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5058
5059 static const WCHAR msiexec_fmt[] = {
5060 '%','s',
5061 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5062 '\"','%','s','\"',0};
5063 static const WCHAR install_fmt[] = {
5064 '/','I',' ','\"','%','s','\"',' ',
5065 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5066 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5067 WCHAR buffer[256], sysdir[MAX_PATH];
5068 HKEY hkey;
5069 WCHAR squished_pc[100];
5070
5071 squash_guid(package->ProductCode,squished_pc);
5072
5073 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5074 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5075 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5076 squished_pc);
5077
5078 msi_reg_set_val_str( hkey, squished_pc, buffer );
5079 RegCloseKey(hkey);
5080
5081 TRACE("Reboot command %s\n",debugstr_w(buffer));
5082
5083 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5084 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5085
5086 msi_reg_set_val_str( hkey, squished_pc, buffer );
5087 RegCloseKey(hkey);
5088
5089 return ERROR_INSTALL_SUSPEND;
5090 }
5091
5092 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5093 {
5094 static const WCHAR query[] =
5095 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5096 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5097 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5098 MSIRECORD *rec, *row;
5099 DWORD i, size = 0;
5100 va_list va;
5101 const WCHAR *str;
5102 WCHAR *data;
5103
5104 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5105
5106 rec = MSI_CreateRecord( count + 2 );
5107 str = MSI_RecordGetString( row, 1 );
5108 MSI_RecordSetStringW( rec, 0, str );
5109 msiobj_release( &row->hdr );
5110 MSI_RecordSetInteger( rec, 1, error );
5111
5112 va_start( va, count );
5113 for (i = 0; i < count; i++)
5114 {
5115 str = va_arg( va, const WCHAR *);
5116 MSI_RecordSetStringW( rec, i + 2, str );
5117 }
5118 va_end( va );
5119
5120 MSI_FormatRecordW( package, rec, NULL, &size );
5121 size++;
5122 data = msi_alloc( size * sizeof(WCHAR) );
5123 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5124 else data[0] = 0;
5125 msiobj_release( &rec->hdr );
5126 return data;
5127 }
5128
5129 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5130 {
5131 DWORD attrib;
5132 UINT rc;
5133
5134 /*
5135 * We are currently doing what should be done here in the top level Install
5136 * however for Administrative and uninstalls this step will be needed
5137 */
5138 if (!package->PackagePath)
5139 return ERROR_SUCCESS;
5140
5141 msi_set_sourcedir_props(package, TRUE);
5142
5143 attrib = GetFileAttributesW(package->db->path);
5144 if (attrib == INVALID_FILE_ATTRIBUTES)
5145 {
5146 LPWSTR prompt, msg;
5147 DWORD size = 0;
5148
5149 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5150 package->Context, MSICODE_PRODUCT,
5151 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5152 if (rc == ERROR_MORE_DATA)
5153 {
5154 prompt = msi_alloc(size * sizeof(WCHAR));
5155 MsiSourceListGetInfoW(package->ProductCode, NULL,
5156 package->Context, MSICODE_PRODUCT,
5157 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5158 }
5159 else
5160 prompt = strdupW(package->db->path);
5161
5162 msg = msi_build_error_string(package, 1302, 1, prompt);
5163 msi_free(prompt);
5164 while(attrib == INVALID_FILE_ATTRIBUTES)
5165 {
5166 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5167 if (rc == IDCANCEL)
5168 {
5169 msi_free(msg);
5170 return ERROR_INSTALL_USEREXIT;
5171 }
5172 attrib = GetFileAttributesW(package->db->path);
5173 }
5174 msi_free(msg);
5175 rc = ERROR_SUCCESS;
5176 }
5177 else
5178 return ERROR_SUCCESS;
5179
5180 return rc;
5181 }
5182
5183 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5184 {
5185 HKEY hkey = 0;
5186 LPWSTR buffer, productid = NULL;
5187 UINT i, rc = ERROR_SUCCESS;
5188 MSIRECORD *uirow;
5189
5190 static const WCHAR szPropKeys[][80] =
5191 {
5192 {'P','r','o','d','u','c','t','I','D',0},
5193 {'U','S','E','R','N','A','M','E',0},
5194 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5195 {0},
5196 };
5197
5198 static const WCHAR szRegKeys[][80] =
5199 {
5200 {'P','r','o','d','u','c','t','I','D',0},
5201 {'R','e','g','O','w','n','e','r',0},
5202 {'R','e','g','C','o','m','p','a','n','y',0},
5203 {0},
5204 };
5205
5206 if (msi_check_unpublish(package))
5207 {
5208 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5209 goto end;
5210 }
5211
5212 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5213 if (!productid)
5214 goto end;
5215
5216 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5217 NULL, &hkey, TRUE);
5218 if (rc != ERROR_SUCCESS)
5219 goto end;
5220
5221 for( i = 0; szPropKeys[i][0]; i++ )
5222 {
5223 buffer = msi_dup_property( package->db, szPropKeys[i] );
5224 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5225 msi_free( buffer );
5226 }
5227
5228 end:
5229 uirow = MSI_CreateRecord( 1 );
5230 MSI_RecordSetStringW( uirow, 1, productid );
5231 msi_ui_actiondata( package, szRegisterUser, uirow );
5232 msiobj_release( &uirow->hdr );
5233
5234 msi_free(productid);
5235 RegCloseKey(hkey);
5236 return rc;
5237 }
5238
5239
5240 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5241 {
5242 UINT rc;
5243
5244 package->script->InWhatSequence |= SEQUENCE_EXEC;
5245 rc = ACTION_ProcessExecSequence(package,FALSE);
5246 return rc;
5247 }
5248
5249 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5250 {
5251 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5252 WCHAR productid_85[21], component_85[21], *ret;
5253 GUID clsid;
5254 DWORD sz;
5255
5256 /* > is used if there is a component GUID and < if not. */
5257
5258 productid_85[0] = 0;
5259 component_85[0] = 0;
5260 CLSIDFromString( package->ProductCode, &clsid );
5261
5262 encode_base85_guid( &clsid, productid_85 );
5263 if (component)
5264 {
5265 CLSIDFromString( component->ComponentId, &clsid );
5266 encode_base85_guid( &clsid, component_85 );
5267 }
5268
5269 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5270 debugstr_w(component_85));
5271
5272 sz = 20 + strlenW( feature ) + 20 + 3;
5273 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5274 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5275 return ret;
5276 }
5277
5278 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5279 {
5280 MSIPACKAGE *package = param;
5281 LPCWSTR compgroupid, component, feature, qualifier, text;
5282 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5283 HKEY hkey = NULL;
5284 UINT rc;
5285 MSICOMPONENT *comp;
5286 MSIFEATURE *feat;
5287 DWORD sz;
5288 MSIRECORD *uirow;
5289 int len;
5290
5291 feature = MSI_RecordGetString(rec, 5);
5292 feat = msi_get_loaded_feature(package, feature);
5293 if (!feat)
5294 return ERROR_SUCCESS;
5295
5296 feat->Action = msi_get_feature_action( package, feat );
5297 if (feat->Action != INSTALLSTATE_LOCAL &&
5298 feat->Action != INSTALLSTATE_SOURCE &&
5299 feat->Action != INSTALLSTATE_ADVERTISED)
5300 {
5301 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5302 return ERROR_SUCCESS;
5303 }
5304
5305 component = MSI_RecordGetString(rec, 3);
5306 comp = msi_get_loaded_component(package, component);
5307 if (!comp)
5308 return ERROR_SUCCESS;
5309
5310 compgroupid = MSI_RecordGetString(rec,1);
5311 qualifier = MSI_RecordGetString(rec,2);
5312
5313 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5314 if (rc != ERROR_SUCCESS)
5315 goto end;
5316
5317 advertise = msi_create_component_advertise_string( package, comp, feature );
5318 text = MSI_RecordGetString( rec, 4 );
5319 if (text)
5320 {
5321 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5322 strcpyW( p, advertise );
5323 strcatW( p, text );
5324 msi_free( advertise );
5325 advertise = p;
5326 }
5327 existing = msi_reg_get_val_str( hkey, qualifier );
5328
5329 sz = strlenW( advertise ) + 1;
5330 if (existing)
5331 {
5332 for (p = existing; *p; p += len)
5333 {
5334 len = strlenW( p ) + 1;
5335 if (strcmpW( advertise, p )) sz += len;
5336 }
5337 }
5338 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5339 {
5340 rc = ERROR_OUTOFMEMORY;
5341 goto end;
5342 }
5343 q = output;
5344 if (existing)
5345 {
5346 for (p = existing; *p; p += len)
5347 {
5348 len = strlenW( p ) + 1;
5349 if (strcmpW( advertise, p ))
5350 {
5351 memcpy( q, p, len * sizeof(WCHAR) );
5352 q += len;
5353 }
5354 }
5355 }
5356 strcpyW( q, advertise );
5357 q[strlenW( q ) + 1] = 0;
5358
5359 msi_reg_set_val_multi_str( hkey, qualifier, output );
5360
5361 end:
5362 RegCloseKey(hkey);
5363 msi_free( output );
5364 msi_free( advertise );
5365 msi_free( existing );
5366
5367 /* the UI chunk */
5368 uirow = MSI_CreateRecord( 2 );
5369 MSI_RecordSetStringW( uirow, 1, compgroupid );
5370 MSI_RecordSetStringW( uirow, 2, qualifier);
5371 msi_ui_actiondata( package, szPublishComponents, uirow );
5372 msiobj_release( &uirow->hdr );
5373 /* FIXME: call ui_progress? */
5374
5375 return rc;
5376 }
5377
5378 /*
5379 * At present I am ignorning the advertised components part of this and only
5380 * focusing on the qualified component sets
5381 */
5382 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5383 {
5384 static const WCHAR query[] = {
5385 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5386 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5387 MSIQUERY *view;
5388 UINT rc;
5389
5390 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5391 if (rc != ERROR_SUCCESS)
5392 return ERROR_SUCCESS;
5393
5394 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5395 msiobj_release(&view->hdr);
5396 return rc;
5397 }
5398
5399 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5400 {
5401 static const WCHAR szInstallerComponents[] = {
5402 'S','o','f','t','w','a','r','e','\\',
5403 'M','i','c','r','o','s','o','f','t','\\',
5404 'I','n','s','t','a','l','l','e','r','\\',
5405 'C','o','m','p','o','n','e','n','t','s','\\',0};
5406
5407 MSIPACKAGE *package = param;
5408 LPCWSTR compgroupid, component, feature, qualifier;
5409 MSICOMPONENT *comp;
5410 MSIFEATURE *feat;
5411 MSIRECORD *uirow;
5412 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5413 LONG res;
5414
5415 feature = MSI_RecordGetString( rec, 5 );
5416 feat = msi_get_loaded_feature( package, feature );
5417 if (!feat)
5418 return ERROR_SUCCESS;
5419
5420 feat->Action = msi_get_feature_action( package, feat );
5421 if (feat->Action != INSTALLSTATE_ABSENT)
5422 {
5423 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5424 return ERROR_SUCCESS;
5425 }
5426
5427 component = MSI_RecordGetString( rec, 3 );
5428 comp = msi_get_loaded_component( package, component );
5429 if (!comp)
5430 return ERROR_SUCCESS;
5431
5432 compgroupid = MSI_RecordGetString( rec, 1 );
5433 qualifier = MSI_RecordGetString( rec, 2 );
5434
5435 squash_guid( compgroupid, squashed );
5436 strcpyW( keypath, szInstallerComponents );
5437 strcatW( keypath, squashed );
5438
5439 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5440 if (res != ERROR_SUCCESS)
5441 {
5442 WARN("Unable to delete component key %d\n", res);
5443 }
5444
5445 uirow = MSI_CreateRecord( 2 );
5446 MSI_RecordSetStringW( uirow, 1, compgroupid );
5447 MSI_RecordSetStringW( uirow, 2, qualifier );
5448 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5449 msiobj_release( &uirow->hdr );
5450
5451 return ERROR_SUCCESS;
5452 }
5453
5454 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5455 {
5456 static const WCHAR query[] = {
5457 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5458 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5459 MSIQUERY *view;
5460 UINT rc;
5461
5462 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5463 if (rc != ERROR_SUCCESS)
5464 return ERROR_SUCCESS;
5465
5466 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5467 msiobj_release( &view->hdr );
5468 return rc;
5469 }
5470
5471 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5472 {
5473 static const WCHAR query[] =
5474 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5475 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5476 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5477 MSIPACKAGE *package = param;
5478 MSICOMPONENT *component;
5479 MSIRECORD *row;
5480 MSIFILE *file;
5481 SC_HANDLE hscm = NULL, service = NULL;
5482 LPCWSTR comp, key;
5483 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5484 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5485 DWORD serv_type, start_type, err_control;
5486 SERVICE_DESCRIPTIONW sd = {NULL};
5487
5488 comp = MSI_RecordGetString( rec, 12 );
5489 component = msi_get_loaded_component( package, comp );
5490 if (!component)
5491 {
5492 WARN("service component not found\n");
5493 goto done;
5494 }
5495 component->Action = msi_get_component_action( package, component );
5496 if (component->Action != INSTALLSTATE_LOCAL)
5497 {
5498 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5499 goto done;
5500 }
5501 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5502 if (!hscm)
5503 {
5504 ERR("Failed to open the SC Manager!\n");
5505 goto done;
5506 }
5507
5508 start_type = MSI_RecordGetInteger(rec, 5);
5509 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5510 goto done;
5511
5512 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5513 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5514 serv_type = MSI_RecordGetInteger(rec, 4);
5515 err_control = MSI_RecordGetInteger(rec, 6);
5516 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5517 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5518 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5519 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5520 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5521 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5522
5523 /* fetch the service path */
5524 row = MSI_QueryGetRecord(package->db, query, comp);
5525 if (!row)
5526 {
5527 ERR("Query failed\n");
5528 goto done;
5529 }
5530 key = MSI_RecordGetString(row, 6);
5531 file = msi_get_loaded_file(package, key);
5532 msiobj_release(&row->hdr);
5533 if (!file)
5534 {
5535 ERR("Failed to load the service file\n");
5536 goto done;
5537 }
5538
5539 if (!args || !args[0]) image_path = file->TargetPath;
5540 else
5541 {
5542 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5543 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5544 return ERROR_OUTOFMEMORY;
5545
5546 strcpyW(image_path, file->TargetPath);
5547 strcatW(image_path, szSpace);
5548 strcatW(image_path, args);
5549 }
5550 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5551 start_type, err_control, image_path, load_order,
5552 NULL, depends, serv_name, pass);
5553
5554 if (!service)
5555 {
5556 if (GetLastError() != ERROR_SERVICE_EXISTS)
5557 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5558 }
5559 else if (sd.lpDescription)
5560 {
5561 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5562 WARN("failed to set service description %u\n", GetLastError());
5563 }
5564
5565 if (image_path != file->TargetPath) msi_free(image_path);
5566 done:
5567 CloseServiceHandle(service);
5568 CloseServiceHandle(hscm);
5569 msi_free(name);
5570 msi_free(disp);
5571 msi_free(sd.lpDescription);
5572 msi_free(load_order);
5573 msi_free(serv_name);
5574 msi_free(pass);
5575 msi_free(depends);
5576 msi_free(args);
5577
5578 return ERROR_SUCCESS;
5579 }
5580
5581 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5582 {
5583 static const WCHAR query[] = {
5584 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5585 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5586 MSIQUERY *view;
5587 UINT rc;
5588
5589 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5590 if (rc != ERROR_SUCCESS)
5591 return ERROR_SUCCESS;
5592
5593 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5594 msiobj_release(&view->hdr);
5595 return rc;
5596 }
5597
5598 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5599 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5600 {
5601 LPCWSTR *vector, *temp_vector;
5602 LPWSTR p, q;
5603 DWORD sep_len;
5604
5605 static const WCHAR separator[] = {'[','~',']',0};
5606
5607 *numargs = 0;
5608 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5609
5610 if (!args)
5611 return NULL;
5612
5613 vector = msi_alloc(sizeof(LPWSTR));
5614 if (!vector)
5615 return NULL;
5616
5617 p = args;
5618 do
5619 {
5620 (*numargs)++;
5621 vector[*numargs - 1] = p;
5622
5623 if ((q = strstrW(p, separator)))
5624 {
5625 *q = '\0';
5626
5627 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5628 if (!temp_vector)
5629 {
5630 msi_free(vector);
5631 return NULL;
5632 }
5633 vector = temp_vector;
5634
5635 p = q + sep_len;
5636 }
5637 } while (q);
5638
5639 return vector;
5640 }
5641
5642 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5643 {
5644 MSIPACKAGE *package = param;
5645 MSICOMPONENT *comp;
5646 MSIRECORD *uirow;
5647 SC_HANDLE scm = NULL, service = NULL;
5648 LPCWSTR component, *vector = NULL;
5649 LPWSTR name, args, display_name = NULL;
5650 DWORD event, numargs, len, wait, dummy;
5651 UINT r = ERROR_FUNCTION_FAILED;
5652 SERVICE_STATUS_PROCESS status;
5653 ULONGLONG start_time;
5654
5655 component = MSI_RecordGetString(rec, 6);
5656 comp = msi_get_loaded_component(package, component);
5657 if (!comp)
5658 return ERROR_SUCCESS;
5659
5660 comp->Action = msi_get_component_action( package, comp );
5661 if (comp->Action != INSTALLSTATE_LOCAL)
5662 {
5663 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5664 return ERROR_SUCCESS;
5665 }
5666
5667 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5668 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5669 event = MSI_RecordGetInteger(rec, 3);
5670 wait = MSI_RecordGetInteger(rec, 5);
5671
5672 if (!(event & msidbServiceControlEventStart))
5673 {
5674 r = ERROR_SUCCESS;
5675 goto done;
5676 }
5677
5678 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5679 if (!scm)
5680 {
5681 ERR("Failed to open the service control manager\n");
5682 goto done;
5683 }
5684
5685 len = 0;
5686 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5687 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5688 {
5689 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5690 GetServiceDisplayNameW( scm, name, display_name, &len );
5691 }
5692
5693 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5694 if (!service)
5695 {
5696 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5697 goto done;
5698 }
5699
5700 vector = msi_service_args_to_vector(args, &numargs);
5701
5702 if (!StartServiceW(service, numargs, vector) &&
5703 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5704 {
5705 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5706 goto done;
5707 }
5708
5709 r = ERROR_SUCCESS;
5710 if (wait)
5711 {
5712 /* wait for at most 30 seconds for the service to be up and running */
5713 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5714 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5715 {
5716 TRACE("failed to query service status (%u)\n", GetLastError());
5717 goto done;
5718 }
5719 start_time = GetTickCount64();
5720 while (status.dwCurrentState == SERVICE_START_PENDING)
5721 {
5722 if (GetTickCount64() - start_time > 30000) break;
5723 Sleep(1000);
5724 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5725 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5726 {
5727 TRACE("failed to query service status (%u)\n", GetLastError());
5728 goto done;
5729 }
5730 }
5731 if (status.dwCurrentState != SERVICE_RUNNING)
5732 {
5733 WARN("service failed to start %u\n", status.dwCurrentState);
5734 r = ERROR_FUNCTION_FAILED;
5735 }
5736 }
5737
5738 done:
5739 uirow = MSI_CreateRecord( 2 );
5740 MSI_RecordSetStringW( uirow, 1, display_name );
5741 MSI_RecordSetStringW( uirow, 2, name );
5742 msi_ui_actiondata( package, szStartServices, uirow );
5743 msiobj_release( &uirow->hdr );
5744
5745 CloseServiceHandle(service);
5746 CloseServiceHandle(scm);
5747
5748 msi_free(name);
5749 msi_free(args);
5750 msi_free(vector);
5751 msi_free(display_name);
5752 return r;
5753 }
5754
5755 static UINT ACTION_StartServices( MSIPACKAGE *package )
5756 {
5757 static const WCHAR query[] = {
5758 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5759 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5760 MSIQUERY *view;
5761 UINT rc;
5762
5763 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5764 if (rc != ERROR_SUCCESS)
5765 return ERROR_SUCCESS;
5766
5767 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5768 msiobj_release(&view->hdr);
5769 return rc;
5770 }
5771
5772 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5773 {
5774 DWORD i, needed, count;
5775 ENUM_SERVICE_STATUSW *dependencies;
5776 SERVICE_STATUS ss;
5777 SC_HANDLE depserv;
5778
5779 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5780 0, &needed, &count))
5781 return TRUE;
5782
5783 if (GetLastError() != ERROR_MORE_DATA)
5784 return FALSE;
5785
5786 dependencies = msi_alloc(needed);
5787 if (!dependencies)
5788 return FALSE;
5789
5790 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5791 needed, &needed, &count))
5792 goto error;
5793
5794 for (i = 0; i < count; i++)
5795 {
5796 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5797 SERVICE_STOP | SERVICE_QUERY_STATUS);
5798 if (!depserv)
5799 goto error;
5800
5801 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5802 goto error;
5803 }
5804
5805 return TRUE;
5806
5807 error:
5808 msi_free(dependencies);
5809 return FALSE;
5810 }
5811
5812 static UINT stop_service( LPCWSTR name )
5813 {
5814 SC_HANDLE scm = NULL, service = NULL;
5815 SERVICE_STATUS status;
5816 SERVICE_STATUS_PROCESS ssp;
5817 DWORD needed;
5818
5819 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5820 if (!scm)
5821 {
5822 WARN("Failed to open the SCM: %d\n", GetLastError());
5823 goto done;
5824 }
5825
5826 service = OpenServiceW(scm, name,
5827 SERVICE_STOP |
5828 SERVICE_QUERY_STATUS |
5829 SERVICE_ENUMERATE_DEPENDENTS);
5830 if (!service)
5831 {
5832 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5833 goto done;
5834 }
5835
5836 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5837 sizeof(SERVICE_STATUS_PROCESS), &needed))
5838 {
5839 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5840 goto done;
5841 }
5842
5843 if (ssp.dwCurrentState == SERVICE_STOPPED)
5844 goto done;
5845
5846 stop_service_dependents(scm, service);
5847
5848 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5849 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5850
5851 done:
5852 CloseServiceHandle(service);
5853 CloseServiceHandle(scm);
5854
5855 return ERROR_SUCCESS;
5856 }
5857
5858 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5859 {
5860 MSIPACKAGE *package = param;
5861 MSICOMPONENT *comp;
5862 MSIRECORD *uirow;
5863 LPCWSTR component;
5864 LPWSTR name = NULL, display_name = NULL;
5865 DWORD event, len;
5866 SC_HANDLE scm;
5867
5868 event = MSI_RecordGetInteger( rec, 3 );
5869 if (!(event & msidbServiceControlEventStop))
5870 return ERROR_SUCCESS;
5871
5872 component = MSI_RecordGetString( rec, 6 );
5873 comp = msi_get_loaded_component( package, component );
5874 if (!comp)
5875 return ERROR_SUCCESS;
5876
5877 comp->Action = msi_get_component_action( package, comp );
5878 if (comp->Action != INSTALLSTATE_ABSENT)
5879 {
5880 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5881 return ERROR_SUCCESS;
5882 }
5883
5884 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5885 if (!scm)
5886 {
5887 ERR("Failed to open the service control manager\n");
5888 goto done;
5889 }
5890
5891 len = 0;
5892 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5893 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5894 {
5895 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5896 GetServiceDisplayNameW( scm, name, display_name, &len );
5897 }
5898 CloseServiceHandle( scm );
5899
5900 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5901 stop_service( name );
5902
5903 done:
5904 uirow = MSI_CreateRecord( 2 );
5905 MSI_RecordSetStringW( uirow, 1, display_name );
5906 MSI_RecordSetStringW( uirow, 2, name );
5907 msi_ui_actiondata( package, szStopServices, uirow );
5908 msiobj_release( &uirow->hdr );
5909
5910 msi_free( name );
5911 msi_free( display_name );
5912 return ERROR_SUCCESS;
5913 }
5914
5915 static UINT ACTION_StopServices( MSIPACKAGE *package )
5916 {
5917 static const WCHAR query[] = {
5918 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5919 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5920 MSIQUERY *view;
5921 UINT rc;
5922
5923 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5924 if (rc != ERROR_SUCCESS)
5925 return ERROR_SUCCESS;
5926
5927 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5928 msiobj_release(&view->hdr);
5929 return rc;
5930 }
5931
5932 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5933 {
5934 MSIPACKAGE *package = param;
5935 MSICOMPONENT *comp;
5936 MSIRECORD *uirow;
5937 LPWSTR name = NULL, display_name = NULL;
5938 DWORD event, len;
5939 SC_HANDLE scm = NULL, service = NULL;
5940
5941 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
5942 if (!comp)
5943 return ERROR_SUCCESS;
5944
5945 event = MSI_RecordGetInteger( rec, 3 );
5946 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5947
5948 comp->Action = msi_get_component_action( package, comp );
5949 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
5950 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
5951 {
5952 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
5953 msi_free( name );
5954 return ERROR_SUCCESS;
5955 }
5956 stop_service( name );
5957
5958 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5959 if (!scm)
5960 {
5961 WARN("Failed to open the SCM: %d\n", GetLastError());
5962 goto done;
5963 }
5964
5965 len = 0;
5966 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5967 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5968 {
5969 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5970 GetServiceDisplayNameW( scm, name, display_name, &len );
5971 }
5972
5973 service = OpenServiceW( scm, name, DELETE );
5974 if (!service)
5975 {
5976 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5977 goto done;
5978 }
5979
5980 if (!DeleteService( service ))
5981 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5982
5983 done:
5984 uirow = MSI_CreateRecord( 2 );
5985 MSI_RecordSetStringW( uirow, 1, display_name );
5986 MSI_RecordSetStringW( uirow, 2, name );
5987 msi_ui_actiondata( package, szDeleteServices, uirow );
5988 msiobj_release( &uirow->hdr );
5989
5990 CloseServiceHandle( service );
5991 CloseServiceHandle( scm );
5992 msi_free( name );
5993 msi_free( display_name );
5994
5995 return ERROR_SUCCESS;
5996 }
5997
5998 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5999 {
6000 static const WCHAR query[] = {
6001 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6002 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6003 MSIQUERY *view;
6004 UINT rc;
6005
6006 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6007 if (rc != ERROR_SUCCESS)
6008 return ERROR_SUCCESS;
6009
6010 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6011 msiobj_release( &view->hdr );
6012 return rc;
6013 }
6014
6015 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6016 {
6017 MSIPACKAGE *package = param;
6018 LPWSTR driver, driver_path, ptr;
6019 WCHAR outpath[MAX_PATH];
6020 MSIFILE *driver_file = NULL, *setup_file = NULL;
6021 MSICOMPONENT *comp;
6022 MSIRECORD *uirow;
6023 LPCWSTR desc, file_key, component;
6024 DWORD len, usage;
6025 UINT r = ERROR_SUCCESS;
6026
6027 static const WCHAR driver_fmt[] = {
6028 'D','r','i','v','e','r','=','%','s',0};
6029 static const WCHAR setup_fmt[] = {
6030 'S','e','t','u','p','=','%','s',0};
6031 static const WCHAR usage_fmt[] = {
6032 'F','i','l','e','U','s','a','g','e','=','1',0};
6033
6034 component = MSI_RecordGetString( rec, 2 );
6035 comp = msi_get_loaded_component( package, component );
6036 if (!comp)
6037 return ERROR_SUCCESS;
6038
6039 comp->Action = msi_get_component_action( package, comp );
6040 if (comp->Action != INSTALLSTATE_LOCAL)
6041 {
6042 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6043 return ERROR_SUCCESS;
6044 }
6045 desc = MSI_RecordGetString(rec, 3);
6046
6047 file_key = MSI_RecordGetString( rec, 4 );
6048 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6049
6050 file_key = MSI_RecordGetString( rec, 5 );
6051 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6052
6053 if (!driver_file)
6054 {
6055 ERR("ODBC Driver entry not found!\n");
6056 return ERROR_FUNCTION_FAILED;
6057 }
6058
6059 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6060 if (setup_file)
6061 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6062 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6063
6064 driver = msi_alloc(len * sizeof(WCHAR));
6065 if (!driver)
6066 return ERROR_OUTOFMEMORY;
6067
6068 ptr = driver;
6069 lstrcpyW(ptr, desc);
6070 ptr += lstrlenW(ptr) + 1;
6071
6072 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6073 ptr += len + 1;
6074
6075 if (setup_file)
6076 {
6077 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6078 ptr += len + 1;
6079 }
6080
6081 lstrcpyW(ptr, usage_fmt);
6082 ptr += lstrlenW(ptr) + 1;
6083 *ptr = '\0';
6084
6085 if (!driver_file->TargetPath)
6086 {
6087 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6088 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6089 }
6090 driver_path = strdupW(driver_file->TargetPath);
6091 ptr = strrchrW(driver_path, '\\');
6092 if (ptr) *ptr = '\0';
6093
6094 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6095 NULL, ODBC_INSTALL_COMPLETE, &usage))
6096 {
6097 ERR("Failed to install SQL driver!\n");
6098 r = ERROR_FUNCTION_FAILED;
6099 }
6100
6101 uirow = MSI_CreateRecord( 5 );
6102 MSI_RecordSetStringW( uirow, 1, desc );
6103 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6104 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6105 msi_ui_actiondata( package, szInstallODBC, uirow );
6106 msiobj_release( &uirow->hdr );
6107
6108 msi_free(driver);
6109 msi_free(driver_path);
6110
6111 return r;
6112 }
6113
6114 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6115 {
6116 MSIPACKAGE *package = param;
6117 LPWSTR translator, translator_path, ptr;
6118 WCHAR outpath[MAX_PATH];
6119 MSIFILE *translator_file = NULL, *setup_file = NULL;
6120 MSICOMPONENT *comp;
6121 MSIRECORD *uirow;
6122 LPCWSTR desc, file_key, component;
6123 DWORD len, usage;
6124 UINT r = ERROR_SUCCESS;
6125
6126 static const WCHAR translator_fmt[] = {
6127 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6128 static const WCHAR setup_fmt[] = {
6129 'S','e','t','u','p','=','%','s',0};
6130
6131 component = MSI_RecordGetString( rec, 2 );
6132 comp = msi_get_loaded_component( package, component );
6133 if (!comp)
6134 return ERROR_SUCCESS;
6135
6136 comp->Action = msi_get_component_action( package, comp );
6137 if (comp->Action != INSTALLSTATE_LOCAL)
6138 {
6139 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6140 return ERROR_SUCCESS;
6141 }
6142 desc = MSI_RecordGetString(rec, 3);
6143
6144 file_key = MSI_RecordGetString( rec, 4 );
6145 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6146
6147 file_key = MSI_RecordGetString( rec, 5 );
6148 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6149
6150 if (!translator_file)
6151 {
6152 ERR("ODBC Translator entry not found!\n");
6153 return ERROR_FUNCTION_FAILED;
6154 }
6155
6156 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6157 if (setup_file)
6158 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6159
6160 translator = msi_alloc(len * sizeof(WCHAR));
6161 if (!translator)
6162 return ERROR_OUTOFMEMORY;
6163
6164 ptr = translator;
6165 lstrcpyW(ptr, desc);
6166 ptr += lstrlenW(ptr) + 1;
6167
6168 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6169 ptr += len + 1;
6170
6171 if (setup_file)
6172 {
6173 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6174 ptr += len + 1;
6175 }
6176 *ptr = '\0';
6177
6178 translator_path = strdupW(translator_file->TargetPath);
6179 ptr = strrchrW(translator_path, '\\');
6180 if (ptr) *ptr = '\0';
6181
6182 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6183 NULL, ODBC_INSTALL_COMPLETE, &usage))
6184 {
6185 ERR("Failed to install SQL translator!\n");
6186 r = ERROR_FUNCTION_FAILED;
6187 }
6188
6189 uirow = MSI_CreateRecord( 5 );
6190 MSI_RecordSetStringW( uirow, 1, desc );
6191 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6192 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6193 msi_ui_actiondata( package, szInstallODBC, uirow );
6194 msiobj_release( &uirow->hdr );
6195
6196 msi_free(translator);
6197 msi_free(translator_path);
6198
6199 return r;
6200 }
6201
6202 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6203 {
6204 MSIPACKAGE *package = param;
6205 MSICOMPONENT *comp;
6206 LPWSTR attrs;
6207 LPCWSTR desc, driver, component;
6208 WORD request = ODBC_ADD_SYS_DSN;
6209 INT registration;
6210 DWORD len;
6211 UINT r = ERROR_SUCCESS;
6212 MSIRECORD *uirow;
6213
6214 static const WCHAR attrs_fmt[] = {
6215 'D','S','N','=','%','s',0 };
6216
6217 component = MSI_RecordGetString( rec, 2 );
6218 comp = msi_get_loaded_component( package, component );
6219 if (!comp)
6220 return ERROR_SUCCESS;
6221
6222 comp->Action = msi_get_component_action( package, comp );
6223 if (comp->Action != INSTALLSTATE_LOCAL)
6224 {
6225 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6226 return ERROR_SUCCESS;
6227 }
6228
6229 desc = MSI_RecordGetString(rec, 3);
6230 driver = MSI_RecordGetString(rec, 4);
6231 registration = MSI_RecordGetInteger(rec, 5);
6232
6233 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6234 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6235
6236 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6237 attrs = msi_alloc(len * sizeof(WCHAR));
6238 if (!attrs)
6239 return ERROR_OUTOFMEMORY;
6240
6241 len = sprintfW(attrs, attrs_fmt, desc);
6242 attrs[len + 1] = 0;
6243
6244 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6245 {
6246 ERR("Failed to install SQL data source!\n");
6247 r = ERROR_FUNCTION_FAILED;
6248 }
6249
6250 uirow = MSI_CreateRecord( 5 );
6251 MSI_RecordSetStringW( uirow, 1, desc );
6252 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6253 MSI_RecordSetInteger( uirow, 3, request );
6254 msi_ui_actiondata( package, szInstallODBC, uirow );
6255 msiobj_release( &uirow->hdr );
6256
6257 msi_free(attrs);
6258
6259 return r;
6260 }
6261
6262 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6263 {
6264 static const WCHAR driver_query[] = {
6265 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6266 'O','D','B','C','D','r','i','v','e','r',0};
6267 static const WCHAR translator_query[] = {
6268 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6269 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6270 static const WCHAR source_query[] = {
6271 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6272 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6273 MSIQUERY *view;
6274 UINT rc;
6275
6276 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6277 if (rc == ERROR_SUCCESS)
6278 {
6279 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6280 msiobj_release(&view->hdr);
6281 if (rc != ERROR_SUCCESS)
6282 return rc;
6283 }
6284 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6285 if (rc == ERROR_SUCCESS)
6286 {
6287 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6288 msiobj_release(&view->hdr);
6289 if (rc != ERROR_SUCCESS)
6290 return rc;
6291 }
6292 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6293 if (rc == ERROR_SUCCESS)
6294 {
6295 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6296 msiobj_release(&view->hdr);
6297 if (rc != ERROR_SUCCESS)
6298 return rc;
6299 }
6300 return ERROR_SUCCESS;
6301 }
6302
6303 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6304 {
6305 MSIPACKAGE *package = param;
6306 MSICOMPONENT *comp;
6307 MSIRECORD *uirow;
6308 DWORD usage;
6309 LPCWSTR desc, component;
6310
6311 component = MSI_RecordGetString( rec, 2 );
6312 comp = msi_get_loaded_component( package, component );
6313 if (!comp)
6314 return ERROR_SUCCESS;
6315
6316 comp->Action = msi_get_component_action( package, comp );
6317 if (comp->Action != INSTALLSTATE_ABSENT)
6318 {
6319 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6320 return ERROR_SUCCESS;
6321 }
6322
6323 desc = MSI_RecordGetString( rec, 3 );
6324 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6325 {
6326 WARN("Failed to remove ODBC driver\n");
6327 }
6328 else if (!usage)
6329 {
6330 FIXME("Usage count reached 0\n");
6331 }
6332
6333 uirow = MSI_CreateRecord( 2 );
6334 MSI_RecordSetStringW( uirow, 1, desc );
6335 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6336 msi_ui_actiondata( package, szRemoveODBC, uirow );
6337 msiobj_release( &uirow->hdr );
6338
6339 return ERROR_SUCCESS;
6340 }
6341
6342 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6343 {
6344 MSIPACKAGE *package = param;
6345 MSICOMPONENT *comp;
6346 MSIRECORD *uirow;
6347 DWORD usage;
6348 LPCWSTR desc, component;
6349
6350 component = MSI_RecordGetString( rec, 2 );
6351 comp = msi_get_loaded_component( package, component );
6352 if (!comp)
6353 return ERROR_SUCCESS;
6354
6355 comp->Action = msi_get_component_action( package, comp );
6356 if (comp->Action != INSTALLSTATE_ABSENT)
6357 {
6358 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6359 return ERROR_SUCCESS;
6360 }
6361
6362 desc = MSI_RecordGetString( rec, 3 );
6363 if (!SQLRemoveTranslatorW( desc, &usage ))
6364 {
6365 WARN("Failed to remove ODBC translator\n");
6366 }
6367 else if (!usage)
6368 {
6369 FIXME("Usage count reached 0\n");
6370 }
6371
6372 uirow = MSI_CreateRecord( 2 );
6373 MSI_RecordSetStringW( uirow, 1, desc );
6374 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6375 msi_ui_actiondata( package, szRemoveODBC, uirow );
6376 msiobj_release( &uirow->hdr );
6377
6378 return ERROR_SUCCESS;
6379 }
6380
6381 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6382 {
6383 MSIPACKAGE *package = param;
6384 MSICOMPONENT *comp;
6385 MSIRECORD *uirow;
6386 LPWSTR attrs;
6387 LPCWSTR desc, driver, component;
6388 WORD request = ODBC_REMOVE_SYS_DSN;
6389 INT registration;
6390 DWORD len;
6391
6392 static const WCHAR attrs_fmt[] = {
6393 'D','S','N','=','%','s',0 };
6394
6395 component = MSI_RecordGetString( rec, 2 );
6396 comp = msi_get_loaded_component( package, component );
6397 if (!comp)
6398 return ERROR_SUCCESS;
6399
6400 comp->Action = msi_get_component_action( package, comp );
6401 if (comp->Action != INSTALLSTATE_ABSENT)
6402 {
6403 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6404 return ERROR_SUCCESS;
6405 }
6406
6407 desc = MSI_RecordGetString( rec, 3 );
6408 driver = MSI_RecordGetString( rec, 4 );
6409 registration = MSI_RecordGetInteger( rec, 5 );
6410
6411 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6412 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6413
6414 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6415 attrs = msi_alloc( len * sizeof(WCHAR) );
6416 if (!attrs)
6417 return ERROR_OUTOFMEMORY;
6418
6419 FIXME("Use ODBCSourceAttribute table\n");
6420
6421 len = sprintfW( attrs, attrs_fmt, desc );
6422 attrs[len + 1] = 0;
6423
6424 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6425 {
6426 WARN("Failed to remove ODBC data source\n");
6427 }
6428 msi_free( attrs );
6429
6430 uirow = MSI_CreateRecord( 3 );
6431 MSI_RecordSetStringW( uirow, 1, desc );
6432 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6433 MSI_RecordSetInteger( uirow, 3, request );
6434 msi_ui_actiondata( package, szRemoveODBC, uirow );
6435 msiobj_release( &uirow->hdr );
6436
6437 return ERROR_SUCCESS;
6438 }
6439
6440 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6441 {
6442 static const WCHAR driver_query[] = {
6443 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6444 'O','D','B','C','D','r','i','v','e','r',0};
6445 static const WCHAR translator_query[] = {
6446 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6447 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6448 static const WCHAR source_query[] = {
6449 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6450 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6451 MSIQUERY *view;
6452 UINT rc;
6453
6454 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6455 if (rc == ERROR_SUCCESS)
6456 {
6457 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6458 msiobj_release( &view->hdr );
6459 if (rc != ERROR_SUCCESS)
6460 return rc;
6461 }
6462 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6463 if (rc == ERROR_SUCCESS)
6464 {
6465 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6466 msiobj_release( &view->hdr );
6467 if (rc != ERROR_SUCCESS)
6468 return rc;
6469 }
6470 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6471 if (rc == ERROR_SUCCESS)
6472 {
6473 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6474 msiobj_release( &view->hdr );
6475 if (rc != ERROR_SUCCESS)
6476 return rc;
6477 }
6478 return ERROR_SUCCESS;
6479 }
6480
6481 #define ENV_ACT_SETALWAYS 0x1
6482 #define ENV_ACT_SETABSENT 0x2
6483 #define ENV_ACT_REMOVE 0x4
6484 #define ENV_ACT_REMOVEMATCH 0x8
6485
6486 #define ENV_MOD_MACHINE 0x20000000
6487 #define ENV_MOD_APPEND 0x40000000
6488 #define ENV_MOD_PREFIX 0x80000000
6489 #define ENV_MOD_MASK 0xC0000000
6490
6491 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6492
6493 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6494 {
6495 LPCWSTR cptr = *name;
6496
6497 static const WCHAR prefix[] = {'[','~',']',0};
6498 static const int prefix_len = 3;
6499
6500 *flags = 0;
6501 while (*cptr)
6502 {
6503 if (*cptr == '=')
6504 *flags |= ENV_ACT_SETALWAYS;
6505 else if (*cptr == '+')
6506 *flags |= ENV_ACT_SETABSENT;
6507 else if (*cptr == '-')
6508 *flags |= ENV_ACT_REMOVE;
6509 else if (*cptr == '!')
6510 *flags |= ENV_ACT_REMOVEMATCH;
6511 else if (*cptr == '*')
6512 *flags |= ENV_MOD_MACHINE;
6513 else
6514 break;
6515
6516 cptr++;
6517 (*name)++;
6518 }
6519
6520 if (!*cptr)
6521 {
6522 ERR("Missing environment variable\n");
6523 return ERROR_FUNCTION_FAILED;
6524 }
6525
6526 if (*value)
6527 {
6528 LPCWSTR ptr = *value;
6529 if (!strncmpW(ptr, prefix, prefix_len))
6530 {
6531 if (ptr[prefix_len] == szSemiColon[0])
6532 {
6533 *flags |= ENV_MOD_APPEND;
6534 *value += lstrlenW(prefix);
6535 }
6536 else
6537 {
6538 *value = NULL;
6539 }
6540 }
6541 else if (lstrlenW(*value) >= prefix_len)
6542 {
6543 ptr += lstrlenW(ptr) - prefix_len;
6544 if (!strcmpW( ptr, prefix ))
6545 {
6546 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6547 {
6548 *flags |= ENV_MOD_PREFIX;
6549 /* the "[~]" will be removed by deformat_string */;
6550 }
6551 else
6552 {
6553 *value = NULL;
6554 }
6555 }
6556 }
6557 }
6558
6559 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6560 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6561 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6562 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6563 {
6564 ERR("Invalid flags: %08x\n", *flags);
6565 return ERROR_FUNCTION_FAILED;
6566 }
6567
6568 if (!*flags)
6569 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6570
6571 return ERROR_SUCCESS;
6572 }
6573
6574 static UINT open_env_key( DWORD flags, HKEY *key )
6575 {
6576 static const WCHAR user_env[] =
6577 {'E','n','v','i','r','o','n','m','e','n','t',0};
6578 static const WCHAR machine_env[] =
6579 {'S','y','s','t','e','m','\\',
6580 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6581 'C','o','n','t','r','o','l','\\',
6582 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6583 'E','n','v','i','r','o','n','m','e','n','t',0};
6584 const WCHAR *env;
6585 HKEY root;
6586 LONG res;
6587
6588 if (flags & ENV_MOD_MACHINE)
6589 {
6590 env = machine_env;
6591 root = HKEY_LOCAL_MACHINE;
6592 }
6593 else
6594 {
6595 env = user_env;
6596 root = HKEY_CURRENT_USER;
6597 }
6598
6599 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6600 if (res != ERROR_SUCCESS)
6601 {
6602 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6603 return ERROR_FUNCTION_FAILED;
6604 }
6605
6606 return ERROR_SUCCESS;
6607 }
6608
6609 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6610 {
6611 MSIPACKAGE *package = param;
6612 LPCWSTR name, value, component;
6613 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6614 DWORD flags, type, size;
6615 UINT res;
6616 HKEY env = NULL;
6617 MSICOMPONENT *comp;
6618 MSIRECORD *uirow;
6619 int action = 0;
6620
6621 component = MSI_RecordGetString(rec, 4);
6622 comp = msi_get_loaded_component(package, component);
6623 if (!comp)
6624 return ERROR_SUCCESS;
6625
6626 comp->Action = msi_get_component_action( package, comp );
6627 if (comp->Action != INSTALLSTATE_LOCAL)
6628 {
6629 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6630 return ERROR_SUCCESS;
6631 }
6632 name = MSI_RecordGetString(rec, 2);
6633 value = MSI_RecordGetString(rec, 3);
6634
6635 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6636
6637 res = env_parse_flags(&name, &value, &flags);
6638 if (res != ERROR_SUCCESS || !value)
6639 goto done;
6640
6641 if (value && !deformat_string(package, value, &deformatted))
6642 {
6643 res = ERROR_OUTOFMEMORY;
6644 goto done;
6645 }
6646
6647 value = deformatted;
6648
6649 res = open_env_key( flags, &env );
6650 if (res != ERROR_SUCCESS)
6651 goto done;
6652
6653 if (flags & ENV_MOD_MACHINE)
6654 action |= 0x20000000;
6655
6656 size = 0;
6657 type = REG_SZ;
6658 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6659 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6660 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6661 goto done;
6662
6663 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6664 {
6665 action = 0x2;
6666
6667 /* Nothing to do. */
6668 if (!value)
6669 {
6670 res = ERROR_SUCCESS;
6671 goto done;
6672 }
6673
6674 /* If we are appending but the string was empty, strip ; */
6675 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6676
6677 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6678 newval = strdupW(value);
6679 if (!newval)
6680 {
6681 res = ERROR_OUTOFMEMORY;
6682 goto done;
6683 }
6684 }
6685 else
6686 {
6687 action = 0x1;
6688
6689 /* Contrary to MSDN, +-variable to [~];path works */
6690 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6691 {
6692 res = ERROR_SUCCESS;
6693 goto done;
6694 }
6695
6696 data = msi_alloc(size);
6697 if (!data)
6698 {
6699 RegCloseKey(env);
6700 return ERROR_OUTOFMEMORY;
6701 }
6702
6703 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6704 if (res != ERROR_SUCCESS)
6705 goto done;
6706
6707 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6708 {
6709 action = 0x4;
6710 res = RegDeleteValueW(env, name);
6711 if (res != ERROR_SUCCESS)
6712 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6713 goto done;
6714 }
6715
6716 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6717 if (flags & ENV_MOD_MASK)
6718 {
6719 DWORD mod_size;
6720 int multiplier = 0;
6721 if (flags & ENV_MOD_APPEND) multiplier++;
6722 if (flags & ENV_MOD_PREFIX) multiplier++;
6723 mod_size = lstrlenW(value) * multiplier;
6724 size += mod_size * sizeof(WCHAR);
6725 }
6726
6727 newval = msi_alloc(size);
6728 ptr = newval;
6729 if (!newval)
6730 {
6731 res = ERROR_OUTOFMEMORY;
6732 goto done;
6733 }
6734
6735 if (flags & ENV_MOD_PREFIX)
6736 {
6737 lstrcpyW(newval, value);
6738 ptr = newval + lstrlenW(value);
6739 action |= 0x80000000;
6740 }
6741
6742 lstrcpyW(ptr, data);
6743
6744 if (flags & ENV_MOD_APPEND)
6745 {
6746 lstrcatW(newval, value);
6747 action |= 0x40000000;
6748 }
6749 }
6750 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6751 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6752 if (res)
6753 {
6754 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6755 }
6756
6757 done:
6758 uirow = MSI_CreateRecord( 3 );
6759 MSI_RecordSetStringW( uirow, 1, name );
6760 MSI_RecordSetStringW( uirow, 2, newval );
6761 MSI_RecordSetInteger( uirow, 3, action );
6762 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6763 msiobj_release( &uirow->hdr );
6764
6765 if (env) RegCloseKey(env);
6766 msi_free(deformatted);
6767 msi_free(data);
6768 msi_free(newval);
6769 return res;
6770 }
6771
6772 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6773 {
6774 static const WCHAR query[] = {
6775 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6776 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6777 MSIQUERY *view;
6778 UINT rc;
6779
6780 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6781 if (rc != ERROR_SUCCESS)
6782 return ERROR_SUCCESS;
6783
6784 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6785 msiobj_release(&view->hdr);
6786 return rc;
6787 }
6788
6789 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6790 {
6791 MSIPACKAGE *package = param;
6792 LPCWSTR name, value, component;
6793 LPWSTR deformatted = NULL;
6794 DWORD flags;
6795 HKEY env;
6796 MSICOMPONENT *comp;
6797 MSIRECORD *uirow;
6798 int action = 0;
6799 LONG res;
6800 UINT r;
6801
6802 component = MSI_RecordGetString( rec, 4 );
6803 comp = msi_get_loaded_component( package, component );
6804 if (!comp)
6805 return ERROR_SUCCESS;
6806
6807 comp->Action = msi_get_component_action( package, comp );
6808 if (comp->Action != INSTALLSTATE_ABSENT)
6809 {
6810 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6811 return ERROR_SUCCESS;
6812 }
6813 name = MSI_RecordGetString( rec, 2 );
6814 value = MSI_RecordGetString( rec, 3 );
6815
6816 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6817
6818 r = env_parse_flags( &name, &value, &flags );
6819 if (r != ERROR_SUCCESS)
6820 return r;
6821
6822 if (!(flags & ENV_ACT_REMOVE))
6823 {
6824 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6825 return ERROR_SUCCESS;
6826 }
6827
6828 if (value && !deformat_string( package, value, &deformatted ))
6829 return ERROR_OUTOFMEMORY;
6830
6831 value = deformatted;
6832
6833 r = open_env_key( flags, &env );
6834 if (r != ERROR_SUCCESS)
6835 {
6836 r = ERROR_SUCCESS;
6837 goto done;
6838 }
6839
6840 if (flags & ENV_MOD_MACHINE)
6841 action |= 0x20000000;
6842
6843 TRACE("Removing %s\n", debugstr_w(name));
6844
6845 res = RegDeleteValueW( env, name );
6846 if (res != ERROR_SUCCESS)
6847 {
6848 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6849 r = ERROR_SUCCESS;
6850 }
6851
6852 done:
6853 uirow = MSI_CreateRecord( 3 );
6854 MSI_RecordSetStringW( uirow, 1, name );
6855 MSI_RecordSetStringW( uirow, 2, value );
6856 MSI_RecordSetInteger( uirow, 3, action );
6857 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6858 msiobj_release( &uirow->hdr );
6859
6860 if (env) RegCloseKey( env );
6861 msi_free( deformatted );
6862 return r;
6863 }
6864
6865 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6866 {
6867 static const WCHAR query[] = {
6868 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6869 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6870 MSIQUERY *view;
6871 UINT rc;
6872
6873 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6874 if (rc != ERROR_SUCCESS)
6875 return ERROR_SUCCESS;
6876
6877 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6878 msiobj_release( &view->hdr );
6879 return rc;
6880 }
6881
6882 UINT msi_validate_product_id( MSIPACKAGE *package )
6883 {
6884 LPWSTR key, template, id;
6885 UINT r = ERROR_SUCCESS;
6886
6887 id = msi_dup_property( package->db, szProductID );
6888 if (id)
6889 {
6890 msi_free( id );
6891 return ERROR_SUCCESS;
6892 }
6893 template = msi_dup_property( package->db, szPIDTemplate );
6894 key = msi_dup_property( package->db, szPIDKEY );
6895 if (key && template)
6896 {
6897 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6898 r = msi_set_property( package->db, szProductID, key );
6899 }
6900 msi_free( template );
6901 msi_free( key );
6902 return r;
6903 }
6904
6905 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6906 {
6907 return msi_validate_product_id( package );
6908 }
6909
6910 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6911 {
6912 TRACE("\n");
6913 package->need_reboot_at_end = 1;
6914 return ERROR_SUCCESS;
6915 }
6916
6917 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6918 {
6919 static const WCHAR szAvailableFreeReg[] =
6920 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6921 MSIRECORD *uirow;
6922 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6923
6924 TRACE("%p %d kilobytes\n", package, space);
6925
6926 uirow = MSI_CreateRecord( 1 );
6927 MSI_RecordSetInteger( uirow, 1, space );
6928 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6929 msiobj_release( &uirow->hdr );
6930
6931 return ERROR_SUCCESS;
6932 }
6933
6934 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6935 {
6936 TRACE("%p\n", package);
6937
6938 msi_set_property( package->db, szRollbackDisabled, szOne );
6939 return ERROR_SUCCESS;
6940 }
6941
6942 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6943 {
6944 FIXME("%p\n", package);
6945 return ERROR_SUCCESS;
6946 }
6947
6948 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6949 {
6950 static const WCHAR driver_query[] = {
6951 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6952 'O','D','B','C','D','r','i','v','e','r',0};
6953 static const WCHAR translator_query[] = {
6954 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6955 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6956 MSIQUERY *view;
6957 UINT r, count;
6958
6959 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6960 if (r == ERROR_SUCCESS)
6961 {
6962 count = 0;
6963 r = MSI_IterateRecords( view, &count, NULL, package );
6964 msiobj_release( &view->hdr );
6965 if (r != ERROR_SUCCESS)
6966 return r;
6967 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6968 }
6969 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6970 if (r == ERROR_SUCCESS)
6971 {
6972 count = 0;
6973 r = MSI_IterateRecords( view, &count, NULL, package );
6974 msiobj_release( &view->hdr );
6975 if (r != ERROR_SUCCESS)
6976 return r;
6977 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6978 }
6979 return ERROR_SUCCESS;
6980 }
6981
6982 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6983 {
6984 MSIPACKAGE *package = param;
6985 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6986 WCHAR *value;
6987
6988 if ((value = msi_dup_property( package->db, property )))
6989 {
6990 FIXME("remove %s\n", debugstr_w(value));
6991 msi_free( value );
6992 }
6993 return ERROR_SUCCESS;
6994 }
6995
6996 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6997 {
6998 static const WCHAR query[] = {
6999 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
7000 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
7001 MSIQUERY *view;
7002 UINT r;
7003
7004 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7005 if (r == ERROR_SUCCESS)
7006 {
7007 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7008 msiobj_release( &view->hdr );
7009 if (r != ERROR_SUCCESS)
7010 return r;
7011 }
7012 return ERROR_SUCCESS;
7013 }
7014
7015 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7016 {
7017 MSIPACKAGE *package = param;
7018 int attributes = MSI_RecordGetInteger( rec, 5 );
7019
7020 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7021 {
7022 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7023 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7024 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7025 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7026 HKEY hkey;
7027 UINT r;
7028
7029 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7030 {
7031 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7032 if (r != ERROR_SUCCESS)
7033 return ERROR_SUCCESS;
7034 }
7035 else
7036 {
7037 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7038 if (r != ERROR_SUCCESS)
7039 return ERROR_SUCCESS;
7040 }
7041 RegCloseKey( hkey );
7042
7043 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7044 debugstr_w(upgrade_code), debugstr_w(version_min),
7045 debugstr_w(version_max), debugstr_w(language));
7046 }
7047 return ERROR_SUCCESS;
7048 }
7049
7050 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7051 {
7052 static const WCHAR query[] = {
7053 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7054 'U','p','g','r','a','d','e',0};
7055 MSIQUERY *view;
7056 UINT r;
7057
7058 if (msi_get_property_int( package->db, szInstalled, 0 ))
7059 {
7060 TRACE("product is installed, skipping action\n");
7061 return ERROR_SUCCESS;
7062 }
7063 if (msi_get_property_int( package->db, szPreselected, 0 ))
7064 {
7065 TRACE("Preselected property is set, not migrating feature states\n");
7066 return ERROR_SUCCESS;
7067 }
7068 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7069 if (r == ERROR_SUCCESS)
7070 {
7071 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7072 msiobj_release( &view->hdr );
7073 if (r != ERROR_SUCCESS)
7074 return r;
7075 }
7076 return ERROR_SUCCESS;
7077 }
7078
7079 static void bind_image( const char *filename, const char *path )
7080 {
7081 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7082 {
7083 WARN("failed to bind image %u\n", GetLastError());
7084 }
7085 }
7086
7087 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7088 {
7089 UINT i;
7090 MSIFILE *file;
7091 MSIPACKAGE *package = param;
7092 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7093 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7094 char *filenameA, *pathA;
7095 WCHAR *pathW, **path_list;
7096
7097 if (!(file = msi_get_loaded_file( package, key )))
7098 {
7099 WARN("file %s not found\n", debugstr_w(key));
7100 return ERROR_SUCCESS;
7101 }
7102 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7103 path_list = msi_split_string( paths, ';' );
7104 if (!path_list) bind_image( filenameA, NULL );
7105 else
7106 {
7107 for (i = 0; path_list[i] && path_list[i][0]; i++)
7108 {
7109 deformat_string( package, path_list[i], &pathW );
7110 if ((pathA = strdupWtoA( pathW )))
7111 {
7112 bind_image( filenameA, pathA );
7113 msi_free( pathA );
7114 }
7115 msi_free( pathW );
7116 }
7117 }
7118 msi_free( path_list );
7119 msi_free( filenameA );
7120 return ERROR_SUCCESS;
7121 }
7122
7123 static UINT ACTION_BindImage( MSIPACKAGE *package )
7124 {
7125 static const WCHAR query[] = {
7126 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7127 'B','i','n','d','I','m','a','g','e',0};
7128 MSIQUERY *view;
7129 UINT r;
7130
7131 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7132 if (r == ERROR_SUCCESS)
7133 {
7134 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7135 msiobj_release( &view->hdr );
7136 if (r != ERROR_SUCCESS)
7137 return r;
7138 }
7139 return ERROR_SUCCESS;
7140 }
7141
7142 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7143 {
7144 static const WCHAR query[] = {
7145 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7146 MSIQUERY *view;
7147 DWORD count = 0;
7148 UINT r;
7149
7150 r = MSI_OpenQuery( package->db, &view, query, table );
7151 if (r == ERROR_SUCCESS)
7152 {
7153 r = MSI_IterateRecords(view, &count, NULL, package);
7154 msiobj_release(&view->hdr);
7155 if (r != ERROR_SUCCESS)
7156 return r;
7157 }
7158 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7159 return ERROR_SUCCESS;
7160 }
7161
7162 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7163 {
7164 static const WCHAR table[] = {
7165 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7166 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7167 }
7168
7169 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7170 {
7171 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7172 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7173 }
7174
7175 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7176 {
7177 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7178 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7179 }
7180
7181 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7182 {
7183 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7184 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7185 }
7186
7187 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7188 {
7189 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7190 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7191 }
7192
7193 static const struct
7194 {
7195 const WCHAR *action;
7196 UINT (*handler)(MSIPACKAGE *);
7197 const WCHAR *action_rollback;
7198 }
7199 StandardActions[] =
7200 {
7201 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7202 { szAppSearch, ACTION_AppSearch, NULL },
7203 { szBindImage, ACTION_BindImage, NULL },
7204 { szCCPSearch, ACTION_CCPSearch, NULL },
7205 { szCostFinalize, ACTION_CostFinalize, NULL },
7206 { szCostInitialize, ACTION_CostInitialize, NULL },
7207 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7208 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7209 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7210 { szDisableRollback, ACTION_DisableRollback, NULL },
7211 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7212 { szExecuteAction, ACTION_ExecuteAction, NULL },
7213 { szFileCost, ACTION_FileCost, NULL },
7214 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7215 { szForceReboot, ACTION_ForceReboot, NULL },
7216 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7217 { szInstallExecute, ACTION_InstallExecute, NULL },
7218 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7219 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7220 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7221 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7222 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7223 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7224 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7225 { szInstallValidate, ACTION_InstallValidate, NULL },
7226 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7227 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7228 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7229 { szMoveFiles, ACTION_MoveFiles, NULL },
7230 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7231 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7232 { szPatchFiles, ACTION_PatchFiles, NULL },
7233 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7234 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7235 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7236 { szPublishProduct, ACTION_PublishProduct, NULL },
7237 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7238 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7239 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7240 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7241 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7242 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7243 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7244 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7245 { szRegisterUser, ACTION_RegisterUser, NULL },
7246 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7247 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7248 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7249 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7250 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7251 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7252 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7253 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7254 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7255 { szResolveSource, ACTION_ResolveSource, NULL },
7256 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7257 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7258 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7259 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7260 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7261 { szStartServices, ACTION_StartServices, szStopServices },
7262 { szStopServices, ACTION_StopServices, szStartServices },
7263 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7264 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7265 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7266 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7267 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7268 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7269 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7270 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7271 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7272 { szValidateProductID, ACTION_ValidateProductID, NULL },
7273 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7274 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7275 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7276 { NULL, NULL, NULL }
7277 };
7278
7279 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7280 {
7281 BOOL ret = FALSE;
7282 UINT i;
7283
7284 i = 0;
7285 while (StandardActions[i].action != NULL)
7286 {
7287 if (!strcmpW( StandardActions[i].action, action ))
7288 {
7289 ui_actionstart( package, action );
7290 if (StandardActions[i].handler)
7291 {
7292 ui_actioninfo( package, action, TRUE, 0 );
7293 *rc = StandardActions[i].handler( package );
7294 ui_actioninfo( package, action, FALSE, *rc );
7295
7296 if (StandardActions[i].action_rollback && !package->need_rollback)
7297 {
7298 TRACE("scheduling rollback action\n");
7299 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7300 }
7301 }
7302 else
7303 {
7304 FIXME("unhandled standard action %s\n", debugstr_w(action));
7305 *rc = ERROR_SUCCESS;
7306 }
7307 ret = TRUE;
7308 break;
7309 }
7310 i++;
7311 }
7312 return ret;
7313 }
7314
7315 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7316 {
7317 UINT rc = ERROR_SUCCESS;
7318 BOOL handled;
7319
7320 TRACE("Performing action (%s)\n", debugstr_w(action));
7321
7322 handled = ACTION_HandleStandardAction(package, action, &rc);
7323
7324 if (!handled)
7325 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7326
7327 if (!handled)
7328 {
7329 WARN("unhandled msi action %s\n", debugstr_w(action));
7330 rc = ERROR_FUNCTION_NOT_CALLED;
7331 }
7332
7333 return rc;
7334 }
7335
7336 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7337 {
7338 UINT rc = ERROR_SUCCESS;
7339 BOOL handled = FALSE;
7340
7341 TRACE("Performing action (%s)\n", debugstr_w(action));
7342
7343 handled = ACTION_HandleStandardAction(package, action, &rc);
7344
7345 if (!handled)
7346 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7347
7348 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7349 handled = TRUE;
7350
7351 if (!handled)
7352 {
7353 WARN("unhandled msi action %s\n", debugstr_w(action));
7354 rc = ERROR_FUNCTION_NOT_CALLED;
7355 }
7356
7357 return rc;
7358 }
7359
7360 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7361 {
7362 UINT rc = ERROR_SUCCESS;
7363 MSIRECORD *row;
7364
7365 static const WCHAR query[] =
7366 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7367 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7368 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7369 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7370 static const WCHAR ui_query[] =
7371 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7372 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7373 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7374 ' ', '=',' ','%','i',0};
7375
7376 if (needs_ui_sequence(package))
7377 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7378 else
7379 row = MSI_QueryGetRecord(package->db, query, seq);
7380
7381 if (row)
7382 {
7383 LPCWSTR action, cond;
7384
7385 TRACE("Running the actions\n");
7386
7387 /* check conditions */
7388 cond = MSI_RecordGetString(row, 2);
7389
7390 /* this is a hack to skip errors in the condition code */
7391 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7392 {
7393 msiobj_release(&row->hdr);
7394 return ERROR_SUCCESS;
7395 }
7396
7397 action = MSI_RecordGetString(row, 1);
7398 if (!action)
7399 {
7400 ERR("failed to fetch action\n");
7401 msiobj_release(&row->hdr);
7402 return ERROR_FUNCTION_FAILED;
7403 }
7404
7405 if (needs_ui_sequence(package))
7406 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7407 else
7408 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7409
7410 msiobj_release(&row->hdr);
7411 }
7412
7413 return rc;
7414 }
7415
7416 /****************************************************
7417 * TOP level entry points
7418 *****************************************************/
7419
7420 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7421 LPCWSTR szCommandLine )
7422 {
7423 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7424 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7425 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7426 WCHAR *reinstall = NULL;
7427 BOOL ui_exists;
7428 UINT rc;
7429
7430 msi_set_property( package->db, szAction, szInstall );
7431
7432 package->script->InWhatSequence = SEQUENCE_INSTALL;
7433
7434 if (szPackagePath)
7435 {
7436 LPWSTR p, dir;
7437 LPCWSTR file;
7438
7439 dir = strdupW(szPackagePath);
7440 p = strrchrW(dir, '\\');
7441 if (p)
7442 {
7443 *(++p) = 0;
7444 file = szPackagePath + (p - dir);
7445 }
7446 else
7447 {
7448 msi_free(dir);
7449 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7450 GetCurrentDirectoryW(MAX_PATH, dir);
7451 lstrcatW(dir, szBackSlash);
7452 file = szPackagePath;
7453 }
7454
7455 msi_free( package->PackagePath );
7456 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7457 if (!package->PackagePath)
7458 {
7459 msi_free(dir);
7460 return ERROR_OUTOFMEMORY;
7461 }
7462
7463 lstrcpyW(package->PackagePath, dir);
7464 lstrcatW(package->PackagePath, file);
7465 msi_free(dir);
7466
7467 msi_set_sourcedir_props(package, FALSE);
7468 }
7469
7470 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7471 if (rc != ERROR_SUCCESS)
7472 return rc;
7473
7474 msi_apply_transforms( package );
7475 msi_apply_patches( package );
7476
7477 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7478 {
7479 TRACE("setting reinstall property\n");
7480 msi_set_property( package->db, szReinstall, szAll );
7481 }
7482
7483 /* properties may have been added by a transform */
7484 msi_clone_properties( package );
7485
7486 msi_parse_command_line( package, szCommandLine, FALSE );
7487 msi_adjust_privilege_properties( package );
7488 msi_set_context( package );
7489
7490 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7491 {
7492 TRACE("disabling rollback\n");
7493 msi_set_property( package->db, szRollbackDisabled, szOne );
7494 }
7495
7496 if (needs_ui_sequence( package))
7497 {
7498 package->script->InWhatSequence |= SEQUENCE_UI;
7499 rc = ACTION_ProcessUISequence(package);
7500 ui_exists = ui_sequence_exists(package);
7501 if (rc == ERROR_SUCCESS || !ui_exists)
7502 {
7503 package->script->InWhatSequence |= SEQUENCE_EXEC;
7504 rc = ACTION_ProcessExecSequence(package, ui_exists);
7505 }
7506 }
7507 else
7508 rc = ACTION_ProcessExecSequence(package, FALSE);
7509
7510 package->script->CurrentlyScripting = FALSE;
7511
7512 /* process the ending type action */
7513 if (rc == ERROR_SUCCESS)
7514 ACTION_PerformActionSequence(package, -1);
7515 else if (rc == ERROR_INSTALL_USEREXIT)
7516 ACTION_PerformActionSequence(package, -2);
7517 else if (rc == ERROR_INSTALL_SUSPEND)
7518 ACTION_PerformActionSequence(package, -4);
7519 else /* failed */
7520 {
7521 ACTION_PerformActionSequence(package, -3);
7522 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7523 {
7524 package->need_rollback = TRUE;
7525 }
7526 }
7527
7528 /* finish up running custom actions */
7529 ACTION_FinishCustomActions(package);
7530
7531 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
7532 {
7533 WARN("installation failed, running rollback script\n");
7534 execute_script( package, SCRIPT_ROLLBACK );
7535 }
7536 msi_free( reinstall );
7537
7538 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7539 return ERROR_SUCCESS_REBOOT_REQUIRED;
7540
7541 return rc;
7542 }
7543
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.