msi: Resolve the target path for the ODBC driver file if necessary.
[wine/multimedia.git] / dlls / msi / action.c
blobc1d3b496393d6cf1578c8bd1328666670246658e
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "winreg.h"
29 #include "winsvc.h"
30 #include "odbcinst.h"
31 #include "wine/debug.h"
32 #include "msidefs.h"
33 #include "msipriv.h"
34 #include "winuser.h"
35 #include "shlobj.h"
36 #include "objbase.h"
37 #include "mscoree.h"
38 #include "shlwapi.h"
39 #include "imagehlp.h"
40 #include "wine/unicode.h"
41 #include "winver.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48 static const WCHAR szCreateFolders[] =
49 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
50 static const WCHAR szCostFinalize[] =
51 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
52 static const WCHAR szWriteRegistryValues[] =
53 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
54 static const WCHAR szFileCost[] =
55 {'F','i','l','e','C','o','s','t',0};
56 static const WCHAR szInstallInitialize[] =
57 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
58 static const WCHAR szInstallValidate[] =
59 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
60 static const WCHAR szLaunchConditions[] =
61 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
62 static const WCHAR szProcessComponents[] =
63 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
64 static const WCHAR szRegisterTypeLibraries[] =
65 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
66 static const WCHAR szCreateShortcuts[] =
67 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
68 static const WCHAR szPublishProduct[] =
69 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
70 static const WCHAR szWriteIniValues[] =
71 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
72 static const WCHAR szSelfRegModules[] =
73 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
74 static const WCHAR szPublishFeatures[] =
75 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
76 static const WCHAR szRegisterProduct[] =
77 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
78 static const WCHAR szInstallExecute[] =
79 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
80 static const WCHAR szInstallExecuteAgain[] =
81 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
82 static const WCHAR szInstallFinalize[] =
83 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
84 static const WCHAR szForceReboot[] =
85 {'F','o','r','c','e','R','e','b','o','o','t',0};
86 static const WCHAR szResolveSource[] =
87 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
88 static const WCHAR szAllocateRegistrySpace[] =
89 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
90 static const WCHAR szBindImage[] =
91 {'B','i','n','d','I','m','a','g','e',0};
92 static const WCHAR szDeleteServices[] =
93 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
94 static const WCHAR szDisableRollback[] =
95 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
96 static const WCHAR szExecuteAction[] =
97 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
98 static const WCHAR szInstallAdminPackage[] =
99 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
100 static const WCHAR szInstallSFPCatalogFile[] =
101 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
102 static const WCHAR szIsolateComponents[] =
103 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
104 static const WCHAR szMigrateFeatureStates[] =
105 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
106 static const WCHAR szMsiUnpublishAssemblies[] =
107 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
108 static const WCHAR szInstallODBC[] =
109 {'I','n','s','t','a','l','l','O','D','B','C',0};
110 static const WCHAR szInstallServices[] =
111 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
112 static const WCHAR szPublishComponents[] =
113 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
114 static const WCHAR szRegisterComPlus[] =
115 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
116 static const WCHAR szRegisterUser[] =
117 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
118 static const WCHAR szRemoveEnvironmentStrings[] =
119 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
120 static const WCHAR szRemoveExistingProducts[] =
121 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
122 static const WCHAR szRemoveFolders[] =
123 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
124 static const WCHAR szRemoveIniValues[] =
125 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
126 static const WCHAR szRemoveODBC[] =
127 {'R','e','m','o','v','e','O','D','B','C',0};
128 static const WCHAR szRemoveRegistryValues[] =
129 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
130 static const WCHAR szRemoveShortcuts[] =
131 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
132 static const WCHAR szRMCCPSearch[] =
133 {'R','M','C','C','P','S','e','a','r','c','h',0};
134 static const WCHAR szScheduleReboot[] =
135 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
136 static const WCHAR szSelfUnregModules[] =
137 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
138 static const WCHAR szSetODBCFolders[] =
139 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
140 static const WCHAR szStartServices[] =
141 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
142 static const WCHAR szStopServices[] =
143 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
144 static const WCHAR szUnpublishComponents[] =
145 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
146 static const WCHAR szUnpublishFeatures[] =
147 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
148 static const WCHAR szUnregisterComPlus[] =
149 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
150 static const WCHAR szUnregisterTypeLibraries[] =
151 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
152 static const WCHAR szValidateProductID[] =
153 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
154 static const WCHAR szWriteEnvironmentStrings[] =
155 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
157 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
159 static const WCHAR Query_t[] =
160 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
161 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
162 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
163 ' ','\'','%','s','\'',0};
164 MSIRECORD * row;
166 row = MSI_QueryGetRecord( package->db, Query_t, action );
167 if (!row)
168 return;
169 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
170 msiobj_release(&row->hdr);
173 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
174 UINT rc)
176 MSIRECORD * row;
177 static const WCHAR template_s[]=
178 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
179 '%','s', '.',0};
180 static const WCHAR template_e[]=
181 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
182 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
183 '%','i','.',0};
184 static const WCHAR format[] =
185 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
186 WCHAR message[1024];
187 WCHAR timet[0x100];
189 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
190 if (start)
191 sprintfW(message,template_s,timet,action);
192 else
193 sprintfW(message,template_e,timet,action,rc);
195 row = MSI_CreateRecord(1);
196 MSI_RecordSetStringW(row,1,message);
198 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
199 msiobj_release(&row->hdr);
202 enum parse_state
204 state_whitespace,
205 state_token,
206 state_quote
209 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
211 enum parse_state state = state_quote;
212 const WCHAR *p;
213 WCHAR *out = value;
214 int ignore, in_quotes = 0, count = 0, len = 0;
216 for (p = str; *p; p++)
218 ignore = 0;
219 switch (state)
221 case state_whitespace:
222 switch (*p)
224 case ' ':
225 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;
240 break;
242 case state_token:
243 switch (*p)
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;
262 break;
264 case state_quote:
265 switch (*p)
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;
284 break;
286 default: break;
288 if (!ignore) *out++ = *p;
291 done:
292 if (!len) *value = 0;
293 else *out = 0;
295 *quotes = count;
296 return p - str;
299 static void remove_quotes( WCHAR *str )
301 WCHAR *p = str;
302 int len = strlenW( str );
304 while ((p = strchrW( p, '"' )))
306 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
307 p++;
311 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
312 BOOL preserve_case )
314 LPCWSTR ptr, ptr2;
315 int num_quotes;
316 DWORD len;
317 WCHAR *prop, *val;
318 UINT r;
320 if (!szCommandLine)
321 return ERROR_SUCCESS;
323 ptr = szCommandLine;
324 while (*ptr)
326 while (*ptr == ' ') ptr++;
327 if (!*ptr) break;
329 ptr2 = strchrW( ptr, '=' );
330 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
332 len = ptr2 - ptr;
333 if (!len) return ERROR_INVALID_COMMAND_LINE;
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 );
340 ptr2++;
341 while (*ptr2 == ' ') ptr2++;
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)
348 WARN("unbalanced quotes\n");
349 msi_free( val );
350 msi_free( prop );
351 return ERROR_INVALID_COMMAND_LINE;
353 remove_quotes( val );
354 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
356 r = msi_set_property( package->db, prop, val );
357 if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
358 msi_reset_folders( package, TRUE );
360 msi_free( val );
361 msi_free( prop );
363 ptr = ptr2 + len;
366 return ERROR_SUCCESS;
369 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
371 LPCWSTR pc;
372 LPWSTR p, *ret = NULL;
373 UINT count = 0;
375 if (!str)
376 return ret;
378 /* count the number of substrings */
379 for ( pc = str, count = 0; pc; count++ )
381 pc = strchrW( pc, sep );
382 if (pc)
383 pc++;
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;
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++ )
397 p = strchrW( p, sep );
398 if (p)
399 *p++ = 0;
402 return ret;
405 static BOOL ui_sequence_exists( MSIPACKAGE *package )
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','`',' ','>',' ','0',' ',
411 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
412 MSIQUERY *view;
413 UINT rc;
415 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
416 if (rc == ERROR_SUCCESS)
418 msiobj_release(&view->hdr);
419 return TRUE;
421 return FALSE;
424 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
426 LPWSTR source, check;
428 if (msi_get_property_int( package->db, szInstalled, 0 ))
430 HKEY hkey;
432 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
433 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
434 RegCloseKey( hkey );
436 else
438 LPWSTR p, db;
439 DWORD len;
441 db = msi_dup_property( package->db, szOriginalDatabase );
442 if (!db)
443 return ERROR_OUTOFMEMORY;
445 p = strrchrW( db, '\\' );
446 if (!p)
448 p = strrchrW( db, '/' );
449 if (!p)
451 msi_free(db);
452 return ERROR_SUCCESS;
456 len = p - db + 2;
457 source = msi_alloc( len * sizeof(WCHAR) );
458 lstrcpynW( source, db, len );
459 msi_free( db );
462 check = msi_dup_property( package->db, szSourceDir );
463 if (!check || replace)
465 UINT r = msi_set_property( package->db, szSourceDir, source );
466 if (r == ERROR_SUCCESS)
467 msi_reset_folders( package, TRUE );
469 msi_free( check );
471 check = msi_dup_property( package->db, szSOURCEDIR );
472 if (!check || replace)
473 msi_set_property( package->db, szSOURCEDIR, source );
475 msi_free( check );
476 msi_free( source );
478 return ERROR_SUCCESS;
481 static BOOL needs_ui_sequence(MSIPACKAGE *package)
483 return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
486 UINT msi_set_context(MSIPACKAGE *package)
488 UINT r = msi_locate_product( package->ProductCode, &package->Context );
489 if (r != ERROR_SUCCESS)
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;
497 return ERROR_SUCCESS;
500 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
502 UINT rc;
503 LPCWSTR cond, action;
504 MSIPACKAGE *package = param;
506 action = MSI_RecordGetString(row,1);
507 if (!action)
509 ERR("Error is retrieving action name\n");
510 return ERROR_FUNCTION_FAILED;
513 /* check conditions */
514 cond = MSI_RecordGetString(row,2);
516 /* this is a hack to skip errors in the condition code */
517 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
519 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
520 return ERROR_SUCCESS;
523 if (needs_ui_sequence(package))
524 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
525 else
526 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
528 msi_dialog_check_messages( NULL );
530 if (package->CurrentInstallState != ERROR_SUCCESS)
531 rc = package->CurrentInstallState;
533 if (rc == ERROR_FUNCTION_NOT_CALLED)
534 rc = ERROR_SUCCESS;
536 if (rc != ERROR_SUCCESS)
537 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
539 if (package->need_reboot_now)
541 TRACE("action %s asked for immediate reboot, suspending installation\n",
542 debugstr_w(action));
543 rc = ACTION_ForceReboot( package );
545 return rc;
548 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
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 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
554 '`','S','e','q','u','e','n','c','e','`',0};
555 MSIQUERY *view;
556 UINT r;
558 TRACE("%p %s\n", package, debugstr_w(table));
560 r = MSI_OpenQuery( package->db, &view, query, table );
561 if (r == ERROR_SUCCESS)
563 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
564 msiobj_release(&view->hdr);
566 return r;
569 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
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;
587 if (package->script->ExecuteSequenceRun)
589 TRACE("Execute Sequence already Run\n");
590 return ERROR_SUCCESS;
593 package->script->ExecuteSequenceRun = TRUE;
595 /* get the sequence number */
596 if (UIran)
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);
603 rc = MSI_OpenQuery(package->db, &view, query, seq);
604 if (rc == ERROR_SUCCESS)
606 TRACE("Running the actions\n");
608 msi_set_property(package->db, szSourceDir, NULL);
609 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
610 msiobj_release(&view->hdr);
612 return rc;
615 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
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','`',' ','>',' ','0',' ',
621 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
622 MSIQUERY *view;
623 UINT rc;
625 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
626 if (rc == ERROR_SUCCESS)
628 TRACE("Running the actions\n");
629 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
630 msiobj_release(&view->hdr);
632 return rc;
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 )
641 BOOL ret=FALSE;
642 UINT arc;
644 arc = ACTION_CustomAction(package, action, script, force);
646 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
648 *rc = arc;
649 ret = TRUE;
651 return ret;
654 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
656 MSICOMPONENT *comp;
658 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
660 if (!strcmpW( Component, comp->Component )) return comp;
662 return NULL;
665 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
667 MSIFEATURE *feature;
669 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
671 if (!strcmpW( Feature, feature->Feature )) return feature;
673 return NULL;
676 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
678 MSIFILE *file;
680 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
682 if (!strcmpW( key, file->File )) return file;
684 return NULL;
687 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
689 MSIFILEPATCH *patch;
691 /* FIXME: There might be more than one patch */
692 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
694 if (!strcmpW( key, patch->File->File )) return patch;
696 return NULL;
699 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
701 MSIFOLDER *folder;
703 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
705 if (!strcmpW( dir, folder->Directory )) return folder;
707 return NULL;
711 * Recursively create all directories in the path.
712 * shamelessly stolen from setupapi/queue.c
714 BOOL msi_create_full_path( const WCHAR *path )
716 BOOL ret = TRUE;
717 WCHAR *new_path;
718 int len;
720 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
721 strcpyW( new_path, path );
723 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
724 new_path[len - 1] = 0;
726 while (!CreateDirectoryW( new_path, NULL ))
728 WCHAR *slash;
729 DWORD last_error = GetLastError();
730 if (last_error == ERROR_ALREADY_EXISTS) break;
731 if (last_error != ERROR_PATH_NOT_FOUND)
733 ret = FALSE;
734 break;
736 if (!(slash = strrchrW( new_path, '\\' )))
738 ret = FALSE;
739 break;
741 len = slash - new_path;
742 new_path[len] = 0;
743 if (!msi_create_full_path( new_path ))
745 ret = FALSE;
746 break;
748 new_path[len] = '\\';
750 msi_free( new_path );
751 return ret;
754 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
756 MSIRECORD *row;
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 );
766 msi_dialog_check_messages( NULL );
769 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
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;
779 if (!package->LastAction || strcmpW( package->LastAction, action ))
781 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
783 if (MSI_RecordIsNull( row, 3 ))
785 msiobj_release( &row->hdr );
786 return;
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 );
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 );
804 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
806 if (!comp->Enabled)
808 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
809 return INSTALLSTATE_UNKNOWN;
811 if (package->need_rollback) return comp->Installed;
812 return comp->ActionRequest;
815 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
817 if (package->need_rollback) return feature->Installed;
818 return feature->ActionRequest;
821 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
823 MSIPACKAGE *package = param;
824 LPCWSTR dir, component, full_path;
825 MSIRECORD *uirow;
826 MSIFOLDER *folder;
827 MSICOMPONENT *comp;
829 component = MSI_RecordGetString(row, 2);
830 if (!component)
831 return ERROR_SUCCESS;
833 comp = msi_get_loaded_component(package, component);
834 if (!comp)
835 return ERROR_SUCCESS;
837 comp->Action = msi_get_component_action( package, comp );
838 if (comp->Action != INSTALLSTATE_LOCAL)
840 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
841 return ERROR_SUCCESS;
844 dir = MSI_RecordGetString(row,1);
845 if (!dir)
847 ERR("Unable to get folder id\n");
848 return ERROR_SUCCESS;
851 uirow = MSI_CreateRecord(1);
852 MSI_RecordSetStringW(uirow, 1, dir);
853 msi_ui_actiondata(package, szCreateFolders, uirow);
854 msiobj_release(&uirow->hdr);
856 full_path = msi_get_target_folder( package, dir );
857 if (!full_path)
859 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
860 return ERROR_SUCCESS;
862 TRACE("folder is %s\n", debugstr_w(full_path));
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;
870 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
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;
878 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
879 if (rc != ERROR_SUCCESS)
880 return ERROR_SUCCESS;
882 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
883 msiobj_release(&view->hdr);
884 return rc;
887 static void remove_persistent_folder( MSIFOLDER *folder )
889 FolderList *fl;
891 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
893 remove_persistent_folder( fl->folder );
895 if (folder->persistent && folder->State != FOLDER_STATE_REMOVED)
897 if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED;
901 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
903 MSIPACKAGE *package = param;
904 LPCWSTR dir, component, full_path;
905 MSIRECORD *uirow;
906 MSIFOLDER *folder;
907 MSICOMPONENT *comp;
909 component = MSI_RecordGetString(row, 2);
910 if (!component)
911 return ERROR_SUCCESS;
913 comp = msi_get_loaded_component(package, component);
914 if (!comp)
915 return ERROR_SUCCESS;
917 comp->Action = msi_get_component_action( package, comp );
918 if (comp->Action != INSTALLSTATE_ABSENT)
920 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
921 return ERROR_SUCCESS;
924 dir = MSI_RecordGetString( row, 1 );
925 if (!dir)
927 ERR("Unable to get folder id\n");
928 return ERROR_SUCCESS;
931 full_path = msi_get_target_folder( package, dir );
932 if (!full_path)
934 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
935 return ERROR_SUCCESS;
937 TRACE("folder is %s\n", debugstr_w(full_path));
939 uirow = MSI_CreateRecord( 1 );
940 MSI_RecordSetStringW( uirow, 1, dir );
941 msi_ui_actiondata( package, szRemoveFolders, uirow );
942 msiobj_release( &uirow->hdr );
944 folder = msi_get_loaded_folder( package, dir );
945 remove_persistent_folder( folder );
946 return ERROR_SUCCESS;
949 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
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;
957 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
958 if (rc != ERROR_SUCCESS)
959 return ERROR_SUCCESS;
961 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
962 msiobj_release( &view->hdr );
963 return rc;
966 static UINT load_component( MSIRECORD *row, LPVOID param )
968 MSIPACKAGE *package = param;
969 MSICOMPONENT *comp;
971 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
972 if (!comp)
973 return ERROR_FUNCTION_FAILED;
975 list_add_tail( &package->components, &comp->entry );
977 /* fill in the data */
978 comp->Component = msi_dup_record_field( row, 1 );
980 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
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 );
988 comp->Installed = INSTALLSTATE_UNKNOWN;
989 comp->Action = INSTALLSTATE_UNKNOWN;
990 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
992 comp->assembly = msi_load_assembly( package, comp );
993 return ERROR_SUCCESS;
996 UINT msi_load_all_components( MSIPACKAGE *package )
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;
1004 if (!list_empty(&package->components))
1005 return ERROR_SUCCESS;
1007 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1008 if (r != ERROR_SUCCESS)
1009 return r;
1011 if (!msi_init_assembly_caches( package ))
1013 ERR("can't initialize assembly caches\n");
1014 msiobj_release( &view->hdr );
1015 return ERROR_FUNCTION_FAILED;
1018 r = MSI_IterateRecords(view, NULL, load_component, package);
1019 msiobj_release(&view->hdr);
1020 msi_destroy_assembly_caches( package );
1021 return r;
1024 typedef struct {
1025 MSIPACKAGE *package;
1026 MSIFEATURE *feature;
1027 } _ilfs;
1029 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1031 ComponentList *cl;
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 );
1039 return ERROR_SUCCESS;
1042 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1044 FeatureList *fl;
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 );
1052 return ERROR_SUCCESS;
1055 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1057 _ilfs* ilfs = param;
1058 LPCWSTR component;
1059 MSICOMPONENT *comp;
1061 component = MSI_RecordGetString(row,1);
1063 /* check to see if the component is already loaded */
1064 comp = msi_get_loaded_component( ilfs->package, component );
1065 if (!comp)
1067 WARN("ignoring unknown component %s\n", debugstr_w(component));
1068 return ERROR_SUCCESS;
1070 add_feature_component( ilfs->feature, comp );
1071 comp->Enabled = TRUE;
1073 return ERROR_SUCCESS;
1076 static UINT load_feature(MSIRECORD * row, LPVOID param)
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;
1089 /* fill in the data */
1091 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1092 if (!feature)
1093 return ERROR_NOT_ENOUGH_MEMORY;
1095 list_init( &feature->Children );
1096 list_init( &feature->Components );
1098 feature->Feature = msi_dup_record_field( row, 1 );
1100 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
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 );
1106 if (!MSI_RecordIsNull(row,5))
1107 feature->Display = MSI_RecordGetInteger(row,5);
1109 feature->Level= MSI_RecordGetInteger(row,6);
1110 feature->Directory = msi_dup_record_field( row, 7 );
1111 feature->Attributes = MSI_RecordGetInteger(row,8);
1113 feature->Installed = INSTALLSTATE_UNKNOWN;
1114 feature->Action = INSTALLSTATE_UNKNOWN;
1115 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1117 list_add_tail( &package->features, &feature->entry );
1119 /* load feature components */
1121 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
1122 if (rc != ERROR_SUCCESS)
1123 return ERROR_SUCCESS;
1125 ilfs.package = package;
1126 ilfs.feature = feature;
1128 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1129 msiobj_release(&view->hdr);
1130 return rc;
1133 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1135 MSIPACKAGE *package = param;
1136 MSIFEATURE *parent, *child;
1138 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1139 if (!child)
1140 return ERROR_FUNCTION_FAILED;
1142 if (!child->Feature_Parent)
1143 return ERROR_SUCCESS;
1145 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1146 if (!parent)
1147 return ERROR_FUNCTION_FAILED;
1149 add_feature_child( parent, child );
1150 return ERROR_SUCCESS;
1153 UINT msi_load_all_features( MSIPACKAGE *package )
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;
1162 if (!list_empty(&package->features))
1163 return ERROR_SUCCESS;
1165 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1166 if (r != ERROR_SUCCESS)
1167 return r;
1169 r = MSI_IterateRecords( view, NULL, load_feature, package );
1170 if (r != ERROR_SUCCESS)
1172 msiobj_release( &view->hdr );
1173 return r;
1175 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1176 msiobj_release( &view->hdr );
1177 return r;
1180 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1182 if (!p)
1183 return p;
1184 p = strchrW(p, ch);
1185 if (!p)
1186 return p;
1187 *p = 0;
1188 return p+1;
1191 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
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;
1201 TRACE("%s\n", debugstr_w(file->File));
1203 r = MSI_OpenQuery(package->db, &view, query, file->File);
1204 if (r != ERROR_SUCCESS)
1205 goto done;
1207 r = MSI_ViewExecute(view, NULL);
1208 if (r != ERROR_SUCCESS)
1209 goto done;
1211 r = MSI_ViewFetch(view, &row);
1212 if (r != ERROR_SUCCESS)
1213 goto done;
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);
1221 done:
1222 if (view) msiobj_release(&view->hdr);
1223 if (row) msiobj_release(&row->hdr);
1224 return r;
1227 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
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};
1235 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1236 if (!row)
1238 WARN("query failed\n");
1239 return ERROR_FUNCTION_FAILED;
1242 file->disk_id = MSI_RecordGetInteger( row, 1 );
1243 msiobj_release( &row->hdr );
1244 return ERROR_SUCCESS;
1247 static UINT load_file(MSIRECORD *row, LPVOID param)
1249 MSIPACKAGE* package = param;
1250 LPCWSTR component;
1251 MSIFILE *file;
1253 /* fill in the data */
1255 file = msi_alloc_zero( sizeof (MSIFILE) );
1256 if (!file)
1257 return ERROR_NOT_ENOUGH_MEMORY;
1259 file->File = msi_dup_record_field( row, 1 );
1261 component = MSI_RecordGetString( row, 2 );
1262 file->Component = msi_get_loaded_component( package, component );
1264 if (!file->Component)
1266 WARN("Component not found: %s\n", debugstr_w(component));
1267 msi_free(file->File);
1268 msi_free(file);
1269 return ERROR_SUCCESS;
1272 file->FileName = msi_dup_record_field( row, 3 );
1273 msi_reduce_to_long_filename( file->FileName );
1275 file->ShortName = msi_dup_record_field( row, 3 );
1276 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
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 );
1284 file->state = msifs_invalid;
1286 /* if the compressed bits are not set in the file attributes,
1287 * then read the information from the package word count property
1289 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1291 file->IsCompressed = FALSE;
1293 else if (file->Attributes &
1294 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1296 file->IsCompressed = TRUE;
1298 else if (file->Attributes & msidbFileAttributesNoncompressed)
1300 file->IsCompressed = FALSE;
1302 else
1304 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1307 load_file_hash(package, file);
1308 load_file_disk_id(package, file);
1310 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1312 list_add_tail( &package->files, &file->entry );
1314 return ERROR_SUCCESS;
1317 static UINT load_all_files(MSIPACKAGE *package)
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;
1326 if (!list_empty(&package->files))
1327 return ERROR_SUCCESS;
1329 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1330 if (rc != ERROR_SUCCESS)
1331 return ERROR_SUCCESS;
1333 rc = MSI_IterateRecords(view, NULL, load_file, package);
1334 msiobj_release(&view->hdr);
1335 return rc;
1338 static UINT load_media( MSIRECORD *row, LPVOID param )
1340 MSIPACKAGE *package = param;
1341 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1342 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
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;
1350 static UINT load_all_media( MSIPACKAGE *package )
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;
1359 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1360 if (r != ERROR_SUCCESS)
1361 return ERROR_SUCCESS;
1363 r = MSI_IterateRecords( view, NULL, load_media, package );
1364 msiobj_release( &view->hdr );
1365 return r;
1368 static UINT load_patch(MSIRECORD *row, LPVOID param)
1370 MSIPACKAGE *package = param;
1371 MSIFILEPATCH *patch;
1372 LPWSTR file_key;
1374 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1375 if (!patch)
1376 return ERROR_NOT_ENOUGH_MEMORY;
1378 file_key = msi_dup_record_field( row, 1 );
1379 patch->File = msi_get_loaded_file( package, file_key );
1380 msi_free(file_key);
1382 if( !patch->File )
1384 ERR("Failed to find target for patch in File table\n");
1385 msi_free(patch);
1386 return ERROR_FUNCTION_FAILED;
1389 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1391 /* FIXME: The database should be properly transformed */
1392 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1394 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1395 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1396 patch->IsApplied = FALSE;
1398 /* FIXME:
1399 * Header field - for patch validation.
1400 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1403 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1405 list_add_tail( &package->filepatches, &patch->entry );
1407 return ERROR_SUCCESS;
1410 static UINT load_all_patches(MSIPACKAGE *package)
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;
1419 if (!list_empty(&package->filepatches))
1420 return ERROR_SUCCESS;
1422 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
1423 if (rc != ERROR_SUCCESS)
1424 return ERROR_SUCCESS;
1426 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1427 msiobj_release(&view->hdr);
1428 return rc;
1431 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
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;
1439 folder->persistent = FALSE;
1440 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1442 if (!MSI_ViewExecute( view, NULL ))
1444 MSIRECORD *rec;
1445 if (!MSI_ViewFetch( view, &rec ))
1447 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1448 folder->persistent = TRUE;
1449 msiobj_release( &rec->hdr );
1452 msiobj_release( &view->hdr );
1454 return ERROR_SUCCESS;
1457 static UINT load_folder( MSIRECORD *row, LPVOID param )
1459 MSIPACKAGE *package = param;
1460 static WCHAR szEmpty[] = { 0 };
1461 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1462 MSIFOLDER *folder;
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);
1470 TRACE("%s\n", debugstr_w(folder->Directory));
1472 /* split src and target dir */
1473 tgt_short = p;
1474 src_short = folder_split_path( p, ':' );
1476 /* split the long and short paths */
1477 tgt_long = folder_split_path( tgt_short, '|' );
1478 src_long = folder_split_path( src_short, '|' );
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;
1486 if (!tgt_long)
1487 tgt_long = tgt_short;
1489 if (!src_short) {
1490 src_short = tgt_short;
1491 src_long = tgt_long;
1494 if (!src_long)
1495 src_long = src_short;
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);
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 ));
1507 load_folder_persistence( package, folder );
1509 list_add_tail( &package->folders, &folder->entry );
1510 return ERROR_SUCCESS;
1513 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1515 FolderList *fl;
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;
1523 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1525 MSIPACKAGE *package = param;
1526 MSIFOLDER *parent, *child;
1528 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1529 return ERROR_FUNCTION_FAILED;
1531 if (!child->Parent) return ERROR_SUCCESS;
1533 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1534 return ERROR_FUNCTION_FAILED;
1536 return add_folder_child( parent, child );
1539 static UINT load_all_folders( MSIPACKAGE *package )
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;
1547 if (!list_empty(&package->folders))
1548 return ERROR_SUCCESS;
1550 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1551 if (r != ERROR_SUCCESS)
1552 return r;
1554 r = MSI_IterateRecords( view, NULL, load_folder, package );
1555 if (r != ERROR_SUCCESS)
1557 msiobj_release( &view->hdr );
1558 return r;
1560 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1561 msiobj_release( &view->hdr );
1562 return r;
1565 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1567 msi_set_property( package->db, szCostingComplete, szZero );
1568 msi_set_property( package->db, szRootDrive, szCRoot );
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 );
1577 return ERROR_SUCCESS;
1580 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
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 );
1588 static UINT execute_script( MSIPACKAGE *package, UINT script )
1590 UINT i, rc = ERROR_SUCCESS;
1592 TRACE("executing script %u\n", script);
1594 if (!package->script)
1596 ERR("no script!\n");
1597 return ERROR_FUNCTION_FAILED;
1599 if (script == SCRIPT_ROLLBACK)
1601 for (i = package->script->ActionCount[script]; i > 0; i--)
1603 rc = execute_script_action( package, script, i - 1 );
1604 if (rc != ERROR_SUCCESS) break;
1607 else
1609 for (i = 0; i < package->script->ActionCount[script]; i++)
1611 rc = execute_script_action( package, script, i );
1612 if (rc != ERROR_SUCCESS) break;
1615 msi_free_action_script(package, script);
1616 return rc;
1619 static UINT ACTION_FileCost(MSIPACKAGE *package)
1621 return ERROR_SUCCESS;
1624 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1626 MSICOMPONENT *comp;
1627 UINT r;
1629 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1631 if (!comp->ComponentId) continue;
1633 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1634 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1635 &comp->Installed );
1636 if (r == ERROR_SUCCESS) continue;
1638 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1639 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1640 &comp->Installed );
1641 if (r == ERROR_SUCCESS) continue;
1643 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1644 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1645 &comp->Installed );
1646 if (r == ERROR_SUCCESS) continue;
1648 comp->Installed = INSTALLSTATE_ABSENT;
1652 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1654 MSIFEATURE *feature;
1656 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1658 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1660 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1661 feature->Installed = INSTALLSTATE_ABSENT;
1662 else
1663 feature->Installed = state;
1667 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1669 return (feature->Level > 0 && feature->Level <= level);
1672 static BOOL process_state_property(MSIPACKAGE* package, int level,
1673 LPCWSTR property, INSTALLSTATE state)
1675 LPWSTR override;
1676 MSIFEATURE *feature;
1678 override = msi_dup_property( package->db, property );
1679 if (!override)
1680 return FALSE;
1682 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1684 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1685 continue;
1687 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1689 if (!strcmpiW( override, szAll ))
1691 if (feature->Installed != state)
1693 feature->Action = state;
1694 feature->ActionRequest = state;
1697 else
1699 LPWSTR ptr = override;
1700 LPWSTR ptr2 = strchrW(override,',');
1702 while (ptr)
1704 int len = ptr2 - ptr;
1706 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1707 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1709 if (feature->Installed != state)
1711 feature->Action = state;
1712 feature->ActionRequest = state;
1714 break;
1716 if (ptr2)
1718 ptr=ptr2+1;
1719 ptr2 = strchrW(ptr,',');
1721 else
1722 break;
1726 msi_free(override);
1727 return TRUE;
1730 static BOOL process_overrides( MSIPACKAGE *package, int level )
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;
1740 /* all these activation/deactivation things happen in order and things
1741 * later on the list override things earlier on the list.
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
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 );
1762 if (ret)
1763 msi_set_property( package->db, szPreselected, szOne );
1765 return ret;
1768 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1770 int level;
1771 MSICOMPONENT* component;
1772 MSIFEATURE *feature;
1774 TRACE("Checking Install Level\n");
1776 level = msi_get_property_int(package->db, szInstallLevel, 1);
1778 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1780 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1782 if (!is_feature_selected( feature, level )) continue;
1784 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1786 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1788 feature->Action = INSTALLSTATE_SOURCE;
1789 feature->ActionRequest = INSTALLSTATE_SOURCE;
1791 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1793 feature->Action = INSTALLSTATE_ADVERTISED;
1794 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1796 else
1798 feature->Action = INSTALLSTATE_LOCAL;
1799 feature->ActionRequest = INSTALLSTATE_LOCAL;
1803 /* disable child features of unselected parent or follow parent */
1804 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1806 FeatureList *fl;
1808 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1810 if (!is_feature_selected( feature, level ))
1812 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1813 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1815 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
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;
1826 else /* preselected */
1828 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1830 if (!is_feature_selected( feature, level )) continue;
1832 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1834 if (feature->Installed == INSTALLSTATE_ABSENT)
1836 feature->Action = INSTALLSTATE_UNKNOWN;
1837 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1839 else
1841 feature->Action = feature->Installed;
1842 feature->ActionRequest = feature->Installed;
1846 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1848 FeatureList *fl;
1850 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1852 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent &&
1853 (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise)))
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;
1865 /* now we want to set component state based based on feature state */
1866 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1868 ComponentList *cl;
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);
1874 if (!is_feature_selected( feature, level )) continue;
1876 /* features with components that have compressed files are made local */
1877 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1879 if (cl->component->ForceLocalState &&
1880 feature->ActionRequest == INSTALLSTATE_SOURCE)
1882 feature->Action = INSTALLSTATE_LOCAL;
1883 feature->ActionRequest = INSTALLSTATE_LOCAL;
1884 break;
1888 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1890 component = cl->component;
1892 switch (feature->ActionRequest)
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;
1920 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1922 /* check if it's local or source */
1923 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1924 (component->hasLocalFeature || component->hasSourceFeature))
1926 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1927 !component->ForceLocalState)
1929 component->Action = INSTALLSTATE_SOURCE;
1930 component->ActionRequest = INSTALLSTATE_SOURCE;
1932 else
1934 component->Action = INSTALLSTATE_LOCAL;
1935 component->ActionRequest = INSTALLSTATE_LOCAL;
1937 continue;
1940 /* if any feature is local, the component must be local too */
1941 if (component->hasLocalFeature)
1943 component->Action = INSTALLSTATE_LOCAL;
1944 component->ActionRequest = INSTALLSTATE_LOCAL;
1945 continue;
1947 if (component->hasSourceFeature)
1949 component->Action = INSTALLSTATE_SOURCE;
1950 component->ActionRequest = INSTALLSTATE_SOURCE;
1951 continue;
1953 if (component->hasAdvertiseFeature)
1955 component->Action = INSTALLSTATE_ADVERTISED;
1956 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1957 continue;
1959 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1960 if (component->anyAbsent &&
1961 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1963 component->Action = INSTALLSTATE_ABSENT;
1964 component->ActionRequest = INSTALLSTATE_ABSENT;
1968 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1970 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1972 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1973 component->Action = INSTALLSTATE_LOCAL;
1974 component->ActionRequest = INSTALLSTATE_LOCAL;
1977 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1978 component->Installed == INSTALLSTATE_SOURCE &&
1979 component->hasSourceFeature)
1981 component->Action = INSTALLSTATE_UNKNOWN;
1982 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1985 TRACE("component %s (installed %d request %d action %d)\n",
1986 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1989 return ERROR_SUCCESS;
1992 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1994 MSIPACKAGE *package = param;
1995 LPCWSTR name;
1996 MSIFEATURE *feature;
1998 name = MSI_RecordGetString( row, 1 );
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
2005 LPCWSTR Condition;
2006 Condition = MSI_RecordGetString(row,3);
2008 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2010 int level = MSI_RecordGetInteger(row,2);
2011 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2012 feature->Level = level;
2015 return ERROR_SUCCESS;
2018 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2020 static const WCHAR name[] = {'\\',0};
2021 VS_FIXEDFILEINFO *ptr, *ret;
2022 LPVOID version;
2023 DWORD versize, handle;
2024 UINT sz;
2026 versize = GetFileVersionInfoSizeW( filename, &handle );
2027 if (!versize)
2028 return NULL;
2030 version = msi_alloc( versize );
2031 if (!version)
2032 return NULL;
2034 GetFileVersionInfoW( filename, 0, versize, version );
2036 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2038 msi_free( version );
2039 return NULL;
2042 ret = msi_alloc( sz );
2043 memcpy( ret, ptr, sz );
2045 msi_free( version );
2046 return ret;
2049 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2051 DWORD ms, ls;
2053 msi_parse_version_string( version, &ms, &ls );
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;
2062 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2064 DWORD ms1, ms2;
2066 msi_parse_version_string( ver1, &ms1, NULL );
2067 msi_parse_version_string( ver2, &ms2, NULL );
2069 if (ms1 > ms2) return 1;
2070 else if (ms1 < ms2) return -1;
2071 return 0;
2074 DWORD msi_get_disk_file_size( LPCWSTR filename )
2076 HANDLE file;
2077 DWORD size;
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;
2083 size = GetFileSize( file, NULL );
2084 TRACE("size is %u\n", size);
2085 CloseHandle( file );
2086 return size;
2089 BOOL msi_file_hash_matches( MSIFILE *file )
2091 UINT r;
2092 MSIFILEHASHINFO hash;
2094 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2095 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2096 if (r != ERROR_SUCCESS)
2097 return FALSE;
2099 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2102 static WCHAR *get_temp_dir( void )
2104 static UINT id;
2105 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2107 GetTempPathW( MAX_PATH, tmp );
2108 for (;;)
2110 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2111 if (CreateDirectoryW( dir, NULL )) break;
2113 return strdupW( dir );
2117 * msi_build_directory_name()
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.
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.
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.
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 \
2135 WCHAR *msi_build_directory_name( DWORD count, ... )
2137 DWORD sz = 1, i;
2138 WCHAR *dir;
2139 va_list va;
2141 va_start( va, count );
2142 for (i = 0; i < count; i++)
2144 const WCHAR *str = va_arg( va, const WCHAR * );
2145 if (str) sz += strlenW( str ) + 1;
2147 va_end( va );
2149 dir = msi_alloc( sz * sizeof(WCHAR) );
2150 dir[0] = 0;
2152 va_start( va, count );
2153 for (i = 0; i < count; i++)
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 );
2160 va_end( va );
2161 return dir;
2164 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2166 MSIASSEMBLY *assembly = file->Component->assembly;
2168 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2170 msi_free( file->TargetPath );
2171 if (assembly && !assembly->application)
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 );
2177 else
2179 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2180 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2183 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2186 static UINT calculate_file_cost( MSIPACKAGE *package )
2188 VS_FIXEDFILEINFO *file_version;
2189 WCHAR *font_version;
2190 MSIFILE *file;
2192 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2194 MSICOMPONENT *comp = file->Component;
2195 DWORD file_size;
2197 if (!comp->Enabled) continue;
2199 if (file->IsCompressed)
2200 comp->ForceLocalState = TRUE;
2202 set_target_path( package, file );
2204 if ((comp->assembly && !comp->assembly->installed) ||
2205 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2207 comp->Cost += file->FileSize;
2208 continue;
2210 file_size = msi_get_disk_file_size( file->TargetPath );
2212 if (file->Version)
2214 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2216 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2218 comp->Cost += file->FileSize - file_size;
2220 msi_free( file_version );
2221 continue;
2223 else if ((font_version = msi_font_version_from_file( file->TargetPath )))
2225 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2227 comp->Cost += file->FileSize - file_size;
2229 msi_free( font_version );
2230 continue;
2233 if (file_size != file->FileSize)
2235 comp->Cost += file->FileSize - file_size;
2238 return ERROR_SUCCESS;
2241 WCHAR *msi_normalize_path( const WCHAR *in )
2243 const WCHAR *p = in;
2244 WCHAR *q, *ret;
2245 int n, len = strlenW( in ) + 2;
2247 if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
2249 len = 0;
2250 while (1)
2252 /* copy until the end of the string or a space */
2253 while (*p != ' ' && (*q = *p))
2255 p++, len++;
2256 /* reduce many backslashes to one */
2257 if (*p != '\\' || *q != '\\')
2258 q++;
2261 /* quit at the end of the string */
2262 if (!*p)
2263 break;
2265 /* count the number of spaces */
2266 n = 0;
2267 while (p[n] == ' ')
2268 n++;
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--;
2276 while (q - ret > 0 && q[-1] == ' ') q--;
2277 if (q - ret > 0 && q[-1] != '\\')
2279 q[0] = '\\';
2280 q[1] = 0;
2282 return ret;
2285 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2287 FolderList *fl;
2288 MSIFOLDER *folder, *parent, *child;
2289 WCHAR *path, *normalized_path;
2291 TRACE("resolving %s\n", debugstr_w(name));
2293 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2295 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2297 if (!load_prop || !(path = msi_dup_property( package->db, szTargetDir )))
2299 path = msi_dup_property( package->db, szRootDrive );
2302 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2304 if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
2306 parent = msi_get_loaded_folder( package, folder->Parent );
2307 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2309 else
2310 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2312 normalized_path = msi_normalize_path( path );
2313 msi_free( path );
2314 if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
2316 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2317 msi_free( normalized_path );
2318 return;
2320 msi_set_property( package->db, folder->Directory, normalized_path );
2321 msi_free( folder->ResolvedTarget );
2322 folder->ResolvedTarget = normalized_path;
2324 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2326 child = fl->folder;
2327 msi_resolve_target_folder( package, child->Directory, load_prop );
2329 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2332 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
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;
2344 TRACE("Building directory properties\n");
2345 msi_resolve_target_folder( package, szTargetDir, TRUE );
2347 TRACE("Evaluating component conditions\n");
2348 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2350 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2352 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2353 comp->Enabled = FALSE;
2355 else
2356 comp->Enabled = TRUE;
2359 /* read components states from the registry */
2360 ACTION_GetComponentInstallStates(package);
2361 ACTION_GetFeatureInstallStates(package);
2363 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2365 TRACE("Evaluating feature conditions\n");
2367 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2368 if (rc == ERROR_SUCCESS)
2370 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2371 msiobj_release( &view->hdr );
2372 if (rc != ERROR_SUCCESS)
2373 return rc;
2377 TRACE("Calculating file cost\n");
2378 calculate_file_cost( package );
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);
2387 /* FIXME: check volume disk space */
2388 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2390 return MSI_SetFeatureStates(package);
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)
2398 LPSTR data = NULL;
2400 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2402 if (value[1]=='x')
2404 LPWSTR ptr;
2405 CHAR byte[5];
2406 LPWSTR deformated = NULL;
2407 int count;
2409 deformat_string(package, &value[2], &deformated);
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;
2419 data = msi_alloc(*size);
2421 byte[0] = '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)
2428 byte[2]= '0';
2429 byte[3]= *ptr;
2430 ptr++;
2431 data[count] = (BYTE)strtol(byte,NULL,0);
2432 count ++;
2433 TRACE("Uneven byte count\n");
2435 while (*ptr)
2437 byte[2]= *ptr;
2438 ptr++;
2439 byte[3]= *ptr;
2440 ptr++;
2441 data[count] = (BYTE)strtol(byte,NULL,0);
2442 count ++;
2444 msi_free(deformated);
2446 TRACE("Data %i bytes(%i)\n",*size,count);
2448 else
2450 LPWSTR deformated;
2451 LPWSTR p;
2452 DWORD d = 0;
2453 deformat_string(package, &value[1], &deformated);
2455 *type=REG_DWORD;
2456 *size = sizeof(DWORD);
2457 data = msi_alloc(*size);
2458 p = deformated;
2459 if (*p == '-')
2460 p++;
2461 while (*p)
2463 if ( (*p < '0') || (*p > '9') )
2464 break;
2465 d *= 10;
2466 d += (*p - '0');
2467 p++;
2469 if (deformated[0] == '-')
2470 d = -d;
2471 *(LPDWORD)data = d;
2472 TRACE("DWORD %i\n",*(LPDWORD)data);
2474 msi_free(deformated);
2477 else
2479 static const WCHAR szMulti[] = {'[','~',']',0};
2480 LPCWSTR ptr;
2481 *type=REG_SZ;
2483 if (value[0]=='#')
2485 if (value[1]=='%')
2487 ptr = &value[2];
2488 *type=REG_EXPAND_SZ;
2490 else
2491 ptr = &value[1];
2493 else
2494 ptr=value;
2496 if (strstrW(value, szMulti))
2497 *type = REG_MULTI_SZ;
2499 /* remove initial delimiter */
2500 if (!strncmpW(value, szMulti, 3))
2501 ptr = value + 3;
2503 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2505 /* add double NULL terminator */
2506 if (*type == REG_MULTI_SZ)
2508 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2509 data = msi_realloc_zero(data, *size);
2512 return data;
2515 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2517 const WCHAR *ret;
2519 switch (root)
2521 case -1:
2522 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2524 *root_key = HKEY_LOCAL_MACHINE;
2525 ret = szHLM;
2527 else
2529 *root_key = HKEY_CURRENT_USER;
2530 ret = szHCU;
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;
2554 return ret;
2557 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2559 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2560 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2562 if (is_64bit && package->platform == PLATFORM_INTEL &&
2563 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2565 UINT size;
2566 WCHAR *path_32node;
2568 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2569 if (!(path_32node = msi_alloc( size ))) return NULL;
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;
2578 return strdupW( path );
2581 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
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;
2595 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2597 component = MSI_RecordGetString(row, 6);
2598 comp = msi_get_loaded_component(package,component);
2599 if (!comp)
2600 return ERROR_SUCCESS;
2602 comp->Action = msi_get_component_action( package, comp );
2603 if (comp->Action != INSTALLSTATE_LOCAL)
2605 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2606 return ERROR_SUCCESS;
2609 name = MSI_RecordGetString(row, 4);
2610 if( MSI_RecordIsNull(row,5) && name )
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;
2621 root = MSI_RecordGetInteger(row,2);
2622 key = MSI_RecordGetString(row, 3);
2624 szRoot = get_root_key( package, root, &root_key );
2625 if (!szRoot)
2626 return ERROR_SUCCESS;
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);
2634 keypath = get_keypath( package, root_key, deformated );
2635 msi_free( deformated );
2636 if (RegCreateKeyW( root_key, keypath, &hkey ))
2638 ERR("Could not create key %s\n", debugstr_w(keypath));
2639 msi_free(uikey);
2640 msi_free(keypath);
2641 return ERROR_SUCCESS;
2644 value = MSI_RecordGetString(row,5);
2645 if (value)
2646 value_data = parse_value(package, value, &type, &size);
2647 else
2649 value_data = (LPSTR)strdupW(szEmpty);
2650 size = sizeof(szEmpty);
2651 type = REG_SZ;
2654 deformat_string(package, name, &deformated);
2656 if (!check_first)
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);
2662 else
2664 DWORD sz = 0;
2665 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2666 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2668 TRACE("value %s of %s checked already exists\n",
2669 debugstr_w(deformated), debugstr_w(uikey));
2671 else
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);
2679 RegCloseKey(hkey);
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 );
2689 msi_free(value_data);
2690 msi_free(deformated);
2691 msi_free(uikey);
2692 msi_free(keypath);
2694 return ERROR_SUCCESS;
2697 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
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;
2705 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2706 if (rc != ERROR_SUCCESS)
2707 return ERROR_SUCCESS;
2709 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2710 msiobj_release(&view->hdr);
2711 return rc;
2714 static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *value )
2716 LONG res;
2717 HKEY hkey;
2718 DWORD num_subkeys, num_values;
2720 if (!(res = RegOpenKeyW( root, keypath, &hkey )))
2722 if ((res = RegDeleteValueW( hkey, value )))
2724 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
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)
2731 TRACE("removing empty key %s\n", debugstr_w(keypath));
2732 RegDeleteKeyW( root, keypath );
2734 return;
2736 TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
2739 static void delete_reg_key( HKEY root, const WCHAR *keypath )
2741 LONG res = RegDeleteTreeW( root, keypath );
2742 if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res);
2745 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
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;
2757 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2759 component = MSI_RecordGetString( row, 6 );
2760 comp = msi_get_loaded_component( package, component );
2761 if (!comp)
2762 return ERROR_SUCCESS;
2764 comp->Action = msi_get_component_action( package, comp );
2765 if (comp->Action != INSTALLSTATE_ABSENT)
2767 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2768 return ERROR_SUCCESS;
2771 name = MSI_RecordGetString( row, 4 );
2772 if (MSI_RecordIsNull( row, 5 ) && name )
2774 if (name[0] == '+' && !name[1])
2775 return ERROR_SUCCESS;
2776 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2778 delete_key = TRUE;
2779 name = NULL;
2783 root = MSI_RecordGetInteger( row, 2 );
2784 key_str = MSI_RecordGetString( row, 3 );
2786 root_key_str = get_root_key( package, root, &hkey_root );
2787 if (!root_key_str)
2788 return ERROR_SUCCESS;
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 );
2796 deformat_string( package, name, &deformated_name );
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 );
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 );
2810 msi_free( ui_key_str );
2811 msi_free( deformated_name );
2812 return ERROR_SUCCESS;
2815 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
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;
2827 component = MSI_RecordGetString( row, 5 );
2828 comp = msi_get_loaded_component( package, component );
2829 if (!comp)
2830 return ERROR_SUCCESS;
2832 comp->Action = msi_get_component_action( package, comp );
2833 if (comp->Action != INSTALLSTATE_LOCAL)
2835 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2836 return ERROR_SUCCESS;
2839 if ((name = MSI_RecordGetString( row, 4 )))
2841 if (name[0] == '-' && !name[1])
2843 delete_key = TRUE;
2844 name = NULL;
2848 root = MSI_RecordGetInteger( row, 2 );
2849 key_str = MSI_RecordGetString( row, 3 );
2851 root_key_str = get_root_key( package, root, &hkey_root );
2852 if (!root_key_str)
2853 return ERROR_SUCCESS;
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 );
2861 deformat_string( package, name, &deformated_name );
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 );
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 );
2875 msi_free( ui_key_str );
2876 msi_free( deformated_name );
2877 return ERROR_SUCCESS;
2880 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
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;
2891 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2892 if (rc == ERROR_SUCCESS)
2894 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2895 msiobj_release( &view->hdr );
2896 if (rc != ERROR_SUCCESS)
2897 return rc;
2899 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2900 if (rc == ERROR_SUCCESS)
2902 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2903 msiobj_release( &view->hdr );
2904 if (rc != ERROR_SUCCESS)
2905 return rc;
2907 return ERROR_SUCCESS;
2910 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2912 package->script->CurrentlyScripting = TRUE;
2914 return ERROR_SUCCESS;
2918 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
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;
2930 TRACE("InstallValidate\n");
2932 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2933 if (rc == ERROR_SUCCESS)
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;
2941 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2942 total += COMPONENT_PROGRESS_VALUE;
2944 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2945 total += file->FileSize;
2947 msi_ui_progress( package, 0, total, 0, 0 );
2949 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2951 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2952 debugstr_w(feature->Feature), feature->Installed,
2953 feature->ActionRequest, feature->Action);
2955 return ERROR_SUCCESS;
2958 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2960 MSIPACKAGE* package = param;
2961 LPCWSTR cond = NULL;
2962 LPCWSTR message = NULL;
2963 UINT r;
2965 static const WCHAR title[]=
2966 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2968 cond = MSI_RecordGetString(row,1);
2970 r = MSI_EvaluateConditionW(package,cond);
2971 if (r == MSICONDITION_FALSE)
2973 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
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);
2982 return ERROR_INSTALL_FAILURE;
2985 return ERROR_SUCCESS;
2988 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
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;
2996 TRACE("Checking launch conditions\n");
2998 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2999 if (rc != ERROR_SUCCESS)
3000 return ERROR_SUCCESS;
3002 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3003 msiobj_release(&view->hdr);
3004 return rc;
3007 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3010 if (!cmp->KeyPath)
3011 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3013 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
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[] = {'%','0','2','i',':','\\','%','s','\\',0};
3020 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3021 MSIRECORD *row;
3022 UINT root, len;
3023 LPWSTR deformated, buffer, deformated_name;
3024 LPCWSTR key, name;
3026 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3027 if (!row)
3028 return NULL;
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);
3036 len = strlenW(deformated) + 6;
3037 if (deformated_name)
3038 len+=strlenW(deformated_name);
3040 buffer = msi_alloc( len *sizeof(WCHAR));
3042 if (deformated_name)
3043 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3044 else
3045 sprintfW(buffer,fmt,root,deformated);
3047 msi_free(deformated);
3048 msi_free(deformated_name);
3049 msiobj_release(&row->hdr);
3051 return buffer;
3053 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3055 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3056 return NULL;
3058 else
3060 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3062 if (file)
3063 return strdupW( file->TargetPath );
3065 return NULL;
3068 static HKEY openSharedDLLsKey(void)
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};
3078 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3079 return hkey;
3082 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3084 HKEY hkey;
3085 DWORD count=0;
3086 DWORD type;
3087 DWORD sz = sizeof(count);
3088 DWORD rc;
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;
3098 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3100 HKEY hkey;
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;
3111 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3113 MSIFEATURE *feature;
3114 INT count = 0;
3115 BOOL write = FALSE;
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
3125 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3126 write = (count > 0);
3128 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3129 write = TRUE;
3132 /* increment counts */
3133 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3135 ComponentList *cl;
3137 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3138 continue;
3140 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3142 if ( cl->component == comp )
3143 count++;
3147 /* decrement counts */
3148 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3150 ComponentList *cl;
3152 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3153 continue;
3155 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3157 if ( cl->component == comp )
3158 count--;
3162 /* ref count all the files in the component */
3163 if (write)
3165 MSIFILE *file;
3167 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3169 if (file->Component == comp)
3170 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3174 /* add a count for permanent */
3175 if (comp->Attributes & msidbComponentAttributesPermanent)
3176 count ++;
3178 comp->RefCount = count;
3180 if (write)
3181 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3184 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3186 if (comp->assembly)
3188 const WCHAR prefixW[] = {'<','\\',0};
3189 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3190 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3192 if (keypath)
3194 strcpyW( keypath, prefixW );
3195 strcatW( keypath, comp->assembly->display_name );
3197 return keypath;
3199 return resolve_keypath( package, comp );
3202 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3204 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3205 UINT rc;
3206 MSICOMPONENT *comp;
3207 HKEY hkey;
3209 TRACE("\n");
3211 squash_guid(package->ProductCode,squished_pc);
3212 msi_set_sourcedir_props(package, FALSE);
3214 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3216 MSIRECORD *uirow;
3217 INSTALLSTATE action;
3219 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3220 if (!comp->ComponentId)
3221 continue;
3223 squash_guid( comp->ComponentId, squished_cc );
3224 msi_free( comp->FullKeypath );
3225 comp->FullKeypath = build_full_keypath( package, comp );
3227 ACTION_RefCountComponent( package, comp );
3229 if (package->need_rollback) action = comp->Installed;
3230 else action = comp->ActionRequest;
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);
3236 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
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);
3243 if (rc != ERROR_SUCCESS)
3244 continue;
3246 if (comp->Attributes & msidbComponentAttributesPermanent)
3248 static const WCHAR szPermKey[] =
3249 { '0','0','0','0','0','0','0','0','0','0','0','0',
3250 '0','0','0','0','0','0','0','0','0','0','0','0',
3251 '0','0','0','0','0','0','0','0',0 };
3253 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3255 if (action == INSTALLSTATE_LOCAL)
3256 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3257 else
3259 MSIFILE *file;
3260 MSIRECORD *row;
3261 LPWSTR ptr, ptr2;
3262 WCHAR source[MAX_PATH];
3263 WCHAR base[MAX_PATH];
3264 LPWSTR sourcepath;
3266 static const WCHAR fmt[] = {'%','0','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};
3274 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3275 continue;
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);
3282 lstrcpyW(base, package->PackagePath);
3283 ptr = strrchrW(base, '\\');
3284 *(ptr + 1) = '\0';
3286 sourcepath = msi_resolve_file_source(package, file);
3287 ptr = sourcepath + lstrlenW(base);
3288 lstrcpyW(ptr2, ptr);
3289 msi_free(sourcepath);
3291 msi_reg_set_val_str(hkey, squished_pc, source);
3293 RegCloseKey(hkey);
3295 else if (action == INSTALLSTATE_ABSENT)
3297 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3298 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3299 else
3300 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
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 );
3311 return ERROR_SUCCESS;
3314 typedef struct {
3315 CLSID clsid;
3316 LPWSTR source;
3318 LPWSTR path;
3319 ITypeLib *ptLib;
3320 } typelib_struct;
3322 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3323 LPWSTR lpszName, LONG_PTR lParam)
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;
3331 if (!IS_INTRESOURCE(lpszName))
3333 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3334 return TRUE;
3337 sz = strlenW(tl_struct->source)+4;
3338 sz *= sizeof(WCHAR);
3340 if ((INT_PTR)lpszName == 1)
3341 tl_struct->path = strdupW(tl_struct->source);
3342 else
3344 tl_struct->path = msi_alloc(sz);
3345 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3348 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3349 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3350 if (FAILED(res))
3352 msi_free(tl_struct->path);
3353 tl_struct->path = NULL;
3355 return TRUE;
3358 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3359 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3361 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3362 return FALSE;
3365 msi_free(tl_struct->path);
3366 tl_struct->path = NULL;
3368 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3369 ITypeLib_Release(tl_struct->ptLib);
3371 return TRUE;
3374 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
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;
3385 component = MSI_RecordGetString(row,3);
3386 comp = msi_get_loaded_component(package,component);
3387 if (!comp)
3388 return ERROR_SUCCESS;
3390 comp->Action = msi_get_component_action( package, comp );
3391 if (comp->Action != INSTALLSTATE_LOCAL)
3393 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3394 return ERROR_SUCCESS;
3397 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3399 TRACE("component has no key path\n");
3400 return ERROR_SUCCESS;
3402 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3404 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3405 if (module)
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;
3413 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3414 (LONG_PTR)&tl_struct);
3416 if (tl_struct.path)
3418 LPCWSTR helpid, help_path = NULL;
3419 HRESULT res;
3421 helpid = MSI_RecordGetString(row,6);
3423 if (helpid) help_path = msi_get_target_folder( package, helpid );
3424 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
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));
3431 ITypeLib_Release(tl_struct.ptLib);
3432 msi_free(tl_struct.path);
3434 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3436 FreeLibrary(module);
3437 msi_free(tl_struct.source);
3439 else
3441 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3442 if (FAILED(hr))
3444 ERR("Failed to load type library: %08x\n", hr);
3445 return ERROR_INSTALL_FAILURE;
3448 ITypeLib_Release(tlib);
3451 return ERROR_SUCCESS;
3454 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
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;
3462 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3463 if (rc != ERROR_SUCCESS)
3464 return ERROR_SUCCESS;
3466 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3467 msiobj_release(&view->hdr);
3468 return rc;
3471 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
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;
3482 component = MSI_RecordGetString( row, 3 );
3483 comp = msi_get_loaded_component( package, component );
3484 if (!comp)
3485 return ERROR_SUCCESS;
3487 comp->Action = msi_get_component_action( package, comp );
3488 if (comp->Action != INSTALLSTATE_ABSENT)
3490 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3491 return ERROR_SUCCESS;
3493 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3495 guid = MSI_RecordGetString( row, 1 );
3496 CLSIDFromString( guid, &libid );
3497 version = MSI_RecordGetInteger( row, 4 );
3498 language = MSI_RecordGetInteger( row, 2 );
3500 #ifdef _WIN64
3501 syskind = SYS_WIN64;
3502 #else
3503 syskind = SYS_WIN32;
3504 #endif
3506 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3507 if (FAILED(hr))
3509 WARN("Failed to unregister typelib: %08x\n", hr);
3512 return ERROR_SUCCESS;
3515 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
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;
3523 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3524 if (rc != ERROR_SUCCESS)
3525 return ERROR_SUCCESS;
3527 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3528 msiobj_release( &view->hdr );
3529 return rc;
3532 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3534 static const WCHAR szlnk[] = {'.','l','n','k',0};
3535 LPCWSTR directory, extension, link_folder;
3536 LPWSTR link_file, filename;
3538 directory = MSI_RecordGetString( row, 2 );
3539 link_folder = msi_get_target_folder( package, directory );
3540 if (!link_folder)
3542 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3543 return NULL;
3545 /* may be needed because of a bug somewhere else */
3546 msi_create_full_path( link_folder );
3548 filename = msi_dup_record_field( row, 3 );
3549 msi_reduce_to_long_filename( filename );
3551 extension = strchrW( filename, '.' );
3552 if (!extension || strcmpiW( extension, szlnk ))
3554 int len = strlenW( filename );
3555 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3556 memcpy( filename + len, szlnk, sizeof(szlnk) );
3558 link_file = msi_build_directory_name( 2, link_folder, filename );
3559 msi_free( filename );
3561 return link_file;
3564 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
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;
3570 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3571 folder = msi_dup_property( package->db, szWindowsFolder );
3572 else
3574 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3575 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3576 msi_free( appdata );
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;
3586 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
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;
3596 component = MSI_RecordGetString(row, 4);
3597 comp = msi_get_loaded_component(package, component);
3598 if (!comp)
3599 return ERROR_SUCCESS;
3601 comp->Action = msi_get_component_action( package, comp );
3602 if (comp->Action != INSTALLSTATE_LOCAL)
3604 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3605 return ERROR_SUCCESS;
3607 msi_ui_actiondata( package, szCreateShortcuts, row );
3609 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3610 &IID_IShellLinkW, (LPVOID *) &sl );
3612 if (FAILED( res ))
3614 ERR("CLSID_ShellLink not available\n");
3615 goto err;
3618 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3619 if (FAILED( res ))
3621 ERR("QueryInterface(IID_IPersistFile) failed\n");
3622 goto err;
3625 target = MSI_RecordGetString(row, 5);
3626 if (strchrW(target, '['))
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 );
3633 else
3635 FIXME("poorly handled shortcut format, advertised shortcut\n");
3636 IShellLinkW_SetPath(sl,comp->FullKeypath);
3639 if (!MSI_RecordIsNull(row,6))
3641 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3642 deformat_string(package, arguments, &deformated);
3643 IShellLinkW_SetArguments(sl,deformated);
3644 msi_free(deformated);
3647 if (!MSI_RecordIsNull(row,7))
3649 LPCWSTR description = MSI_RecordGetString(row, 7);
3650 IShellLinkW_SetDescription(sl, description);
3653 if (!MSI_RecordIsNull(row,8))
3654 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3656 if (!MSI_RecordIsNull(row,9))
3658 INT index;
3659 LPCWSTR icon = MSI_RecordGetString(row, 9);
3661 path = msi_build_icon_path(package, icon);
3662 index = MSI_RecordGetInteger(row,10);
3664 /* no value means 0 */
3665 if (index == MSI_NULL_INTEGER)
3666 index = 0;
3668 IShellLinkW_SetIconLocation(sl, path, index);
3669 msi_free(path);
3672 if (!MSI_RecordIsNull(row,11))
3673 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3675 if (!MSI_RecordIsNull(row,12))
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 );
3681 link_file = get_link_file(package, row);
3683 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3684 IPersistFile_Save(pf, link_file, FALSE);
3685 msi_free(link_file);
3687 err:
3688 if (pf)
3689 IPersistFile_Release( pf );
3690 if (sl)
3691 IShellLinkW_Release( sl );
3693 return ERROR_SUCCESS;
3696 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
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;
3705 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3706 if (rc != ERROR_SUCCESS)
3707 return ERROR_SUCCESS;
3709 res = CoInitialize( NULL );
3711 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3712 msiobj_release(&view->hdr);
3714 if (SUCCEEDED(res)) CoUninitialize();
3715 return rc;
3718 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3720 MSIPACKAGE *package = param;
3721 LPWSTR link_file;
3722 LPCWSTR component;
3723 MSICOMPONENT *comp;
3725 component = MSI_RecordGetString( row, 4 );
3726 comp = msi_get_loaded_component( package, component );
3727 if (!comp)
3728 return ERROR_SUCCESS;
3730 comp->Action = msi_get_component_action( package, comp );
3731 if (comp->Action != INSTALLSTATE_ABSENT)
3733 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3734 return ERROR_SUCCESS;
3736 msi_ui_actiondata( package, szRemoveShortcuts, row );
3738 link_file = get_link_file( package, row );
3740 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3741 if (!DeleteFileW( link_file ))
3743 WARN("Failed to remove shortcut file %u\n", GetLastError());
3745 msi_free( link_file );
3747 return ERROR_SUCCESS;
3750 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
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;
3758 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3759 if (rc != ERROR_SUCCESS)
3760 return ERROR_SUCCESS;
3762 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3763 msiobj_release( &view->hdr );
3764 return rc;
3767 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3769 MSIPACKAGE* package = param;
3770 HANDLE the_file;
3771 LPWSTR FilePath;
3772 LPCWSTR FileName;
3773 CHAR buffer[1024];
3774 DWORD sz;
3775 UINT rc;
3777 FileName = MSI_RecordGetString(row,1);
3778 if (!FileName)
3780 ERR("Unable to get FileName\n");
3781 return ERROR_SUCCESS;
3784 FilePath = msi_build_icon_path(package, FileName);
3786 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3788 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3789 FILE_ATTRIBUTE_NORMAL, NULL);
3791 if (the_file == INVALID_HANDLE_VALUE)
3793 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3794 msi_free(FilePath);
3795 return ERROR_SUCCESS;
3800 DWORD write;
3801 sz = 1024;
3802 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3803 if (rc != ERROR_SUCCESS)
3805 ERR("Failed to get stream\n");
3806 CloseHandle(the_file);
3807 DeleteFileW(FilePath);
3808 break;
3810 WriteFile(the_file,buffer,sz,&write,NULL);
3811 } while (sz == 1024);
3813 msi_free(FilePath);
3814 CloseHandle(the_file);
3816 return ERROR_SUCCESS;
3819 static UINT msi_publish_icons(MSIPACKAGE *package)
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;
3827 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3828 if (r == ERROR_SUCCESS)
3830 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3831 msiobj_release(&view->hdr);
3832 if (r != ERROR_SUCCESS)
3833 return r;
3835 return ERROR_SUCCESS;
3838 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3840 UINT r;
3841 HKEY source;
3842 LPWSTR buffer;
3843 MSIMEDIADISK *disk;
3844 MSISOURCELISTINFO *info;
3846 r = RegCreateKeyW(hkey, szSourceList, &source);
3847 if (r != ERROR_SUCCESS)
3848 return r;
3850 RegCloseKey(source);
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;
3859 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3860 package->Context, MSICODE_PRODUCT,
3861 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3862 if (r != ERROR_SUCCESS)
3863 return r;
3865 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3866 package->Context, MSICODE_PRODUCT,
3867 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3868 if (r != ERROR_SUCCESS)
3869 return r;
3871 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
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);
3882 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3884 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3885 disk->context, disk->options,
3886 disk->disk_id, disk->volume_label, disk->disk_prompt);
3889 return ERROR_SUCCESS;
3892 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
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;
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};
3913 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3914 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3915 msi_free(buffer);
3917 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3918 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3920 /* FIXME */
3921 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3923 buffer = msi_dup_property(package->db, szARPProductIcon);
3924 if (buffer)
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);
3932 buffer = msi_dup_property(package->db, szProductVersion);
3933 if (buffer)
3935 DWORD verdword = msi_version_str_to_dword(buffer);
3936 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3937 msi_free(buffer);
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);
3945 hdb = alloc_msihandle(&package->db->hdr);
3946 if (!hdb)
3947 return ERROR_NOT_ENOUGH_MEMORY;
3949 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3950 MsiCloseHandle(hdb);
3951 if (r != ERROR_SUCCESS)
3952 goto done;
3954 size = MAX_PATH;
3955 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3956 NULL, guids, &size);
3957 if (r != ERROR_SUCCESS)
3958 goto done;
3960 ptr = strchrW(guids, ';');
3961 if (ptr) *ptr = 0;
3962 squash_guid(guids, packcode);
3963 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3965 done:
3966 MsiCloseHandle(suminfo);
3967 return ERROR_SUCCESS;
3970 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3972 UINT r;
3973 HKEY hkey;
3974 LPWSTR upgrade;
3975 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3977 upgrade = msi_dup_property(package->db, szUpgradeCode);
3978 if (!upgrade)
3979 return ERROR_SUCCESS;
3981 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3982 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3983 else
3984 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3986 if (r != ERROR_SUCCESS)
3988 WARN("failed to open upgrade code key\n");
3989 msi_free(upgrade);
3990 return ERROR_SUCCESS;
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;
3999 static BOOL msi_check_publish(MSIPACKAGE *package)
4001 MSIFEATURE *feature;
4003 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4005 feature->Action = msi_get_feature_action( package, feature );
4006 if (feature->Action == INSTALLSTATE_LOCAL)
4007 return TRUE;
4010 return FALSE;
4013 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4015 MSIFEATURE *feature;
4017 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4019 feature->Action = msi_get_feature_action( package, feature );
4020 if (feature->Action != INSTALLSTATE_ABSENT)
4021 return FALSE;
4024 return TRUE;
4027 static UINT msi_publish_patches( MSIPACKAGE *package )
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;
4038 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4039 if (r != ERROR_SUCCESS)
4040 return ERROR_FUNCTION_FAILED;
4042 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4043 if (res != ERROR_SUCCESS)
4045 r = ERROR_FUNCTION_FAILED;
4046 goto done;
4049 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4050 if (r != ERROR_SUCCESS)
4051 goto done;
4053 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4055 squash_guid( patch->patchcode, patch_squashed );
4056 len += strlenW( patch_squashed ) + 1;
4059 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4060 if (!all_patches)
4061 goto done;
4063 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4065 HKEY patch_key;
4067 squash_guid( patch->patchcode, p );
4068 p += strlenW( p ) + 1;
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;
4076 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4077 if (r != ERROR_SUCCESS)
4078 goto done;
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;
4086 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4088 res = GetLastError();
4089 ERR("Unable to copy patch package %d\n", res);
4090 goto done;
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;
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;
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;
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;
4113 done:
4114 RegCloseKey( product_patches_key );
4115 RegCloseKey( patches_key );
4116 RegCloseKey( product_key );
4117 msi_free( all_patches );
4118 return r;
4121 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4123 UINT rc;
4124 HKEY hukey = NULL, hudkey = NULL;
4125 MSIRECORD *uirow;
4127 if (!list_empty(&package->patches))
4129 rc = msi_publish_patches(package);
4130 if (rc != ERROR_SUCCESS)
4131 goto end;
4134 /* FIXME: also need to publish if the product is in advertise mode */
4135 if (!msi_check_publish(package))
4136 return ERROR_SUCCESS;
4138 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4139 &hukey, TRUE);
4140 if (rc != ERROR_SUCCESS)
4141 goto end;
4143 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4144 NULL, &hudkey, TRUE);
4145 if (rc != ERROR_SUCCESS)
4146 goto end;
4148 rc = msi_publish_upgrade_code(package);
4149 if (rc != ERROR_SUCCESS)
4150 goto end;
4152 rc = msi_publish_product_properties(package, hukey);
4153 if (rc != ERROR_SUCCESS)
4154 goto end;
4156 rc = msi_publish_sourcelist(package, hukey);
4157 if (rc != ERROR_SUCCESS)
4158 goto end;
4160 rc = msi_publish_icons(package);
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 );
4168 RegCloseKey(hukey);
4169 RegCloseKey(hudkey);
4170 return rc;
4173 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4175 WCHAR *filename, *ptr, *folder, *ret;
4176 const WCHAR *dirprop;
4178 filename = msi_dup_record_field( row, 2 );
4179 if (filename && (ptr = strchrW( filename, '|' )))
4180 ptr++;
4181 else
4182 ptr = filename;
4184 dirprop = MSI_RecordGetString( row, 3 );
4185 if (dirprop)
4187 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4188 if (!folder) folder = msi_dup_property( package->db, dirprop );
4190 else
4191 folder = msi_dup_property( package->db, szWindowsFolder );
4193 if (!folder)
4195 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4196 msi_free( filename );
4197 return NULL;
4200 ret = msi_build_directory_name( 2, folder, ptr );
4202 msi_free( filename );
4203 msi_free( folder );
4204 return ret;
4207 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
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;
4216 component = MSI_RecordGetString(row, 8);
4217 comp = msi_get_loaded_component(package,component);
4218 if (!comp)
4219 return ERROR_SUCCESS;
4221 comp->Action = msi_get_component_action( package, comp );
4222 if (comp->Action != INSTALLSTATE_LOCAL)
4224 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4225 return ERROR_SUCCESS;
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);
4234 deformat_string(package,section,&deformated_section);
4235 deformat_string(package,key,&deformated_key);
4236 deformat_string(package,value,&deformated_value);
4238 fullname = get_ini_file_name(package, row);
4240 if (action == 0)
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);
4248 else if (action == 1)
4250 WCHAR returned[10];
4251 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4252 returned, 10, fullname);
4253 if (returned[0] == 0)
4255 TRACE("Adding value %s to section %s in %s\n",
4256 debugstr_w(deformated_key), debugstr_w(deformated_section),
4257 debugstr_w(fullname));
4259 WritePrivateProfileStringW(deformated_section, deformated_key,
4260 deformated_value, fullname);
4263 else if (action == 3)
4264 FIXME("Append to existing section not yet implemented\n");
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 );
4274 msi_free(fullname);
4275 msi_free(deformated_key);
4276 msi_free(deformated_value);
4277 msi_free(deformated_section);
4278 return ERROR_SUCCESS;
4281 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
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;
4289 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4290 if (rc != ERROR_SUCCESS)
4291 return ERROR_SUCCESS;
4293 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4294 msiobj_release(&view->hdr);
4295 return rc;
4298 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
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;
4307 component = MSI_RecordGetString( row, 8 );
4308 comp = msi_get_loaded_component( package, component );
4309 if (!comp)
4310 return ERROR_SUCCESS;
4312 comp->Action = msi_get_component_action( package, comp );
4313 if (comp->Action != INSTALLSTATE_ABSENT)
4315 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4316 return ERROR_SUCCESS;
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 );
4325 deformat_string( package, section, &deformated_section );
4326 deformat_string( package, key, &deformated_key );
4327 deformat_string( package, value, &deformated_value );
4329 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4331 filename = get_ini_file_name( package, row );
4333 TRACE("Removing key %s from section %s in %s\n",
4334 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4336 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4338 WARN("Unable to remove key %u\n", GetLastError());
4340 msi_free( filename );
4342 else
4343 FIXME("Unsupported action %d\n", action);
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 );
4354 msi_free( deformated_key );
4355 msi_free( deformated_value );
4356 msi_free( deformated_section );
4357 return ERROR_SUCCESS;
4360 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
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;
4369 component = MSI_RecordGetString( row, 8 );
4370 comp = msi_get_loaded_component( package, component );
4371 if (!comp)
4372 return ERROR_SUCCESS;
4374 comp->Action = msi_get_component_action( package, comp );
4375 if (comp->Action != INSTALLSTATE_LOCAL)
4377 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4378 return ERROR_SUCCESS;
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 );
4387 deformat_string( package, section, &deformated_section );
4388 deformat_string( package, key, &deformated_key );
4389 deformat_string( package, value, &deformated_value );
4391 if (action == msidbIniFileActionRemoveLine)
4393 filename = get_ini_file_name( package, row );
4395 TRACE("Removing key %s from section %s in %s\n",
4396 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4398 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4400 WARN("Unable to remove key %u\n", GetLastError());
4402 msi_free( filename );
4404 else
4405 FIXME("Unsupported action %d\n", action);
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 );
4415 msi_free( deformated_key );
4416 msi_free( deformated_value );
4417 msi_free( deformated_section );
4418 return ERROR_SUCCESS;
4421 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
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;
4432 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4433 if (rc == ERROR_SUCCESS)
4435 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4436 msiobj_release( &view->hdr );
4437 if (rc != ERROR_SUCCESS)
4438 return rc;
4440 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4441 if (rc == ERROR_SUCCESS)
4443 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4444 msiobj_release( &view->hdr );
4445 if (rc != ERROR_SUCCESS)
4446 return rc;
4448 return ERROR_SUCCESS;
4451 static void register_dll( const WCHAR *dll, BOOL unregister )
4453 HMODULE hmod;
4455 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4456 if (hmod)
4458 HRESULT (WINAPI *func_ptr)( void );
4459 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4461 func_ptr = (void *)GetProcAddress( hmod, func );
4462 if (func_ptr)
4464 HRESULT hr = func_ptr();
4465 if (FAILED( hr ))
4466 WARN("failed to register dll 0x%08x\n", hr);
4468 else
4469 WARN("entry point %s not found\n", func);
4470 FreeLibrary( hmod );
4471 return;
4473 WARN("failed to load library %u\n", GetLastError());
4476 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4478 MSIPACKAGE *package = param;
4479 LPCWSTR filename;
4480 MSIFILE *file;
4481 MSIRECORD *uirow;
4483 filename = MSI_RecordGetString( row, 1 );
4484 file = msi_get_loaded_file( package, filename );
4485 if (!file)
4487 WARN("unable to find file %s\n", debugstr_w(filename));
4488 return ERROR_SUCCESS;
4490 file->Component->Action = msi_get_component_action( package, file->Component );
4491 if (file->Component->Action != INSTALLSTATE_LOCAL)
4493 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4494 return ERROR_SUCCESS;
4497 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4498 register_dll( file->TargetPath, FALSE );
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 );
4506 return ERROR_SUCCESS;
4509 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
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;
4517 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4518 if (rc != ERROR_SUCCESS)
4519 return ERROR_SUCCESS;
4521 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4522 msiobj_release(&view->hdr);
4523 return rc;
4526 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4528 MSIPACKAGE *package = param;
4529 LPCWSTR filename;
4530 MSIFILE *file;
4531 MSIRECORD *uirow;
4533 filename = MSI_RecordGetString( row, 1 );
4534 file = msi_get_loaded_file( package, filename );
4535 if (!file)
4537 WARN("unable to find file %s\n", debugstr_w(filename));
4538 return ERROR_SUCCESS;
4540 file->Component->Action = msi_get_component_action( package, file->Component );
4541 if (file->Component->Action != INSTALLSTATE_ABSENT)
4543 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4544 return ERROR_SUCCESS;
4547 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4548 register_dll( file->TargetPath, TRUE );
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 );
4556 return ERROR_SUCCESS;
4559 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
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;
4567 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4568 if (rc != ERROR_SUCCESS)
4569 return ERROR_SUCCESS;
4571 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4572 msiobj_release( &view->hdr );
4573 return rc;
4576 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4578 MSIFEATURE *feature;
4579 UINT rc;
4580 HKEY hkey = NULL, userdata = NULL;
4582 if (!msi_check_publish(package))
4583 return ERROR_SUCCESS;
4585 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4586 &hkey, TRUE);
4587 if (rc != ERROR_SUCCESS)
4588 goto end;
4590 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4591 &userdata, TRUE);
4592 if (rc != ERROR_SUCCESS)
4593 goto end;
4595 /* here the guids are base 85 encoded */
4596 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4598 ComponentList *cl;
4599 LPWSTR data = NULL;
4600 GUID clsid;
4601 INT size;
4602 BOOL absent = FALSE;
4603 MSIRECORD *uirow;
4605 if (feature->Action != INSTALLSTATE_LOCAL &&
4606 feature->Action != INSTALLSTATE_SOURCE &&
4607 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4609 size = 1;
4610 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4612 size += 21;
4614 if (feature->Feature_Parent)
4615 size += strlenW( feature->Feature_Parent )+2;
4617 data = msi_alloc(size * sizeof(WCHAR));
4619 data[0] = 0;
4620 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4622 MSICOMPONENT* component = cl->component;
4623 WCHAR buf[21];
4625 buf[0] = 0;
4626 if (component->ComponentId)
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);
4636 if (feature->Feature_Parent)
4638 static const WCHAR sep[] = {'\2',0};
4639 strcatW(data,sep);
4640 strcatW(data,feature->Feature_Parent);
4643 msi_reg_set_val_str( userdata, feature->Feature, data );
4644 msi_free(data);
4646 size = 0;
4647 if (feature->Feature_Parent)
4648 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4649 if (!absent)
4651 size += sizeof(WCHAR);
4652 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4653 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4655 else
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);
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? */
4676 end:
4677 RegCloseKey(hkey);
4678 RegCloseKey(userdata);
4679 return rc;
4682 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4684 UINT r;
4685 HKEY hkey;
4686 MSIRECORD *uirow;
4688 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4690 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4691 &hkey, FALSE);
4692 if (r == ERROR_SUCCESS)
4694 RegDeleteValueW(hkey, feature->Feature);
4695 RegCloseKey(hkey);
4698 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4699 &hkey, FALSE);
4700 if (r == ERROR_SUCCESS)
4702 RegDeleteValueW(hkey, feature->Feature);
4703 RegCloseKey(hkey);
4706 uirow = MSI_CreateRecord( 1 );
4707 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4708 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4709 msiobj_release( &uirow->hdr );
4711 return ERROR_SUCCESS;
4714 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4716 MSIFEATURE *feature;
4718 if (!msi_check_unpublish(package))
4719 return ERROR_SUCCESS;
4721 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4723 msi_unpublish_feature(package, feature);
4726 return ERROR_SUCCESS;
4729 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4731 SYSTEMTIME systime;
4732 DWORD size, langid;
4733 WCHAR date[9], *val, *buffer;
4734 const WCHAR *prop, *key;
4736 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','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};
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
4819 const WCHAR **p = propval;
4821 while (*p)
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);
4830 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4831 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4833 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
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);
4840 /* FIXME: Write real Estimated Size when we have it */
4841 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4843 GetLocalTime(&systime);
4844 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4845 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4847 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4848 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4850 buffer = msi_dup_property(package->db, szProductVersion);
4851 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4852 if (buffer)
4854 DWORD verdword = msi_version_str_to_dword(buffer);
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);
4862 return ERROR_SUCCESS;
4865 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4867 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4868 MSIRECORD *uirow;
4869 LPWSTR upgrade_code;
4870 HKEY hkey, props, upgrade_key;
4871 UINT rc;
4873 /* FIXME: also need to publish if the product is in advertise mode */
4874 if (!msi_check_publish(package))
4875 return ERROR_SUCCESS;
4877 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4878 if (rc != ERROR_SUCCESS)
4879 return rc;
4881 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4882 if (rc != ERROR_SUCCESS)
4883 goto done;
4885 rc = msi_publish_install_properties(package, hkey);
4886 if (rc != ERROR_SUCCESS)
4887 goto done;
4889 rc = msi_publish_install_properties(package, props);
4890 if (rc != ERROR_SUCCESS)
4891 goto done;
4893 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4894 if (upgrade_code)
4896 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4897 if (rc == ERROR_SUCCESS)
4899 squash_guid( package->ProductCode, squashed_pc );
4900 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4901 RegCloseKey( upgrade_key );
4903 msi_free( upgrade_code );
4905 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4906 package->delete_on_close = FALSE;
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 );
4914 RegCloseKey(hkey);
4915 return ERROR_SUCCESS;
4918 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4920 return execute_script(package, SCRIPT_INSTALL);
4923 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4925 MSIPACKAGE *package = param;
4926 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4927 WCHAR *p, *icon_path;
4929 if (!icon) return ERROR_SUCCESS;
4930 if ((icon_path = msi_build_icon_path( package, icon )))
4932 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4933 DeleteFileW( icon_path );
4934 if ((p = strrchrW( icon_path, '\\' )))
4936 *p = 0;
4937 RemoveDirectoryW( icon_path );
4939 msi_free( icon_path );
4941 return ERROR_SUCCESS;
4944 static UINT msi_unpublish_icons( MSIPACKAGE *package )
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;
4951 r = MSI_DatabaseOpenViewW( package->db, query, &view );
4952 if (r == ERROR_SUCCESS)
4954 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4955 msiobj_release( &view->hdr );
4956 if (r != ERROR_SUCCESS)
4957 return r;
4959 return ERROR_SUCCESS;
4962 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
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;
4971 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4973 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4975 features = msi_split_string( remove, ',' );
4976 for (i = 0; features && features[i]; i++)
4978 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4980 msi_free(features);
4982 if (!full_uninstall)
4983 return ERROR_SUCCESS;
4985 MSIREG_DeleteProductKey(package->ProductCode);
4986 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4987 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4989 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4990 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4991 MSIREG_DeleteUserProductKey(package->ProductCode);
4992 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4994 upgrade = msi_dup_property(package->db, szUpgradeCode);
4995 if (upgrade)
4997 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4998 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4999 msi_free(upgrade);
5002 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5004 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5005 if (!strcmpW( package->ProductCode, patch->products ))
5007 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5008 patch->delete_on_close = TRUE;
5010 /* FIXME: remove local patch package if this is the last product */
5012 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5013 package->delete_on_close = TRUE;
5015 msi_unpublish_icons( package );
5016 return ERROR_SUCCESS;
5019 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5021 UINT rc;
5022 WCHAR *remove;
5024 /* turn off scheduling */
5025 package->script->CurrentlyScripting= FALSE;
5027 /* first do the same as an InstallExecute */
5028 rc = ACTION_InstallExecute(package);
5029 if (rc != ERROR_SUCCESS)
5030 return rc;
5032 /* then handle commit actions */
5033 rc = execute_script(package, SCRIPT_COMMIT);
5034 if (rc != ERROR_SUCCESS)
5035 return rc;
5037 remove = msi_dup_property(package->db, szRemove);
5038 rc = msi_unpublish_product(package, remove);
5039 msi_free(remove);
5040 return rc;
5043 UINT ACTION_ForceReboot(MSIPACKAGE *package)
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};
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];
5071 squash_guid(package->ProductCode,squished_pc);
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);
5078 msi_reg_set_val_str( hkey, squished_pc, buffer );
5079 RegCloseKey(hkey);
5081 TRACE("Reboot command %s\n",debugstr_w(buffer));
5083 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5084 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5086 msi_reg_set_val_str( hkey, squished_pc, buffer );
5087 RegCloseKey(hkey);
5089 return ERROR_INSTALL_SUSPEND;
5092 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
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;
5104 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
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 );
5112 va_start( va, count );
5113 for (i = 0; i < count; i++)
5115 str = va_arg( va, const WCHAR *);
5116 MSI_RecordSetStringW( rec, i + 2, str );
5118 va_end( va );
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;
5129 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5131 DWORD attrib;
5132 UINT rc;
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
5138 if (!package->PackagePath)
5139 return ERROR_SUCCESS;
5141 msi_set_sourcedir_props(package, TRUE);
5143 attrib = GetFileAttributesW(package->db->path);
5144 if (attrib == INVALID_FILE_ATTRIBUTES)
5146 LPWSTR prompt, msg;
5147 DWORD size = 0;
5149 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5150 package->Context, MSICODE_PRODUCT,
5151 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5152 if (rc == ERROR_MORE_DATA)
5154 prompt = msi_alloc(size * sizeof(WCHAR));
5155 MsiSourceListGetInfoW(package->ProductCode, NULL,
5156 package->Context, MSICODE_PRODUCT,
5157 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5159 else
5160 prompt = strdupW(package->db->path);
5162 msg = msi_build_error_string(package, 1302, 1, prompt);
5163 msi_free(prompt);
5164 while(attrib == INVALID_FILE_ATTRIBUTES)
5166 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5167 if (rc == IDCANCEL)
5169 msi_free(msg);
5170 return ERROR_INSTALL_USEREXIT;
5172 attrib = GetFileAttributesW(package->db->path);
5174 msi_free(msg);
5175 rc = ERROR_SUCCESS;
5177 else
5178 return ERROR_SUCCESS;
5180 return rc;
5183 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5185 HKEY hkey = 0;
5186 LPWSTR buffer, productid = NULL;
5187 UINT i, rc = ERROR_SUCCESS;
5188 MSIRECORD *uirow;
5190 static const WCHAR szPropKeys[][80] =
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},
5198 static const WCHAR szRegKeys[][80] =
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},
5206 if (msi_check_unpublish(package))
5208 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5209 goto end;
5212 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5213 if (!productid)
5214 goto end;
5216 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5217 NULL, &hkey, TRUE);
5218 if (rc != ERROR_SUCCESS)
5219 goto end;
5221 for( i = 0; szPropKeys[i][0]; i++ )
5223 buffer = msi_dup_property( package->db, szPropKeys[i] );
5224 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5225 msi_free( buffer );
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 );
5234 msi_free(productid);
5235 RegCloseKey(hkey);
5236 return rc;
5240 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5242 UINT rc;
5244 package->script->InWhatSequence |= SEQUENCE_EXEC;
5245 rc = ACTION_ProcessExecSequence(package,FALSE);
5246 return rc;
5249 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
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;
5256 /* > is used if there is a component GUID and < if not. */
5258 productid_85[0] = 0;
5259 component_85[0] = 0;
5260 CLSIDFromString( package->ProductCode, &clsid );
5262 encode_base85_guid( &clsid, productid_85 );
5263 if (component)
5265 CLSIDFromString( component->ComponentId, &clsid );
5266 encode_base85_guid( &clsid, component_85 );
5269 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5270 debugstr_w(component_85));
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;
5278 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
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;
5291 feature = MSI_RecordGetString(rec, 5);
5292 feat = msi_get_loaded_feature(package, feature);
5293 if (!feat)
5294 return ERROR_SUCCESS;
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)
5301 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5302 return ERROR_SUCCESS;
5305 component = MSI_RecordGetString(rec, 3);
5306 comp = msi_get_loaded_component(package, component);
5307 if (!comp)
5308 return ERROR_SUCCESS;
5310 compgroupid = MSI_RecordGetString(rec,1);
5311 qualifier = MSI_RecordGetString(rec,2);
5313 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5314 if (rc != ERROR_SUCCESS)
5315 goto end;
5317 advertise = msi_create_component_advertise_string( package, comp, feature );
5318 text = MSI_RecordGetString( rec, 4 );
5319 if (text)
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;
5327 existing = msi_reg_get_val_str( hkey, qualifier );
5329 sz = strlenW( advertise ) + 1;
5330 if (existing)
5332 for (p = existing; *p; p += len)
5334 len = strlenW( p ) + 1;
5335 if (strcmpW( advertise, p )) sz += len;
5338 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5340 rc = ERROR_OUTOFMEMORY;
5341 goto end;
5343 q = output;
5344 if (existing)
5346 for (p = existing; *p; p += len)
5348 len = strlenW( p ) + 1;
5349 if (strcmpW( advertise, p ))
5351 memcpy( q, p, len * sizeof(WCHAR) );
5352 q += len;
5356 strcpyW( q, advertise );
5357 q[strlenW( q ) + 1] = 0;
5359 msi_reg_set_val_multi_str( hkey, qualifier, output );
5361 end:
5362 RegCloseKey(hkey);
5363 msi_free( output );
5364 msi_free( advertise );
5365 msi_free( existing );
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? */
5375 return rc;
5379 * At present I am ignorning the advertised components part of this and only
5380 * focusing on the qualified component sets
5382 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
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;
5390 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5391 if (rc != ERROR_SUCCESS)
5392 return ERROR_SUCCESS;
5394 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5395 msiobj_release(&view->hdr);
5396 return rc;
5399 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
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};
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;
5415 feature = MSI_RecordGetString( rec, 5 );
5416 feat = msi_get_loaded_feature( package, feature );
5417 if (!feat)
5418 return ERROR_SUCCESS;
5420 feat->Action = msi_get_feature_action( package, feat );
5421 if (feat->Action != INSTALLSTATE_ABSENT)
5423 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5424 return ERROR_SUCCESS;
5427 component = MSI_RecordGetString( rec, 3 );
5428 comp = msi_get_loaded_component( package, component );
5429 if (!comp)
5430 return ERROR_SUCCESS;
5432 compgroupid = MSI_RecordGetString( rec, 1 );
5433 qualifier = MSI_RecordGetString( rec, 2 );
5435 squash_guid( compgroupid, squashed );
5436 strcpyW( keypath, szInstallerComponents );
5437 strcatW( keypath, squashed );
5439 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5440 if (res != ERROR_SUCCESS)
5442 WARN("Unable to delete component key %d\n", res);
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 );
5451 return ERROR_SUCCESS;
5454 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
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;
5462 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5463 if (rc != ERROR_SUCCESS)
5464 return ERROR_SUCCESS;
5466 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5467 msiobj_release( &view->hdr );
5468 return rc;
5471 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
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};
5488 comp = MSI_RecordGetString( rec, 12 );
5489 component = msi_get_loaded_component( package, comp );
5490 if (!component)
5492 WARN("service component not found\n");
5493 goto done;
5495 component->Action = msi_get_component_action( package, component );
5496 if (component->Action != INSTALLSTATE_LOCAL)
5498 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5499 goto done;
5501 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5502 if (!hscm)
5504 ERR("Failed to open the SC Manager!\n");
5505 goto done;
5508 start_type = MSI_RecordGetInteger(rec, 5);
5509 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5510 goto done;
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);
5523 /* fetch the service path */
5524 row = MSI_QueryGetRecord(package->db, query, comp);
5525 if (!row)
5527 ERR("Query failed\n");
5528 goto done;
5530 key = MSI_RecordGetString(row, 6);
5531 file = msi_get_loaded_file(package, key);
5532 msiobj_release(&row->hdr);
5533 if (!file)
5535 ERR("Failed to load the service file\n");
5536 goto done;
5539 if (!args || !args[0]) image_path = file->TargetPath;
5540 else
5542 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5543 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5544 return ERROR_OUTOFMEMORY;
5546 strcpyW(image_path, file->TargetPath);
5547 strcatW(image_path, szSpace);
5548 strcatW(image_path, args);
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);
5554 if (!service)
5556 if (GetLastError() != ERROR_SERVICE_EXISTS)
5557 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5559 else if (sd.lpDescription)
5561 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5562 WARN("failed to set service description %u\n", GetLastError());
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);
5578 return ERROR_SUCCESS;
5581 static UINT ACTION_InstallServices( MSIPACKAGE *package )
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;
5589 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5590 if (rc != ERROR_SUCCESS)
5591 return ERROR_SUCCESS;
5593 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5594 msiobj_release(&view->hdr);
5595 return rc;
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)
5601 LPCWSTR *vector, *temp_vector;
5602 LPWSTR p, q;
5603 DWORD sep_len;
5605 static const WCHAR separator[] = {'[','~',']',0};
5607 *numargs = 0;
5608 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5610 if (!args)
5611 return NULL;
5613 vector = msi_alloc(sizeof(LPWSTR));
5614 if (!vector)
5615 return NULL;
5617 p = args;
5620 (*numargs)++;
5621 vector[*numargs - 1] = p;
5623 if ((q = strstrW(p, separator)))
5625 *q = '\0';
5627 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5628 if (!temp_vector)
5630 msi_free(vector);
5631 return NULL;
5633 vector = temp_vector;
5635 p = q + sep_len;
5637 } while (q);
5639 return vector;
5642 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
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;
5655 component = MSI_RecordGetString(rec, 6);
5656 comp = msi_get_loaded_component(package, component);
5657 if (!comp)
5658 return ERROR_SUCCESS;
5660 comp->Action = msi_get_component_action( package, comp );
5661 if (comp->Action != INSTALLSTATE_LOCAL)
5663 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5664 return ERROR_SUCCESS;
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);
5672 if (!(event & msidbServiceControlEventStart))
5674 r = ERROR_SUCCESS;
5675 goto done;
5678 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5679 if (!scm)
5681 ERR("Failed to open the service control manager\n");
5682 goto done;
5685 len = 0;
5686 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5687 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5689 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5690 GetServiceDisplayNameW( scm, name, display_name, &len );
5693 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5694 if (!service)
5696 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5697 goto done;
5700 vector = msi_service_args_to_vector(args, &numargs);
5702 if (!StartServiceW(service, numargs, vector) &&
5703 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5705 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5706 goto done;
5709 r = ERROR_SUCCESS;
5710 if (wait)
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))
5716 TRACE("failed to query service status (%u)\n", GetLastError());
5717 goto done;
5719 start_time = GetTickCount64();
5720 while (status.dwCurrentState == SERVICE_START_PENDING)
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))
5727 TRACE("failed to query service status (%u)\n", GetLastError());
5728 goto done;
5731 if (status.dwCurrentState != SERVICE_RUNNING)
5733 WARN("service failed to start %u\n", status.dwCurrentState);
5734 r = ERROR_FUNCTION_FAILED;
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 );
5745 CloseServiceHandle(service);
5746 CloseServiceHandle(scm);
5748 msi_free(name);
5749 msi_free(args);
5750 msi_free(vector);
5751 msi_free(display_name);
5752 return r;
5755 static UINT ACTION_StartServices( MSIPACKAGE *package )
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;
5763 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5764 if (rc != ERROR_SUCCESS)
5765 return ERROR_SUCCESS;
5767 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5768 msiobj_release(&view->hdr);
5769 return rc;
5772 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5774 DWORD i, needed, count;
5775 ENUM_SERVICE_STATUSW *dependencies;
5776 SERVICE_STATUS ss;
5777 SC_HANDLE depserv;
5779 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5780 0, &needed, &count))
5781 return TRUE;
5783 if (GetLastError() != ERROR_MORE_DATA)
5784 return FALSE;
5786 dependencies = msi_alloc(needed);
5787 if (!dependencies)
5788 return FALSE;
5790 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5791 needed, &needed, &count))
5792 goto error;
5794 for (i = 0; i < count; i++)
5796 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5797 SERVICE_STOP | SERVICE_QUERY_STATUS);
5798 if (!depserv)
5799 goto error;
5801 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5802 goto error;
5805 return TRUE;
5807 error:
5808 msi_free(dependencies);
5809 return FALSE;
5812 static UINT stop_service( LPCWSTR name )
5814 SC_HANDLE scm = NULL, service = NULL;
5815 SERVICE_STATUS status;
5816 SERVICE_STATUS_PROCESS ssp;
5817 DWORD needed;
5819 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5820 if (!scm)
5822 WARN("Failed to open the SCM: %d\n", GetLastError());
5823 goto done;
5826 service = OpenServiceW(scm, name,
5827 SERVICE_STOP |
5828 SERVICE_QUERY_STATUS |
5829 SERVICE_ENUMERATE_DEPENDENTS);
5830 if (!service)
5832 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5833 goto done;
5836 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5837 sizeof(SERVICE_STATUS_PROCESS), &needed))
5839 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5840 goto done;
5843 if (ssp.dwCurrentState == SERVICE_STOPPED)
5844 goto done;
5846 stop_service_dependents(scm, service);
5848 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5849 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5851 done:
5852 CloseServiceHandle(service);
5853 CloseServiceHandle(scm);
5855 return ERROR_SUCCESS;
5858 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
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;
5868 event = MSI_RecordGetInteger( rec, 3 );
5869 if (!(event & msidbServiceControlEventStop))
5870 return ERROR_SUCCESS;
5872 component = MSI_RecordGetString( rec, 6 );
5873 comp = msi_get_loaded_component( package, component );
5874 if (!comp)
5875 return ERROR_SUCCESS;
5877 comp->Action = msi_get_component_action( package, comp );
5878 if (comp->Action != INSTALLSTATE_ABSENT)
5880 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5881 return ERROR_SUCCESS;
5884 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5885 if (!scm)
5887 ERR("Failed to open the service control manager\n");
5888 goto done;
5891 len = 0;
5892 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5893 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5895 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5896 GetServiceDisplayNameW( scm, name, display_name, &len );
5898 CloseServiceHandle( scm );
5900 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5901 stop_service( name );
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 );
5910 msi_free( name );
5911 msi_free( display_name );
5912 return ERROR_SUCCESS;
5915 static UINT ACTION_StopServices( MSIPACKAGE *package )
5917 static const WCHAR query[] = {
5918 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5919 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5920 MSIQUERY *view;
5921 UINT rc;
5923 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5924 if (rc != ERROR_SUCCESS)
5925 return ERROR_SUCCESS;
5927 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5928 msiobj_release(&view->hdr);
5929 return rc;
5932 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
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;
5941 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
5942 if (!comp)
5943 return ERROR_SUCCESS;
5945 event = MSI_RecordGetInteger( rec, 3 );
5946 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5948 comp->Action = msi_get_component_action( package, comp );
5949 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
5950 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
5952 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
5953 msi_free( name );
5954 return ERROR_SUCCESS;
5956 stop_service( name );
5958 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5959 if (!scm)
5961 WARN("Failed to open the SCM: %d\n", GetLastError());
5962 goto done;
5965 len = 0;
5966 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5967 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5969 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5970 GetServiceDisplayNameW( scm, name, display_name, &len );
5973 service = OpenServiceW( scm, name, DELETE );
5974 if (!service)
5976 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5977 goto done;
5980 if (!DeleteService( service ))
5981 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
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 );
5990 CloseServiceHandle( service );
5991 CloseServiceHandle( scm );
5992 msi_free( name );
5993 msi_free( display_name );
5995 return ERROR_SUCCESS;
5998 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
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;
6006 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6007 if (rc != ERROR_SUCCESS)
6008 return ERROR_SUCCESS;
6010 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6011 msiobj_release( &view->hdr );
6012 return rc;
6015 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
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;
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};
6034 component = MSI_RecordGetString( rec, 2 );
6035 comp = msi_get_loaded_component( package, component );
6036 if (!comp)
6037 return ERROR_SUCCESS;
6039 comp->Action = msi_get_component_action( package, comp );
6040 if (comp->Action != INSTALLSTATE_LOCAL)
6042 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6043 return ERROR_SUCCESS;
6045 desc = MSI_RecordGetString(rec, 3);
6047 file_key = MSI_RecordGetString( rec, 4 );
6048 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6050 file_key = MSI_RecordGetString( rec, 5 );
6051 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6053 if (!driver_file)
6055 ERR("ODBC Driver entry not found!\n");
6056 return ERROR_FUNCTION_FAILED;
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 */
6064 driver = msi_alloc(len * sizeof(WCHAR));
6065 if (!driver)
6066 return ERROR_OUTOFMEMORY;
6068 ptr = driver;
6069 lstrcpyW(ptr, desc);
6070 ptr += lstrlenW(ptr) + 1;
6072 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6073 ptr += len + 1;
6075 if (setup_file)
6077 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6078 ptr += len + 1;
6081 lstrcpyW(ptr, usage_fmt);
6082 ptr += lstrlenW(ptr) + 1;
6083 *ptr = '\0';
6085 if (!driver_file->TargetPath)
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 );
6090 driver_path = strdupW(driver_file->TargetPath);
6091 ptr = strrchrW(driver_path, '\\');
6092 if (ptr) *ptr = '\0';
6094 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6095 NULL, ODBC_INSTALL_COMPLETE, &usage))
6097 ERR("Failed to install SQL driver!\n");
6098 r = ERROR_FUNCTION_FAILED;
6101 uirow = MSI_CreateRecord( 5 );
6102 MSI_RecordSetStringW( uirow, 1, desc );
6103 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6104 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6105 msi_ui_actiondata( package, szInstallODBC, uirow );
6106 msiobj_release( &uirow->hdr );
6108 msi_free(driver);
6109 msi_free(driver_path);
6111 return r;
6114 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
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;
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};
6131 component = MSI_RecordGetString( rec, 2 );
6132 comp = msi_get_loaded_component( package, component );
6133 if (!comp)
6134 return ERROR_SUCCESS;
6136 comp->Action = msi_get_component_action( package, comp );
6137 if (comp->Action != INSTALLSTATE_LOCAL)
6139 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6140 return ERROR_SUCCESS;
6142 desc = MSI_RecordGetString(rec, 3);
6144 file_key = MSI_RecordGetString( rec, 4 );
6145 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6147 file_key = MSI_RecordGetString( rec, 5 );
6148 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6150 if (!translator_file)
6152 ERR("ODBC Translator entry not found!\n");
6153 return ERROR_FUNCTION_FAILED;
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);
6160 translator = msi_alloc(len * sizeof(WCHAR));
6161 if (!translator)
6162 return ERROR_OUTOFMEMORY;
6164 ptr = translator;
6165 lstrcpyW(ptr, desc);
6166 ptr += lstrlenW(ptr) + 1;
6168 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6169 ptr += len + 1;
6171 if (setup_file)
6173 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6174 ptr += len + 1;
6176 *ptr = '\0';
6178 translator_path = strdupW(translator_file->TargetPath);
6179 ptr = strrchrW(translator_path, '\\');
6180 if (ptr) *ptr = '\0';
6182 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6183 NULL, ODBC_INSTALL_COMPLETE, &usage))
6185 ERR("Failed to install SQL translator!\n");
6186 r = ERROR_FUNCTION_FAILED;
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 );
6196 msi_free(translator);
6197 msi_free(translator_path);
6199 return r;
6202 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
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;
6214 static const WCHAR attrs_fmt[] = {
6215 'D','S','N','=','%','s',0 };
6217 component = MSI_RecordGetString( rec, 2 );
6218 comp = msi_get_loaded_component( package, component );
6219 if (!comp)
6220 return ERROR_SUCCESS;
6222 comp->Action = msi_get_component_action( package, comp );
6223 if (comp->Action != INSTALLSTATE_LOCAL)
6225 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6226 return ERROR_SUCCESS;
6229 desc = MSI_RecordGetString(rec, 3);
6230 driver = MSI_RecordGetString(rec, 4);
6231 registration = MSI_RecordGetInteger(rec, 5);
6233 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6234 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6236 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6237 attrs = msi_alloc(len * sizeof(WCHAR));
6238 if (!attrs)
6239 return ERROR_OUTOFMEMORY;
6241 len = sprintfW(attrs, attrs_fmt, desc);
6242 attrs[len + 1] = 0;
6244 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6246 ERR("Failed to install SQL data source!\n");
6247 r = ERROR_FUNCTION_FAILED;
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 );
6257 msi_free(attrs);
6259 return r;
6262 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
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;
6276 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6277 if (rc == ERROR_SUCCESS)
6279 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6280 msiobj_release(&view->hdr);
6281 if (rc != ERROR_SUCCESS)
6282 return rc;
6284 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6285 if (rc == ERROR_SUCCESS)
6287 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6288 msiobj_release(&view->hdr);
6289 if (rc != ERROR_SUCCESS)
6290 return rc;
6292 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6293 if (rc == ERROR_SUCCESS)
6295 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6296 msiobj_release(&view->hdr);
6297 if (rc != ERROR_SUCCESS)
6298 return rc;
6300 return ERROR_SUCCESS;
6303 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6305 MSIPACKAGE *package = param;
6306 MSICOMPONENT *comp;
6307 MSIRECORD *uirow;
6308 DWORD usage;
6309 LPCWSTR desc, component;
6311 component = MSI_RecordGetString( rec, 2 );
6312 comp = msi_get_loaded_component( package, component );
6313 if (!comp)
6314 return ERROR_SUCCESS;
6316 comp->Action = msi_get_component_action( package, comp );
6317 if (comp->Action != INSTALLSTATE_ABSENT)
6319 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6320 return ERROR_SUCCESS;
6323 desc = MSI_RecordGetString( rec, 3 );
6324 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6326 WARN("Failed to remove ODBC driver\n");
6328 else if (!usage)
6330 FIXME("Usage count reached 0\n");
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 );
6339 return ERROR_SUCCESS;
6342 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6344 MSIPACKAGE *package = param;
6345 MSICOMPONENT *comp;
6346 MSIRECORD *uirow;
6347 DWORD usage;
6348 LPCWSTR desc, component;
6350 component = MSI_RecordGetString( rec, 2 );
6351 comp = msi_get_loaded_component( package, component );
6352 if (!comp)
6353 return ERROR_SUCCESS;
6355 comp->Action = msi_get_component_action( package, comp );
6356 if (comp->Action != INSTALLSTATE_ABSENT)
6358 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6359 return ERROR_SUCCESS;
6362 desc = MSI_RecordGetString( rec, 3 );
6363 if (!SQLRemoveTranslatorW( desc, &usage ))
6365 WARN("Failed to remove ODBC translator\n");
6367 else if (!usage)
6369 FIXME("Usage count reached 0\n");
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 );
6378 return ERROR_SUCCESS;
6381 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
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;
6392 static const WCHAR attrs_fmt[] = {
6393 'D','S','N','=','%','s',0 };
6395 component = MSI_RecordGetString( rec, 2 );
6396 comp = msi_get_loaded_component( package, component );
6397 if (!comp)
6398 return ERROR_SUCCESS;
6400 comp->Action = msi_get_component_action( package, comp );
6401 if (comp->Action != INSTALLSTATE_ABSENT)
6403 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6404 return ERROR_SUCCESS;
6407 desc = MSI_RecordGetString( rec, 3 );
6408 driver = MSI_RecordGetString( rec, 4 );
6409 registration = MSI_RecordGetInteger( rec, 5 );
6411 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6412 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6414 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6415 attrs = msi_alloc( len * sizeof(WCHAR) );
6416 if (!attrs)
6417 return ERROR_OUTOFMEMORY;
6419 FIXME("Use ODBCSourceAttribute table\n");
6421 len = sprintfW( attrs, attrs_fmt, desc );
6422 attrs[len + 1] = 0;
6424 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6426 WARN("Failed to remove ODBC data source\n");
6428 msi_free( attrs );
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 );
6437 return ERROR_SUCCESS;
6440 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
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;
6454 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6455 if (rc == ERROR_SUCCESS)
6457 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6458 msiobj_release( &view->hdr );
6459 if (rc != ERROR_SUCCESS)
6460 return rc;
6462 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6463 if (rc == ERROR_SUCCESS)
6465 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6466 msiobj_release( &view->hdr );
6467 if (rc != ERROR_SUCCESS)
6468 return rc;
6470 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6471 if (rc == ERROR_SUCCESS)
6473 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6474 msiobj_release( &view->hdr );
6475 if (rc != ERROR_SUCCESS)
6476 return rc;
6478 return ERROR_SUCCESS;
6481 #define ENV_ACT_SETALWAYS 0x1
6482 #define ENV_ACT_SETABSENT 0x2
6483 #define ENV_ACT_REMOVE 0x4
6484 #define ENV_ACT_REMOVEMATCH 0x8
6486 #define ENV_MOD_MACHINE 0x20000000
6487 #define ENV_MOD_APPEND 0x40000000
6488 #define ENV_MOD_PREFIX 0x80000000
6489 #define ENV_MOD_MASK 0xC0000000
6491 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6493 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6495 LPCWSTR cptr = *name;
6497 static const WCHAR prefix[] = {'[','~',']',0};
6498 static const int prefix_len = 3;
6500 *flags = 0;
6501 while (*cptr)
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;
6516 cptr++;
6517 (*name)++;
6520 if (!*cptr)
6522 ERR("Missing environment variable\n");
6523 return ERROR_FUNCTION_FAILED;
6526 if (*value)
6528 LPCWSTR ptr = *value;
6529 if (!strncmpW(ptr, prefix, prefix_len))
6531 if (ptr[prefix_len] == szSemiColon[0])
6533 *flags |= ENV_MOD_APPEND;
6534 *value += lstrlenW(prefix);
6536 else
6538 *value = NULL;
6541 else if (lstrlenW(*value) >= prefix_len)
6543 ptr += lstrlenW(ptr) - prefix_len;
6544 if (!strcmpW( ptr, prefix ))
6546 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6548 *flags |= ENV_MOD_PREFIX;
6549 /* the "[~]" will be removed by deformat_string */;
6551 else
6553 *value = NULL;
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))
6564 ERR("Invalid flags: %08x\n", *flags);
6565 return ERROR_FUNCTION_FAILED;
6568 if (!*flags)
6569 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6571 return ERROR_SUCCESS;
6574 static UINT open_env_key( DWORD flags, HKEY *key )
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;
6588 if (flags & ENV_MOD_MACHINE)
6590 env = machine_env;
6591 root = HKEY_LOCAL_MACHINE;
6593 else
6595 env = user_env;
6596 root = HKEY_CURRENT_USER;
6599 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6600 if (res != ERROR_SUCCESS)
6602 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6603 return ERROR_FUNCTION_FAILED;
6606 return ERROR_SUCCESS;
6609 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
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;
6621 component = MSI_RecordGetString(rec, 4);
6622 comp = msi_get_loaded_component(package, component);
6623 if (!comp)
6624 return ERROR_SUCCESS;
6626 comp->Action = msi_get_component_action( package, comp );
6627 if (comp->Action != INSTALLSTATE_LOCAL)
6629 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6630 return ERROR_SUCCESS;
6632 name = MSI_RecordGetString(rec, 2);
6633 value = MSI_RecordGetString(rec, 3);
6635 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6637 res = env_parse_flags(&name, &value, &flags);
6638 if (res != ERROR_SUCCESS || !value)
6639 goto done;
6641 if (value && !deformat_string(package, value, &deformatted))
6643 res = ERROR_OUTOFMEMORY;
6644 goto done;
6647 value = deformatted;
6649 res = open_env_key( flags, &env );
6650 if (res != ERROR_SUCCESS)
6651 goto done;
6653 if (flags & ENV_MOD_MACHINE)
6654 action |= 0x20000000;
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;
6663 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6665 action = 0x2;
6667 /* Nothing to do. */
6668 if (!value)
6670 res = ERROR_SUCCESS;
6671 goto done;
6674 /* If we are appending but the string was empty, strip ; */
6675 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6677 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6678 newval = strdupW(value);
6679 if (!newval)
6681 res = ERROR_OUTOFMEMORY;
6682 goto done;
6685 else
6687 action = 0x1;
6689 /* Contrary to MSDN, +-variable to [~];path works */
6690 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6692 res = ERROR_SUCCESS;
6693 goto done;
6696 data = msi_alloc(size);
6697 if (!data)
6699 RegCloseKey(env);
6700 return ERROR_OUTOFMEMORY;
6703 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6704 if (res != ERROR_SUCCESS)
6705 goto done;
6707 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
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;
6716 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6717 if (flags & ENV_MOD_MASK)
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);
6727 newval = msi_alloc(size);
6728 ptr = newval;
6729 if (!newval)
6731 res = ERROR_OUTOFMEMORY;
6732 goto done;
6735 if (flags & ENV_MOD_PREFIX)
6737 lstrcpyW(newval, value);
6738 ptr = newval + lstrlenW(value);
6739 action |= 0x80000000;
6742 lstrcpyW(ptr, data);
6744 if (flags & ENV_MOD_APPEND)
6746 lstrcatW(newval, value);
6747 action |= 0x40000000;
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)
6754 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
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 );
6765 if (env) RegCloseKey(env);
6766 msi_free(deformatted);
6767 msi_free(data);
6768 msi_free(newval);
6769 return res;
6772 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
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;
6780 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6781 if (rc != ERROR_SUCCESS)
6782 return ERROR_SUCCESS;
6784 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6785 msiobj_release(&view->hdr);
6786 return rc;
6789 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
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;
6802 component = MSI_RecordGetString( rec, 4 );
6803 comp = msi_get_loaded_component( package, component );
6804 if (!comp)
6805 return ERROR_SUCCESS;
6807 comp->Action = msi_get_component_action( package, comp );
6808 if (comp->Action != INSTALLSTATE_ABSENT)
6810 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6811 return ERROR_SUCCESS;
6813 name = MSI_RecordGetString( rec, 2 );
6814 value = MSI_RecordGetString( rec, 3 );
6816 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6818 r = env_parse_flags( &name, &value, &flags );
6819 if (r != ERROR_SUCCESS)
6820 return r;
6822 if (!(flags & ENV_ACT_REMOVE))
6824 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6825 return ERROR_SUCCESS;
6828 if (value && !deformat_string( package, value, &deformatted ))
6829 return ERROR_OUTOFMEMORY;
6831 value = deformatted;
6833 r = open_env_key( flags, &env );
6834 if (r != ERROR_SUCCESS)
6836 r = ERROR_SUCCESS;
6837 goto done;
6840 if (flags & ENV_MOD_MACHINE)
6841 action |= 0x20000000;
6843 TRACE("Removing %s\n", debugstr_w(name));
6845 res = RegDeleteValueW( env, name );
6846 if (res != ERROR_SUCCESS)
6848 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6849 r = ERROR_SUCCESS;
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 );
6860 if (env) RegCloseKey( env );
6861 msi_free( deformatted );
6862 return r;
6865 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
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;
6873 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6874 if (rc != ERROR_SUCCESS)
6875 return ERROR_SUCCESS;
6877 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6878 msiobj_release( &view->hdr );
6879 return rc;
6882 UINT msi_validate_product_id( MSIPACKAGE *package )
6884 LPWSTR key, template, id;
6885 UINT r = ERROR_SUCCESS;
6887 id = msi_dup_property( package->db, szProductID );
6888 if (id)
6890 msi_free( id );
6891 return ERROR_SUCCESS;
6893 template = msi_dup_property( package->db, szPIDTemplate );
6894 key = msi_dup_property( package->db, szPIDKEY );
6895 if (key && template)
6897 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6898 r = msi_set_property( package->db, szProductID, key );
6900 msi_free( template );
6901 msi_free( key );
6902 return r;
6905 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6907 return msi_validate_product_id( package );
6910 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6912 TRACE("\n");
6913 package->need_reboot_at_end = 1;
6914 return ERROR_SUCCESS;
6917 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
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 );
6924 TRACE("%p %d kilobytes\n", package, space);
6926 uirow = MSI_CreateRecord( 1 );
6927 MSI_RecordSetInteger( uirow, 1, space );
6928 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6929 msiobj_release( &uirow->hdr );
6931 return ERROR_SUCCESS;
6934 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6936 TRACE("%p\n", package);
6938 msi_set_property( package->db, szRollbackDisabled, szOne );
6939 return ERROR_SUCCESS;
6942 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6944 FIXME("%p\n", package);
6945 return ERROR_SUCCESS;
6948 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
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;
6959 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6960 if (r == ERROR_SUCCESS)
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);
6969 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6970 if (r == ERROR_SUCCESS)
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);
6979 return ERROR_SUCCESS;
6982 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6984 MSIPACKAGE *package = param;
6985 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6986 WCHAR *value;
6988 if ((value = msi_dup_property( package->db, property )))
6990 FIXME("remove %s\n", debugstr_w(value));
6991 msi_free( value );
6993 return ERROR_SUCCESS;
6996 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
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;
7004 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7005 if (r == ERROR_SUCCESS)
7007 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7008 msiobj_release( &view->hdr );
7009 if (r != ERROR_SUCCESS)
7010 return r;
7012 return ERROR_SUCCESS;
7015 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7017 MSIPACKAGE *package = param;
7018 int attributes = MSI_RecordGetInteger( rec, 5 );
7020 if (attributes & msidbUpgradeAttributesMigrateFeatures)
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;
7029 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7031 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7032 if (r != ERROR_SUCCESS)
7033 return ERROR_SUCCESS;
7035 else
7037 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7038 if (r != ERROR_SUCCESS)
7039 return ERROR_SUCCESS;
7041 RegCloseKey( hkey );
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));
7047 return ERROR_SUCCESS;
7050 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
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;
7058 if (msi_get_property_int( package->db, szInstalled, 0 ))
7060 TRACE("product is installed, skipping action\n");
7061 return ERROR_SUCCESS;
7063 if (msi_get_property_int( package->db, szPreselected, 0 ))
7065 TRACE("Preselected property is set, not migrating feature states\n");
7066 return ERROR_SUCCESS;
7068 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7069 if (r == ERROR_SUCCESS)
7071 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7072 msiobj_release( &view->hdr );
7073 if (r != ERROR_SUCCESS)
7074 return r;
7076 return ERROR_SUCCESS;
7079 static void bind_image( const char *filename, const char *path )
7081 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7083 WARN("failed to bind image %u\n", GetLastError());
7087 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
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;
7097 if (!(file = msi_get_loaded_file( package, key )))
7099 WARN("file %s not found\n", debugstr_w(key));
7100 return ERROR_SUCCESS;
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
7107 for (i = 0; path_list[i] && path_list[i][0]; i++)
7109 deformat_string( package, path_list[i], &pathW );
7110 if ((pathA = strdupWtoA( pathW )))
7112 bind_image( filenameA, pathA );
7113 msi_free( pathA );
7115 msi_free( pathW );
7118 msi_free( path_list );
7119 msi_free( filenameA );
7120 return ERROR_SUCCESS;
7123 static UINT ACTION_BindImage( MSIPACKAGE *package )
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;
7131 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7132 if (r == ERROR_SUCCESS)
7134 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7135 msiobj_release( &view->hdr );
7136 if (r != ERROR_SUCCESS)
7137 return r;
7139 return ERROR_SUCCESS;
7142 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
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;
7150 r = MSI_OpenQuery( package->db, &view, query, table );
7151 if (r == ERROR_SUCCESS)
7153 r = MSI_IterateRecords(view, &count, NULL, package);
7154 msiobj_release(&view->hdr);
7155 if (r != ERROR_SUCCESS)
7156 return r;
7158 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7159 return ERROR_SUCCESS;
7162 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
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 );
7169 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7171 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7172 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7175 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7177 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7178 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7181 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7183 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7184 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7187 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
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 );
7193 static const struct
7195 const WCHAR *action;
7196 UINT (*handler)(MSIPACKAGE *);
7197 const WCHAR *action_rollback;
7199 StandardActions[] =
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 }
7279 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7281 BOOL ret = FALSE;
7282 UINT i;
7284 i = 0;
7285 while (StandardActions[i].action != NULL)
7287 if (!strcmpW( StandardActions[i].action, action ))
7289 ui_actionstart( package, action );
7290 if (StandardActions[i].handler)
7292 ui_actioninfo( package, action, TRUE, 0 );
7293 *rc = StandardActions[i].handler( package );
7294 ui_actioninfo( package, action, FALSE, *rc );
7296 if (StandardActions[i].action_rollback && !package->need_rollback)
7298 TRACE("scheduling rollback action\n");
7299 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7302 else
7304 FIXME("unhandled standard action %s\n", debugstr_w(action));
7305 *rc = ERROR_SUCCESS;
7307 ret = TRUE;
7308 break;
7310 i++;
7312 return ret;
7315 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7317 UINT rc = ERROR_SUCCESS;
7318 BOOL handled;
7320 TRACE("Performing action (%s)\n", debugstr_w(action));
7322 handled = ACTION_HandleStandardAction(package, action, &rc);
7324 if (!handled)
7325 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7327 if (!handled)
7329 WARN("unhandled msi action %s\n", debugstr_w(action));
7330 rc = ERROR_FUNCTION_NOT_CALLED;
7333 return rc;
7336 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7338 UINT rc = ERROR_SUCCESS;
7339 BOOL handled = FALSE;
7341 TRACE("Performing action (%s)\n", debugstr_w(action));
7343 handled = ACTION_HandleStandardAction(package, action, &rc);
7345 if (!handled)
7346 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7348 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7349 handled = TRUE;
7351 if (!handled)
7353 WARN("unhandled msi action %s\n", debugstr_w(action));
7354 rc = ERROR_FUNCTION_NOT_CALLED;
7357 return rc;
7360 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7362 UINT rc = ERROR_SUCCESS;
7363 MSIRECORD *row;
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};
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);
7381 if (row)
7383 LPCWSTR action, cond;
7385 TRACE("Running the actions\n");
7387 /* check conditions */
7388 cond = MSI_RecordGetString(row, 2);
7390 /* this is a hack to skip errors in the condition code */
7391 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7393 msiobj_release(&row->hdr);
7394 return ERROR_SUCCESS;
7397 action = MSI_RecordGetString(row, 1);
7398 if (!action)
7400 ERR("failed to fetch action\n");
7401 msiobj_release(&row->hdr);
7402 return ERROR_FUNCTION_FAILED;
7405 if (needs_ui_sequence(package))
7406 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7407 else
7408 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7410 msiobj_release(&row->hdr);
7413 return rc;
7416 /****************************************************
7417 * TOP level entry points
7418 *****************************************************/
7420 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7421 LPCWSTR szCommandLine )
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;
7430 msi_set_property( package->db, szAction, szInstall );
7432 package->script->InWhatSequence = SEQUENCE_INSTALL;
7434 if (szPackagePath)
7436 LPWSTR p, dir;
7437 LPCWSTR file;
7439 dir = strdupW(szPackagePath);
7440 p = strrchrW(dir, '\\');
7441 if (p)
7443 *(++p) = 0;
7444 file = szPackagePath + (p - dir);
7446 else
7448 msi_free(dir);
7449 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7450 GetCurrentDirectoryW(MAX_PATH, dir);
7451 lstrcatW(dir, szBackSlash);
7452 file = szPackagePath;
7455 msi_free( package->PackagePath );
7456 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7457 if (!package->PackagePath)
7459 msi_free(dir);
7460 return ERROR_OUTOFMEMORY;
7463 lstrcpyW(package->PackagePath, dir);
7464 lstrcatW(package->PackagePath, file);
7465 msi_free(dir);
7467 msi_set_sourcedir_props(package, FALSE);
7470 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7471 if (rc != ERROR_SUCCESS)
7472 return rc;
7474 msi_apply_transforms( package );
7475 msi_apply_patches( package );
7477 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7479 TRACE("setting reinstall property\n");
7480 msi_set_property( package->db, szReinstall, szAll );
7483 /* properties may have been added by a transform */
7484 msi_clone_properties( package );
7486 msi_parse_command_line( package, szCommandLine, FALSE );
7487 msi_adjust_privilege_properties( package );
7488 msi_set_context( package );
7490 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7492 TRACE("disabling rollback\n");
7493 msi_set_property( package->db, szRollbackDisabled, szOne );
7496 if (needs_ui_sequence( package))
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)
7503 package->script->InWhatSequence |= SEQUENCE_EXEC;
7504 rc = ACTION_ProcessExecSequence(package, ui_exists);
7507 else
7508 rc = ACTION_ProcessExecSequence(package, FALSE);
7510 package->script->CurrentlyScripting = FALSE;
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 */
7521 ACTION_PerformActionSequence(package, -3);
7522 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7524 package->need_rollback = TRUE;
7528 /* finish up running custom actions */
7529 ACTION_FinishCustomActions(package);
7531 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
7533 WARN("installation failed, running rollback script\n");
7534 execute_script( package, SCRIPT_ROLLBACK );
7536 msi_free( reinstall );
7538 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7539 return ERROR_SUCCESS_REBOOT_REQUIRED;
7541 return rc;