po: Update Japanese translation.
[wine/multimedia.git] / dlls / msi / action.c
blobec008867b2d9e679d7b0e86500c2b91a6f34d4f6
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 BOOL is_special_entry( const WCHAR *name, const WCHAR *value )
2583 return (name && (name[0] == '*' || name[0] == '+') && !name[1] && !value);
2586 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2588 MSIPACKAGE *package = param;
2589 LPSTR value_data = NULL;
2590 HKEY root_key, hkey;
2591 DWORD type,size;
2592 LPWSTR deformated, uikey, keypath;
2593 LPCWSTR szRoot, component, name, key, value;
2594 MSICOMPONENT *comp;
2595 MSIRECORD * uirow;
2596 INT root;
2597 BOOL check_first = FALSE;
2598 UINT rc;
2600 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2602 component = MSI_RecordGetString(row, 6);
2603 comp = msi_get_loaded_component(package,component);
2604 if (!comp)
2605 return ERROR_SUCCESS;
2607 comp->Action = msi_get_component_action( package, comp );
2608 if (comp->Action != INSTALLSTATE_LOCAL)
2610 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2611 return ERROR_SUCCESS;
2614 name = MSI_RecordGetString(row, 4);
2615 if( MSI_RecordIsNull(row,5) && name )
2617 /* null values can have special meanings */
2618 if (name[0]=='-' && name[1] == 0)
2619 return ERROR_SUCCESS;
2620 if ((name[0] == '+' || name[0] == '*') && !name[1])
2621 check_first = TRUE;
2624 root = MSI_RecordGetInteger(row,2);
2625 key = MSI_RecordGetString(row, 3);
2627 szRoot = get_root_key( package, root, &root_key );
2628 if (!szRoot)
2629 return ERROR_SUCCESS;
2631 deformat_string(package, key , &deformated);
2632 size = strlenW(deformated) + strlenW(szRoot) + 1;
2633 uikey = msi_alloc(size*sizeof(WCHAR));
2634 strcpyW(uikey,szRoot);
2635 strcatW(uikey,deformated);
2637 keypath = get_keypath( package, root_key, deformated );
2638 msi_free( deformated );
2639 if (RegCreateKeyW( root_key, keypath, &hkey ))
2641 ERR("Could not create key %s\n", debugstr_w(keypath));
2642 msi_free(uikey);
2643 msi_free(keypath);
2644 return ERROR_SUCCESS;
2647 value = MSI_RecordGetString(row,5);
2648 if (value)
2649 value_data = parse_value(package, value, &type, &size);
2650 else
2652 value_data = (LPSTR)strdupW(szEmpty);
2653 size = sizeof(szEmpty);
2654 type = REG_SZ;
2657 deformat_string(package, name, &deformated);
2658 if (!is_special_entry( name , value ))
2660 if (!check_first)
2662 TRACE("Setting value %s of %s\n", debugstr_w(deformated),
2663 debugstr_w(uikey));
2664 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2666 else
2668 DWORD sz = 0;
2669 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2670 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2672 TRACE("value %s of %s checked already exists\n", debugstr_w(deformated),
2673 debugstr_w(uikey));
2675 else
2677 TRACE("Checked and setting value %s of %s\n", debugstr_w(deformated),
2678 debugstr_w(uikey));
2679 if (deformated || size)
2680 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2684 RegCloseKey(hkey);
2686 uirow = MSI_CreateRecord(3);
2687 MSI_RecordSetStringW(uirow,2,deformated);
2688 MSI_RecordSetStringW(uirow,1,uikey);
2689 if (type == REG_SZ || type == REG_EXPAND_SZ)
2690 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2691 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2692 msiobj_release( &uirow->hdr );
2694 msi_free(value_data);
2695 msi_free(deformated);
2696 msi_free(uikey);
2697 msi_free(keypath);
2699 return ERROR_SUCCESS;
2702 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2704 static const WCHAR query[] = {
2705 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2706 '`','R','e','g','i','s','t','r','y','`',0};
2707 MSIQUERY *view;
2708 UINT rc;
2710 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
2711 if (rc != ERROR_SUCCESS)
2712 return ERROR_SUCCESS;
2714 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2715 msiobj_release(&view->hdr);
2716 return rc;
2719 static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *value )
2721 LONG res;
2722 HKEY hkey;
2723 DWORD num_subkeys, num_values;
2725 if (!(res = RegOpenKeyW( root, keypath, &hkey )))
2727 if ((res = RegDeleteValueW( hkey, value )))
2729 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
2731 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2732 NULL, NULL, NULL, NULL );
2733 RegCloseKey( hkey );
2734 if (!res && !num_subkeys && !num_values)
2736 TRACE("removing empty key %s\n", debugstr_w(keypath));
2737 RegDeleteKeyW( root, keypath );
2739 return;
2741 TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
2744 static void delete_reg_key( HKEY root, const WCHAR *keypath )
2746 LONG res = RegDeleteTreeW( root, keypath );
2747 if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res);
2750 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2752 MSIPACKAGE *package = param;
2753 LPCWSTR component, name, key_str, root_key_str;
2754 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2755 MSICOMPONENT *comp;
2756 MSIRECORD *uirow;
2757 BOOL delete_key = FALSE;
2758 HKEY hkey_root;
2759 UINT size;
2760 INT root;
2762 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2764 component = MSI_RecordGetString( row, 6 );
2765 comp = msi_get_loaded_component( package, component );
2766 if (!comp)
2767 return ERROR_SUCCESS;
2769 comp->Action = msi_get_component_action( package, comp );
2770 if (comp->Action != INSTALLSTATE_ABSENT)
2772 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2773 return ERROR_SUCCESS;
2776 name = MSI_RecordGetString( row, 4 );
2777 if (MSI_RecordIsNull( row, 5 ) && name )
2779 if (name[0] == '+' && !name[1])
2780 return ERROR_SUCCESS;
2781 if ((name[0] == '-' || name[0] == '*') && !name[1])
2783 delete_key = TRUE;
2784 name = NULL;
2788 root = MSI_RecordGetInteger( row, 2 );
2789 key_str = MSI_RecordGetString( row, 3 );
2791 root_key_str = get_root_key( package, root, &hkey_root );
2792 if (!root_key_str)
2793 return ERROR_SUCCESS;
2795 deformat_string( package, key_str, &deformated_key );
2796 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2797 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2798 strcpyW( ui_key_str, root_key_str );
2799 strcatW( ui_key_str, deformated_key );
2801 deformat_string( package, name, &deformated_name );
2803 keypath = get_keypath( package, hkey_root, deformated_key );
2804 msi_free( deformated_key );
2805 if (delete_key) delete_reg_key( hkey_root, keypath );
2806 else delete_reg_value( hkey_root, keypath, deformated_name );
2807 msi_free( keypath );
2809 uirow = MSI_CreateRecord( 2 );
2810 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2811 MSI_RecordSetStringW( uirow, 2, deformated_name );
2812 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2813 msiobj_release( &uirow->hdr );
2815 msi_free( ui_key_str );
2816 msi_free( deformated_name );
2817 return ERROR_SUCCESS;
2820 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2822 MSIPACKAGE *package = param;
2823 LPCWSTR component, name, key_str, root_key_str;
2824 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2825 MSICOMPONENT *comp;
2826 MSIRECORD *uirow;
2827 BOOL delete_key = FALSE;
2828 HKEY hkey_root;
2829 UINT size;
2830 INT root;
2832 component = MSI_RecordGetString( row, 5 );
2833 comp = msi_get_loaded_component( package, component );
2834 if (!comp)
2835 return ERROR_SUCCESS;
2837 comp->Action = msi_get_component_action( package, comp );
2838 if (comp->Action != INSTALLSTATE_LOCAL)
2840 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2841 return ERROR_SUCCESS;
2844 if ((name = MSI_RecordGetString( row, 4 )))
2846 if (name[0] == '-' && !name[1])
2848 delete_key = TRUE;
2849 name = NULL;
2853 root = MSI_RecordGetInteger( row, 2 );
2854 key_str = MSI_RecordGetString( row, 3 );
2856 root_key_str = get_root_key( package, root, &hkey_root );
2857 if (!root_key_str)
2858 return ERROR_SUCCESS;
2860 deformat_string( package, key_str, &deformated_key );
2861 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2862 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2863 strcpyW( ui_key_str, root_key_str );
2864 strcatW( ui_key_str, deformated_key );
2866 deformat_string( package, name, &deformated_name );
2868 keypath = get_keypath( package, hkey_root, deformated_key );
2869 msi_free( deformated_key );
2870 if (delete_key) delete_reg_key( hkey_root, keypath );
2871 else delete_reg_value( hkey_root, keypath, deformated_name );
2872 msi_free( keypath );
2874 uirow = MSI_CreateRecord( 2 );
2875 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2876 MSI_RecordSetStringW( uirow, 2, deformated_name );
2877 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2878 msiobj_release( &uirow->hdr );
2880 msi_free( ui_key_str );
2881 msi_free( deformated_name );
2882 return ERROR_SUCCESS;
2885 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2887 static const WCHAR registry_query[] = {
2888 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2889 '`','R','e','g','i','s','t','r','y','`',0};
2890 static const WCHAR remove_registry_query[] = {
2891 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2892 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
2893 MSIQUERY *view;
2894 UINT rc;
2896 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2897 if (rc == ERROR_SUCCESS)
2899 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2900 msiobj_release( &view->hdr );
2901 if (rc != ERROR_SUCCESS)
2902 return rc;
2904 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2905 if (rc == ERROR_SUCCESS)
2907 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2908 msiobj_release( &view->hdr );
2909 if (rc != ERROR_SUCCESS)
2910 return rc;
2912 return ERROR_SUCCESS;
2915 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2917 package->script->CurrentlyScripting = TRUE;
2919 return ERROR_SUCCESS;
2923 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2925 static const WCHAR query[]= {
2926 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2927 '`','R','e','g','i','s','t','r','y','`',0};
2928 MSICOMPONENT *comp;
2929 DWORD total = 0, count = 0;
2930 MSIQUERY *view;
2931 MSIFEATURE *feature;
2932 MSIFILE *file;
2933 UINT rc;
2935 TRACE("InstallValidate\n");
2937 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
2938 if (rc == ERROR_SUCCESS)
2940 rc = MSI_IterateRecords( view, &count, NULL, package );
2941 msiobj_release( &view->hdr );
2942 if (rc != ERROR_SUCCESS)
2943 return rc;
2944 total += count * REG_PROGRESS_VALUE;
2946 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2947 total += COMPONENT_PROGRESS_VALUE;
2949 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2950 total += file->FileSize;
2952 msi_ui_progress( package, 0, total, 0, 0 );
2954 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2956 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2957 debugstr_w(feature->Feature), feature->Installed,
2958 feature->ActionRequest, feature->Action);
2960 return ERROR_SUCCESS;
2963 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2965 MSIPACKAGE* package = param;
2966 LPCWSTR cond = NULL;
2967 LPCWSTR message = NULL;
2968 UINT r;
2970 static const WCHAR title[]=
2971 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2973 cond = MSI_RecordGetString(row,1);
2975 r = MSI_EvaluateConditionW(package,cond);
2976 if (r == MSICONDITION_FALSE)
2978 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2980 LPWSTR deformated;
2981 message = MSI_RecordGetString(row,2);
2982 deformat_string(package,message,&deformated);
2983 MessageBoxW(NULL,deformated,title,MB_OK);
2984 msi_free(deformated);
2987 return ERROR_INSTALL_FAILURE;
2990 return ERROR_SUCCESS;
2993 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2995 static const WCHAR query[] = {
2996 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2997 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2998 MSIQUERY *view;
2999 UINT rc;
3001 TRACE("Checking launch conditions\n");
3003 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3004 if (rc != ERROR_SUCCESS)
3005 return ERROR_SUCCESS;
3007 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3008 msiobj_release(&view->hdr);
3009 return rc;
3012 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3015 if (!cmp->KeyPath)
3016 return strdupW( msi_get_target_folder( package, cmp->Directory ) );
3018 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3020 static const WCHAR query[] = {
3021 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3022 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
3023 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
3024 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
3025 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3026 MSIRECORD *row;
3027 UINT root, len;
3028 LPWSTR deformated, buffer, deformated_name;
3029 LPCWSTR key, name;
3031 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
3032 if (!row)
3033 return NULL;
3035 root = MSI_RecordGetInteger(row,2);
3036 key = MSI_RecordGetString(row, 3);
3037 name = MSI_RecordGetString(row, 4);
3038 deformat_string(package, key , &deformated);
3039 deformat_string(package, name, &deformated_name);
3041 len = strlenW(deformated) + 6;
3042 if (deformated_name)
3043 len+=strlenW(deformated_name);
3045 buffer = msi_alloc( len *sizeof(WCHAR));
3047 if (deformated_name)
3048 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3049 else
3050 sprintfW(buffer,fmt,root,deformated);
3052 msi_free(deformated);
3053 msi_free(deformated_name);
3054 msiobj_release(&row->hdr);
3056 return buffer;
3058 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3060 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3061 return NULL;
3063 else
3065 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3067 if (file)
3068 return strdupW( file->TargetPath );
3070 return NULL;
3073 static HKEY openSharedDLLsKey(void)
3075 HKEY hkey=0;
3076 static const WCHAR path[] =
3077 {'S','o','f','t','w','a','r','e','\\',
3078 'M','i','c','r','o','s','o','f','t','\\',
3079 'W','i','n','d','o','w','s','\\',
3080 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3081 'S','h','a','r','e','d','D','L','L','s',0};
3083 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3084 return hkey;
3087 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3089 HKEY hkey;
3090 DWORD count=0;
3091 DWORD type;
3092 DWORD sz = sizeof(count);
3093 DWORD rc;
3095 hkey = openSharedDLLsKey();
3096 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3097 if (rc != ERROR_SUCCESS)
3098 count = 0;
3099 RegCloseKey(hkey);
3100 return count;
3103 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3105 HKEY hkey;
3107 hkey = openSharedDLLsKey();
3108 if (count > 0)
3109 msi_reg_set_val_dword( hkey, path, count );
3110 else
3111 RegDeleteValueW(hkey,path);
3112 RegCloseKey(hkey);
3113 return count;
3116 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3118 MSIFEATURE *feature;
3119 INT count = 0;
3120 BOOL write = FALSE;
3122 /* only refcount DLLs */
3123 if (comp->KeyPath == NULL ||
3124 comp->assembly ||
3125 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3126 comp->Attributes & msidbComponentAttributesODBCDataSource)
3127 write = FALSE;
3128 else
3130 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3131 write = (count > 0);
3133 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3134 write = TRUE;
3137 /* increment counts */
3138 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3140 ComponentList *cl;
3142 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3143 continue;
3145 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3147 if ( cl->component == comp )
3148 count++;
3152 /* decrement counts */
3153 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3155 ComponentList *cl;
3157 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3158 continue;
3160 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3162 if ( cl->component == comp )
3163 count--;
3167 /* ref count all the files in the component */
3168 if (write)
3170 MSIFILE *file;
3172 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3174 if (file->Component == comp)
3175 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3179 /* add a count for permanent */
3180 if (comp->Attributes & msidbComponentAttributesPermanent)
3181 count ++;
3183 comp->RefCount = count;
3185 if (write)
3186 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3189 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3191 if (comp->assembly)
3193 const WCHAR prefixW[] = {'<','\\',0};
3194 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3195 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3197 if (keypath)
3199 strcpyW( keypath, prefixW );
3200 strcatW( keypath, comp->assembly->display_name );
3202 return keypath;
3204 return resolve_keypath( package, comp );
3207 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3209 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3210 UINT rc;
3211 MSICOMPONENT *comp;
3212 HKEY hkey;
3214 TRACE("\n");
3216 squash_guid(package->ProductCode,squished_pc);
3217 msi_set_sourcedir_props(package, FALSE);
3219 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3221 MSIRECORD *uirow;
3222 INSTALLSTATE action;
3224 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3225 if (!comp->ComponentId)
3226 continue;
3228 squash_guid( comp->ComponentId, squished_cc );
3229 msi_free( comp->FullKeypath );
3230 comp->FullKeypath = build_full_keypath( package, comp );
3232 ACTION_RefCountComponent( package, comp );
3234 if (package->need_rollback) action = comp->Installed;
3235 else action = comp->ActionRequest;
3237 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3238 debugstr_w(comp->Component), debugstr_w(squished_cc),
3239 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3241 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3243 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3244 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3245 else
3246 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3248 if (rc != ERROR_SUCCESS)
3249 continue;
3251 if (comp->Attributes & msidbComponentAttributesPermanent)
3253 static const WCHAR szPermKey[] =
3254 { '0','0','0','0','0','0','0','0','0','0','0','0',
3255 '0','0','0','0','0','0','0','0','0','0','0','0',
3256 '0','0','0','0','0','0','0','0',0 };
3258 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3260 if (action == INSTALLSTATE_LOCAL)
3261 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3262 else
3264 MSIFILE *file;
3265 MSIRECORD *row;
3266 LPWSTR ptr, ptr2;
3267 WCHAR source[MAX_PATH];
3268 WCHAR base[MAX_PATH];
3269 LPWSTR sourcepath;
3271 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3272 static const WCHAR query[] = {
3273 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3274 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3275 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3276 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3277 '`','D','i','s','k','I','d','`',0};
3279 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3280 continue;
3282 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3283 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3284 ptr2 = strrchrW(source, '\\') + 1;
3285 msiobj_release(&row->hdr);
3287 lstrcpyW(base, package->PackagePath);
3288 ptr = strrchrW(base, '\\');
3289 *(ptr + 1) = '\0';
3291 sourcepath = msi_resolve_file_source(package, file);
3292 ptr = sourcepath + lstrlenW(base);
3293 lstrcpyW(ptr2, ptr);
3294 msi_free(sourcepath);
3296 msi_reg_set_val_str(hkey, squished_pc, source);
3298 RegCloseKey(hkey);
3300 else if (action == INSTALLSTATE_ABSENT)
3302 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3303 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3304 else
3305 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3308 /* UI stuff */
3309 uirow = MSI_CreateRecord(3);
3310 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3311 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3312 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3313 msi_ui_actiondata( package, szProcessComponents, uirow );
3314 msiobj_release( &uirow->hdr );
3316 return ERROR_SUCCESS;
3319 typedef struct {
3320 CLSID clsid;
3321 LPWSTR source;
3323 LPWSTR path;
3324 ITypeLib *ptLib;
3325 } typelib_struct;
3327 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3328 LPWSTR lpszName, LONG_PTR lParam)
3330 TLIBATTR *attr;
3331 typelib_struct *tl_struct = (typelib_struct*) lParam;
3332 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3333 int sz;
3334 HRESULT res;
3336 if (!IS_INTRESOURCE(lpszName))
3338 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3339 return TRUE;
3342 sz = strlenW(tl_struct->source)+4;
3343 sz *= sizeof(WCHAR);
3345 if ((INT_PTR)lpszName == 1)
3346 tl_struct->path = strdupW(tl_struct->source);
3347 else
3349 tl_struct->path = msi_alloc(sz);
3350 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3353 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3354 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3355 if (FAILED(res))
3357 msi_free(tl_struct->path);
3358 tl_struct->path = NULL;
3360 return TRUE;
3363 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3364 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3366 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3367 return FALSE;
3370 msi_free(tl_struct->path);
3371 tl_struct->path = NULL;
3373 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3374 ITypeLib_Release(tl_struct->ptLib);
3376 return TRUE;
3379 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3381 MSIPACKAGE* package = param;
3382 LPCWSTR component;
3383 MSICOMPONENT *comp;
3384 MSIFILE *file;
3385 typelib_struct tl_struct;
3386 ITypeLib *tlib;
3387 HMODULE module;
3388 HRESULT hr;
3390 component = MSI_RecordGetString(row,3);
3391 comp = msi_get_loaded_component(package,component);
3392 if (!comp)
3393 return ERROR_SUCCESS;
3395 comp->Action = msi_get_component_action( package, comp );
3396 if (comp->Action != INSTALLSTATE_LOCAL)
3398 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3399 return ERROR_SUCCESS;
3402 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3404 TRACE("component has no key path\n");
3405 return ERROR_SUCCESS;
3407 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3409 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3410 if (module)
3412 LPCWSTR guid;
3413 guid = MSI_RecordGetString(row,1);
3414 CLSIDFromString( guid, &tl_struct.clsid);
3415 tl_struct.source = strdupW( file->TargetPath );
3416 tl_struct.path = NULL;
3418 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3419 (LONG_PTR)&tl_struct);
3421 if (tl_struct.path)
3423 LPCWSTR helpid, help_path = NULL;
3424 HRESULT res;
3426 helpid = MSI_RecordGetString(row,6);
3428 if (helpid) help_path = msi_get_target_folder( package, helpid );
3429 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3431 if (FAILED(res))
3432 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3433 else
3434 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3436 ITypeLib_Release(tl_struct.ptLib);
3437 msi_free(tl_struct.path);
3439 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3441 FreeLibrary(module);
3442 msi_free(tl_struct.source);
3444 else
3446 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3447 if (FAILED(hr))
3449 ERR("Failed to load type library: %08x\n", hr);
3450 return ERROR_INSTALL_FAILURE;
3453 ITypeLib_Release(tlib);
3456 return ERROR_SUCCESS;
3459 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3461 static const WCHAR query[] = {
3462 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3463 '`','T','y','p','e','L','i','b','`',0};
3464 MSIQUERY *view;
3465 UINT rc;
3467 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3468 if (rc != ERROR_SUCCESS)
3469 return ERROR_SUCCESS;
3471 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3472 msiobj_release(&view->hdr);
3473 return rc;
3476 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3478 MSIPACKAGE *package = param;
3479 LPCWSTR component, guid;
3480 MSICOMPONENT *comp;
3481 GUID libid;
3482 UINT version;
3483 LCID language;
3484 SYSKIND syskind;
3485 HRESULT hr;
3487 component = MSI_RecordGetString( row, 3 );
3488 comp = msi_get_loaded_component( package, component );
3489 if (!comp)
3490 return ERROR_SUCCESS;
3492 comp->Action = msi_get_component_action( package, comp );
3493 if (comp->Action != INSTALLSTATE_ABSENT)
3495 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3496 return ERROR_SUCCESS;
3498 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3500 guid = MSI_RecordGetString( row, 1 );
3501 CLSIDFromString( guid, &libid );
3502 version = MSI_RecordGetInteger( row, 4 );
3503 language = MSI_RecordGetInteger( row, 2 );
3505 #ifdef _WIN64
3506 syskind = SYS_WIN64;
3507 #else
3508 syskind = SYS_WIN32;
3509 #endif
3511 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3512 if (FAILED(hr))
3514 WARN("Failed to unregister typelib: %08x\n", hr);
3517 return ERROR_SUCCESS;
3520 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3522 static const WCHAR query[] = {
3523 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3524 '`','T','y','p','e','L','i','b','`',0};
3525 MSIQUERY *view;
3526 UINT rc;
3528 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3529 if (rc != ERROR_SUCCESS)
3530 return ERROR_SUCCESS;
3532 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3533 msiobj_release( &view->hdr );
3534 return rc;
3537 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3539 static const WCHAR szlnk[] = {'.','l','n','k',0};
3540 LPCWSTR directory, extension, link_folder;
3541 LPWSTR link_file, filename;
3543 directory = MSI_RecordGetString( row, 2 );
3544 link_folder = msi_get_target_folder( package, directory );
3545 if (!link_folder)
3547 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3548 return NULL;
3550 /* may be needed because of a bug somewhere else */
3551 msi_create_full_path( link_folder );
3553 filename = msi_dup_record_field( row, 3 );
3554 msi_reduce_to_long_filename( filename );
3556 extension = strchrW( filename, '.' );
3557 if (!extension || strcmpiW( extension, szlnk ))
3559 int len = strlenW( filename );
3560 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3561 memcpy( filename + len, szlnk, sizeof(szlnk) );
3563 link_file = msi_build_directory_name( 2, link_folder, filename );
3564 msi_free( filename );
3566 return link_file;
3569 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3571 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3572 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3573 WCHAR *folder, *dest, *path;
3575 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3576 folder = msi_dup_property( package->db, szWindowsFolder );
3577 else
3579 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3580 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3581 msi_free( appdata );
3583 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3584 msi_create_full_path( dest );
3585 path = msi_build_directory_name( 2, dest, icon_name );
3586 msi_free( folder );
3587 msi_free( dest );
3588 return path;
3591 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3593 MSIPACKAGE *package = param;
3594 LPWSTR link_file, deformated, path;
3595 LPCWSTR component, target;
3596 MSICOMPONENT *comp;
3597 IShellLinkW *sl = NULL;
3598 IPersistFile *pf = NULL;
3599 HRESULT res;
3601 component = MSI_RecordGetString(row, 4);
3602 comp = msi_get_loaded_component(package, component);
3603 if (!comp)
3604 return ERROR_SUCCESS;
3606 comp->Action = msi_get_component_action( package, comp );
3607 if (comp->Action != INSTALLSTATE_LOCAL)
3609 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3610 return ERROR_SUCCESS;
3612 msi_ui_actiondata( package, szCreateShortcuts, row );
3614 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3615 &IID_IShellLinkW, (LPVOID *) &sl );
3617 if (FAILED( res ))
3619 ERR("CLSID_ShellLink not available\n");
3620 goto err;
3623 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3624 if (FAILED( res ))
3626 ERR("QueryInterface(IID_IPersistFile) failed\n");
3627 goto err;
3630 target = MSI_RecordGetString(row, 5);
3631 if (strchrW(target, '['))
3633 deformat_string( package, target, &path );
3634 TRACE("target path is %s\n", debugstr_w(path));
3635 IShellLinkW_SetPath( sl, path );
3636 msi_free( path );
3638 else
3640 FIXME("poorly handled shortcut format, advertised shortcut\n");
3641 IShellLinkW_SetPath(sl,comp->FullKeypath);
3644 if (!MSI_RecordIsNull(row,6))
3646 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3647 deformat_string(package, arguments, &deformated);
3648 IShellLinkW_SetArguments(sl,deformated);
3649 msi_free(deformated);
3652 if (!MSI_RecordIsNull(row,7))
3654 LPCWSTR description = MSI_RecordGetString(row, 7);
3655 IShellLinkW_SetDescription(sl, description);
3658 if (!MSI_RecordIsNull(row,8))
3659 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3661 if (!MSI_RecordIsNull(row,9))
3663 INT index;
3664 LPCWSTR icon = MSI_RecordGetString(row, 9);
3666 path = msi_build_icon_path(package, icon);
3667 index = MSI_RecordGetInteger(row,10);
3669 /* no value means 0 */
3670 if (index == MSI_NULL_INTEGER)
3671 index = 0;
3673 IShellLinkW_SetIconLocation(sl, path, index);
3674 msi_free(path);
3677 if (!MSI_RecordIsNull(row,11))
3678 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3680 if (!MSI_RecordIsNull(row,12))
3682 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3683 full_path = msi_get_target_folder( package, wkdir );
3684 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3686 link_file = get_link_file(package, row);
3688 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3689 IPersistFile_Save(pf, link_file, FALSE);
3690 msi_free(link_file);
3692 err:
3693 if (pf)
3694 IPersistFile_Release( pf );
3695 if (sl)
3696 IShellLinkW_Release( sl );
3698 return ERROR_SUCCESS;
3701 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3703 static const WCHAR query[] = {
3704 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3705 '`','S','h','o','r','t','c','u','t','`',0};
3706 MSIQUERY *view;
3707 HRESULT res;
3708 UINT rc;
3710 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3711 if (rc != ERROR_SUCCESS)
3712 return ERROR_SUCCESS;
3714 res = CoInitialize( NULL );
3716 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3717 msiobj_release(&view->hdr);
3719 if (SUCCEEDED(res)) CoUninitialize();
3720 return rc;
3723 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3725 MSIPACKAGE *package = param;
3726 LPWSTR link_file;
3727 LPCWSTR component;
3728 MSICOMPONENT *comp;
3730 component = MSI_RecordGetString( row, 4 );
3731 comp = msi_get_loaded_component( package, component );
3732 if (!comp)
3733 return ERROR_SUCCESS;
3735 comp->Action = msi_get_component_action( package, comp );
3736 if (comp->Action != INSTALLSTATE_ABSENT)
3738 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3739 return ERROR_SUCCESS;
3741 msi_ui_actiondata( package, szRemoveShortcuts, row );
3743 link_file = get_link_file( package, row );
3745 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3746 if (!DeleteFileW( link_file ))
3748 WARN("Failed to remove shortcut file %u\n", GetLastError());
3750 msi_free( link_file );
3752 return ERROR_SUCCESS;
3755 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3757 static const WCHAR query[] = {
3758 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3759 '`','S','h','o','r','t','c','u','t','`',0};
3760 MSIQUERY *view;
3761 UINT rc;
3763 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3764 if (rc != ERROR_SUCCESS)
3765 return ERROR_SUCCESS;
3767 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3768 msiobj_release( &view->hdr );
3769 return rc;
3772 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3774 MSIPACKAGE* package = param;
3775 HANDLE the_file;
3776 LPWSTR FilePath;
3777 LPCWSTR FileName;
3778 CHAR buffer[1024];
3779 DWORD sz;
3780 UINT rc;
3782 FileName = MSI_RecordGetString(row,1);
3783 if (!FileName)
3785 ERR("Unable to get FileName\n");
3786 return ERROR_SUCCESS;
3789 FilePath = msi_build_icon_path(package, FileName);
3791 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3793 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3794 FILE_ATTRIBUTE_NORMAL, NULL);
3796 if (the_file == INVALID_HANDLE_VALUE)
3798 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3799 msi_free(FilePath);
3800 return ERROR_SUCCESS;
3805 DWORD write;
3806 sz = 1024;
3807 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3808 if (rc != ERROR_SUCCESS)
3810 ERR("Failed to get stream\n");
3811 CloseHandle(the_file);
3812 DeleteFileW(FilePath);
3813 break;
3815 WriteFile(the_file,buffer,sz,&write,NULL);
3816 } while (sz == 1024);
3818 msi_free(FilePath);
3819 CloseHandle(the_file);
3821 return ERROR_SUCCESS;
3824 static UINT msi_publish_icons(MSIPACKAGE *package)
3826 static const WCHAR query[]= {
3827 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3828 '`','I','c','o','n','`',0};
3829 MSIQUERY *view;
3830 UINT r;
3832 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3833 if (r == ERROR_SUCCESS)
3835 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3836 msiobj_release(&view->hdr);
3837 if (r != ERROR_SUCCESS)
3838 return r;
3840 return ERROR_SUCCESS;
3843 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3845 UINT r;
3846 HKEY source;
3847 LPWSTR buffer;
3848 MSIMEDIADISK *disk;
3849 MSISOURCELISTINFO *info;
3851 r = RegCreateKeyW(hkey, szSourceList, &source);
3852 if (r != ERROR_SUCCESS)
3853 return r;
3855 RegCloseKey(source);
3857 buffer = strrchrW(package->PackagePath, '\\') + 1;
3858 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3859 package->Context, MSICODE_PRODUCT,
3860 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3861 if (r != ERROR_SUCCESS)
3862 return r;
3864 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3865 package->Context, MSICODE_PRODUCT,
3866 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3867 if (r != ERROR_SUCCESS)
3868 return r;
3870 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3871 package->Context, MSICODE_PRODUCT,
3872 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3873 if (r != ERROR_SUCCESS)
3874 return r;
3876 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3878 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3879 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3880 info->options, info->value);
3881 else
3882 MsiSourceListSetInfoW(package->ProductCode, NULL,
3883 info->context, info->options,
3884 info->property, info->value);
3887 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3889 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3890 disk->context, disk->options,
3891 disk->disk_id, disk->volume_label, disk->disk_prompt);
3894 return ERROR_SUCCESS;
3897 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3899 MSIHANDLE hdb, suminfo;
3900 WCHAR guids[MAX_PATH];
3901 WCHAR packcode[SQUISH_GUID_SIZE];
3902 LPWSTR buffer;
3903 LPWSTR ptr;
3904 DWORD langid;
3905 DWORD size;
3906 UINT r;
3908 static const WCHAR szARPProductIcon[] =
3909 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3910 static const WCHAR szAssignment[] =
3911 {'A','s','s','i','g','n','m','e','n','t',0};
3912 static const WCHAR szAdvertiseFlags[] =
3913 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3914 static const WCHAR szClients[] =
3915 {'C','l','i','e','n','t','s',0};
3916 static const WCHAR szColon[] = {':',0};
3918 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3919 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3920 msi_free(buffer);
3922 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3923 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3925 /* FIXME */
3926 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3928 buffer = msi_dup_property(package->db, szARPProductIcon);
3929 if (buffer)
3931 LPWSTR path = msi_build_icon_path(package, buffer);
3932 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3933 msi_free(path);
3934 msi_free(buffer);
3937 buffer = msi_dup_property(package->db, szProductVersion);
3938 if (buffer)
3940 DWORD verdword = msi_version_str_to_dword(buffer);
3941 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3942 msi_free(buffer);
3945 msi_reg_set_val_dword(hkey, szAssignment, 0);
3946 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3947 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3948 msi_reg_set_val_str(hkey, szClients, szColon);
3950 hdb = alloc_msihandle(&package->db->hdr);
3951 if (!hdb)
3952 return ERROR_NOT_ENOUGH_MEMORY;
3954 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3955 MsiCloseHandle(hdb);
3956 if (r != ERROR_SUCCESS)
3957 goto done;
3959 size = MAX_PATH;
3960 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3961 NULL, guids, &size);
3962 if (r != ERROR_SUCCESS)
3963 goto done;
3965 ptr = strchrW(guids, ';');
3966 if (ptr) *ptr = 0;
3967 squash_guid(guids, packcode);
3968 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3970 done:
3971 MsiCloseHandle(suminfo);
3972 return ERROR_SUCCESS;
3975 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3977 UINT r;
3978 HKEY hkey;
3979 LPWSTR upgrade;
3980 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3982 upgrade = msi_dup_property(package->db, szUpgradeCode);
3983 if (!upgrade)
3984 return ERROR_SUCCESS;
3986 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3987 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3988 else
3989 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3991 if (r != ERROR_SUCCESS)
3993 WARN("failed to open upgrade code key\n");
3994 msi_free(upgrade);
3995 return ERROR_SUCCESS;
3997 squash_guid(package->ProductCode, squashed_pc);
3998 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3999 RegCloseKey(hkey);
4000 msi_free(upgrade);
4001 return ERROR_SUCCESS;
4004 static BOOL msi_check_publish(MSIPACKAGE *package)
4006 MSIFEATURE *feature;
4008 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4010 feature->Action = msi_get_feature_action( package, feature );
4011 if (feature->Action == INSTALLSTATE_LOCAL)
4012 return TRUE;
4015 return FALSE;
4018 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4020 MSIFEATURE *feature;
4022 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4024 feature->Action = msi_get_feature_action( package, feature );
4025 if (feature->Action != INSTALLSTATE_ABSENT)
4026 return FALSE;
4029 return TRUE;
4032 static UINT msi_publish_patches( MSIPACKAGE *package )
4034 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4035 WCHAR patch_squashed[GUID_SIZE];
4036 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4037 LONG res;
4038 MSIPATCHINFO *patch;
4039 UINT r;
4040 WCHAR *p, *all_patches = NULL;
4041 DWORD len = 0;
4043 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4044 if (r != ERROR_SUCCESS)
4045 return ERROR_FUNCTION_FAILED;
4047 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4048 if (res != ERROR_SUCCESS)
4050 r = ERROR_FUNCTION_FAILED;
4051 goto done;
4054 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4055 if (r != ERROR_SUCCESS)
4056 goto done;
4058 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4060 squash_guid( patch->patchcode, patch_squashed );
4061 len += strlenW( patch_squashed ) + 1;
4064 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4065 if (!all_patches)
4066 goto done;
4068 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4070 HKEY patch_key;
4072 squash_guid( patch->patchcode, p );
4073 p += strlenW( p ) + 1;
4075 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4076 (const BYTE *)patch->transforms,
4077 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4078 if (res != ERROR_SUCCESS)
4079 goto done;
4081 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4082 if (r != ERROR_SUCCESS)
4083 goto done;
4085 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4086 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4087 RegCloseKey( patch_key );
4088 if (res != ERROR_SUCCESS)
4089 goto done;
4091 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4093 res = GetLastError();
4094 ERR("Unable to copy patch package %d\n", res);
4095 goto done;
4097 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4098 if (res != ERROR_SUCCESS)
4099 goto done;
4101 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4102 RegCloseKey( patch_key );
4103 if (res != ERROR_SUCCESS)
4104 goto done;
4107 all_patches[len] = 0;
4108 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4109 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4110 if (res != ERROR_SUCCESS)
4111 goto done;
4113 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4114 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4115 if (res != ERROR_SUCCESS)
4116 r = ERROR_FUNCTION_FAILED;
4118 done:
4119 RegCloseKey( product_patches_key );
4120 RegCloseKey( patches_key );
4121 RegCloseKey( product_key );
4122 msi_free( all_patches );
4123 return r;
4126 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4128 UINT rc;
4129 HKEY hukey = NULL, hudkey = NULL;
4130 MSIRECORD *uirow;
4132 if (!list_empty(&package->patches))
4134 rc = msi_publish_patches(package);
4135 if (rc != ERROR_SUCCESS)
4136 goto end;
4139 /* FIXME: also need to publish if the product is in advertise mode */
4140 if (!msi_check_publish(package))
4141 return ERROR_SUCCESS;
4143 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4144 &hukey, TRUE);
4145 if (rc != ERROR_SUCCESS)
4146 goto end;
4148 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4149 NULL, &hudkey, TRUE);
4150 if (rc != ERROR_SUCCESS)
4151 goto end;
4153 rc = msi_publish_upgrade_code(package);
4154 if (rc != ERROR_SUCCESS)
4155 goto end;
4157 rc = msi_publish_product_properties(package, hukey);
4158 if (rc != ERROR_SUCCESS)
4159 goto end;
4161 rc = msi_publish_sourcelist(package, hukey);
4162 if (rc != ERROR_SUCCESS)
4163 goto end;
4165 rc = msi_publish_icons(package);
4167 end:
4168 uirow = MSI_CreateRecord( 1 );
4169 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4170 msi_ui_actiondata( package, szPublishProduct, uirow );
4171 msiobj_release( &uirow->hdr );
4173 RegCloseKey(hukey);
4174 RegCloseKey(hudkey);
4175 return rc;
4178 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4180 WCHAR *filename, *ptr, *folder, *ret;
4181 const WCHAR *dirprop;
4183 filename = msi_dup_record_field( row, 2 );
4184 if (filename && (ptr = strchrW( filename, '|' )))
4185 ptr++;
4186 else
4187 ptr = filename;
4189 dirprop = MSI_RecordGetString( row, 3 );
4190 if (dirprop)
4192 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4193 if (!folder) folder = msi_dup_property( package->db, dirprop );
4195 else
4196 folder = msi_dup_property( package->db, szWindowsFolder );
4198 if (!folder)
4200 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4201 msi_free( filename );
4202 return NULL;
4205 ret = msi_build_directory_name( 2, folder, ptr );
4207 msi_free( filename );
4208 msi_free( folder );
4209 return ret;
4212 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4214 MSIPACKAGE *package = param;
4215 LPCWSTR component, section, key, value, identifier;
4216 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4217 MSIRECORD * uirow;
4218 INT action;
4219 MSICOMPONENT *comp;
4221 component = MSI_RecordGetString(row, 8);
4222 comp = msi_get_loaded_component(package,component);
4223 if (!comp)
4224 return ERROR_SUCCESS;
4226 comp->Action = msi_get_component_action( package, comp );
4227 if (comp->Action != INSTALLSTATE_LOCAL)
4229 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4230 return ERROR_SUCCESS;
4233 identifier = MSI_RecordGetString(row,1);
4234 section = MSI_RecordGetString(row,4);
4235 key = MSI_RecordGetString(row,5);
4236 value = MSI_RecordGetString(row,6);
4237 action = MSI_RecordGetInteger(row,7);
4239 deformat_string(package,section,&deformated_section);
4240 deformat_string(package,key,&deformated_key);
4241 deformat_string(package,value,&deformated_value);
4243 fullname = get_ini_file_name(package, row);
4245 if (action == 0)
4247 TRACE("Adding value %s to section %s in %s\n",
4248 debugstr_w(deformated_key), debugstr_w(deformated_section),
4249 debugstr_w(fullname));
4250 WritePrivateProfileStringW(deformated_section, deformated_key,
4251 deformated_value, fullname);
4253 else if (action == 1)
4255 WCHAR returned[10];
4256 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4257 returned, 10, fullname);
4258 if (returned[0] == 0)
4260 TRACE("Adding value %s to section %s in %s\n",
4261 debugstr_w(deformated_key), debugstr_w(deformated_section),
4262 debugstr_w(fullname));
4264 WritePrivateProfileStringW(deformated_section, deformated_key,
4265 deformated_value, fullname);
4268 else if (action == 3)
4269 FIXME("Append to existing section not yet implemented\n");
4271 uirow = MSI_CreateRecord(4);
4272 MSI_RecordSetStringW(uirow,1,identifier);
4273 MSI_RecordSetStringW(uirow,2,deformated_section);
4274 MSI_RecordSetStringW(uirow,3,deformated_key);
4275 MSI_RecordSetStringW(uirow,4,deformated_value);
4276 msi_ui_actiondata( package, szWriteIniValues, uirow );
4277 msiobj_release( &uirow->hdr );
4279 msi_free(fullname);
4280 msi_free(deformated_key);
4281 msi_free(deformated_value);
4282 msi_free(deformated_section);
4283 return ERROR_SUCCESS;
4286 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4288 static const WCHAR query[] = {
4289 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4290 '`','I','n','i','F','i','l','e','`',0};
4291 MSIQUERY *view;
4292 UINT rc;
4294 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4295 if (rc != ERROR_SUCCESS)
4296 return ERROR_SUCCESS;
4298 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4299 msiobj_release(&view->hdr);
4300 return rc;
4303 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4305 MSIPACKAGE *package = param;
4306 LPCWSTR component, section, key, value, identifier;
4307 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4308 MSICOMPONENT *comp;
4309 MSIRECORD *uirow;
4310 INT action;
4312 component = MSI_RecordGetString( row, 8 );
4313 comp = msi_get_loaded_component( package, component );
4314 if (!comp)
4315 return ERROR_SUCCESS;
4317 comp->Action = msi_get_component_action( package, comp );
4318 if (comp->Action != INSTALLSTATE_ABSENT)
4320 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4321 return ERROR_SUCCESS;
4324 identifier = MSI_RecordGetString( row, 1 );
4325 section = MSI_RecordGetString( row, 4 );
4326 key = MSI_RecordGetString( row, 5 );
4327 value = MSI_RecordGetString( row, 6 );
4328 action = MSI_RecordGetInteger( row, 7 );
4330 deformat_string( package, section, &deformated_section );
4331 deformat_string( package, key, &deformated_key );
4332 deformat_string( package, value, &deformated_value );
4334 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4336 filename = get_ini_file_name( package, row );
4338 TRACE("Removing key %s from section %s in %s\n",
4339 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4341 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4343 WARN("Unable to remove key %u\n", GetLastError());
4345 msi_free( filename );
4347 else
4348 FIXME("Unsupported action %d\n", action);
4351 uirow = MSI_CreateRecord( 4 );
4352 MSI_RecordSetStringW( uirow, 1, identifier );
4353 MSI_RecordSetStringW( uirow, 2, deformated_section );
4354 MSI_RecordSetStringW( uirow, 3, deformated_key );
4355 MSI_RecordSetStringW( uirow, 4, deformated_value );
4356 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4357 msiobj_release( &uirow->hdr );
4359 msi_free( deformated_key );
4360 msi_free( deformated_value );
4361 msi_free( deformated_section );
4362 return ERROR_SUCCESS;
4365 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4367 MSIPACKAGE *package = param;
4368 LPCWSTR component, section, key, value, identifier;
4369 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4370 MSICOMPONENT *comp;
4371 MSIRECORD *uirow;
4372 INT action;
4374 component = MSI_RecordGetString( row, 8 );
4375 comp = msi_get_loaded_component( package, component );
4376 if (!comp)
4377 return ERROR_SUCCESS;
4379 comp->Action = msi_get_component_action( package, comp );
4380 if (comp->Action != INSTALLSTATE_LOCAL)
4382 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4383 return ERROR_SUCCESS;
4386 identifier = MSI_RecordGetString( row, 1 );
4387 section = MSI_RecordGetString( row, 4 );
4388 key = MSI_RecordGetString( row, 5 );
4389 value = MSI_RecordGetString( row, 6 );
4390 action = MSI_RecordGetInteger( row, 7 );
4392 deformat_string( package, section, &deformated_section );
4393 deformat_string( package, key, &deformated_key );
4394 deformat_string( package, value, &deformated_value );
4396 if (action == msidbIniFileActionRemoveLine)
4398 filename = get_ini_file_name( package, row );
4400 TRACE("Removing key %s from section %s in %s\n",
4401 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4403 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4405 WARN("Unable to remove key %u\n", GetLastError());
4407 msi_free( filename );
4409 else
4410 FIXME("Unsupported action %d\n", action);
4412 uirow = MSI_CreateRecord( 4 );
4413 MSI_RecordSetStringW( uirow, 1, identifier );
4414 MSI_RecordSetStringW( uirow, 2, deformated_section );
4415 MSI_RecordSetStringW( uirow, 3, deformated_key );
4416 MSI_RecordSetStringW( uirow, 4, deformated_value );
4417 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4418 msiobj_release( &uirow->hdr );
4420 msi_free( deformated_key );
4421 msi_free( deformated_value );
4422 msi_free( deformated_section );
4423 return ERROR_SUCCESS;
4426 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4428 static const WCHAR query[] = {
4429 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4430 '`','I','n','i','F','i','l','e','`',0};
4431 static const WCHAR remove_query[] = {
4432 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4433 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4434 MSIQUERY *view;
4435 UINT rc;
4437 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4438 if (rc == ERROR_SUCCESS)
4440 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4441 msiobj_release( &view->hdr );
4442 if (rc != ERROR_SUCCESS)
4443 return rc;
4445 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4446 if (rc == ERROR_SUCCESS)
4448 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4449 msiobj_release( &view->hdr );
4450 if (rc != ERROR_SUCCESS)
4451 return rc;
4453 return ERROR_SUCCESS;
4456 static void register_dll( const WCHAR *dll, BOOL unregister )
4458 HMODULE hmod;
4460 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4461 if (hmod)
4463 HRESULT (WINAPI *func_ptr)( void );
4464 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4466 func_ptr = (void *)GetProcAddress( hmod, func );
4467 if (func_ptr)
4469 HRESULT hr = func_ptr();
4470 if (FAILED( hr ))
4471 WARN("failed to register dll 0x%08x\n", hr);
4473 else
4474 WARN("entry point %s not found\n", func);
4475 FreeLibrary( hmod );
4476 return;
4478 WARN("failed to load library %u\n", GetLastError());
4481 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4483 MSIPACKAGE *package = param;
4484 LPCWSTR filename;
4485 MSIFILE *file;
4486 MSIRECORD *uirow;
4488 filename = MSI_RecordGetString( row, 1 );
4489 file = msi_get_loaded_file( package, filename );
4490 if (!file)
4492 WARN("unable to find file %s\n", debugstr_w(filename));
4493 return ERROR_SUCCESS;
4495 file->Component->Action = msi_get_component_action( package, file->Component );
4496 if (file->Component->Action != INSTALLSTATE_LOCAL)
4498 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4499 return ERROR_SUCCESS;
4502 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4503 register_dll( file->TargetPath, FALSE );
4505 uirow = MSI_CreateRecord( 2 );
4506 MSI_RecordSetStringW( uirow, 1, file->File );
4507 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4508 msi_ui_actiondata( package, szSelfRegModules, uirow );
4509 msiobj_release( &uirow->hdr );
4511 return ERROR_SUCCESS;
4514 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4516 static const WCHAR query[] = {
4517 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4518 '`','S','e','l','f','R','e','g','`',0};
4519 MSIQUERY *view;
4520 UINT rc;
4522 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4523 if (rc != ERROR_SUCCESS)
4524 return ERROR_SUCCESS;
4526 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4527 msiobj_release(&view->hdr);
4528 return rc;
4531 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4533 MSIPACKAGE *package = param;
4534 LPCWSTR filename;
4535 MSIFILE *file;
4536 MSIRECORD *uirow;
4538 filename = MSI_RecordGetString( row, 1 );
4539 file = msi_get_loaded_file( package, filename );
4540 if (!file)
4542 WARN("unable to find file %s\n", debugstr_w(filename));
4543 return ERROR_SUCCESS;
4545 file->Component->Action = msi_get_component_action( package, file->Component );
4546 if (file->Component->Action != INSTALLSTATE_ABSENT)
4548 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4549 return ERROR_SUCCESS;
4552 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4553 register_dll( file->TargetPath, TRUE );
4555 uirow = MSI_CreateRecord( 2 );
4556 MSI_RecordSetStringW( uirow, 1, file->File );
4557 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4558 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4559 msiobj_release( &uirow->hdr );
4561 return ERROR_SUCCESS;
4564 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4566 static const WCHAR query[] = {
4567 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4568 '`','S','e','l','f','R','e','g','`',0};
4569 MSIQUERY *view;
4570 UINT rc;
4572 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4573 if (rc != ERROR_SUCCESS)
4574 return ERROR_SUCCESS;
4576 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4577 msiobj_release( &view->hdr );
4578 return rc;
4581 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4583 MSIFEATURE *feature;
4584 UINT rc;
4585 HKEY hkey = NULL, userdata = NULL;
4587 if (!msi_check_publish(package))
4588 return ERROR_SUCCESS;
4590 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4591 &hkey, TRUE);
4592 if (rc != ERROR_SUCCESS)
4593 goto end;
4595 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4596 &userdata, TRUE);
4597 if (rc != ERROR_SUCCESS)
4598 goto end;
4600 /* here the guids are base 85 encoded */
4601 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4603 ComponentList *cl;
4604 LPWSTR data = NULL;
4605 GUID clsid;
4606 INT size;
4607 BOOL absent = FALSE;
4608 MSIRECORD *uirow;
4610 if (feature->Action != INSTALLSTATE_LOCAL &&
4611 feature->Action != INSTALLSTATE_SOURCE &&
4612 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4614 size = 1;
4615 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4617 size += 21;
4619 if (feature->Feature_Parent)
4620 size += strlenW( feature->Feature_Parent )+2;
4622 data = msi_alloc(size * sizeof(WCHAR));
4624 data[0] = 0;
4625 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4627 MSICOMPONENT* component = cl->component;
4628 WCHAR buf[21];
4630 buf[0] = 0;
4631 if (component->ComponentId)
4633 TRACE("From %s\n",debugstr_w(component->ComponentId));
4634 CLSIDFromString(component->ComponentId, &clsid);
4635 encode_base85_guid(&clsid,buf);
4636 TRACE("to %s\n",debugstr_w(buf));
4637 strcatW(data,buf);
4641 if (feature->Feature_Parent)
4643 static const WCHAR sep[] = {'\2',0};
4644 strcatW(data,sep);
4645 strcatW(data,feature->Feature_Parent);
4648 msi_reg_set_val_str( userdata, feature->Feature, data );
4649 msi_free(data);
4651 size = 0;
4652 if (feature->Feature_Parent)
4653 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4654 if (!absent)
4656 size += sizeof(WCHAR);
4657 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4658 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4660 else
4662 size += 2*sizeof(WCHAR);
4663 data = msi_alloc(size);
4664 data[0] = 0x6;
4665 data[1] = 0;
4666 if (feature->Feature_Parent)
4667 strcpyW( &data[1], feature->Feature_Parent );
4668 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4669 (LPBYTE)data,size);
4670 msi_free(data);
4673 /* the UI chunk */
4674 uirow = MSI_CreateRecord( 1 );
4675 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4676 msi_ui_actiondata( package, szPublishFeatures, uirow );
4677 msiobj_release( &uirow->hdr );
4678 /* FIXME: call msi_ui_progress? */
4681 end:
4682 RegCloseKey(hkey);
4683 RegCloseKey(userdata);
4684 return rc;
4687 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4689 UINT r;
4690 HKEY hkey;
4691 MSIRECORD *uirow;
4693 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4695 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4696 &hkey, FALSE);
4697 if (r == ERROR_SUCCESS)
4699 RegDeleteValueW(hkey, feature->Feature);
4700 RegCloseKey(hkey);
4703 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4704 &hkey, FALSE);
4705 if (r == ERROR_SUCCESS)
4707 RegDeleteValueW(hkey, feature->Feature);
4708 RegCloseKey(hkey);
4711 uirow = MSI_CreateRecord( 1 );
4712 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4713 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4714 msiobj_release( &uirow->hdr );
4716 return ERROR_SUCCESS;
4719 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4721 MSIFEATURE *feature;
4723 if (!msi_check_unpublish(package))
4724 return ERROR_SUCCESS;
4726 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4728 msi_unpublish_feature(package, feature);
4731 return ERROR_SUCCESS;
4734 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4736 SYSTEMTIME systime;
4737 DWORD size, langid;
4738 WCHAR date[9], *val, *buffer;
4739 const WCHAR *prop, *key;
4741 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4742 static const WCHAR modpath_fmt[] =
4743 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4744 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4745 static const WCHAR szModifyPath[] =
4746 {'M','o','d','i','f','y','P','a','t','h',0};
4747 static const WCHAR szUninstallString[] =
4748 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4749 static const WCHAR szEstimatedSize[] =
4750 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4751 static const WCHAR szDisplayVersion[] =
4752 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4753 static const WCHAR szInstallSource[] =
4754 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4755 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4756 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4757 static const WCHAR szAuthorizedCDFPrefix[] =
4758 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4759 static const WCHAR szARPCONTACT[] =
4760 {'A','R','P','C','O','N','T','A','C','T',0};
4761 static const WCHAR szContact[] =
4762 {'C','o','n','t','a','c','t',0};
4763 static const WCHAR szARPCOMMENTS[] =
4764 {'A','R','P','C','O','M','M','E','N','T','S',0};
4765 static const WCHAR szComments[] =
4766 {'C','o','m','m','e','n','t','s',0};
4767 static const WCHAR szProductName[] =
4768 {'P','r','o','d','u','c','t','N','a','m','e',0};
4769 static const WCHAR szDisplayName[] =
4770 {'D','i','s','p','l','a','y','N','a','m','e',0};
4771 static const WCHAR szARPHELPLINK[] =
4772 {'A','R','P','H','E','L','P','L','I','N','K',0};
4773 static const WCHAR szHelpLink[] =
4774 {'H','e','l','p','L','i','n','k',0};
4775 static const WCHAR szARPHELPTELEPHONE[] =
4776 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4777 static const WCHAR szHelpTelephone[] =
4778 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4779 static const WCHAR szARPINSTALLLOCATION[] =
4780 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4781 static const WCHAR szInstallLocation[] =
4782 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4783 static const WCHAR szManufacturer[] =
4784 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4785 static const WCHAR szPublisher[] =
4786 {'P','u','b','l','i','s','h','e','r',0};
4787 static const WCHAR szARPREADME[] =
4788 {'A','R','P','R','E','A','D','M','E',0};
4789 static const WCHAR szReadme[] =
4790 {'R','e','a','d','M','e',0};
4791 static const WCHAR szARPSIZE[] =
4792 {'A','R','P','S','I','Z','E',0};
4793 static const WCHAR szSize[] =
4794 {'S','i','z','e',0};
4795 static const WCHAR szARPURLINFOABOUT[] =
4796 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4797 static const WCHAR szURLInfoAbout[] =
4798 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4799 static const WCHAR szARPURLUPDATEINFO[] =
4800 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4801 static const WCHAR szURLUpdateInfo[] =
4802 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4803 static const WCHAR szARPSYSTEMCOMPONENT[] =
4804 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4805 static const WCHAR szSystemComponent[] =
4806 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4808 static const WCHAR *propval[] = {
4809 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4810 szARPCONTACT, szContact,
4811 szARPCOMMENTS, szComments,
4812 szProductName, szDisplayName,
4813 szARPHELPLINK, szHelpLink,
4814 szARPHELPTELEPHONE, szHelpTelephone,
4815 szARPINSTALLLOCATION, szInstallLocation,
4816 szSourceDir, szInstallSource,
4817 szManufacturer, szPublisher,
4818 szARPREADME, szReadme,
4819 szARPSIZE, szSize,
4820 szARPURLINFOABOUT, szURLInfoAbout,
4821 szARPURLUPDATEINFO, szURLUpdateInfo,
4822 NULL
4824 const WCHAR **p = propval;
4826 while (*p)
4828 prop = *p++;
4829 key = *p++;
4830 val = msi_dup_property(package->db, prop);
4831 msi_reg_set_val_str(hkey, key, val);
4832 msi_free(val);
4835 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4836 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4838 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4840 size = deformat_string(package, modpath_fmt, &buffer);
4841 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4842 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4843 msi_free(buffer);
4845 /* FIXME: Write real Estimated Size when we have it */
4846 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4848 GetLocalTime(&systime);
4849 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4850 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4852 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4853 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4855 buffer = msi_dup_property(package->db, szProductVersion);
4856 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4857 if (buffer)
4859 DWORD verdword = msi_version_str_to_dword(buffer);
4861 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4862 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4863 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4864 msi_free(buffer);
4867 return ERROR_SUCCESS;
4870 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4872 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4873 MSIRECORD *uirow;
4874 LPWSTR upgrade_code;
4875 HKEY hkey, props, upgrade_key;
4876 UINT rc;
4878 /* FIXME: also need to publish if the product is in advertise mode */
4879 if (!msi_check_publish(package))
4880 return ERROR_SUCCESS;
4882 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4883 if (rc != ERROR_SUCCESS)
4884 return rc;
4886 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4887 if (rc != ERROR_SUCCESS)
4888 goto done;
4890 rc = msi_publish_install_properties(package, hkey);
4891 if (rc != ERROR_SUCCESS)
4892 goto done;
4894 rc = msi_publish_install_properties(package, props);
4895 if (rc != ERROR_SUCCESS)
4896 goto done;
4898 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4899 if (upgrade_code)
4901 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4902 if (rc == ERROR_SUCCESS)
4904 squash_guid( package->ProductCode, squashed_pc );
4905 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4906 RegCloseKey( upgrade_key );
4908 msi_free( upgrade_code );
4910 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4911 package->delete_on_close = FALSE;
4913 done:
4914 uirow = MSI_CreateRecord( 1 );
4915 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4916 msi_ui_actiondata( package, szRegisterProduct, uirow );
4917 msiobj_release( &uirow->hdr );
4919 RegCloseKey(hkey);
4920 return ERROR_SUCCESS;
4923 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4925 return execute_script(package, SCRIPT_INSTALL);
4928 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
4930 MSIPACKAGE *package = param;
4931 const WCHAR *icon = MSI_RecordGetString( row, 1 );
4932 WCHAR *p, *icon_path;
4934 if (!icon) return ERROR_SUCCESS;
4935 if ((icon_path = msi_build_icon_path( package, icon )))
4937 TRACE("removing icon file %s\n", debugstr_w(icon_path));
4938 DeleteFileW( icon_path );
4939 if ((p = strrchrW( icon_path, '\\' )))
4941 *p = 0;
4942 RemoveDirectoryW( icon_path );
4944 msi_free( icon_path );
4946 return ERROR_SUCCESS;
4949 static UINT msi_unpublish_icons( MSIPACKAGE *package )
4951 static const WCHAR query[]= {
4952 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
4953 MSIQUERY *view;
4954 UINT r;
4956 r = MSI_DatabaseOpenViewW( package->db, query, &view );
4957 if (r == ERROR_SUCCESS)
4959 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
4960 msiobj_release( &view->hdr );
4961 if (r != ERROR_SUCCESS)
4962 return r;
4964 return ERROR_SUCCESS;
4967 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4969 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4970 WCHAR *upgrade, **features;
4971 BOOL full_uninstall = TRUE;
4972 MSIFEATURE *feature;
4973 MSIPATCHINFO *patch;
4974 UINT i;
4976 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4978 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4980 features = msi_split_string( remove, ',' );
4981 for (i = 0; features && features[i]; i++)
4983 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4985 msi_free(features);
4987 if (!full_uninstall)
4988 return ERROR_SUCCESS;
4990 MSIREG_DeleteProductKey(package->ProductCode);
4991 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4992 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4994 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4995 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4996 MSIREG_DeleteUserProductKey(package->ProductCode);
4997 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4999 upgrade = msi_dup_property(package->db, szUpgradeCode);
5000 if (upgrade)
5002 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5003 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5004 msi_free(upgrade);
5007 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5009 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5010 if (!strcmpW( package->ProductCode, patch->products ))
5012 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5013 patch->delete_on_close = TRUE;
5015 /* FIXME: remove local patch package if this is the last product */
5017 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5018 package->delete_on_close = TRUE;
5020 msi_unpublish_icons( package );
5021 return ERROR_SUCCESS;
5024 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5026 UINT rc;
5027 WCHAR *remove;
5029 /* turn off scheduling */
5030 package->script->CurrentlyScripting= FALSE;
5032 /* first do the same as an InstallExecute */
5033 rc = ACTION_InstallExecute(package);
5034 if (rc != ERROR_SUCCESS)
5035 return rc;
5037 /* then handle commit actions */
5038 rc = execute_script(package, SCRIPT_COMMIT);
5039 if (rc != ERROR_SUCCESS)
5040 return rc;
5042 remove = msi_dup_property(package->db, szRemove);
5043 rc = msi_unpublish_product(package, remove);
5044 msi_free(remove);
5045 return rc;
5048 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5050 static const WCHAR RunOnce[] = {
5051 'S','o','f','t','w','a','r','e','\\',
5052 'M','i','c','r','o','s','o','f','t','\\',
5053 'W','i','n','d','o','w','s','\\',
5054 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5055 'R','u','n','O','n','c','e',0};
5056 static const WCHAR InstallRunOnce[] = {
5057 'S','o','f','t','w','a','r','e','\\',
5058 'M','i','c','r','o','s','o','f','t','\\',
5059 'W','i','n','d','o','w','s','\\',
5060 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5061 'I','n','s','t','a','l','l','e','r','\\',
5062 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5064 static const WCHAR msiexec_fmt[] = {
5065 '%','s',
5066 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5067 '\"','%','s','\"',0};
5068 static const WCHAR install_fmt[] = {
5069 '/','I',' ','\"','%','s','\"',' ',
5070 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5071 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5072 WCHAR buffer[256], sysdir[MAX_PATH];
5073 HKEY hkey;
5074 WCHAR squished_pc[100];
5076 squash_guid(package->ProductCode,squished_pc);
5078 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5079 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5080 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5081 squished_pc);
5083 msi_reg_set_val_str( hkey, squished_pc, buffer );
5084 RegCloseKey(hkey);
5086 TRACE("Reboot command %s\n",debugstr_w(buffer));
5088 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5089 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5091 msi_reg_set_val_str( hkey, squished_pc, buffer );
5092 RegCloseKey(hkey);
5094 return ERROR_INSTALL_SUSPEND;
5097 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5099 static const WCHAR query[] =
5100 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5101 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5102 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5103 MSIRECORD *rec, *row;
5104 DWORD i, size = 0;
5105 va_list va;
5106 const WCHAR *str;
5107 WCHAR *data;
5109 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5111 rec = MSI_CreateRecord( count + 2 );
5112 str = MSI_RecordGetString( row, 1 );
5113 MSI_RecordSetStringW( rec, 0, str );
5114 msiobj_release( &row->hdr );
5115 MSI_RecordSetInteger( rec, 1, error );
5117 va_start( va, count );
5118 for (i = 0; i < count; i++)
5120 str = va_arg( va, const WCHAR *);
5121 MSI_RecordSetStringW( rec, i + 2, str );
5123 va_end( va );
5125 MSI_FormatRecordW( package, rec, NULL, &size );
5126 size++;
5127 data = msi_alloc( size * sizeof(WCHAR) );
5128 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5129 else data[0] = 0;
5130 msiobj_release( &rec->hdr );
5131 return data;
5134 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5136 DWORD attrib;
5137 UINT rc;
5140 * We are currently doing what should be done here in the top level Install
5141 * however for Administrative and uninstalls this step will be needed
5143 if (!package->PackagePath)
5144 return ERROR_SUCCESS;
5146 msi_set_sourcedir_props(package, TRUE);
5148 attrib = GetFileAttributesW(package->db->path);
5149 if (attrib == INVALID_FILE_ATTRIBUTES)
5151 LPWSTR prompt, msg;
5152 DWORD size = 0;
5154 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5155 package->Context, MSICODE_PRODUCT,
5156 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5157 if (rc == ERROR_MORE_DATA)
5159 prompt = msi_alloc(size * sizeof(WCHAR));
5160 MsiSourceListGetInfoW(package->ProductCode, NULL,
5161 package->Context, MSICODE_PRODUCT,
5162 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5164 else
5165 prompt = strdupW(package->db->path);
5167 msg = msi_build_error_string(package, 1302, 1, prompt);
5168 msi_free(prompt);
5169 while(attrib == INVALID_FILE_ATTRIBUTES)
5171 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
5172 if (rc == IDCANCEL)
5174 msi_free(msg);
5175 return ERROR_INSTALL_USEREXIT;
5177 attrib = GetFileAttributesW(package->db->path);
5179 msi_free(msg);
5180 rc = ERROR_SUCCESS;
5182 else
5183 return ERROR_SUCCESS;
5185 return rc;
5188 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5190 HKEY hkey = 0;
5191 LPWSTR buffer, productid = NULL;
5192 UINT i, rc = ERROR_SUCCESS;
5193 MSIRECORD *uirow;
5195 static const WCHAR szPropKeys[][80] =
5197 {'P','r','o','d','u','c','t','I','D',0},
5198 {'U','S','E','R','N','A','M','E',0},
5199 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5200 {0},
5203 static const WCHAR szRegKeys[][80] =
5205 {'P','r','o','d','u','c','t','I','D',0},
5206 {'R','e','g','O','w','n','e','r',0},
5207 {'R','e','g','C','o','m','p','a','n','y',0},
5208 {0},
5211 if (msi_check_unpublish(package))
5213 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5214 goto end;
5217 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5218 if (!productid)
5219 goto end;
5221 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5222 NULL, &hkey, TRUE);
5223 if (rc != ERROR_SUCCESS)
5224 goto end;
5226 for( i = 0; szPropKeys[i][0]; i++ )
5228 buffer = msi_dup_property( package->db, szPropKeys[i] );
5229 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5230 msi_free( buffer );
5233 end:
5234 uirow = MSI_CreateRecord( 1 );
5235 MSI_RecordSetStringW( uirow, 1, productid );
5236 msi_ui_actiondata( package, szRegisterUser, uirow );
5237 msiobj_release( &uirow->hdr );
5239 msi_free(productid);
5240 RegCloseKey(hkey);
5241 return rc;
5245 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5247 UINT rc;
5249 package->script->InWhatSequence |= SEQUENCE_EXEC;
5250 rc = ACTION_ProcessExecSequence(package,FALSE);
5251 return rc;
5254 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5256 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5257 WCHAR productid_85[21], component_85[21], *ret;
5258 GUID clsid;
5259 DWORD sz;
5261 /* > is used if there is a component GUID and < if not. */
5263 productid_85[0] = 0;
5264 component_85[0] = 0;
5265 CLSIDFromString( package->ProductCode, &clsid );
5267 encode_base85_guid( &clsid, productid_85 );
5268 if (component)
5270 CLSIDFromString( component->ComponentId, &clsid );
5271 encode_base85_guid( &clsid, component_85 );
5274 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5275 debugstr_w(component_85));
5277 sz = 20 + strlenW( feature ) + 20 + 3;
5278 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5279 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5280 return ret;
5283 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5285 MSIPACKAGE *package = param;
5286 LPCWSTR compgroupid, component, feature, qualifier, text;
5287 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5288 HKEY hkey = NULL;
5289 UINT rc;
5290 MSICOMPONENT *comp;
5291 MSIFEATURE *feat;
5292 DWORD sz;
5293 MSIRECORD *uirow;
5294 int len;
5296 feature = MSI_RecordGetString(rec, 5);
5297 feat = msi_get_loaded_feature(package, feature);
5298 if (!feat)
5299 return ERROR_SUCCESS;
5301 feat->Action = msi_get_feature_action( package, feat );
5302 if (feat->Action != INSTALLSTATE_LOCAL &&
5303 feat->Action != INSTALLSTATE_SOURCE &&
5304 feat->Action != INSTALLSTATE_ADVERTISED)
5306 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5307 return ERROR_SUCCESS;
5310 component = MSI_RecordGetString(rec, 3);
5311 comp = msi_get_loaded_component(package, component);
5312 if (!comp)
5313 return ERROR_SUCCESS;
5315 compgroupid = MSI_RecordGetString(rec,1);
5316 qualifier = MSI_RecordGetString(rec,2);
5318 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5319 if (rc != ERROR_SUCCESS)
5320 goto end;
5322 advertise = msi_create_component_advertise_string( package, comp, feature );
5323 text = MSI_RecordGetString( rec, 4 );
5324 if (text)
5326 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5327 strcpyW( p, advertise );
5328 strcatW( p, text );
5329 msi_free( advertise );
5330 advertise = p;
5332 existing = msi_reg_get_val_str( hkey, qualifier );
5334 sz = strlenW( advertise ) + 1;
5335 if (existing)
5337 for (p = existing; *p; p += len)
5339 len = strlenW( p ) + 1;
5340 if (strcmpW( advertise, p )) sz += len;
5343 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5345 rc = ERROR_OUTOFMEMORY;
5346 goto end;
5348 q = output;
5349 if (existing)
5351 for (p = existing; *p; p += len)
5353 len = strlenW( p ) + 1;
5354 if (strcmpW( advertise, p ))
5356 memcpy( q, p, len * sizeof(WCHAR) );
5357 q += len;
5361 strcpyW( q, advertise );
5362 q[strlenW( q ) + 1] = 0;
5364 msi_reg_set_val_multi_str( hkey, qualifier, output );
5366 end:
5367 RegCloseKey(hkey);
5368 msi_free( output );
5369 msi_free( advertise );
5370 msi_free( existing );
5372 /* the UI chunk */
5373 uirow = MSI_CreateRecord( 2 );
5374 MSI_RecordSetStringW( uirow, 1, compgroupid );
5375 MSI_RecordSetStringW( uirow, 2, qualifier);
5376 msi_ui_actiondata( package, szPublishComponents, uirow );
5377 msiobj_release( &uirow->hdr );
5378 /* FIXME: call ui_progress? */
5380 return rc;
5384 * At present I am ignorning the advertised components part of this and only
5385 * focusing on the qualified component sets
5387 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5389 static const WCHAR query[] = {
5390 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5391 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5392 MSIQUERY *view;
5393 UINT rc;
5395 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5396 if (rc != ERROR_SUCCESS)
5397 return ERROR_SUCCESS;
5399 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5400 msiobj_release(&view->hdr);
5401 return rc;
5404 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5406 static const WCHAR szInstallerComponents[] = {
5407 'S','o','f','t','w','a','r','e','\\',
5408 'M','i','c','r','o','s','o','f','t','\\',
5409 'I','n','s','t','a','l','l','e','r','\\',
5410 'C','o','m','p','o','n','e','n','t','s','\\',0};
5412 MSIPACKAGE *package = param;
5413 LPCWSTR compgroupid, component, feature, qualifier;
5414 MSICOMPONENT *comp;
5415 MSIFEATURE *feat;
5416 MSIRECORD *uirow;
5417 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5418 LONG res;
5420 feature = MSI_RecordGetString( rec, 5 );
5421 feat = msi_get_loaded_feature( package, feature );
5422 if (!feat)
5423 return ERROR_SUCCESS;
5425 feat->Action = msi_get_feature_action( package, feat );
5426 if (feat->Action != INSTALLSTATE_ABSENT)
5428 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5429 return ERROR_SUCCESS;
5432 component = MSI_RecordGetString( rec, 3 );
5433 comp = msi_get_loaded_component( package, component );
5434 if (!comp)
5435 return ERROR_SUCCESS;
5437 compgroupid = MSI_RecordGetString( rec, 1 );
5438 qualifier = MSI_RecordGetString( rec, 2 );
5440 squash_guid( compgroupid, squashed );
5441 strcpyW( keypath, szInstallerComponents );
5442 strcatW( keypath, squashed );
5444 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5445 if (res != ERROR_SUCCESS)
5447 WARN("Unable to delete component key %d\n", res);
5450 uirow = MSI_CreateRecord( 2 );
5451 MSI_RecordSetStringW( uirow, 1, compgroupid );
5452 MSI_RecordSetStringW( uirow, 2, qualifier );
5453 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5454 msiobj_release( &uirow->hdr );
5456 return ERROR_SUCCESS;
5459 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5461 static const WCHAR query[] = {
5462 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5463 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5464 MSIQUERY *view;
5465 UINT rc;
5467 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5468 if (rc != ERROR_SUCCESS)
5469 return ERROR_SUCCESS;
5471 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5472 msiobj_release( &view->hdr );
5473 return rc;
5476 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5478 static const WCHAR query[] =
5479 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5480 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5481 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5482 MSIPACKAGE *package = param;
5483 MSICOMPONENT *component;
5484 MSIRECORD *row;
5485 MSIFILE *file;
5486 SC_HANDLE hscm = NULL, service = NULL;
5487 LPCWSTR comp, key;
5488 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5489 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5490 DWORD serv_type, start_type, err_control;
5491 SERVICE_DESCRIPTIONW sd = {NULL};
5493 comp = MSI_RecordGetString( rec, 12 );
5494 component = msi_get_loaded_component( package, comp );
5495 if (!component)
5497 WARN("service component not found\n");
5498 goto done;
5500 component->Action = msi_get_component_action( package, component );
5501 if (component->Action != INSTALLSTATE_LOCAL)
5503 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5504 goto done;
5506 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5507 if (!hscm)
5509 ERR("Failed to open the SC Manager!\n");
5510 goto done;
5513 start_type = MSI_RecordGetInteger(rec, 5);
5514 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5515 goto done;
5517 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5518 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5519 serv_type = MSI_RecordGetInteger(rec, 4);
5520 err_control = MSI_RecordGetInteger(rec, 6);
5521 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5522 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5523 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5524 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5525 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5526 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5528 /* fetch the service path */
5529 row = MSI_QueryGetRecord(package->db, query, comp);
5530 if (!row)
5532 ERR("Query failed\n");
5533 goto done;
5535 key = MSI_RecordGetString(row, 6);
5536 file = msi_get_loaded_file(package, key);
5537 msiobj_release(&row->hdr);
5538 if (!file)
5540 ERR("Failed to load the service file\n");
5541 goto done;
5544 if (!args || !args[0]) image_path = file->TargetPath;
5545 else
5547 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5548 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5549 return ERROR_OUTOFMEMORY;
5551 strcpyW(image_path, file->TargetPath);
5552 strcatW(image_path, szSpace);
5553 strcatW(image_path, args);
5555 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5556 start_type, err_control, image_path, load_order,
5557 NULL, depends, serv_name, pass);
5559 if (!service)
5561 if (GetLastError() != ERROR_SERVICE_EXISTS)
5562 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5564 else if (sd.lpDescription)
5566 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5567 WARN("failed to set service description %u\n", GetLastError());
5570 if (image_path != file->TargetPath) msi_free(image_path);
5571 done:
5572 CloseServiceHandle(service);
5573 CloseServiceHandle(hscm);
5574 msi_free(name);
5575 msi_free(disp);
5576 msi_free(sd.lpDescription);
5577 msi_free(load_order);
5578 msi_free(serv_name);
5579 msi_free(pass);
5580 msi_free(depends);
5581 msi_free(args);
5583 return ERROR_SUCCESS;
5586 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5588 static const WCHAR query[] = {
5589 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5590 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5591 MSIQUERY *view;
5592 UINT rc;
5594 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5595 if (rc != ERROR_SUCCESS)
5596 return ERROR_SUCCESS;
5598 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5599 msiobj_release(&view->hdr);
5600 return rc;
5603 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5604 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5606 LPCWSTR *vector, *temp_vector;
5607 LPWSTR p, q;
5608 DWORD sep_len;
5610 static const WCHAR separator[] = {'[','~',']',0};
5612 *numargs = 0;
5613 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5615 if (!args)
5616 return NULL;
5618 vector = msi_alloc(sizeof(LPWSTR));
5619 if (!vector)
5620 return NULL;
5622 p = args;
5625 (*numargs)++;
5626 vector[*numargs - 1] = p;
5628 if ((q = strstrW(p, separator)))
5630 *q = '\0';
5632 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5633 if (!temp_vector)
5635 msi_free(vector);
5636 return NULL;
5638 vector = temp_vector;
5640 p = q + sep_len;
5642 } while (q);
5644 return vector;
5647 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5649 MSIPACKAGE *package = param;
5650 MSICOMPONENT *comp;
5651 MSIRECORD *uirow;
5652 SC_HANDLE scm = NULL, service = NULL;
5653 LPCWSTR component, *vector = NULL;
5654 LPWSTR name, args, display_name = NULL;
5655 DWORD event, numargs, len, wait, dummy;
5656 UINT r = ERROR_FUNCTION_FAILED;
5657 SERVICE_STATUS_PROCESS status;
5658 ULONGLONG start_time;
5660 component = MSI_RecordGetString(rec, 6);
5661 comp = msi_get_loaded_component(package, component);
5662 if (!comp)
5663 return ERROR_SUCCESS;
5665 comp->Action = msi_get_component_action( package, comp );
5666 if (comp->Action != INSTALLSTATE_LOCAL)
5668 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5669 return ERROR_SUCCESS;
5672 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5673 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5674 event = MSI_RecordGetInteger(rec, 3);
5675 wait = MSI_RecordGetInteger(rec, 5);
5677 if (!(event & msidbServiceControlEventStart))
5679 r = ERROR_SUCCESS;
5680 goto done;
5683 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5684 if (!scm)
5686 ERR("Failed to open the service control manager\n");
5687 goto done;
5690 len = 0;
5691 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5692 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5694 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5695 GetServiceDisplayNameW( scm, name, display_name, &len );
5698 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5699 if (!service)
5701 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5702 goto done;
5705 vector = msi_service_args_to_vector(args, &numargs);
5707 if (!StartServiceW(service, numargs, vector) &&
5708 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5710 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5711 goto done;
5714 r = ERROR_SUCCESS;
5715 if (wait)
5717 /* wait for at most 30 seconds for the service to be up and running */
5718 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5719 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5721 TRACE("failed to query service status (%u)\n", GetLastError());
5722 goto done;
5724 start_time = GetTickCount64();
5725 while (status.dwCurrentState == SERVICE_START_PENDING)
5727 if (GetTickCount64() - start_time > 30000) break;
5728 Sleep(1000);
5729 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5730 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5732 TRACE("failed to query service status (%u)\n", GetLastError());
5733 goto done;
5736 if (status.dwCurrentState != SERVICE_RUNNING)
5738 WARN("service failed to start %u\n", status.dwCurrentState);
5739 r = ERROR_FUNCTION_FAILED;
5743 done:
5744 uirow = MSI_CreateRecord( 2 );
5745 MSI_RecordSetStringW( uirow, 1, display_name );
5746 MSI_RecordSetStringW( uirow, 2, name );
5747 msi_ui_actiondata( package, szStartServices, uirow );
5748 msiobj_release( &uirow->hdr );
5750 CloseServiceHandle(service);
5751 CloseServiceHandle(scm);
5753 msi_free(name);
5754 msi_free(args);
5755 msi_free(vector);
5756 msi_free(display_name);
5757 return r;
5760 static UINT ACTION_StartServices( MSIPACKAGE *package )
5762 static const WCHAR query[] = {
5763 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5764 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5765 MSIQUERY *view;
5766 UINT rc;
5768 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5769 if (rc != ERROR_SUCCESS)
5770 return ERROR_SUCCESS;
5772 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5773 msiobj_release(&view->hdr);
5774 return rc;
5777 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5779 DWORD i, needed, count;
5780 ENUM_SERVICE_STATUSW *dependencies;
5781 SERVICE_STATUS ss;
5782 SC_HANDLE depserv;
5784 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5785 0, &needed, &count))
5786 return TRUE;
5788 if (GetLastError() != ERROR_MORE_DATA)
5789 return FALSE;
5791 dependencies = msi_alloc(needed);
5792 if (!dependencies)
5793 return FALSE;
5795 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5796 needed, &needed, &count))
5797 goto error;
5799 for (i = 0; i < count; i++)
5801 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5802 SERVICE_STOP | SERVICE_QUERY_STATUS);
5803 if (!depserv)
5804 goto error;
5806 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5807 goto error;
5810 return TRUE;
5812 error:
5813 msi_free(dependencies);
5814 return FALSE;
5817 static UINT stop_service( LPCWSTR name )
5819 SC_HANDLE scm = NULL, service = NULL;
5820 SERVICE_STATUS status;
5821 SERVICE_STATUS_PROCESS ssp;
5822 DWORD needed;
5824 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5825 if (!scm)
5827 WARN("Failed to open the SCM: %d\n", GetLastError());
5828 goto done;
5831 service = OpenServiceW(scm, name,
5832 SERVICE_STOP |
5833 SERVICE_QUERY_STATUS |
5834 SERVICE_ENUMERATE_DEPENDENTS);
5835 if (!service)
5837 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5838 goto done;
5841 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5842 sizeof(SERVICE_STATUS_PROCESS), &needed))
5844 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5845 goto done;
5848 if (ssp.dwCurrentState == SERVICE_STOPPED)
5849 goto done;
5851 stop_service_dependents(scm, service);
5853 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5854 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5856 done:
5857 CloseServiceHandle(service);
5858 CloseServiceHandle(scm);
5860 return ERROR_SUCCESS;
5863 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5865 MSIPACKAGE *package = param;
5866 MSICOMPONENT *comp;
5867 MSIRECORD *uirow;
5868 LPCWSTR component;
5869 LPWSTR name = NULL, display_name = NULL;
5870 DWORD event, len;
5871 SC_HANDLE scm;
5873 event = MSI_RecordGetInteger( rec, 3 );
5874 if (!(event & msidbServiceControlEventStop))
5875 return ERROR_SUCCESS;
5877 component = MSI_RecordGetString( rec, 6 );
5878 comp = msi_get_loaded_component( package, component );
5879 if (!comp)
5880 return ERROR_SUCCESS;
5882 comp->Action = msi_get_component_action( package, comp );
5883 if (comp->Action != INSTALLSTATE_ABSENT)
5885 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5886 return ERROR_SUCCESS;
5889 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5890 if (!scm)
5892 ERR("Failed to open the service control manager\n");
5893 goto done;
5896 len = 0;
5897 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5898 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5900 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5901 GetServiceDisplayNameW( scm, name, display_name, &len );
5903 CloseServiceHandle( scm );
5905 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5906 stop_service( name );
5908 done:
5909 uirow = MSI_CreateRecord( 2 );
5910 MSI_RecordSetStringW( uirow, 1, display_name );
5911 MSI_RecordSetStringW( uirow, 2, name );
5912 msi_ui_actiondata( package, szStopServices, uirow );
5913 msiobj_release( &uirow->hdr );
5915 msi_free( name );
5916 msi_free( display_name );
5917 return ERROR_SUCCESS;
5920 static UINT ACTION_StopServices( MSIPACKAGE *package )
5922 static const WCHAR query[] = {
5923 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5924 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5925 MSIQUERY *view;
5926 UINT rc;
5928 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5929 if (rc != ERROR_SUCCESS)
5930 return ERROR_SUCCESS;
5932 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5933 msiobj_release(&view->hdr);
5934 return rc;
5937 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5939 MSIPACKAGE *package = param;
5940 MSICOMPONENT *comp;
5941 MSIRECORD *uirow;
5942 LPWSTR name = NULL, display_name = NULL;
5943 DWORD event, len;
5944 SC_HANDLE scm = NULL, service = NULL;
5946 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
5947 if (!comp)
5948 return ERROR_SUCCESS;
5950 event = MSI_RecordGetInteger( rec, 3 );
5951 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5953 comp->Action = msi_get_component_action( package, comp );
5954 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
5955 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
5957 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
5958 msi_free( name );
5959 return ERROR_SUCCESS;
5961 stop_service( name );
5963 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5964 if (!scm)
5966 WARN("Failed to open the SCM: %d\n", GetLastError());
5967 goto done;
5970 len = 0;
5971 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5972 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5974 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5975 GetServiceDisplayNameW( scm, name, display_name, &len );
5978 service = OpenServiceW( scm, name, DELETE );
5979 if (!service)
5981 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5982 goto done;
5985 if (!DeleteService( service ))
5986 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5988 done:
5989 uirow = MSI_CreateRecord( 2 );
5990 MSI_RecordSetStringW( uirow, 1, display_name );
5991 MSI_RecordSetStringW( uirow, 2, name );
5992 msi_ui_actiondata( package, szDeleteServices, uirow );
5993 msiobj_release( &uirow->hdr );
5995 CloseServiceHandle( service );
5996 CloseServiceHandle( scm );
5997 msi_free( name );
5998 msi_free( display_name );
6000 return ERROR_SUCCESS;
6003 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6005 static const WCHAR query[] = {
6006 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6007 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
6008 MSIQUERY *view;
6009 UINT rc;
6011 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6012 if (rc != ERROR_SUCCESS)
6013 return ERROR_SUCCESS;
6015 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6016 msiobj_release( &view->hdr );
6017 return rc;
6020 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6022 MSIPACKAGE *package = param;
6023 LPWSTR driver, driver_path, ptr;
6024 WCHAR outpath[MAX_PATH];
6025 MSIFILE *driver_file = NULL, *setup_file = NULL;
6026 MSICOMPONENT *comp;
6027 MSIRECORD *uirow;
6028 LPCWSTR desc, file_key, component;
6029 DWORD len, usage;
6030 UINT r = ERROR_SUCCESS;
6032 static const WCHAR driver_fmt[] = {
6033 'D','r','i','v','e','r','=','%','s',0};
6034 static const WCHAR setup_fmt[] = {
6035 'S','e','t','u','p','=','%','s',0};
6036 static const WCHAR usage_fmt[] = {
6037 'F','i','l','e','U','s','a','g','e','=','1',0};
6039 component = MSI_RecordGetString( rec, 2 );
6040 comp = msi_get_loaded_component( package, component );
6041 if (!comp)
6042 return ERROR_SUCCESS;
6044 comp->Action = msi_get_component_action( package, comp );
6045 if (comp->Action != INSTALLSTATE_LOCAL)
6047 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6048 return ERROR_SUCCESS;
6050 desc = MSI_RecordGetString(rec, 3);
6052 file_key = MSI_RecordGetString( rec, 4 );
6053 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6055 file_key = MSI_RecordGetString( rec, 5 );
6056 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6058 if (!driver_file)
6060 ERR("ODBC Driver entry not found!\n");
6061 return ERROR_FUNCTION_FAILED;
6064 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6065 if (setup_file)
6066 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6067 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6069 driver = msi_alloc(len * sizeof(WCHAR));
6070 if (!driver)
6071 return ERROR_OUTOFMEMORY;
6073 ptr = driver;
6074 lstrcpyW(ptr, desc);
6075 ptr += lstrlenW(ptr) + 1;
6077 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6078 ptr += len + 1;
6080 if (setup_file)
6082 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6083 ptr += len + 1;
6086 lstrcpyW(ptr, usage_fmt);
6087 ptr += lstrlenW(ptr) + 1;
6088 *ptr = '\0';
6090 if (!driver_file->TargetPath)
6092 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6093 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6095 driver_path = strdupW(driver_file->TargetPath);
6096 ptr = strrchrW(driver_path, '\\');
6097 if (ptr) *ptr = '\0';
6099 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6100 NULL, ODBC_INSTALL_COMPLETE, &usage))
6102 ERR("Failed to install SQL driver!\n");
6103 r = ERROR_FUNCTION_FAILED;
6106 uirow = MSI_CreateRecord( 5 );
6107 MSI_RecordSetStringW( uirow, 1, desc );
6108 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6109 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6110 msi_ui_actiondata( package, szInstallODBC, uirow );
6111 msiobj_release( &uirow->hdr );
6113 msi_free(driver);
6114 msi_free(driver_path);
6116 return r;
6119 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6121 MSIPACKAGE *package = param;
6122 LPWSTR translator, translator_path, ptr;
6123 WCHAR outpath[MAX_PATH];
6124 MSIFILE *translator_file = NULL, *setup_file = NULL;
6125 MSICOMPONENT *comp;
6126 MSIRECORD *uirow;
6127 LPCWSTR desc, file_key, component;
6128 DWORD len, usage;
6129 UINT r = ERROR_SUCCESS;
6131 static const WCHAR translator_fmt[] = {
6132 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6133 static const WCHAR setup_fmt[] = {
6134 'S','e','t','u','p','=','%','s',0};
6136 component = MSI_RecordGetString( rec, 2 );
6137 comp = msi_get_loaded_component( package, component );
6138 if (!comp)
6139 return ERROR_SUCCESS;
6141 comp->Action = msi_get_component_action( package, comp );
6142 if (comp->Action != INSTALLSTATE_LOCAL)
6144 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6145 return ERROR_SUCCESS;
6147 desc = MSI_RecordGetString(rec, 3);
6149 file_key = MSI_RecordGetString( rec, 4 );
6150 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6152 file_key = MSI_RecordGetString( rec, 5 );
6153 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6155 if (!translator_file)
6157 ERR("ODBC Translator entry not found!\n");
6158 return ERROR_FUNCTION_FAILED;
6161 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6162 if (setup_file)
6163 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6165 translator = msi_alloc(len * sizeof(WCHAR));
6166 if (!translator)
6167 return ERROR_OUTOFMEMORY;
6169 ptr = translator;
6170 lstrcpyW(ptr, desc);
6171 ptr += lstrlenW(ptr) + 1;
6173 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6174 ptr += len + 1;
6176 if (setup_file)
6178 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6179 ptr += len + 1;
6181 *ptr = '\0';
6183 translator_path = strdupW(translator_file->TargetPath);
6184 ptr = strrchrW(translator_path, '\\');
6185 if (ptr) *ptr = '\0';
6187 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6188 NULL, ODBC_INSTALL_COMPLETE, &usage))
6190 ERR("Failed to install SQL translator!\n");
6191 r = ERROR_FUNCTION_FAILED;
6194 uirow = MSI_CreateRecord( 5 );
6195 MSI_RecordSetStringW( uirow, 1, desc );
6196 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6197 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6198 msi_ui_actiondata( package, szInstallODBC, uirow );
6199 msiobj_release( &uirow->hdr );
6201 msi_free(translator);
6202 msi_free(translator_path);
6204 return r;
6207 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6209 MSIPACKAGE *package = param;
6210 MSICOMPONENT *comp;
6211 LPWSTR attrs;
6212 LPCWSTR desc, driver, component;
6213 WORD request = ODBC_ADD_SYS_DSN;
6214 INT registration;
6215 DWORD len;
6216 UINT r = ERROR_SUCCESS;
6217 MSIRECORD *uirow;
6219 static const WCHAR attrs_fmt[] = {
6220 'D','S','N','=','%','s',0 };
6222 component = MSI_RecordGetString( rec, 2 );
6223 comp = msi_get_loaded_component( package, component );
6224 if (!comp)
6225 return ERROR_SUCCESS;
6227 comp->Action = msi_get_component_action( package, comp );
6228 if (comp->Action != INSTALLSTATE_LOCAL)
6230 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6231 return ERROR_SUCCESS;
6234 desc = MSI_RecordGetString(rec, 3);
6235 driver = MSI_RecordGetString(rec, 4);
6236 registration = MSI_RecordGetInteger(rec, 5);
6238 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6239 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6241 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6242 attrs = msi_alloc(len * sizeof(WCHAR));
6243 if (!attrs)
6244 return ERROR_OUTOFMEMORY;
6246 len = sprintfW(attrs, attrs_fmt, desc);
6247 attrs[len + 1] = 0;
6249 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6251 ERR("Failed to install SQL data source!\n");
6252 r = ERROR_FUNCTION_FAILED;
6255 uirow = MSI_CreateRecord( 5 );
6256 MSI_RecordSetStringW( uirow, 1, desc );
6257 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6258 MSI_RecordSetInteger( uirow, 3, request );
6259 msi_ui_actiondata( package, szInstallODBC, uirow );
6260 msiobj_release( &uirow->hdr );
6262 msi_free(attrs);
6264 return r;
6267 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6269 static const WCHAR driver_query[] = {
6270 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6271 'O','D','B','C','D','r','i','v','e','r',0};
6272 static const WCHAR translator_query[] = {
6273 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6274 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6275 static const WCHAR source_query[] = {
6276 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6277 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6278 MSIQUERY *view;
6279 UINT rc;
6281 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6282 if (rc == ERROR_SUCCESS)
6284 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6285 msiobj_release(&view->hdr);
6286 if (rc != ERROR_SUCCESS)
6287 return rc;
6289 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6290 if (rc == ERROR_SUCCESS)
6292 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6293 msiobj_release(&view->hdr);
6294 if (rc != ERROR_SUCCESS)
6295 return rc;
6297 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6298 if (rc == ERROR_SUCCESS)
6300 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6301 msiobj_release(&view->hdr);
6302 if (rc != ERROR_SUCCESS)
6303 return rc;
6305 return ERROR_SUCCESS;
6308 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6310 MSIPACKAGE *package = param;
6311 MSICOMPONENT *comp;
6312 MSIRECORD *uirow;
6313 DWORD usage;
6314 LPCWSTR desc, component;
6316 component = MSI_RecordGetString( rec, 2 );
6317 comp = msi_get_loaded_component( package, component );
6318 if (!comp)
6319 return ERROR_SUCCESS;
6321 comp->Action = msi_get_component_action( package, comp );
6322 if (comp->Action != INSTALLSTATE_ABSENT)
6324 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6325 return ERROR_SUCCESS;
6328 desc = MSI_RecordGetString( rec, 3 );
6329 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6331 WARN("Failed to remove ODBC driver\n");
6333 else if (!usage)
6335 FIXME("Usage count reached 0\n");
6338 uirow = MSI_CreateRecord( 2 );
6339 MSI_RecordSetStringW( uirow, 1, desc );
6340 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6341 msi_ui_actiondata( package, szRemoveODBC, uirow );
6342 msiobj_release( &uirow->hdr );
6344 return ERROR_SUCCESS;
6347 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6349 MSIPACKAGE *package = param;
6350 MSICOMPONENT *comp;
6351 MSIRECORD *uirow;
6352 DWORD usage;
6353 LPCWSTR desc, component;
6355 component = MSI_RecordGetString( rec, 2 );
6356 comp = msi_get_loaded_component( package, component );
6357 if (!comp)
6358 return ERROR_SUCCESS;
6360 comp->Action = msi_get_component_action( package, comp );
6361 if (comp->Action != INSTALLSTATE_ABSENT)
6363 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6364 return ERROR_SUCCESS;
6367 desc = MSI_RecordGetString( rec, 3 );
6368 if (!SQLRemoveTranslatorW( desc, &usage ))
6370 WARN("Failed to remove ODBC translator\n");
6372 else if (!usage)
6374 FIXME("Usage count reached 0\n");
6377 uirow = MSI_CreateRecord( 2 );
6378 MSI_RecordSetStringW( uirow, 1, desc );
6379 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6380 msi_ui_actiondata( package, szRemoveODBC, uirow );
6381 msiobj_release( &uirow->hdr );
6383 return ERROR_SUCCESS;
6386 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6388 MSIPACKAGE *package = param;
6389 MSICOMPONENT *comp;
6390 MSIRECORD *uirow;
6391 LPWSTR attrs;
6392 LPCWSTR desc, driver, component;
6393 WORD request = ODBC_REMOVE_SYS_DSN;
6394 INT registration;
6395 DWORD len;
6397 static const WCHAR attrs_fmt[] = {
6398 'D','S','N','=','%','s',0 };
6400 component = MSI_RecordGetString( rec, 2 );
6401 comp = msi_get_loaded_component( package, component );
6402 if (!comp)
6403 return ERROR_SUCCESS;
6405 comp->Action = msi_get_component_action( package, comp );
6406 if (comp->Action != INSTALLSTATE_ABSENT)
6408 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6409 return ERROR_SUCCESS;
6412 desc = MSI_RecordGetString( rec, 3 );
6413 driver = MSI_RecordGetString( rec, 4 );
6414 registration = MSI_RecordGetInteger( rec, 5 );
6416 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6417 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6419 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6420 attrs = msi_alloc( len * sizeof(WCHAR) );
6421 if (!attrs)
6422 return ERROR_OUTOFMEMORY;
6424 FIXME("Use ODBCSourceAttribute table\n");
6426 len = sprintfW( attrs, attrs_fmt, desc );
6427 attrs[len + 1] = 0;
6429 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6431 WARN("Failed to remove ODBC data source\n");
6433 msi_free( attrs );
6435 uirow = MSI_CreateRecord( 3 );
6436 MSI_RecordSetStringW( uirow, 1, desc );
6437 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6438 MSI_RecordSetInteger( uirow, 3, request );
6439 msi_ui_actiondata( package, szRemoveODBC, uirow );
6440 msiobj_release( &uirow->hdr );
6442 return ERROR_SUCCESS;
6445 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6447 static const WCHAR driver_query[] = {
6448 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6449 'O','D','B','C','D','r','i','v','e','r',0};
6450 static const WCHAR translator_query[] = {
6451 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6452 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6453 static const WCHAR source_query[] = {
6454 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6455 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6456 MSIQUERY *view;
6457 UINT rc;
6459 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6460 if (rc == ERROR_SUCCESS)
6462 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6463 msiobj_release( &view->hdr );
6464 if (rc != ERROR_SUCCESS)
6465 return rc;
6467 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6468 if (rc == ERROR_SUCCESS)
6470 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6471 msiobj_release( &view->hdr );
6472 if (rc != ERROR_SUCCESS)
6473 return rc;
6475 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6476 if (rc == ERROR_SUCCESS)
6478 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6479 msiobj_release( &view->hdr );
6480 if (rc != ERROR_SUCCESS)
6481 return rc;
6483 return ERROR_SUCCESS;
6486 #define ENV_ACT_SETALWAYS 0x1
6487 #define ENV_ACT_SETABSENT 0x2
6488 #define ENV_ACT_REMOVE 0x4
6489 #define ENV_ACT_REMOVEMATCH 0x8
6491 #define ENV_MOD_MACHINE 0x20000000
6492 #define ENV_MOD_APPEND 0x40000000
6493 #define ENV_MOD_PREFIX 0x80000000
6494 #define ENV_MOD_MASK 0xC0000000
6496 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6498 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6500 LPCWSTR cptr = *name;
6502 static const WCHAR prefix[] = {'[','~',']',0};
6503 static const int prefix_len = 3;
6505 *flags = 0;
6506 while (*cptr)
6508 if (*cptr == '=')
6509 *flags |= ENV_ACT_SETALWAYS;
6510 else if (*cptr == '+')
6511 *flags |= ENV_ACT_SETABSENT;
6512 else if (*cptr == '-')
6513 *flags |= ENV_ACT_REMOVE;
6514 else if (*cptr == '!')
6515 *flags |= ENV_ACT_REMOVEMATCH;
6516 else if (*cptr == '*')
6517 *flags |= ENV_MOD_MACHINE;
6518 else
6519 break;
6521 cptr++;
6522 (*name)++;
6525 if (!*cptr)
6527 ERR("Missing environment variable\n");
6528 return ERROR_FUNCTION_FAILED;
6531 if (*value)
6533 LPCWSTR ptr = *value;
6534 if (!strncmpW(ptr, prefix, prefix_len))
6536 if (ptr[prefix_len] == szSemiColon[0])
6538 *flags |= ENV_MOD_APPEND;
6539 *value += lstrlenW(prefix);
6541 else
6543 *value = NULL;
6546 else if (lstrlenW(*value) >= prefix_len)
6548 ptr += lstrlenW(ptr) - prefix_len;
6549 if (!strcmpW( ptr, prefix ))
6551 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6553 *flags |= ENV_MOD_PREFIX;
6554 /* the "[~]" will be removed by deformat_string */;
6556 else
6558 *value = NULL;
6564 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6565 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6566 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6567 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6569 ERR("Invalid flags: %08x\n", *flags);
6570 return ERROR_FUNCTION_FAILED;
6573 if (!*flags)
6574 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6576 return ERROR_SUCCESS;
6579 static UINT open_env_key( DWORD flags, HKEY *key )
6581 static const WCHAR user_env[] =
6582 {'E','n','v','i','r','o','n','m','e','n','t',0};
6583 static const WCHAR machine_env[] =
6584 {'S','y','s','t','e','m','\\',
6585 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6586 'C','o','n','t','r','o','l','\\',
6587 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6588 'E','n','v','i','r','o','n','m','e','n','t',0};
6589 const WCHAR *env;
6590 HKEY root;
6591 LONG res;
6593 if (flags & ENV_MOD_MACHINE)
6595 env = machine_env;
6596 root = HKEY_LOCAL_MACHINE;
6598 else
6600 env = user_env;
6601 root = HKEY_CURRENT_USER;
6604 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6605 if (res != ERROR_SUCCESS)
6607 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6608 return ERROR_FUNCTION_FAILED;
6611 return ERROR_SUCCESS;
6614 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6616 MSIPACKAGE *package = param;
6617 LPCWSTR name, value, component;
6618 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6619 DWORD flags, type, size;
6620 UINT res;
6621 HKEY env = NULL;
6622 MSICOMPONENT *comp;
6623 MSIRECORD *uirow;
6624 int action = 0;
6626 component = MSI_RecordGetString(rec, 4);
6627 comp = msi_get_loaded_component(package, component);
6628 if (!comp)
6629 return ERROR_SUCCESS;
6631 comp->Action = msi_get_component_action( package, comp );
6632 if (comp->Action != INSTALLSTATE_LOCAL)
6634 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6635 return ERROR_SUCCESS;
6637 name = MSI_RecordGetString(rec, 2);
6638 value = MSI_RecordGetString(rec, 3);
6640 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6642 res = env_parse_flags(&name, &value, &flags);
6643 if (res != ERROR_SUCCESS || !value)
6644 goto done;
6646 if (value && !deformat_string(package, value, &deformatted))
6648 res = ERROR_OUTOFMEMORY;
6649 goto done;
6652 value = deformatted;
6654 res = open_env_key( flags, &env );
6655 if (res != ERROR_SUCCESS)
6656 goto done;
6658 if (flags & ENV_MOD_MACHINE)
6659 action |= 0x20000000;
6661 size = 0;
6662 type = REG_SZ;
6663 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6664 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6665 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6666 goto done;
6668 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6670 action = 0x2;
6672 /* Nothing to do. */
6673 if (!value)
6675 res = ERROR_SUCCESS;
6676 goto done;
6679 /* If we are appending but the string was empty, strip ; */
6680 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6682 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6683 newval = strdupW(value);
6684 if (!newval)
6686 res = ERROR_OUTOFMEMORY;
6687 goto done;
6690 else
6692 action = 0x1;
6694 /* Contrary to MSDN, +-variable to [~];path works */
6695 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6697 res = ERROR_SUCCESS;
6698 goto done;
6701 data = msi_alloc(size);
6702 if (!data)
6704 RegCloseKey(env);
6705 return ERROR_OUTOFMEMORY;
6708 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6709 if (res != ERROR_SUCCESS)
6710 goto done;
6712 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6714 action = 0x4;
6715 res = RegDeleteValueW(env, name);
6716 if (res != ERROR_SUCCESS)
6717 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6718 goto done;
6721 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6722 if (flags & ENV_MOD_MASK)
6724 DWORD mod_size;
6725 int multiplier = 0;
6726 if (flags & ENV_MOD_APPEND) multiplier++;
6727 if (flags & ENV_MOD_PREFIX) multiplier++;
6728 mod_size = lstrlenW(value) * multiplier;
6729 size += mod_size * sizeof(WCHAR);
6732 newval = msi_alloc(size);
6733 ptr = newval;
6734 if (!newval)
6736 res = ERROR_OUTOFMEMORY;
6737 goto done;
6740 if (flags & ENV_MOD_PREFIX)
6742 lstrcpyW(newval, value);
6743 ptr = newval + lstrlenW(value);
6744 action |= 0x80000000;
6747 lstrcpyW(ptr, data);
6749 if (flags & ENV_MOD_APPEND)
6751 lstrcatW(newval, value);
6752 action |= 0x40000000;
6755 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6756 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6757 if (res)
6759 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6762 done:
6763 uirow = MSI_CreateRecord( 3 );
6764 MSI_RecordSetStringW( uirow, 1, name );
6765 MSI_RecordSetStringW( uirow, 2, newval );
6766 MSI_RecordSetInteger( uirow, 3, action );
6767 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6768 msiobj_release( &uirow->hdr );
6770 if (env) RegCloseKey(env);
6771 msi_free(deformatted);
6772 msi_free(data);
6773 msi_free(newval);
6774 return res;
6777 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6779 static const WCHAR query[] = {
6780 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6781 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6782 MSIQUERY *view;
6783 UINT rc;
6785 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6786 if (rc != ERROR_SUCCESS)
6787 return ERROR_SUCCESS;
6789 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6790 msiobj_release(&view->hdr);
6791 return rc;
6794 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6796 MSIPACKAGE *package = param;
6797 LPCWSTR name, value, component;
6798 LPWSTR deformatted = NULL;
6799 DWORD flags;
6800 HKEY env;
6801 MSICOMPONENT *comp;
6802 MSIRECORD *uirow;
6803 int action = 0;
6804 LONG res;
6805 UINT r;
6807 component = MSI_RecordGetString( rec, 4 );
6808 comp = msi_get_loaded_component( package, component );
6809 if (!comp)
6810 return ERROR_SUCCESS;
6812 comp->Action = msi_get_component_action( package, comp );
6813 if (comp->Action != INSTALLSTATE_ABSENT)
6815 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6816 return ERROR_SUCCESS;
6818 name = MSI_RecordGetString( rec, 2 );
6819 value = MSI_RecordGetString( rec, 3 );
6821 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6823 r = env_parse_flags( &name, &value, &flags );
6824 if (r != ERROR_SUCCESS)
6825 return r;
6827 if (!(flags & ENV_ACT_REMOVE))
6829 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6830 return ERROR_SUCCESS;
6833 if (value && !deformat_string( package, value, &deformatted ))
6834 return ERROR_OUTOFMEMORY;
6836 value = deformatted;
6838 r = open_env_key( flags, &env );
6839 if (r != ERROR_SUCCESS)
6841 r = ERROR_SUCCESS;
6842 goto done;
6845 if (flags & ENV_MOD_MACHINE)
6846 action |= 0x20000000;
6848 TRACE("Removing %s\n", debugstr_w(name));
6850 res = RegDeleteValueW( env, name );
6851 if (res != ERROR_SUCCESS)
6853 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6854 r = ERROR_SUCCESS;
6857 done:
6858 uirow = MSI_CreateRecord( 3 );
6859 MSI_RecordSetStringW( uirow, 1, name );
6860 MSI_RecordSetStringW( uirow, 2, value );
6861 MSI_RecordSetInteger( uirow, 3, action );
6862 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6863 msiobj_release( &uirow->hdr );
6865 if (env) RegCloseKey( env );
6866 msi_free( deformatted );
6867 return r;
6870 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6872 static const WCHAR query[] = {
6873 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6874 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6875 MSIQUERY *view;
6876 UINT rc;
6878 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6879 if (rc != ERROR_SUCCESS)
6880 return ERROR_SUCCESS;
6882 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6883 msiobj_release( &view->hdr );
6884 return rc;
6887 UINT msi_validate_product_id( MSIPACKAGE *package )
6889 LPWSTR key, template, id;
6890 UINT r = ERROR_SUCCESS;
6892 id = msi_dup_property( package->db, szProductID );
6893 if (id)
6895 msi_free( id );
6896 return ERROR_SUCCESS;
6898 template = msi_dup_property( package->db, szPIDTemplate );
6899 key = msi_dup_property( package->db, szPIDKEY );
6900 if (key && template)
6902 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6903 r = msi_set_property( package->db, szProductID, key );
6905 msi_free( template );
6906 msi_free( key );
6907 return r;
6910 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6912 return msi_validate_product_id( package );
6915 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6917 TRACE("\n");
6918 package->need_reboot_at_end = 1;
6919 return ERROR_SUCCESS;
6922 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6924 static const WCHAR szAvailableFreeReg[] =
6925 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6926 MSIRECORD *uirow;
6927 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6929 TRACE("%p %d kilobytes\n", package, space);
6931 uirow = MSI_CreateRecord( 1 );
6932 MSI_RecordSetInteger( uirow, 1, space );
6933 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6934 msiobj_release( &uirow->hdr );
6936 return ERROR_SUCCESS;
6939 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6941 TRACE("%p\n", package);
6943 msi_set_property( package->db, szRollbackDisabled, szOne );
6944 return ERROR_SUCCESS;
6947 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6949 FIXME("%p\n", package);
6950 return ERROR_SUCCESS;
6953 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6955 static const WCHAR driver_query[] = {
6956 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6957 'O','D','B','C','D','r','i','v','e','r',0};
6958 static const WCHAR translator_query[] = {
6959 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6960 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6961 MSIQUERY *view;
6962 UINT r, count;
6964 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6965 if (r == ERROR_SUCCESS)
6967 count = 0;
6968 r = MSI_IterateRecords( view, &count, NULL, package );
6969 msiobj_release( &view->hdr );
6970 if (r != ERROR_SUCCESS)
6971 return r;
6972 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6974 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6975 if (r == ERROR_SUCCESS)
6977 count = 0;
6978 r = MSI_IterateRecords( view, &count, NULL, package );
6979 msiobj_release( &view->hdr );
6980 if (r != ERROR_SUCCESS)
6981 return r;
6982 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6984 return ERROR_SUCCESS;
6987 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6989 MSIPACKAGE *package = param;
6990 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6991 WCHAR *value;
6993 if ((value = msi_dup_property( package->db, property )))
6995 FIXME("remove %s\n", debugstr_w(value));
6996 msi_free( value );
6998 return ERROR_SUCCESS;
7001 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7003 static const WCHAR query[] = {
7004 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
7005 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
7006 MSIQUERY *view;
7007 UINT r;
7009 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7010 if (r == ERROR_SUCCESS)
7012 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7013 msiobj_release( &view->hdr );
7014 if (r != ERROR_SUCCESS)
7015 return r;
7017 return ERROR_SUCCESS;
7020 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7022 MSIPACKAGE *package = param;
7023 int attributes = MSI_RecordGetInteger( rec, 5 );
7025 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7027 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7028 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7029 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7030 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7031 HKEY hkey;
7032 UINT r;
7034 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7036 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7037 if (r != ERROR_SUCCESS)
7038 return ERROR_SUCCESS;
7040 else
7042 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7043 if (r != ERROR_SUCCESS)
7044 return ERROR_SUCCESS;
7046 RegCloseKey( hkey );
7048 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7049 debugstr_w(upgrade_code), debugstr_w(version_min),
7050 debugstr_w(version_max), debugstr_w(language));
7052 return ERROR_SUCCESS;
7055 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7057 static const WCHAR query[] = {
7058 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7059 'U','p','g','r','a','d','e',0};
7060 MSIQUERY *view;
7061 UINT r;
7063 if (msi_get_property_int( package->db, szInstalled, 0 ))
7065 TRACE("product is installed, skipping action\n");
7066 return ERROR_SUCCESS;
7068 if (msi_get_property_int( package->db, szPreselected, 0 ))
7070 TRACE("Preselected property is set, not migrating feature states\n");
7071 return ERROR_SUCCESS;
7073 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7074 if (r == ERROR_SUCCESS)
7076 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7077 msiobj_release( &view->hdr );
7078 if (r != ERROR_SUCCESS)
7079 return r;
7081 return ERROR_SUCCESS;
7084 static void bind_image( const char *filename, const char *path )
7086 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7088 WARN("failed to bind image %u\n", GetLastError());
7092 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7094 UINT i;
7095 MSIFILE *file;
7096 MSIPACKAGE *package = param;
7097 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7098 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7099 char *filenameA, *pathA;
7100 WCHAR *pathW, **path_list;
7102 if (!(file = msi_get_loaded_file( package, key )))
7104 WARN("file %s not found\n", debugstr_w(key));
7105 return ERROR_SUCCESS;
7107 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7108 path_list = msi_split_string( paths, ';' );
7109 if (!path_list) bind_image( filenameA, NULL );
7110 else
7112 for (i = 0; path_list[i] && path_list[i][0]; i++)
7114 deformat_string( package, path_list[i], &pathW );
7115 if ((pathA = strdupWtoA( pathW )))
7117 bind_image( filenameA, pathA );
7118 msi_free( pathA );
7120 msi_free( pathW );
7123 msi_free( path_list );
7124 msi_free( filenameA );
7125 return ERROR_SUCCESS;
7128 static UINT ACTION_BindImage( MSIPACKAGE *package )
7130 static const WCHAR query[] = {
7131 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7132 'B','i','n','d','I','m','a','g','e',0};
7133 MSIQUERY *view;
7134 UINT r;
7136 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7137 if (r == ERROR_SUCCESS)
7139 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7140 msiobj_release( &view->hdr );
7141 if (r != ERROR_SUCCESS)
7142 return r;
7144 return ERROR_SUCCESS;
7147 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7149 static const WCHAR query[] = {
7150 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7151 MSIQUERY *view;
7152 DWORD count = 0;
7153 UINT r;
7155 r = MSI_OpenQuery( package->db, &view, query, table );
7156 if (r == ERROR_SUCCESS)
7158 r = MSI_IterateRecords(view, &count, NULL, package);
7159 msiobj_release(&view->hdr);
7160 if (r != ERROR_SUCCESS)
7161 return r;
7163 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7164 return ERROR_SUCCESS;
7167 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7169 static const WCHAR table[] = {
7170 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7171 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7174 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7176 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7177 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7180 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7182 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7183 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7186 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7188 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7189 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7192 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7194 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7195 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7198 static const struct
7200 const WCHAR *action;
7201 UINT (*handler)(MSIPACKAGE *);
7202 const WCHAR *action_rollback;
7204 StandardActions[] =
7206 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7207 { szAppSearch, ACTION_AppSearch, NULL },
7208 { szBindImage, ACTION_BindImage, NULL },
7209 { szCCPSearch, ACTION_CCPSearch, NULL },
7210 { szCostFinalize, ACTION_CostFinalize, NULL },
7211 { szCostInitialize, ACTION_CostInitialize, NULL },
7212 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7213 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7214 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7215 { szDisableRollback, ACTION_DisableRollback, NULL },
7216 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7217 { szExecuteAction, ACTION_ExecuteAction, NULL },
7218 { szFileCost, ACTION_FileCost, NULL },
7219 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7220 { szForceReboot, ACTION_ForceReboot, NULL },
7221 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7222 { szInstallExecute, ACTION_InstallExecute, NULL },
7223 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7224 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7225 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7226 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7227 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7228 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7229 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7230 { szInstallValidate, ACTION_InstallValidate, NULL },
7231 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7232 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7233 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7234 { szMoveFiles, ACTION_MoveFiles, NULL },
7235 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7236 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7237 { szPatchFiles, ACTION_PatchFiles, NULL },
7238 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7239 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7240 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7241 { szPublishProduct, ACTION_PublishProduct, NULL },
7242 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7243 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7244 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7245 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7246 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7247 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7248 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7249 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7250 { szRegisterUser, ACTION_RegisterUser, NULL },
7251 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7252 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7253 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7254 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7255 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7256 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7257 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7258 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7259 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7260 { szResolveSource, ACTION_ResolveSource, NULL },
7261 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7262 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7263 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7264 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules },
7265 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7266 { szStartServices, ACTION_StartServices, szStopServices },
7267 { szStopServices, ACTION_StopServices, szStartServices },
7268 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7269 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7270 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7271 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7272 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7273 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7274 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7275 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7276 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7277 { szValidateProductID, ACTION_ValidateProductID, NULL },
7278 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7279 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7280 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7281 { NULL, NULL, NULL }
7284 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7286 BOOL ret = FALSE;
7287 UINT i;
7289 i = 0;
7290 while (StandardActions[i].action != NULL)
7292 if (!strcmpW( StandardActions[i].action, action ))
7294 ui_actionstart( package, action );
7295 if (StandardActions[i].handler)
7297 ui_actioninfo( package, action, TRUE, 0 );
7298 *rc = StandardActions[i].handler( package );
7299 ui_actioninfo( package, action, FALSE, *rc );
7301 if (StandardActions[i].action_rollback && !package->need_rollback)
7303 TRACE("scheduling rollback action\n");
7304 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7307 else
7309 FIXME("unhandled standard action %s\n", debugstr_w(action));
7310 *rc = ERROR_SUCCESS;
7312 ret = TRUE;
7313 break;
7315 i++;
7317 return ret;
7320 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7322 UINT rc = ERROR_SUCCESS;
7323 BOOL handled;
7325 TRACE("Performing action (%s)\n", debugstr_w(action));
7327 handled = ACTION_HandleStandardAction(package, action, &rc);
7329 if (!handled)
7330 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7332 if (!handled)
7334 WARN("unhandled msi action %s\n", debugstr_w(action));
7335 rc = ERROR_FUNCTION_NOT_CALLED;
7338 return rc;
7341 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7343 UINT rc = ERROR_SUCCESS;
7344 BOOL handled = FALSE;
7346 TRACE("Performing action (%s)\n", debugstr_w(action));
7348 package->action_progress_increment = 0;
7349 handled = ACTION_HandleStandardAction(package, action, &rc);
7351 if (!handled)
7352 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7354 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7355 handled = TRUE;
7357 if (!handled)
7359 WARN("unhandled msi action %s\n", debugstr_w(action));
7360 rc = ERROR_FUNCTION_NOT_CALLED;
7363 return rc;
7366 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7368 UINT rc = ERROR_SUCCESS;
7369 MSIRECORD *row;
7371 static const WCHAR query[] =
7372 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7373 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7374 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7375 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7376 static const WCHAR ui_query[] =
7377 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7378 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7379 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7380 ' ', '=',' ','%','i',0};
7382 if (needs_ui_sequence(package))
7383 row = MSI_QueryGetRecord(package->db, ui_query, seq);
7384 else
7385 row = MSI_QueryGetRecord(package->db, query, seq);
7387 if (row)
7389 LPCWSTR action, cond;
7391 TRACE("Running the actions\n");
7393 /* check conditions */
7394 cond = MSI_RecordGetString(row, 2);
7396 /* this is a hack to skip errors in the condition code */
7397 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7399 msiobj_release(&row->hdr);
7400 return ERROR_SUCCESS;
7403 action = MSI_RecordGetString(row, 1);
7404 if (!action)
7406 ERR("failed to fetch action\n");
7407 msiobj_release(&row->hdr);
7408 return ERROR_FUNCTION_FAILED;
7411 if (needs_ui_sequence(package))
7412 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE);
7413 else
7414 rc = ACTION_PerformAction(package, action, SCRIPT_NONE);
7416 msiobj_release(&row->hdr);
7419 return rc;
7422 /****************************************************
7423 * TOP level entry points
7424 *****************************************************/
7426 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7427 LPCWSTR szCommandLine )
7429 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7430 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7431 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7432 WCHAR *reinstall = NULL;
7433 BOOL ui_exists;
7434 UINT rc;
7436 msi_set_property( package->db, szAction, szInstall );
7438 package->script->InWhatSequence = SEQUENCE_INSTALL;
7440 if (szPackagePath)
7442 LPWSTR p, dir;
7443 LPCWSTR file;
7445 dir = strdupW(szPackagePath);
7446 p = strrchrW(dir, '\\');
7447 if (p)
7449 *(++p) = 0;
7450 file = szPackagePath + (p - dir);
7452 else
7454 msi_free(dir);
7455 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7456 GetCurrentDirectoryW(MAX_PATH, dir);
7457 lstrcatW(dir, szBackSlash);
7458 file = szPackagePath;
7461 msi_free( package->PackagePath );
7462 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7463 if (!package->PackagePath)
7465 msi_free(dir);
7466 return ERROR_OUTOFMEMORY;
7469 lstrcpyW(package->PackagePath, dir);
7470 lstrcatW(package->PackagePath, file);
7471 msi_free(dir);
7473 msi_set_sourcedir_props(package, FALSE);
7476 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7477 if (rc != ERROR_SUCCESS)
7478 return rc;
7480 msi_apply_transforms( package );
7481 msi_apply_patches( package );
7483 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7485 TRACE("setting reinstall property\n");
7486 msi_set_property( package->db, szReinstall, szAll );
7489 /* properties may have been added by a transform */
7490 msi_clone_properties( package );
7492 msi_parse_command_line( package, szCommandLine, FALSE );
7493 msi_adjust_privilege_properties( package );
7494 msi_set_context( package );
7496 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7498 TRACE("disabling rollback\n");
7499 msi_set_property( package->db, szRollbackDisabled, szOne );
7502 if (needs_ui_sequence( package))
7504 package->script->InWhatSequence |= SEQUENCE_UI;
7505 rc = ACTION_ProcessUISequence(package);
7506 ui_exists = ui_sequence_exists(package);
7507 if (rc == ERROR_SUCCESS || !ui_exists)
7509 package->script->InWhatSequence |= SEQUENCE_EXEC;
7510 rc = ACTION_ProcessExecSequence(package, ui_exists);
7513 else
7514 rc = ACTION_ProcessExecSequence(package, FALSE);
7516 package->script->CurrentlyScripting = FALSE;
7518 /* process the ending type action */
7519 if (rc == ERROR_SUCCESS)
7520 ACTION_PerformActionSequence(package, -1);
7521 else if (rc == ERROR_INSTALL_USEREXIT)
7522 ACTION_PerformActionSequence(package, -2);
7523 else if (rc == ERROR_INSTALL_SUSPEND)
7524 ACTION_PerformActionSequence(package, -4);
7525 else /* failed */
7527 ACTION_PerformActionSequence(package, -3);
7528 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7530 package->need_rollback = TRUE;
7534 /* finish up running custom actions */
7535 ACTION_FinishCustomActions(package);
7537 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
7539 WARN("installation failed, running rollback script\n");
7540 execute_script( package, SCRIPT_ROLLBACK );
7542 msi_free( reinstall );
7544 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7545 return ERROR_SUCCESS_REBOOT_REQUIRED;
7547 return rc;