server: Set debug enable bits briefly to commit the addresses to kernel.
[wine/multimedia.git] / dlls / msi / action.c
blob0ac6dbacf483e2412ef97e609776198e67a2d4fd
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "winreg.h"
29 #include "winsvc.h"
30 #include "odbcinst.h"
31 #include "wine/debug.h"
32 #include "msidefs.h"
33 #include "msipriv.h"
34 #include "winuser.h"
35 #include "shlobj.h"
36 #include "objbase.h"
37 #include "mscoree.h"
38 #include "shlwapi.h"
39 #include "imagehlp.h"
40 #include "wine/unicode.h"
41 #include "winver.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48 static const WCHAR szCreateFolders[] =
49 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
50 static const WCHAR szCostFinalize[] =
51 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
52 static const WCHAR szWriteRegistryValues[] =
53 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
54 static const WCHAR szFileCost[] =
55 {'F','i','l','e','C','o','s','t',0};
56 static const WCHAR szInstallInitialize[] =
57 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
58 static const WCHAR szInstallValidate[] =
59 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
60 static const WCHAR szLaunchConditions[] =
61 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
62 static const WCHAR szProcessComponents[] =
63 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
64 static const WCHAR szRegisterTypeLibraries[] =
65 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
66 static const WCHAR szCreateShortcuts[] =
67 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
68 static const WCHAR szPublishProduct[] =
69 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
70 static const WCHAR szWriteIniValues[] =
71 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
72 static const WCHAR szSelfRegModules[] =
73 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
74 static const WCHAR szPublishFeatures[] =
75 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
76 static const WCHAR szRegisterProduct[] =
77 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
78 static const WCHAR szInstallExecute[] =
79 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
80 static const WCHAR szInstallExecuteAgain[] =
81 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
82 static const WCHAR szInstallFinalize[] =
83 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
84 static const WCHAR szForceReboot[] =
85 {'F','o','r','c','e','R','e','b','o','o','t',0};
86 static const WCHAR szResolveSource[] =
87 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
88 static const WCHAR szAllocateRegistrySpace[] =
89 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
90 static const WCHAR szBindImage[] =
91 {'B','i','n','d','I','m','a','g','e',0};
92 static const WCHAR szDeleteServices[] =
93 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
94 static const WCHAR szDisableRollback[] =
95 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
96 static const WCHAR szExecuteAction[] =
97 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
98 static const WCHAR szInstallAdminPackage[] =
99 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
100 static const WCHAR szInstallSFPCatalogFile[] =
101 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
102 static const WCHAR szIsolateComponents[] =
103 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
104 static const WCHAR szMigrateFeatureStates[] =
105 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
106 static const WCHAR szMsiUnpublishAssemblies[] =
107 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
108 static const WCHAR szInstallODBC[] =
109 {'I','n','s','t','a','l','l','O','D','B','C',0};
110 static const WCHAR szInstallServices[] =
111 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
112 static const WCHAR szPublishComponents[] =
113 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
114 static const WCHAR szRegisterComPlus[] =
115 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
116 static const WCHAR szRegisterUser[] =
117 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
118 static const WCHAR szRemoveEnvironmentStrings[] =
119 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
120 static const WCHAR szRemoveExistingProducts[] =
121 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
122 static const WCHAR szRemoveFolders[] =
123 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
124 static const WCHAR szRemoveIniValues[] =
125 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
126 static const WCHAR szRemoveODBC[] =
127 {'R','e','m','o','v','e','O','D','B','C',0};
128 static const WCHAR szRemoveRegistryValues[] =
129 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
130 static const WCHAR szRemoveShortcuts[] =
131 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
132 static const WCHAR szRMCCPSearch[] =
133 {'R','M','C','C','P','S','e','a','r','c','h',0};
134 static const WCHAR szScheduleReboot[] =
135 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
136 static const WCHAR szSelfUnregModules[] =
137 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
138 static const WCHAR szSetODBCFolders[] =
139 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
140 static const WCHAR szStartServices[] =
141 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
142 static const WCHAR szStopServices[] =
143 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
144 static const WCHAR szUnpublishComponents[] =
145 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
146 static const WCHAR szUnpublishFeatures[] =
147 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
148 static const WCHAR szUnregisterComPlus[] =
149 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
150 static const WCHAR szUnregisterTypeLibraries[] =
151 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
152 static const WCHAR szValidateProductID[] =
153 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
154 static const WCHAR szWriteEnvironmentStrings[] =
155 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
157 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
159 static const WCHAR Query_t[] =
160 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
161 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
162 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
163 ' ','\'','%','s','\'',0};
164 MSIRECORD * row;
166 row = MSI_QueryGetRecord( package->db, Query_t, action );
167 if (!row)
168 return;
169 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
170 msiobj_release(&row->hdr);
173 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
174 UINT rc)
176 MSIRECORD * row;
177 static const WCHAR template_s[]=
178 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
179 '%','s', '.',0};
180 static const WCHAR template_e[]=
181 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
182 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
183 '%','i','.',0};
184 static const WCHAR format[] =
185 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
186 WCHAR message[1024];
187 WCHAR timet[0x100];
189 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
190 if (start)
191 sprintfW(message,template_s,timet,action);
192 else
193 sprintfW(message,template_e,timet,action,rc);
195 row = MSI_CreateRecord(1);
196 MSI_RecordSetStringW(row,1,message);
198 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
199 msiobj_release(&row->hdr);
202 enum parse_state
204 state_whitespace,
205 state_token,
206 state_quote
209 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
211 enum parse_state state = state_quote;
212 const WCHAR *p;
213 WCHAR *out = value;
214 int ignore, in_quotes = 0, count = 0, len = 0;
216 for (p = str; *p; p++)
218 ignore = 0;
219 switch (state)
221 case state_whitespace:
222 switch (*p)
224 case ' ':
225 if (!count) goto done;
226 in_quotes = 1;
227 ignore = 1;
228 len++;
229 break;
230 case '"':
231 state = state_quote;
232 if (in_quotes && p[1] != '\"') count--;
233 else count++;
234 break;
235 default:
236 state = state_token;
237 if (!count) in_quotes = 0;
238 else in_quotes = 1;
239 len++;
240 break;
242 break;
244 case state_token:
245 switch (*p)
247 case '"':
248 state = state_quote;
249 if (in_quotes) count--;
250 else count++;
251 break;
252 case ' ':
253 state = state_whitespace;
254 if (!count) goto done;
255 in_quotes = 1;
256 len++;
257 break;
258 default:
259 if (!count) in_quotes = 0;
260 else in_quotes = 1;
261 len++;
262 break;
264 break;
266 case state_quote:
267 switch (*p)
269 case '"':
270 if (in_quotes && p[1] != '\"') count--;
271 else count++;
272 break;
273 case ' ':
274 state = state_whitespace;
275 if (!count || (count > 1 && !len)) goto done;
276 in_quotes = 1;
277 len++;
278 break;
279 default:
280 state = state_token;
281 if (!count) in_quotes = 0;
282 else in_quotes = 1;
283 len++;
284 break;
286 break;
288 default: break;
290 if (!ignore) *out++ = *p;
293 done:
294 if (!len) *value = 0;
295 else *out = 0;
297 *quotes = count;
298 return p - str;
301 static void remove_quotes( WCHAR *str )
303 WCHAR *p = str;
304 int len = strlenW( str );
306 while ((p = strchrW( p, '"' )))
308 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
309 p++;
313 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
314 BOOL preserve_case )
316 LPCWSTR ptr, ptr2;
317 int num_quotes;
318 DWORD len;
319 WCHAR *prop, *val;
320 UINT r;
322 if (!szCommandLine)
323 return ERROR_SUCCESS;
325 ptr = szCommandLine;
326 while (*ptr)
328 while (*ptr == ' ') ptr++;
329 if (!*ptr) break;
331 ptr2 = strchrW( ptr, '=' );
332 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
334 len = ptr2 - ptr;
335 if (!len) return ERROR_INVALID_COMMAND_LINE;
337 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
338 memcpy( prop, ptr, len * sizeof(WCHAR) );
339 prop[len] = 0;
340 if (!preserve_case) struprW( prop );
342 ptr2++;
343 while (*ptr2 == ' ') ptr2++;
345 num_quotes = 0;
346 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
347 len = parse_prop( ptr2, val, &num_quotes );
348 if (num_quotes % 2)
350 WARN("unbalanced quotes\n");
351 msi_free( val );
352 msi_free( prop );
353 return ERROR_INVALID_COMMAND_LINE;
355 remove_quotes( val );
356 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
358 r = msi_set_property( package->db, prop, val );
359 if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
360 msi_reset_folders( package, TRUE );
362 msi_free( val );
363 msi_free( prop );
365 ptr = ptr2 + len;
368 return ERROR_SUCCESS;
371 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
373 LPCWSTR pc;
374 LPWSTR p, *ret = NULL;
375 UINT count = 0;
377 if (!str)
378 return ret;
380 /* count the number of substrings */
381 for ( pc = str, count = 0; pc; count++ )
383 pc = strchrW( pc, sep );
384 if (pc)
385 pc++;
388 /* allocate space for an array of substring pointers and the substrings */
389 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
390 (lstrlenW(str)+1) * sizeof(WCHAR) );
391 if (!ret)
392 return ret;
394 /* copy the string and set the pointers */
395 p = (LPWSTR) &ret[count+1];
396 lstrcpyW( p, str );
397 for( count = 0; (ret[count] = p); count++ )
399 p = strchrW( p, sep );
400 if (p)
401 *p++ = 0;
404 return ret;
407 static BOOL ui_sequence_exists( MSIPACKAGE *package )
409 MSIQUERY *view;
410 UINT rc;
412 static const WCHAR ExecSeqQuery [] =
413 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
414 '`','I','n','s','t','a','l','l',
415 'U','I','S','e','q','u','e','n','c','e','`',
416 ' ','W','H','E','R','E',' ',
417 '`','S','e','q','u','e','n','c','e','`',' ',
418 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
419 '`','S','e','q','u','e','n','c','e','`',0};
421 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
422 if (rc == ERROR_SUCCESS)
424 msiobj_release(&view->hdr);
425 return TRUE;
428 return FALSE;
431 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
433 LPWSTR source, check;
435 if (msi_get_property_int( package->db, szInstalled, 0 ))
437 HKEY hkey;
439 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
440 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
441 RegCloseKey( hkey );
443 else
445 LPWSTR p, db;
446 DWORD len;
448 db = msi_dup_property( package->db, szOriginalDatabase );
449 if (!db)
450 return ERROR_OUTOFMEMORY;
452 p = strrchrW( db, '\\' );
453 if (!p)
455 p = strrchrW( db, '/' );
456 if (!p)
458 msi_free(db);
459 return ERROR_SUCCESS;
463 len = p - db + 2;
464 source = msi_alloc( len * sizeof(WCHAR) );
465 lstrcpynW( source, db, len );
466 msi_free( db );
469 check = msi_dup_property( package->db, szSourceDir );
470 if (!check || replace)
472 UINT r = msi_set_property( package->db, szSourceDir, source );
473 if (r == ERROR_SUCCESS)
474 msi_reset_folders( package, TRUE );
476 msi_free( check );
478 check = msi_dup_property( package->db, szSOURCEDIR );
479 if (!check || replace)
480 msi_set_property( package->db, szSOURCEDIR, source );
482 msi_free( check );
483 msi_free( source );
485 return ERROR_SUCCESS;
488 static BOOL needs_ui_sequence(MSIPACKAGE *package)
490 INT level = msi_get_property_int(package->db, szUILevel, 0);
491 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
494 UINT msi_set_context(MSIPACKAGE *package)
496 int num;
498 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
500 num = msi_get_property_int(package->db, szAllUsers, 0);
501 if (num == 1 || num == 2)
502 package->Context = MSIINSTALLCONTEXT_MACHINE;
504 return ERROR_SUCCESS;
507 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
509 UINT rc;
510 LPCWSTR cond, action;
511 MSIPACKAGE *package = param;
513 action = MSI_RecordGetString(row,1);
514 if (!action)
516 ERR("Error is retrieving action name\n");
517 return ERROR_FUNCTION_FAILED;
520 /* check conditions */
521 cond = MSI_RecordGetString(row,2);
523 /* this is a hack to skip errors in the condition code */
524 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
526 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
527 return ERROR_SUCCESS;
530 if (needs_ui_sequence(package))
531 rc = ACTION_PerformUIAction(package, action, -1);
532 else
533 rc = ACTION_PerformAction(package, action, -1);
535 msi_dialog_check_messages( NULL );
537 if (package->CurrentInstallState != ERROR_SUCCESS)
538 rc = package->CurrentInstallState;
540 if (rc == ERROR_FUNCTION_NOT_CALLED)
541 rc = ERROR_SUCCESS;
543 if (rc != ERROR_SUCCESS)
544 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
546 return rc;
549 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
551 MSIQUERY * view;
552 UINT r;
553 static const WCHAR query[] =
554 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
555 '`','%','s','`',
556 ' ','W','H','E','R','E',' ',
557 '`','S','e','q','u','e','n','c','e','`',' ',
558 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
559 '`','S','e','q','u','e','n','c','e','`',0};
561 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
563 r = MSI_OpenQuery( package->db, &view, query, szTable );
564 if (r == ERROR_SUCCESS)
566 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
567 msiobj_release(&view->hdr);
570 return r;
573 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
575 MSIQUERY * view;
576 UINT rc;
577 static const WCHAR ExecSeqQuery[] =
578 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
579 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
580 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
581 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
582 'O','R','D','E','R',' ', 'B','Y',' ',
583 '`','S','e','q','u','e','n','c','e','`',0 };
584 static const WCHAR IVQuery[] =
585 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
586 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
587 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
588 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
589 ' ','\'', 'I','n','s','t','a','l','l',
590 'V','a','l','i','d','a','t','e','\'', 0};
591 INT seq = 0;
593 if (package->script->ExecuteSequenceRun)
595 TRACE("Execute Sequence already Run\n");
596 return ERROR_SUCCESS;
599 package->script->ExecuteSequenceRun = TRUE;
601 /* get the sequence number */
602 if (UIran)
604 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
605 if( !row )
606 return ERROR_FUNCTION_FAILED;
607 seq = MSI_RecordGetInteger(row,1);
608 msiobj_release(&row->hdr);
611 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
612 if (rc == ERROR_SUCCESS)
614 TRACE("Running the actions\n");
616 msi_set_property(package->db, szSourceDir, NULL);
618 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
619 msiobj_release(&view->hdr);
622 return rc;
625 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
627 MSIQUERY * view;
628 UINT rc;
629 static const WCHAR ExecSeqQuery [] =
630 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
631 '`','I','n','s','t','a','l','l',
632 'U','I','S','e','q','u','e','n','c','e','`',
633 ' ','W','H','E','R','E',' ',
634 '`','S','e','q','u','e','n','c','e','`',' ',
635 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
636 '`','S','e','q','u','e','n','c','e','`',0};
638 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
639 if (rc == ERROR_SUCCESS)
641 TRACE("Running the actions\n");
643 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
644 msiobj_release(&view->hdr);
647 return rc;
650 /********************************************************
651 * ACTION helper functions and functions that perform the actions
652 *******************************************************/
653 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
654 UINT* rc, UINT script, BOOL force )
656 BOOL ret=FALSE;
657 UINT arc;
659 arc = ACTION_CustomAction(package, action, script, force);
661 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
663 *rc = arc;
664 ret = TRUE;
666 return ret;
669 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
671 MSICOMPONENT *comp;
673 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
675 if (!strcmpW( Component, comp->Component )) return comp;
677 return NULL;
680 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
682 MSIFEATURE *feature;
684 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
686 if (!strcmpW( Feature, feature->Feature )) return feature;
688 return NULL;
691 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
693 MSIFILE *file;
695 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
697 if (!strcmpW( key, file->File )) return file;
699 return NULL;
702 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
704 MSIFILEPATCH *patch;
706 /* FIXME: There might be more than one patch */
707 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
709 if (!strcmpW( key, patch->File->File )) return patch;
711 return NULL;
714 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
716 MSIFOLDER *folder;
718 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
720 if (!strcmpW( dir, folder->Directory )) return folder;
722 return NULL;
726 * Recursively create all directories in the path.
727 * shamelessly stolen from setupapi/queue.c
729 BOOL msi_create_full_path( const WCHAR *path )
731 BOOL ret = TRUE;
732 WCHAR *new_path;
733 int len;
735 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
736 strcpyW( new_path, path );
738 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
739 new_path[len - 1] = 0;
741 while (!CreateDirectoryW( new_path, NULL ))
743 WCHAR *slash;
744 DWORD last_error = GetLastError();
745 if (last_error == ERROR_ALREADY_EXISTS) break;
746 if (last_error != ERROR_PATH_NOT_FOUND)
748 ret = FALSE;
749 break;
751 if (!(slash = strrchrW( new_path, '\\' )))
753 ret = FALSE;
754 break;
756 len = slash - new_path;
757 new_path[len] = 0;
758 if (!msi_create_full_path( new_path ))
760 ret = FALSE;
761 break;
763 new_path[len] = '\\';
765 msi_free( new_path );
766 return ret;
769 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
771 MSIRECORD *row;
773 row = MSI_CreateRecord( 4 );
774 MSI_RecordSetInteger( row, 1, a );
775 MSI_RecordSetInteger( row, 2, b );
776 MSI_RecordSetInteger( row, 3, c );
777 MSI_RecordSetInteger( row, 4, d );
778 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
779 msiobj_release( &row->hdr );
781 msi_dialog_check_messages( NULL );
784 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
786 static const WCHAR query[] =
787 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
788 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
789 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
790 WCHAR message[1024];
791 MSIRECORD *row = 0;
792 DWORD size;
794 if (!package->LastAction || strcmpW( package->LastAction, action ))
796 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
798 if (MSI_RecordIsNull( row, 3 ))
800 msiobj_release( &row->hdr );
801 return;
803 /* update the cached action format */
804 msi_free( package->ActionFormat );
805 package->ActionFormat = msi_dup_record_field( row, 3 );
806 msi_free( package->LastAction );
807 package->LastAction = strdupW( action );
808 msiobj_release( &row->hdr );
810 size = 1024;
811 MSI_RecordSetStringW( record, 0, package->ActionFormat );
812 MSI_FormatRecordW( package, record, message, &size );
813 row = MSI_CreateRecord( 1 );
814 MSI_RecordSetStringW( row, 1, message );
815 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
816 msiobj_release( &row->hdr );
819 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
821 if (!comp->Enabled)
823 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
824 return INSTALLSTATE_UNKNOWN;
826 if (package->need_rollback) return comp->Installed;
827 return comp->ActionRequest;
830 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
832 if (package->need_rollback) return feature->Installed;
833 return feature->ActionRequest;
836 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
838 MSIPACKAGE *package = param;
839 LPCWSTR dir, component, full_path;
840 MSIRECORD *uirow;
841 MSIFOLDER *folder;
842 MSICOMPONENT *comp;
844 component = MSI_RecordGetString(row, 2);
845 if (!component)
846 return ERROR_SUCCESS;
848 comp = msi_get_loaded_component(package, component);
849 if (!comp)
850 return ERROR_SUCCESS;
852 comp->Action = msi_get_component_action( package, comp );
853 if (comp->Action != INSTALLSTATE_LOCAL)
855 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
856 return ERROR_SUCCESS;
859 dir = MSI_RecordGetString(row,1);
860 if (!dir)
862 ERR("Unable to get folder id\n");
863 return ERROR_SUCCESS;
866 uirow = MSI_CreateRecord(1);
867 MSI_RecordSetStringW(uirow, 1, dir);
868 msi_ui_actiondata(package, szCreateFolders, uirow);
869 msiobj_release(&uirow->hdr);
871 full_path = msi_get_target_folder( package, dir );
872 if (!full_path)
874 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
875 return ERROR_SUCCESS;
877 TRACE("folder is %s\n", debugstr_w(full_path));
879 folder = msi_get_loaded_folder( package, dir );
880 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
881 folder->State = FOLDER_STATE_CREATED;
882 return ERROR_SUCCESS;
885 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
887 static const WCHAR query[] =
888 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
889 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
890 UINT rc;
891 MSIQUERY *view;
893 /* create all the empty folders specified in the CreateFolder table */
894 rc = MSI_DatabaseOpenViewW(package->db, query, &view );
895 if (rc != ERROR_SUCCESS)
896 return ERROR_SUCCESS;
898 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
899 msiobj_release(&view->hdr);
901 return rc;
904 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
906 MSIPACKAGE *package = param;
907 LPCWSTR dir, component, full_path;
908 MSIRECORD *uirow;
909 MSIFOLDER *folder;
910 MSICOMPONENT *comp;
912 component = MSI_RecordGetString(row, 2);
913 if (!component)
914 return ERROR_SUCCESS;
916 comp = msi_get_loaded_component(package, component);
917 if (!comp)
918 return ERROR_SUCCESS;
920 comp->Action = msi_get_component_action( package, comp );
921 if (comp->Action != INSTALLSTATE_ABSENT)
923 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
924 return ERROR_SUCCESS;
927 dir = MSI_RecordGetString( row, 1 );
928 if (!dir)
930 ERR("Unable to get folder id\n");
931 return ERROR_SUCCESS;
934 full_path = msi_get_target_folder( package, dir );
935 if (!full_path)
937 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
938 return ERROR_SUCCESS;
940 TRACE("folder is %s\n", debugstr_w(full_path));
942 uirow = MSI_CreateRecord( 1 );
943 MSI_RecordSetStringW( uirow, 1, dir );
944 msi_ui_actiondata( package, szRemoveFolders, uirow );
945 msiobj_release( &uirow->hdr );
947 RemoveDirectoryW( full_path );
948 folder = msi_get_loaded_folder( package, dir );
949 folder->State = FOLDER_STATE_REMOVED;
950 return ERROR_SUCCESS;
953 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
955 static const WCHAR query[] =
956 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
957 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
959 MSIQUERY *view;
960 UINT rc;
962 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
963 if (rc != ERROR_SUCCESS)
964 return ERROR_SUCCESS;
966 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
967 msiobj_release( &view->hdr );
969 return rc;
972 static UINT load_component( MSIRECORD *row, LPVOID param )
974 MSIPACKAGE *package = param;
975 MSICOMPONENT *comp;
977 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
978 if (!comp)
979 return ERROR_FUNCTION_FAILED;
981 list_add_tail( &package->components, &comp->entry );
983 /* fill in the data */
984 comp->Component = msi_dup_record_field( row, 1 );
986 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
988 comp->ComponentId = msi_dup_record_field( row, 2 );
989 comp->Directory = msi_dup_record_field( row, 3 );
990 comp->Attributes = MSI_RecordGetInteger(row,4);
991 comp->Condition = msi_dup_record_field( row, 5 );
992 comp->KeyPath = msi_dup_record_field( row, 6 );
994 comp->Installed = INSTALLSTATE_UNKNOWN;
995 comp->Action = INSTALLSTATE_UNKNOWN;
996 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
998 comp->assembly = msi_load_assembly( package, comp );
999 return ERROR_SUCCESS;
1002 UINT msi_load_all_components( MSIPACKAGE *package )
1004 static const WCHAR query[] = {
1005 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1006 '`','C','o','m','p','o','n','e','n','t','`',0 };
1007 MSIQUERY *view;
1008 UINT r;
1010 if (!list_empty(&package->components))
1011 return ERROR_SUCCESS;
1013 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1014 if (r != ERROR_SUCCESS)
1015 return r;
1017 if (!msi_init_assembly_caches( package ))
1019 ERR("can't initialize assembly caches\n");
1020 msiobj_release( &view->hdr );
1021 return ERROR_FUNCTION_FAILED;
1024 r = MSI_IterateRecords(view, NULL, load_component, package);
1025 msiobj_release(&view->hdr);
1027 msi_destroy_assembly_caches( package );
1028 return r;
1031 typedef struct {
1032 MSIPACKAGE *package;
1033 MSIFEATURE *feature;
1034 } _ilfs;
1036 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1038 ComponentList *cl;
1040 cl = msi_alloc( sizeof (*cl) );
1041 if ( !cl )
1042 return ERROR_NOT_ENOUGH_MEMORY;
1043 cl->component = comp;
1044 list_add_tail( &feature->Components, &cl->entry );
1046 return ERROR_SUCCESS;
1049 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1051 FeatureList *fl;
1053 fl = msi_alloc( sizeof(*fl) );
1054 if ( !fl )
1055 return ERROR_NOT_ENOUGH_MEMORY;
1056 fl->feature = child;
1057 list_add_tail( &parent->Children, &fl->entry );
1059 return ERROR_SUCCESS;
1062 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1064 _ilfs* ilfs = param;
1065 LPCWSTR component;
1066 MSICOMPONENT *comp;
1068 component = MSI_RecordGetString(row,1);
1070 /* check to see if the component is already loaded */
1071 comp = msi_get_loaded_component( ilfs->package, component );
1072 if (!comp)
1074 ERR("unknown component %s\n", debugstr_w(component));
1075 return ERROR_FUNCTION_FAILED;
1078 add_feature_component( ilfs->feature, comp );
1079 comp->Enabled = TRUE;
1081 return ERROR_SUCCESS;
1084 static UINT load_feature(MSIRECORD * row, LPVOID param)
1086 MSIPACKAGE* package = param;
1087 MSIFEATURE* feature;
1088 static const WCHAR Query1[] =
1089 {'S','E','L','E','C','T',' ',
1090 '`','C','o','m','p','o','n','e','n','t','_','`',
1091 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1092 'C','o','m','p','o','n','e','n','t','s','`',' ',
1093 'W','H','E','R','E',' ',
1094 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1095 MSIQUERY * view;
1096 UINT rc;
1097 _ilfs ilfs;
1099 /* fill in the data */
1101 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1102 if (!feature)
1103 return ERROR_NOT_ENOUGH_MEMORY;
1105 list_init( &feature->Children );
1106 list_init( &feature->Components );
1108 feature->Feature = msi_dup_record_field( row, 1 );
1110 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1112 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1113 feature->Title = msi_dup_record_field( row, 3 );
1114 feature->Description = msi_dup_record_field( row, 4 );
1116 if (!MSI_RecordIsNull(row,5))
1117 feature->Display = MSI_RecordGetInteger(row,5);
1119 feature->Level= MSI_RecordGetInteger(row,6);
1120 feature->Directory = msi_dup_record_field( row, 7 );
1121 feature->Attributes = MSI_RecordGetInteger(row,8);
1123 feature->Installed = INSTALLSTATE_UNKNOWN;
1124 feature->Action = INSTALLSTATE_UNKNOWN;
1125 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1127 list_add_tail( &package->features, &feature->entry );
1129 /* load feature components */
1131 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1132 if (rc != ERROR_SUCCESS)
1133 return ERROR_SUCCESS;
1135 ilfs.package = package;
1136 ilfs.feature = feature;
1138 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1139 msiobj_release(&view->hdr);
1141 return ERROR_SUCCESS;
1144 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1146 MSIPACKAGE *package = param;
1147 MSIFEATURE *parent, *child;
1149 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
1150 if (!child)
1151 return ERROR_FUNCTION_FAILED;
1153 if (!child->Feature_Parent)
1154 return ERROR_SUCCESS;
1156 parent = msi_get_loaded_feature( package, child->Feature_Parent );
1157 if (!parent)
1158 return ERROR_FUNCTION_FAILED;
1160 add_feature_child( parent, child );
1161 return ERROR_SUCCESS;
1164 UINT msi_load_all_features( MSIPACKAGE *package )
1166 static const WCHAR query[] = {
1167 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1168 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1169 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1170 MSIQUERY *view;
1171 UINT r;
1173 if (!list_empty(&package->features))
1174 return ERROR_SUCCESS;
1176 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1177 if (r != ERROR_SUCCESS)
1178 return r;
1180 r = MSI_IterateRecords( view, NULL, load_feature, package );
1181 if (r != ERROR_SUCCESS)
1182 return r;
1184 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1185 msiobj_release( &view->hdr );
1187 return r;
1190 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1192 if (!p)
1193 return p;
1194 p = strchrW(p, ch);
1195 if (!p)
1196 return p;
1197 *p = 0;
1198 return p+1;
1201 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1203 static const WCHAR query[] = {
1204 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1205 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1206 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1207 MSIQUERY *view = NULL;
1208 MSIRECORD *row = NULL;
1209 UINT r;
1211 TRACE("%s\n", debugstr_w(file->File));
1213 r = MSI_OpenQuery(package->db, &view, query, file->File);
1214 if (r != ERROR_SUCCESS)
1215 goto done;
1217 r = MSI_ViewExecute(view, NULL);
1218 if (r != ERROR_SUCCESS)
1219 goto done;
1221 r = MSI_ViewFetch(view, &row);
1222 if (r != ERROR_SUCCESS)
1223 goto done;
1225 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1226 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1227 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1228 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1229 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1231 done:
1232 if (view) msiobj_release(&view->hdr);
1233 if (row) msiobj_release(&row->hdr);
1234 return r;
1237 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1239 MSIRECORD *row;
1240 static const WCHAR query[] = {
1241 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1242 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1243 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1245 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1246 if (!row)
1248 WARN("query failed\n");
1249 return ERROR_FUNCTION_FAILED;
1252 file->disk_id = MSI_RecordGetInteger( row, 1 );
1253 msiobj_release( &row->hdr );
1254 return ERROR_SUCCESS;
1257 static UINT load_file(MSIRECORD *row, LPVOID param)
1259 MSIPACKAGE* package = param;
1260 LPCWSTR component;
1261 MSIFILE *file;
1263 /* fill in the data */
1265 file = msi_alloc_zero( sizeof (MSIFILE) );
1266 if (!file)
1267 return ERROR_NOT_ENOUGH_MEMORY;
1269 file->File = msi_dup_record_field( row, 1 );
1271 component = MSI_RecordGetString( row, 2 );
1272 file->Component = msi_get_loaded_component( package, component );
1274 if (!file->Component)
1276 WARN("Component not found: %s\n", debugstr_w(component));
1277 msi_free(file->File);
1278 msi_free(file);
1279 return ERROR_SUCCESS;
1282 file->FileName = msi_dup_record_field( row, 3 );
1283 msi_reduce_to_long_filename( file->FileName );
1285 file->ShortName = msi_dup_record_field( row, 3 );
1286 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1288 file->FileSize = MSI_RecordGetInteger( row, 4 );
1289 file->Version = msi_dup_record_field( row, 5 );
1290 file->Language = msi_dup_record_field( row, 6 );
1291 file->Attributes = MSI_RecordGetInteger( row, 7 );
1292 file->Sequence = MSI_RecordGetInteger( row, 8 );
1294 file->state = msifs_invalid;
1296 /* if the compressed bits are not set in the file attributes,
1297 * then read the information from the package word count property
1299 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1301 file->IsCompressed = FALSE;
1303 else if (file->Attributes &
1304 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1306 file->IsCompressed = TRUE;
1308 else if (file->Attributes & msidbFileAttributesNoncompressed)
1310 file->IsCompressed = FALSE;
1312 else
1314 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1317 load_file_hash(package, file);
1318 load_file_disk_id(package, file);
1320 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1322 list_add_tail( &package->files, &file->entry );
1324 return ERROR_SUCCESS;
1327 static UINT load_all_files(MSIPACKAGE *package)
1329 MSIQUERY * view;
1330 UINT rc;
1331 static const WCHAR Query[] =
1332 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1333 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1334 '`','S','e','q','u','e','n','c','e','`', 0};
1336 if (!list_empty(&package->files))
1337 return ERROR_SUCCESS;
1339 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1340 if (rc != ERROR_SUCCESS)
1341 return ERROR_SUCCESS;
1343 rc = MSI_IterateRecords(view, NULL, load_file, package);
1344 msiobj_release(&view->hdr);
1346 return ERROR_SUCCESS;
1349 static UINT load_media( MSIRECORD *row, LPVOID param )
1351 MSIPACKAGE *package = param;
1352 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1353 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1355 /* FIXME: load external cabinets and directory sources too */
1356 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
1357 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1358 return ERROR_SUCCESS;
1361 static UINT load_all_media( MSIPACKAGE *package )
1363 static const WCHAR query[] =
1364 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
1365 'O','R','D','E','R',' ','B','Y',' ','`','D','i','s','k','I','d','`',0};
1366 MSIQUERY *view;
1367 UINT r;
1369 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1370 if (r != ERROR_SUCCESS) return ERROR_SUCCESS;
1372 MSI_IterateRecords( view, NULL, load_media, package );
1373 msiobj_release( &view->hdr );
1374 return ERROR_SUCCESS;
1377 static UINT load_patch(MSIRECORD *row, LPVOID param)
1379 MSIPACKAGE *package = param;
1380 MSIFILEPATCH *patch;
1381 LPWSTR file_key;
1383 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
1384 if (!patch)
1385 return ERROR_NOT_ENOUGH_MEMORY;
1387 file_key = msi_dup_record_field( row, 1 );
1388 patch->File = msi_get_loaded_file( package, file_key );
1389 msi_free(file_key);
1391 if( !patch->File )
1393 ERR("Failed to find target for patch in File table\n");
1394 msi_free(patch);
1395 return ERROR_FUNCTION_FAILED;
1398 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1400 /* FIXME: The database should be properly transformed */
1401 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
1403 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1404 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1405 patch->IsApplied = FALSE;
1407 /* FIXME:
1408 * Header field - for patch validation.
1409 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1412 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
1414 list_add_tail( &package->filepatches, &patch->entry );
1416 return ERROR_SUCCESS;
1419 static UINT load_all_patches(MSIPACKAGE *package)
1421 MSIQUERY *view;
1422 UINT rc;
1423 static const WCHAR Query[] =
1424 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1425 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
1426 '`','S','e','q','u','e','n','c','e','`',0};
1428 if (!list_empty(&package->filepatches))
1429 return ERROR_SUCCESS;
1431 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1432 if (rc != ERROR_SUCCESS)
1433 return ERROR_SUCCESS;
1435 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1436 msiobj_release(&view->hdr);
1438 return ERROR_SUCCESS;
1441 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1443 static const WCHAR query[] = {
1444 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1445 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
1446 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
1447 MSIQUERY *view;
1449 folder->persistent = FALSE;
1450 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
1452 if (!MSI_ViewExecute( view, NULL ))
1454 MSIRECORD *rec;
1455 if (!MSI_ViewFetch( view, &rec ))
1457 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1458 folder->persistent = TRUE;
1459 msiobj_release( &rec->hdr );
1462 msiobj_release( &view->hdr );
1464 return ERROR_SUCCESS;
1467 static UINT load_folder( MSIRECORD *row, LPVOID param )
1469 MSIPACKAGE *package = param;
1470 static WCHAR szEmpty[] = { 0 };
1471 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1472 MSIFOLDER *folder;
1474 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1475 list_init( &folder->children );
1476 folder->Directory = msi_dup_record_field( row, 1 );
1477 folder->Parent = msi_dup_record_field( row, 2 );
1478 p = msi_dup_record_field(row, 3);
1480 TRACE("%s\n", debugstr_w(folder->Directory));
1482 /* split src and target dir */
1483 tgt_short = p;
1484 src_short = folder_split_path( p, ':' );
1486 /* split the long and short paths */
1487 tgt_long = folder_split_path( tgt_short, '|' );
1488 src_long = folder_split_path( src_short, '|' );
1490 /* check for no-op dirs */
1491 if (tgt_short && !strcmpW( szDot, tgt_short ))
1492 tgt_short = szEmpty;
1493 if (src_short && !strcmpW( szDot, src_short ))
1494 src_short = szEmpty;
1496 if (!tgt_long)
1497 tgt_long = tgt_short;
1499 if (!src_short) {
1500 src_short = tgt_short;
1501 src_long = tgt_long;
1504 if (!src_long)
1505 src_long = src_short;
1507 /* FIXME: use the target short path too */
1508 folder->TargetDefault = strdupW(tgt_long);
1509 folder->SourceShortPath = strdupW(src_short);
1510 folder->SourceLongPath = strdupW(src_long);
1511 msi_free(p);
1513 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1514 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1515 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1517 load_folder_persistence( package, folder );
1519 list_add_tail( &package->folders, &folder->entry );
1520 return ERROR_SUCCESS;
1523 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1525 FolderList *fl;
1527 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1528 fl->folder = child;
1529 list_add_tail( &parent->children, &fl->entry );
1530 return ERROR_SUCCESS;
1533 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1535 MSIPACKAGE *package = param;
1536 MSIFOLDER *parent, *child;
1538 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1539 return ERROR_FUNCTION_FAILED;
1541 if (!child->Parent) return ERROR_SUCCESS;
1543 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1544 return ERROR_FUNCTION_FAILED;
1546 return add_folder_child( parent, child );
1549 static UINT load_all_folders( MSIPACKAGE *package )
1551 static const WCHAR query[] = {
1552 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1553 '`','D','i','r','e','c','t','o','r','y','`',0 };
1554 MSIQUERY *view;
1555 UINT r;
1557 if (!list_empty(&package->folders))
1558 return ERROR_SUCCESS;
1560 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1561 if (r != ERROR_SUCCESS)
1562 return r;
1564 r = MSI_IterateRecords( view, NULL, load_folder, package );
1565 if (r != ERROR_SUCCESS)
1567 msiobj_release( &view->hdr );
1568 return r;
1570 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1571 msiobj_release( &view->hdr );
1572 return r;
1575 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1577 msi_set_property( package->db, szCostingComplete, szZero );
1578 msi_set_property( package->db, szRootDrive, szCRoot );
1580 load_all_folders( package );
1581 msi_load_all_components( package );
1582 msi_load_all_features( package );
1583 load_all_files( package );
1584 load_all_patches( package );
1585 load_all_media( package );
1587 return ERROR_SUCCESS;
1590 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index )
1592 const WCHAR *action = package->script->Actions[script][index];
1593 ui_actionstart( package, action );
1594 TRACE("executing %s\n", debugstr_w(action));
1595 return ACTION_PerformAction( package, action, script );
1598 static UINT execute_script( MSIPACKAGE *package, UINT script )
1600 UINT i, rc = ERROR_SUCCESS;
1602 TRACE("executing script %u\n", script);
1604 if (!package->script)
1606 ERR("no script!\n");
1607 return ERROR_FUNCTION_FAILED;
1609 if (script == ROLLBACK_SCRIPT)
1611 for (i = package->script->ActionCount[script]; i > 0; i--)
1613 rc = execute_script_action( package, script, i - 1 );
1614 if (rc != ERROR_SUCCESS) break;
1617 else
1619 for (i = 0; i < package->script->ActionCount[script]; i++)
1621 rc = execute_script_action( package, script, i );
1622 if (rc != ERROR_SUCCESS) break;
1625 msi_free_action_script(package, script);
1626 return rc;
1629 static UINT ACTION_FileCost(MSIPACKAGE *package)
1631 return ERROR_SUCCESS;
1634 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1636 MSICOMPONENT *comp;
1637 UINT r;
1639 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1641 if (!comp->ComponentId) continue;
1643 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1644 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1645 &comp->Installed );
1646 if (r != ERROR_SUCCESS)
1647 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1648 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1649 &comp->Installed );
1650 if (r != ERROR_SUCCESS)
1651 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1652 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1653 &comp->Installed );
1654 if (r != ERROR_SUCCESS)
1655 comp->Installed = INSTALLSTATE_ABSENT;
1659 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1661 MSIFEATURE *feature;
1663 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1665 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1667 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1668 feature->Installed = INSTALLSTATE_ABSENT;
1669 else
1670 feature->Installed = state;
1674 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1676 return (feature->Level > 0 && feature->Level <= level);
1679 static BOOL process_state_property(MSIPACKAGE* package, int level,
1680 LPCWSTR property, INSTALLSTATE state)
1682 LPWSTR override;
1683 MSIFEATURE *feature;
1685 override = msi_dup_property( package->db, property );
1686 if (!override)
1687 return FALSE;
1689 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1691 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1692 continue;
1694 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1696 if (!strcmpiW( override, szAll ))
1698 if (feature->Installed != state)
1700 feature->Action = state;
1701 feature->ActionRequest = state;
1704 else
1706 LPWSTR ptr = override;
1707 LPWSTR ptr2 = strchrW(override,',');
1709 while (ptr)
1711 int len = ptr2 - ptr;
1713 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1714 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1716 if (feature->Installed != state)
1718 feature->Action = state;
1719 feature->ActionRequest = state;
1721 break;
1723 if (ptr2)
1725 ptr=ptr2+1;
1726 ptr2 = strchrW(ptr,',');
1728 else
1729 break;
1733 msi_free(override);
1734 return TRUE;
1737 static BOOL process_overrides( MSIPACKAGE *package, int level )
1739 static const WCHAR szAddLocal[] =
1740 {'A','D','D','L','O','C','A','L',0};
1741 static const WCHAR szAddSource[] =
1742 {'A','D','D','S','O','U','R','C','E',0};
1743 static const WCHAR szAdvertise[] =
1744 {'A','D','V','E','R','T','I','S','E',0};
1745 BOOL ret = FALSE;
1747 /* all these activation/deactivation things happen in order and things
1748 * later on the list override things earlier on the list.
1750 * 0 INSTALLLEVEL processing
1751 * 1 ADDLOCAL
1752 * 2 REMOVE
1753 * 3 ADDSOURCE
1754 * 4 ADDDEFAULT
1755 * 5 REINSTALL
1756 * 6 ADVERTISE
1757 * 7 COMPADDLOCAL
1758 * 8 COMPADDSOURCE
1759 * 9 FILEADDLOCAL
1760 * 10 FILEADDSOURCE
1761 * 11 FILEADDDEFAULT
1763 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1764 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1765 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1766 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1767 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1769 if (ret)
1770 msi_set_property( package->db, szPreselected, szOne );
1772 return ret;
1775 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1777 int level;
1778 MSICOMPONENT* component;
1779 MSIFEATURE *feature;
1781 TRACE("Checking Install Level\n");
1783 level = msi_get_property_int(package->db, szInstallLevel, 1);
1785 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1787 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1789 if (!is_feature_selected( feature, level )) continue;
1791 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1793 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1795 feature->Action = INSTALLSTATE_SOURCE;
1796 feature->ActionRequest = INSTALLSTATE_SOURCE;
1798 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1800 feature->Action = INSTALLSTATE_ADVERTISED;
1801 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1803 else
1805 feature->Action = INSTALLSTATE_LOCAL;
1806 feature->ActionRequest = INSTALLSTATE_LOCAL;
1810 /* disable child features of unselected parent or follow parent */
1811 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1813 FeatureList *fl;
1815 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1817 if (!is_feature_selected( feature, level ))
1819 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1820 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1822 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1824 fl->feature->Action = feature->Action;
1825 fl->feature->ActionRequest = feature->ActionRequest;
1830 else /* preselected */
1832 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1834 if (!is_feature_selected( feature, level )) continue;
1836 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1838 if (feature->Installed == INSTALLSTATE_ABSENT)
1840 feature->Action = INSTALLSTATE_UNKNOWN;
1841 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1843 else
1845 feature->Action = feature->Installed;
1846 feature->ActionRequest = feature->Installed;
1850 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1852 FeatureList *fl;
1854 if (!is_feature_selected( feature, level )) continue;
1856 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1858 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1860 fl->feature->Action = feature->Action;
1861 fl->feature->ActionRequest = feature->ActionRequest;
1867 /* now we want to set component state based based on feature state */
1868 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1870 ComponentList *cl;
1872 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1873 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1874 feature->ActionRequest, feature->Action);
1876 if (!is_feature_selected( feature, level )) continue;
1878 /* features with components that have compressed files are made local */
1879 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1881 if (cl->component->ForceLocalState &&
1882 feature->ActionRequest == INSTALLSTATE_SOURCE)
1884 feature->Action = INSTALLSTATE_LOCAL;
1885 feature->ActionRequest = INSTALLSTATE_LOCAL;
1886 break;
1890 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1892 component = cl->component;
1894 switch (feature->ActionRequest)
1896 case INSTALLSTATE_ABSENT:
1897 component->anyAbsent = 1;
1898 break;
1899 case INSTALLSTATE_ADVERTISED:
1900 component->hasAdvertiseFeature = 1;
1901 break;
1902 case INSTALLSTATE_SOURCE:
1903 component->hasSourceFeature = 1;
1904 break;
1905 case INSTALLSTATE_LOCAL:
1906 component->hasLocalFeature = 1;
1907 break;
1908 case INSTALLSTATE_DEFAULT:
1909 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1910 component->hasAdvertiseFeature = 1;
1911 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1912 component->hasSourceFeature = 1;
1913 else
1914 component->hasLocalFeature = 1;
1915 break;
1916 default:
1917 break;
1922 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1924 /* check if it's local or source */
1925 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1926 (component->hasLocalFeature || component->hasSourceFeature))
1928 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1929 !component->ForceLocalState)
1931 component->Action = INSTALLSTATE_SOURCE;
1932 component->ActionRequest = INSTALLSTATE_SOURCE;
1934 else
1936 component->Action = INSTALLSTATE_LOCAL;
1937 component->ActionRequest = INSTALLSTATE_LOCAL;
1939 continue;
1942 /* if any feature is local, the component must be local too */
1943 if (component->hasLocalFeature)
1945 component->Action = INSTALLSTATE_LOCAL;
1946 component->ActionRequest = INSTALLSTATE_LOCAL;
1947 continue;
1949 if (component->hasSourceFeature)
1951 component->Action = INSTALLSTATE_SOURCE;
1952 component->ActionRequest = INSTALLSTATE_SOURCE;
1953 continue;
1955 if (component->hasAdvertiseFeature)
1957 component->Action = INSTALLSTATE_ADVERTISED;
1958 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1959 continue;
1961 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1962 if (component->anyAbsent &&
1963 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
1965 component->Action = INSTALLSTATE_ABSENT;
1966 component->ActionRequest = INSTALLSTATE_ABSENT;
1970 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1972 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1974 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1975 component->Action = INSTALLSTATE_LOCAL;
1976 component->ActionRequest = INSTALLSTATE_LOCAL;
1979 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1980 component->Installed == INSTALLSTATE_SOURCE &&
1981 component->hasSourceFeature)
1983 component->Action = INSTALLSTATE_UNKNOWN;
1984 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1987 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
1988 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1991 return ERROR_SUCCESS;
1994 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1996 MSIPACKAGE *package = param;
1997 LPCWSTR name;
1998 MSIFEATURE *feature;
2000 name = MSI_RecordGetString( row, 1 );
2002 feature = msi_get_loaded_feature( package, name );
2003 if (!feature)
2004 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2005 else
2007 LPCWSTR Condition;
2008 Condition = MSI_RecordGetString(row,3);
2010 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2012 int level = MSI_RecordGetInteger(row,2);
2013 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2014 feature->Level = level;
2017 return ERROR_SUCCESS;
2020 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2022 static const WCHAR name[] = {'\\',0};
2023 VS_FIXEDFILEINFO *ptr, *ret;
2024 LPVOID version;
2025 DWORD versize, handle;
2026 UINT sz;
2028 versize = GetFileVersionInfoSizeW( filename, &handle );
2029 if (!versize)
2030 return NULL;
2032 version = msi_alloc( versize );
2033 if (!version)
2034 return NULL;
2036 GetFileVersionInfoW( filename, 0, versize, version );
2038 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2040 msi_free( version );
2041 return NULL;
2044 ret = msi_alloc( sz );
2045 memcpy( ret, ptr, sz );
2047 msi_free( version );
2048 return ret;
2051 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2053 DWORD ms, ls;
2055 msi_parse_version_string( version, &ms, &ls );
2057 if (fi->dwFileVersionMS > ms) return 1;
2058 else if (fi->dwFileVersionMS < ms) return -1;
2059 else if (fi->dwFileVersionLS > ls) return 1;
2060 else if (fi->dwFileVersionLS < ls) return -1;
2061 return 0;
2064 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2066 DWORD ms1, ms2;
2068 msi_parse_version_string( ver1, &ms1, NULL );
2069 msi_parse_version_string( ver2, &ms2, NULL );
2071 if (ms1 > ms2) return 1;
2072 else if (ms1 < ms2) return -1;
2073 return 0;
2076 DWORD msi_get_disk_file_size( LPCWSTR filename )
2078 HANDLE file;
2079 DWORD size;
2081 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2082 if (file == INVALID_HANDLE_VALUE)
2083 return INVALID_FILE_SIZE;
2085 size = GetFileSize( file, NULL );
2086 TRACE("size is %u\n", size);
2087 CloseHandle( file );
2088 return size;
2091 BOOL msi_file_hash_matches( MSIFILE *file )
2093 UINT r;
2094 MSIFILEHASHINFO hash;
2096 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2097 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2098 if (r != ERROR_SUCCESS)
2099 return FALSE;
2101 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2104 static WCHAR *get_temp_dir( void )
2106 static UINT id;
2107 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2109 GetTempPathW( MAX_PATH, tmp );
2110 for (;;)
2112 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2113 if (CreateDirectoryW( dir, NULL )) break;
2115 return strdupW( dir );
2119 * msi_build_directory_name()
2121 * This function is to save messing round with directory names
2122 * It handles adding backslashes between path segments,
2123 * and can add \ at the end of the directory name if told to.
2125 * It takes a variable number of arguments.
2126 * It always allocates a new string for the result, so make sure
2127 * to free the return value when finished with it.
2129 * The first arg is the number of path segments that follow.
2130 * The arguments following count are a list of path segments.
2131 * A path segment may be NULL.
2133 * Path segments will be added with a \ separating them.
2134 * A \ will not be added after the last segment, however if the
2135 * last segment is NULL, then the last character will be a \
2137 WCHAR *msi_build_directory_name( DWORD count, ... )
2139 DWORD sz = 1, i;
2140 WCHAR *dir;
2141 va_list va;
2143 va_start( va, count );
2144 for (i = 0; i < count; i++)
2146 const WCHAR *str = va_arg( va, const WCHAR * );
2147 if (str) sz += strlenW( str ) + 1;
2149 va_end( va );
2151 dir = msi_alloc( sz * sizeof(WCHAR) );
2152 dir[0] = 0;
2154 va_start( va, count );
2155 for (i = 0; i < count; i++)
2157 const WCHAR *str = va_arg( va, const WCHAR * );
2158 if (!str) continue;
2159 strcatW( dir, str );
2160 if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
2162 va_end( va );
2163 return dir;
2166 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2168 MSIASSEMBLY *assembly = file->Component->assembly;
2170 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2172 msi_free( file->TargetPath );
2173 if (assembly && !assembly->application)
2175 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2176 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2177 msi_track_tempfile( package, file->TargetPath );
2179 else
2181 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2182 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2185 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2188 static UINT calculate_file_cost( MSIPACKAGE *package )
2190 VS_FIXEDFILEINFO *file_version;
2191 WCHAR *font_version;
2192 MSIFILE *file;
2194 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2196 MSICOMPONENT *comp = file->Component;
2197 DWORD file_size;
2199 if (!comp->Enabled) continue;
2201 if (file->IsCompressed)
2202 comp->ForceLocalState = TRUE;
2204 set_target_path( package, file );
2206 if ((comp->assembly && !comp->assembly->installed) ||
2207 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2209 comp->Cost += file->FileSize;
2210 continue;
2212 file_size = msi_get_disk_file_size( file->TargetPath );
2214 if (file->Version)
2216 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2218 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2220 comp->Cost += file->FileSize - file_size;
2222 msi_free( file_version );
2223 continue;
2225 else if ((font_version = font_version_from_file( file->TargetPath )))
2227 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2229 comp->Cost += file->FileSize - file_size;
2231 msi_free( font_version );
2232 continue;
2235 if (file_size != file->FileSize)
2237 comp->Cost += file->FileSize - file_size;
2240 return ERROR_SUCCESS;
2243 void msi_clean_path( WCHAR *p )
2245 WCHAR *q = p;
2246 int n, len = 0;
2248 while (1)
2250 /* copy until the end of the string or a space */
2251 while (*p != ' ' && (*q = *p))
2253 p++, len++;
2254 /* reduce many backslashes to one */
2255 if (*p != '\\' || *q != '\\')
2256 q++;
2259 /* quit at the end of the string */
2260 if (!*p)
2261 break;
2263 /* count the number of spaces */
2264 n = 0;
2265 while (p[n] == ' ')
2266 n++;
2268 /* if it's leading or trailing space, skip it */
2269 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2270 p += n;
2271 else /* copy n spaces */
2272 while (n && (*q++ = *p++)) n--;
2276 static WCHAR *get_target_dir_property( MSIDATABASE *db )
2278 int len;
2279 WCHAR *path, *target_dir = msi_dup_property( db, szTargetDir );
2281 if (!target_dir) return NULL;
2283 len = strlenW( target_dir );
2284 if (target_dir[len - 1] == '\\') return target_dir;
2285 if ((path = msi_alloc( (len + 2) * sizeof(WCHAR) )))
2287 strcpyW( path, target_dir );
2288 path[len] = '\\';
2289 path[len + 1] = 0;
2291 msi_free( target_dir );
2292 return path;
2295 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2297 FolderList *fl;
2298 MSIFOLDER *folder, *parent, *child;
2299 WCHAR *path;
2301 TRACE("resolving %s\n", debugstr_w(name));
2303 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2305 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
2307 if (!load_prop || !(path = get_target_dir_property( package->db )))
2309 path = msi_dup_property( package->db, szRootDrive );
2312 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2314 parent = msi_get_loaded_folder( package, folder->Parent );
2315 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2317 msi_clean_path( path );
2318 if (folder->ResolvedTarget && !strcmpiW( path, folder->ResolvedTarget ))
2320 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2321 msi_free( path );
2322 return;
2324 msi_set_property( package->db, folder->Directory, path );
2325 msi_free( folder->ResolvedTarget );
2326 folder->ResolvedTarget = path;
2328 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2330 child = fl->folder;
2331 msi_resolve_target_folder( package, child->Directory, load_prop );
2333 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2336 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2338 static const WCHAR condition_query[] =
2339 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','C','o','n','d','i','t','i','o','n','`',0};
2340 static const WCHAR szOutOfDiskSpace[] =
2341 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2342 MSICOMPONENT *comp;
2343 UINT rc = ERROR_SUCCESS;
2344 MSIQUERY * view;
2345 LPWSTR level;
2347 TRACE("Building directory properties\n");
2348 msi_resolve_target_folder( package, szTargetDir, TRUE );
2350 TRACE("Evaluating component conditions\n");
2351 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2353 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2355 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2356 comp->Enabled = FALSE;
2358 else
2359 comp->Enabled = TRUE;
2362 /* read components states from the registry */
2363 ACTION_GetComponentInstallStates(package);
2364 ACTION_GetFeatureInstallStates(package);
2366 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
2368 TRACE("Evaluating feature conditions\n");
2370 rc = MSI_DatabaseOpenViewW( package->db, condition_query, &view );
2371 if (rc == ERROR_SUCCESS)
2373 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2374 msiobj_release( &view->hdr );
2378 TRACE("Calculating file cost\n");
2379 calculate_file_cost( package );
2381 msi_set_property( package->db, szCostingComplete, szOne );
2382 /* set default run level if not set */
2383 level = msi_dup_property( package->db, szInstallLevel );
2384 if (!level)
2385 msi_set_property( package->db, szInstallLevel, szOne );
2386 msi_free(level);
2388 /* FIXME: check volume disk space */
2389 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2391 return MSI_SetFeatureStates(package);
2394 /* OK this value is "interpreted" and then formatted based on the
2395 first few characters */
2396 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2397 DWORD *size)
2399 LPSTR data = NULL;
2401 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2403 if (value[1]=='x')
2405 LPWSTR ptr;
2406 CHAR byte[5];
2407 LPWSTR deformated = NULL;
2408 int count;
2410 deformat_string(package, &value[2], &deformated);
2412 /* binary value type */
2413 ptr = deformated;
2414 *type = REG_BINARY;
2415 if (strlenW(ptr)%2)
2416 *size = (strlenW(ptr)/2)+1;
2417 else
2418 *size = strlenW(ptr)/2;
2420 data = msi_alloc(*size);
2422 byte[0] = '0';
2423 byte[1] = 'x';
2424 byte[4] = 0;
2425 count = 0;
2426 /* if uneven pad with a zero in front */
2427 if (strlenW(ptr)%2)
2429 byte[2]= '0';
2430 byte[3]= *ptr;
2431 ptr++;
2432 data[count] = (BYTE)strtol(byte,NULL,0);
2433 count ++;
2434 TRACE("Uneven byte count\n");
2436 while (*ptr)
2438 byte[2]= *ptr;
2439 ptr++;
2440 byte[3]= *ptr;
2441 ptr++;
2442 data[count] = (BYTE)strtol(byte,NULL,0);
2443 count ++;
2445 msi_free(deformated);
2447 TRACE("Data %i bytes(%i)\n",*size,count);
2449 else
2451 LPWSTR deformated;
2452 LPWSTR p;
2453 DWORD d = 0;
2454 deformat_string(package, &value[1], &deformated);
2456 *type=REG_DWORD;
2457 *size = sizeof(DWORD);
2458 data = msi_alloc(*size);
2459 p = deformated;
2460 if (*p == '-')
2461 p++;
2462 while (*p)
2464 if ( (*p < '0') || (*p > '9') )
2465 break;
2466 d *= 10;
2467 d += (*p - '0');
2468 p++;
2470 if (deformated[0] == '-')
2471 d = -d;
2472 *(LPDWORD)data = d;
2473 TRACE("DWORD %i\n",*(LPDWORD)data);
2475 msi_free(deformated);
2478 else
2480 static const WCHAR szMulti[] = {'[','~',']',0};
2481 LPCWSTR ptr;
2482 *type=REG_SZ;
2484 if (value[0]=='#')
2486 if (value[1]=='%')
2488 ptr = &value[2];
2489 *type=REG_EXPAND_SZ;
2491 else
2492 ptr = &value[1];
2494 else
2495 ptr=value;
2497 if (strstrW(value, szMulti))
2498 *type = REG_MULTI_SZ;
2500 /* remove initial delimiter */
2501 if (!strncmpW(value, szMulti, 3))
2502 ptr = value + 3;
2504 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2506 /* add double NULL terminator */
2507 if (*type == REG_MULTI_SZ)
2509 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2510 data = msi_realloc_zero(data, *size);
2513 return data;
2516 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2518 const WCHAR *ret;
2520 switch (root)
2522 case -1:
2523 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2525 *root_key = HKEY_LOCAL_MACHINE;
2526 ret = szHLM;
2528 else
2530 *root_key = HKEY_CURRENT_USER;
2531 ret = szHCU;
2533 break;
2534 case 0:
2535 *root_key = HKEY_CLASSES_ROOT;
2536 ret = szHCR;
2537 break;
2538 case 1:
2539 *root_key = HKEY_CURRENT_USER;
2540 ret = szHCU;
2541 break;
2542 case 2:
2543 *root_key = HKEY_LOCAL_MACHINE;
2544 ret = szHLM;
2545 break;
2546 case 3:
2547 *root_key = HKEY_USERS;
2548 ret = szHU;
2549 break;
2550 default:
2551 ERR("Unknown root %i\n", root);
2552 return NULL;
2555 return ret;
2558 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2560 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2561 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2563 if (is_64bit && package->platform == PLATFORM_INTEL &&
2564 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2566 UINT size;
2567 WCHAR *path_32node;
2569 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR);
2570 if (!(path_32node = msi_alloc( size ))) return NULL;
2572 memcpy( path_32node, path, len * sizeof(WCHAR) );
2573 strcpyW( path_32node + len, szWow6432Node );
2574 strcatW( path_32node, szBackSlash );
2575 strcatW( path_32node, path + len );
2576 return path_32node;
2579 return strdupW( path );
2582 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2584 MSIPACKAGE *package = param;
2585 LPSTR value_data = NULL;
2586 HKEY root_key, hkey;
2587 DWORD type,size;
2588 LPWSTR deformated, uikey, keypath;
2589 LPCWSTR szRoot, component, name, key, value;
2590 MSICOMPONENT *comp;
2591 MSIRECORD * uirow;
2592 INT root;
2593 BOOL check_first = FALSE;
2594 UINT rc;
2596 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2598 component = MSI_RecordGetString(row, 6);
2599 comp = msi_get_loaded_component(package,component);
2600 if (!comp)
2601 return ERROR_SUCCESS;
2603 comp->Action = msi_get_component_action( package, comp );
2604 if (comp->Action != INSTALLSTATE_LOCAL)
2606 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2607 return ERROR_SUCCESS;
2610 name = MSI_RecordGetString(row, 4);
2611 if( MSI_RecordIsNull(row,5) && name )
2613 /* null values can have special meanings */
2614 if (name[0]=='-' && name[1] == 0)
2615 return ERROR_SUCCESS;
2616 else if ((name[0]=='+' && name[1] == 0) ||
2617 (name[0] == '*' && name[1] == 0))
2618 name = NULL;
2619 check_first = TRUE;
2622 root = MSI_RecordGetInteger(row,2);
2623 key = MSI_RecordGetString(row, 3);
2625 szRoot = get_root_key( package, root, &root_key );
2626 if (!szRoot)
2627 return ERROR_SUCCESS;
2629 deformat_string(package, key , &deformated);
2630 size = strlenW(deformated) + strlenW(szRoot) + 1;
2631 uikey = msi_alloc(size*sizeof(WCHAR));
2632 strcpyW(uikey,szRoot);
2633 strcatW(uikey,deformated);
2635 keypath = get_keypath( package, root_key, deformated );
2636 msi_free( deformated );
2637 if (RegCreateKeyW( root_key, keypath, &hkey ))
2639 ERR("Could not create key %s\n", debugstr_w(keypath));
2640 msi_free(uikey);
2641 msi_free(keypath);
2642 return ERROR_SUCCESS;
2645 value = MSI_RecordGetString(row,5);
2646 if (value)
2647 value_data = parse_value(package, value, &type, &size);
2648 else
2650 value_data = (LPSTR)strdupW(szEmpty);
2651 size = sizeof(szEmpty);
2652 type = REG_SZ;
2655 deformat_string(package, name, &deformated);
2657 if (!check_first)
2659 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2660 debugstr_w(uikey));
2661 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2663 else
2665 DWORD sz = 0;
2666 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2667 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2669 TRACE("value %s of %s checked already exists\n",
2670 debugstr_w(deformated), debugstr_w(uikey));
2672 else
2674 TRACE("Checked and setting value %s of %s\n",
2675 debugstr_w(deformated), debugstr_w(uikey));
2676 if (deformated || size)
2677 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2680 RegCloseKey(hkey);
2682 uirow = MSI_CreateRecord(3);
2683 MSI_RecordSetStringW(uirow,2,deformated);
2684 MSI_RecordSetStringW(uirow,1,uikey);
2685 if (type == REG_SZ || type == REG_EXPAND_SZ)
2686 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2687 msi_ui_actiondata( package, szWriteRegistryValues, uirow );
2688 msiobj_release( &uirow->hdr );
2690 msi_free(value_data);
2691 msi_free(deformated);
2692 msi_free(uikey);
2693 msi_free(keypath);
2695 return ERROR_SUCCESS;
2698 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2700 UINT rc;
2701 MSIQUERY * view;
2702 static const WCHAR ExecSeqQuery[] =
2703 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2704 '`','R','e','g','i','s','t','r','y','`',0 };
2706 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2707 if (rc != ERROR_SUCCESS)
2708 return ERROR_SUCCESS;
2710 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2711 msiobj_release(&view->hdr);
2712 return rc;
2715 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2717 LONG res;
2718 HKEY hkey;
2719 DWORD num_subkeys, num_values;
2721 if (delete_key)
2723 if ((res = RegDeleteTreeW( hkey_root, key )))
2725 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2727 return;
2730 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2732 if ((res = RegDeleteValueW( hkey, value )))
2734 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2736 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2737 NULL, NULL, NULL, NULL );
2738 RegCloseKey( hkey );
2739 if (!res && !num_subkeys && !num_values)
2741 TRACE("Removing empty key %s\n", debugstr_w(key));
2742 RegDeleteKeyW( hkey_root, key );
2744 return;
2746 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), 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 else if ((name[0] == '-' && !name[1]) || (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 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2806 msi_free( keypath );
2808 uirow = MSI_CreateRecord( 2 );
2809 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2810 MSI_RecordSetStringW( uirow, 2, deformated_name );
2811 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2812 msiobj_release( &uirow->hdr );
2814 msi_free( ui_key_str );
2815 msi_free( deformated_name );
2816 return ERROR_SUCCESS;
2819 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2821 MSIPACKAGE *package = param;
2822 LPCWSTR component, name, key_str, root_key_str;
2823 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2824 MSICOMPONENT *comp;
2825 MSIRECORD *uirow;
2826 BOOL delete_key = FALSE;
2827 HKEY hkey_root;
2828 UINT size;
2829 INT root;
2831 component = MSI_RecordGetString( row, 5 );
2832 comp = msi_get_loaded_component( package, component );
2833 if (!comp)
2834 return ERROR_SUCCESS;
2836 comp->Action = msi_get_component_action( package, comp );
2837 if (comp->Action != INSTALLSTATE_LOCAL)
2839 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2840 return ERROR_SUCCESS;
2843 if ((name = MSI_RecordGetString( row, 4 )))
2845 if (name[0] == '-' && !name[1])
2847 delete_key = TRUE;
2848 name = NULL;
2852 root = MSI_RecordGetInteger( row, 2 );
2853 key_str = MSI_RecordGetString( row, 3 );
2855 root_key_str = get_root_key( package, root, &hkey_root );
2856 if (!root_key_str)
2857 return ERROR_SUCCESS;
2859 deformat_string( package, key_str, &deformated_key );
2860 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2861 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2862 strcpyW( ui_key_str, root_key_str );
2863 strcatW( ui_key_str, deformated_key );
2865 deformat_string( package, name, &deformated_name );
2867 keypath = get_keypath( package, hkey_root, deformated_key );
2868 msi_free( deformated_key );
2869 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2870 msi_free( keypath );
2872 uirow = MSI_CreateRecord( 2 );
2873 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2874 MSI_RecordSetStringW( uirow, 2, deformated_name );
2875 msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
2876 msiobj_release( &uirow->hdr );
2878 msi_free( ui_key_str );
2879 msi_free( deformated_name );
2880 return ERROR_SUCCESS;
2883 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2885 UINT rc;
2886 MSIQUERY *view;
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 };
2894 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2895 if (rc == ERROR_SUCCESS)
2897 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2898 msiobj_release( &view->hdr );
2899 if (rc != ERROR_SUCCESS)
2900 return rc;
2903 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2904 if (rc == ERROR_SUCCESS)
2906 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2907 msiobj_release( &view->hdr );
2908 if (rc != ERROR_SUCCESS)
2909 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 MSICOMPONENT *comp;
2926 DWORD total = 0, count = 0;
2927 static const WCHAR q1[]=
2928 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2929 '`','R','e','g','i','s','t','r','y','`',0};
2930 UINT rc;
2931 MSIQUERY * view;
2932 MSIFEATURE *feature;
2933 MSIFILE *file;
2935 TRACE("InstallValidate\n");
2937 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2938 if (rc == ERROR_SUCCESS)
2940 MSI_IterateRecords( view, &count, NULL, package );
2941 msiobj_release( &view->hdr );
2942 total += count * REG_PROGRESS_VALUE;
2944 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2945 total += COMPONENT_PROGRESS_VALUE;
2947 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2948 total += file->FileSize;
2950 msi_ui_progress( package, 0, total, 0, 0 );
2952 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2954 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2955 debugstr_w(feature->Feature), feature->Installed,
2956 feature->ActionRequest, feature->Action);
2959 return ERROR_SUCCESS;
2962 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2964 MSIPACKAGE* package = param;
2965 LPCWSTR cond = NULL;
2966 LPCWSTR message = NULL;
2967 UINT r;
2969 static const WCHAR title[]=
2970 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2972 cond = MSI_RecordGetString(row,1);
2974 r = MSI_EvaluateConditionW(package,cond);
2975 if (r == MSICONDITION_FALSE)
2977 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2979 LPWSTR deformated;
2980 message = MSI_RecordGetString(row,2);
2981 deformat_string(package,message,&deformated);
2982 MessageBoxW(NULL,deformated,title,MB_OK);
2983 msi_free(deformated);
2986 return ERROR_INSTALL_FAILURE;
2989 return ERROR_SUCCESS;
2992 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2994 UINT rc;
2995 MSIQUERY * view = NULL;
2996 static const WCHAR ExecSeqQuery[] =
2997 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2998 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3000 TRACE("Checking launch conditions\n");
3002 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3003 if (rc != ERROR_SUCCESS)
3004 return ERROR_SUCCESS;
3006 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3007 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 MSIRECORD * row = 0;
3021 UINT root,len;
3022 LPWSTR deformated,buffer,deformated_name;
3023 LPCWSTR key,name;
3024 static const WCHAR ExecSeqQuery[] =
3025 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3026 '`','R','e','g','i','s','t','r','y','`',' ',
3027 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3028 ' ','=',' ' ,'\'','%','s','\'',0 };
3029 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3030 static const WCHAR fmt2[]=
3031 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3033 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3034 if (!row)
3035 return NULL;
3037 root = MSI_RecordGetInteger(row,2);
3038 key = MSI_RecordGetString(row, 3);
3039 name = MSI_RecordGetString(row, 4);
3040 deformat_string(package, key , &deformated);
3041 deformat_string(package, name, &deformated_name);
3043 len = strlenW(deformated) + 6;
3044 if (deformated_name)
3045 len+=strlenW(deformated_name);
3047 buffer = msi_alloc( len *sizeof(WCHAR));
3049 if (deformated_name)
3050 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3051 else
3052 sprintfW(buffer,fmt,root,deformated);
3054 msi_free(deformated);
3055 msi_free(deformated_name);
3056 msiobj_release(&row->hdr);
3058 return buffer;
3060 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3062 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3063 return NULL;
3065 else
3067 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3069 if (file)
3070 return strdupW( file->TargetPath );
3072 return NULL;
3075 static HKEY openSharedDLLsKey(void)
3077 HKEY hkey=0;
3078 static const WCHAR path[] =
3079 {'S','o','f','t','w','a','r','e','\\',
3080 'M','i','c','r','o','s','o','f','t','\\',
3081 'W','i','n','d','o','w','s','\\',
3082 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3083 'S','h','a','r','e','d','D','L','L','s',0};
3085 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3086 return hkey;
3089 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3091 HKEY hkey;
3092 DWORD count=0;
3093 DWORD type;
3094 DWORD sz = sizeof(count);
3095 DWORD rc;
3097 hkey = openSharedDLLsKey();
3098 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3099 if (rc != ERROR_SUCCESS)
3100 count = 0;
3101 RegCloseKey(hkey);
3102 return count;
3105 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3107 HKEY hkey;
3109 hkey = openSharedDLLsKey();
3110 if (count > 0)
3111 msi_reg_set_val_dword( hkey, path, count );
3112 else
3113 RegDeleteValueW(hkey,path);
3114 RegCloseKey(hkey);
3115 return count;
3118 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3120 MSIFEATURE *feature;
3121 INT count = 0;
3122 BOOL write = FALSE;
3124 /* only refcount DLLs */
3125 if (comp->KeyPath == NULL ||
3126 comp->assembly ||
3127 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3128 comp->Attributes & msidbComponentAttributesODBCDataSource)
3129 write = FALSE;
3130 else
3132 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3133 write = (count > 0);
3135 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3136 write = TRUE;
3139 /* increment counts */
3140 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3142 ComponentList *cl;
3144 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3145 continue;
3147 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3149 if ( cl->component == comp )
3150 count++;
3154 /* decrement counts */
3155 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3157 ComponentList *cl;
3159 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3160 continue;
3162 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3164 if ( cl->component == comp )
3165 count--;
3169 /* ref count all the files in the component */
3170 if (write)
3172 MSIFILE *file;
3174 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3176 if (file->Component == comp)
3177 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3181 /* add a count for permanent */
3182 if (comp->Attributes & msidbComponentAttributesPermanent)
3183 count ++;
3185 comp->RefCount = count;
3187 if (write)
3188 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3191 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3193 if (comp->assembly)
3195 const WCHAR prefixW[] = {'<','\\',0};
3196 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3197 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3199 if (keypath)
3201 strcpyW( keypath, prefixW );
3202 strcatW( keypath, comp->assembly->display_name );
3204 return keypath;
3206 return resolve_keypath( package, comp );
3209 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3211 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE];
3212 UINT rc;
3213 MSICOMPONENT *comp;
3214 HKEY hkey;
3216 TRACE("\n");
3218 squash_guid(package->ProductCode,squished_pc);
3219 msi_set_sourcedir_props(package, FALSE);
3221 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3223 MSIRECORD *uirow;
3224 INSTALLSTATE action;
3226 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3227 if (!comp->ComponentId)
3228 continue;
3230 squash_guid( comp->ComponentId, squished_cc );
3231 msi_free( comp->FullKeypath );
3232 comp->FullKeypath = build_full_keypath( package, comp );
3234 ACTION_RefCountComponent( package, comp );
3236 if (package->need_rollback) action = comp->Installed;
3237 else action = comp->ActionRequest;
3239 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n",
3240 debugstr_w(comp->Component), debugstr_w(squished_cc),
3241 debugstr_w(comp->FullKeypath), comp->RefCount, action);
3243 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3245 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3246 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3247 else
3248 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3250 if (rc != ERROR_SUCCESS)
3251 continue;
3253 if (comp->Attributes & msidbComponentAttributesPermanent)
3255 static const WCHAR szPermKey[] =
3256 { '0','0','0','0','0','0','0','0','0','0','0','0',
3257 '0','0','0','0','0','0','0','0','0','0','0','0',
3258 '0','0','0','0','0','0','0','0',0 };
3260 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3262 if (action == INSTALLSTATE_LOCAL)
3263 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3264 else
3266 MSIFILE *file;
3267 MSIRECORD *row;
3268 LPWSTR ptr, ptr2;
3269 WCHAR source[MAX_PATH];
3270 WCHAR base[MAX_PATH];
3271 LPWSTR sourcepath;
3273 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3274 static const WCHAR query[] = {
3275 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3276 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3277 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3278 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3279 '`','D','i','s','k','I','d','`',0};
3281 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3282 continue;
3284 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3285 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3286 ptr2 = strrchrW(source, '\\') + 1;
3287 msiobj_release(&row->hdr);
3289 lstrcpyW(base, package->PackagePath);
3290 ptr = strrchrW(base, '\\');
3291 *(ptr + 1) = '\0';
3293 sourcepath = msi_resolve_file_source(package, file);
3294 ptr = sourcepath + lstrlenW(base);
3295 lstrcpyW(ptr2, ptr);
3296 msi_free(sourcepath);
3298 msi_reg_set_val_str(hkey, squished_pc, source);
3300 RegCloseKey(hkey);
3302 else if (action == INSTALLSTATE_ABSENT)
3304 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3305 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3306 else
3307 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3310 /* UI stuff */
3311 uirow = MSI_CreateRecord(3);
3312 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3313 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3314 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3315 msi_ui_actiondata( package, szProcessComponents, uirow );
3316 msiobj_release( &uirow->hdr );
3318 return ERROR_SUCCESS;
3321 typedef struct {
3322 CLSID clsid;
3323 LPWSTR source;
3325 LPWSTR path;
3326 ITypeLib *ptLib;
3327 } typelib_struct;
3329 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3330 LPWSTR lpszName, LONG_PTR lParam)
3332 TLIBATTR *attr;
3333 typelib_struct *tl_struct = (typelib_struct*) lParam;
3334 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3335 int sz;
3336 HRESULT res;
3338 if (!IS_INTRESOURCE(lpszName))
3340 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3341 return TRUE;
3344 sz = strlenW(tl_struct->source)+4;
3345 sz *= sizeof(WCHAR);
3347 if ((INT_PTR)lpszName == 1)
3348 tl_struct->path = strdupW(tl_struct->source);
3349 else
3351 tl_struct->path = msi_alloc(sz);
3352 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3355 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3356 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3357 if (FAILED(res))
3359 msi_free(tl_struct->path);
3360 tl_struct->path = NULL;
3362 return TRUE;
3365 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3366 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3368 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3369 return FALSE;
3372 msi_free(tl_struct->path);
3373 tl_struct->path = NULL;
3375 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3376 ITypeLib_Release(tl_struct->ptLib);
3378 return TRUE;
3381 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3383 MSIPACKAGE* package = param;
3384 LPCWSTR component;
3385 MSICOMPONENT *comp;
3386 MSIFILE *file;
3387 typelib_struct tl_struct;
3388 ITypeLib *tlib;
3389 HMODULE module;
3390 HRESULT hr;
3392 component = MSI_RecordGetString(row,3);
3393 comp = msi_get_loaded_component(package,component);
3394 if (!comp)
3395 return ERROR_SUCCESS;
3397 comp->Action = msi_get_component_action( package, comp );
3398 if (comp->Action != INSTALLSTATE_LOCAL)
3400 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3401 return ERROR_SUCCESS;
3404 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3406 TRACE("component has no key path\n");
3407 return ERROR_SUCCESS;
3409 msi_ui_actiondata( package, szRegisterTypeLibraries, row );
3411 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3412 if (module)
3414 LPCWSTR guid;
3415 guid = MSI_RecordGetString(row,1);
3416 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3417 tl_struct.source = strdupW( file->TargetPath );
3418 tl_struct.path = NULL;
3420 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3421 (LONG_PTR)&tl_struct);
3423 if (tl_struct.path)
3425 LPCWSTR helpid, help_path = NULL;
3426 HRESULT res;
3428 helpid = MSI_RecordGetString(row,6);
3430 if (helpid) help_path = msi_get_target_folder( package, helpid );
3431 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3433 if (FAILED(res))
3434 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3435 else
3436 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3438 ITypeLib_Release(tl_struct.ptLib);
3439 msi_free(tl_struct.path);
3441 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3443 FreeLibrary(module);
3444 msi_free(tl_struct.source);
3446 else
3448 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3449 if (FAILED(hr))
3451 ERR("Failed to load type library: %08x\n", hr);
3452 return ERROR_INSTALL_FAILURE;
3455 ITypeLib_Release(tlib);
3458 return ERROR_SUCCESS;
3461 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3464 * OK this is a bit confusing.. I am given a _Component key and I believe
3465 * that the file that is being registered as a type library is the "key file
3466 * of that component" which I interpret to mean "The file in the KeyPath of
3467 * that component".
3469 UINT rc;
3470 MSIQUERY * view;
3471 static const WCHAR Query[] =
3472 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3473 '`','T','y','p','e','L','i','b','`',0};
3475 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3476 if (rc != ERROR_SUCCESS)
3477 return ERROR_SUCCESS;
3479 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3480 msiobj_release(&view->hdr);
3481 return rc;
3484 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3486 MSIPACKAGE *package = param;
3487 LPCWSTR component, guid;
3488 MSICOMPONENT *comp;
3489 GUID libid;
3490 UINT version;
3491 LCID language;
3492 SYSKIND syskind;
3493 HRESULT hr;
3495 component = MSI_RecordGetString( row, 3 );
3496 comp = msi_get_loaded_component( package, component );
3497 if (!comp)
3498 return ERROR_SUCCESS;
3500 comp->Action = msi_get_component_action( package, comp );
3501 if (comp->Action != INSTALLSTATE_ABSENT)
3503 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3504 return ERROR_SUCCESS;
3506 msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
3508 guid = MSI_RecordGetString( row, 1 );
3509 CLSIDFromString( (LPCWSTR)guid, &libid );
3510 version = MSI_RecordGetInteger( row, 4 );
3511 language = MSI_RecordGetInteger( row, 2 );
3513 #ifdef _WIN64
3514 syskind = SYS_WIN64;
3515 #else
3516 syskind = SYS_WIN32;
3517 #endif
3519 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3520 if (FAILED(hr))
3522 WARN("Failed to unregister typelib: %08x\n", hr);
3525 return ERROR_SUCCESS;
3528 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3530 UINT rc;
3531 MSIQUERY *view;
3532 static const WCHAR query[] =
3533 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3534 '`','T','y','p','e','L','i','b','`',0};
3536 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3537 if (rc != ERROR_SUCCESS)
3538 return ERROR_SUCCESS;
3540 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3541 msiobj_release( &view->hdr );
3542 return rc;
3545 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3547 static const WCHAR szlnk[] = {'.','l','n','k',0};
3548 LPCWSTR directory, extension, link_folder;
3549 LPWSTR link_file, filename;
3551 directory = MSI_RecordGetString( row, 2 );
3552 link_folder = msi_get_target_folder( package, directory );
3554 /* may be needed because of a bug somewhere else */
3555 msi_create_full_path( link_folder );
3557 filename = msi_dup_record_field( row, 3 );
3558 msi_reduce_to_long_filename( filename );
3560 extension = strchrW( filename, '.' );
3561 if (!extension || strcmpiW( extension, szlnk ))
3563 int len = strlenW( filename );
3564 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3565 memcpy( filename + len, szlnk, sizeof(szlnk) );
3567 link_file = msi_build_directory_name( 2, link_folder, filename );
3568 msi_free( filename );
3570 return link_file;
3573 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3575 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3576 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3577 WCHAR *folder, *dest, *path;
3579 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3580 folder = msi_dup_property( package->db, szWindowsFolder );
3581 else
3583 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3584 folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3585 msi_free( appdata );
3587 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3588 msi_create_full_path( dest );
3589 path = msi_build_directory_name( 2, dest, icon_name );
3590 msi_free( folder );
3591 msi_free( dest );
3592 return path;
3595 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3597 MSIPACKAGE *package = param;
3598 LPWSTR link_file, deformated, path;
3599 LPCWSTR component, target;
3600 MSICOMPONENT *comp;
3601 IShellLinkW *sl = NULL;
3602 IPersistFile *pf = NULL;
3603 HRESULT res;
3605 component = MSI_RecordGetString(row, 4);
3606 comp = msi_get_loaded_component(package, component);
3607 if (!comp)
3608 return ERROR_SUCCESS;
3610 comp->Action = msi_get_component_action( package, comp );
3611 if (comp->Action != INSTALLSTATE_LOCAL)
3613 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3614 return ERROR_SUCCESS;
3616 msi_ui_actiondata( package, szCreateShortcuts, row );
3618 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3619 &IID_IShellLinkW, (LPVOID *) &sl );
3621 if (FAILED( res ))
3623 ERR("CLSID_ShellLink not available\n");
3624 goto err;
3627 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3628 if (FAILED( res ))
3630 ERR("QueryInterface(IID_IPersistFile) failed\n");
3631 goto err;
3634 target = MSI_RecordGetString(row, 5);
3635 if (strchrW(target, '['))
3637 deformat_string(package, target, &deformated);
3638 IShellLinkW_SetPath(sl,deformated);
3639 msi_free(deformated);
3641 else
3643 FIXME("poorly handled shortcut format, advertised shortcut\n");
3644 IShellLinkW_SetPath(sl,comp->FullKeypath);
3647 if (!MSI_RecordIsNull(row,6))
3649 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3650 deformat_string(package, arguments, &deformated);
3651 IShellLinkW_SetArguments(sl,deformated);
3652 msi_free(deformated);
3655 if (!MSI_RecordIsNull(row,7))
3657 LPCWSTR description = MSI_RecordGetString(row, 7);
3658 IShellLinkW_SetDescription(sl, description);
3661 if (!MSI_RecordIsNull(row,8))
3662 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3664 if (!MSI_RecordIsNull(row,9))
3666 INT index;
3667 LPCWSTR icon = MSI_RecordGetString(row, 9);
3669 path = msi_build_icon_path(package, icon);
3670 index = MSI_RecordGetInteger(row,10);
3672 /* no value means 0 */
3673 if (index == MSI_NULL_INTEGER)
3674 index = 0;
3676 IShellLinkW_SetIconLocation(sl, path, index);
3677 msi_free(path);
3680 if (!MSI_RecordIsNull(row,11))
3681 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3683 if (!MSI_RecordIsNull(row,12))
3685 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3686 full_path = msi_get_target_folder( package, wkdir );
3687 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3689 link_file = get_link_file(package, row);
3691 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3692 IPersistFile_Save(pf, link_file, FALSE);
3693 msi_free(link_file);
3695 err:
3696 if (pf)
3697 IPersistFile_Release( pf );
3698 if (sl)
3699 IShellLinkW_Release( sl );
3701 return ERROR_SUCCESS;
3704 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3706 UINT rc;
3707 HRESULT res;
3708 MSIQUERY * view;
3709 static const WCHAR Query[] =
3710 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3711 '`','S','h','o','r','t','c','u','t','`',0};
3713 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3714 if (rc != ERROR_SUCCESS)
3715 return ERROR_SUCCESS;
3717 res = CoInitialize( NULL );
3719 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3720 msiobj_release(&view->hdr);
3722 if (SUCCEEDED(res))
3723 CoUninitialize();
3725 return rc;
3728 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3730 MSIPACKAGE *package = param;
3731 LPWSTR link_file;
3732 LPCWSTR component;
3733 MSICOMPONENT *comp;
3735 component = MSI_RecordGetString( row, 4 );
3736 comp = msi_get_loaded_component( package, component );
3737 if (!comp)
3738 return ERROR_SUCCESS;
3740 comp->Action = msi_get_component_action( package, comp );
3741 if (comp->Action != INSTALLSTATE_ABSENT)
3743 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3744 return ERROR_SUCCESS;
3746 msi_ui_actiondata( package, szRemoveShortcuts, row );
3748 link_file = get_link_file( package, row );
3750 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3751 if (!DeleteFileW( link_file ))
3753 WARN("Failed to remove shortcut file %u\n", GetLastError());
3755 msi_free( link_file );
3757 return ERROR_SUCCESS;
3760 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3762 UINT rc;
3763 MSIQUERY *view;
3764 static const WCHAR query[] =
3765 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3766 '`','S','h','o','r','t','c','u','t','`',0};
3768 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3769 if (rc != ERROR_SUCCESS)
3770 return ERROR_SUCCESS;
3772 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3773 msiobj_release( &view->hdr );
3775 return rc;
3778 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3780 MSIPACKAGE* package = param;
3781 HANDLE the_file;
3782 LPWSTR FilePath;
3783 LPCWSTR FileName;
3784 CHAR buffer[1024];
3785 DWORD sz;
3786 UINT rc;
3788 FileName = MSI_RecordGetString(row,1);
3789 if (!FileName)
3791 ERR("Unable to get FileName\n");
3792 return ERROR_SUCCESS;
3795 FilePath = msi_build_icon_path(package, FileName);
3797 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3799 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3800 FILE_ATTRIBUTE_NORMAL, NULL);
3802 if (the_file == INVALID_HANDLE_VALUE)
3804 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3805 msi_free(FilePath);
3806 return ERROR_SUCCESS;
3811 DWORD write;
3812 sz = 1024;
3813 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3814 if (rc != ERROR_SUCCESS)
3816 ERR("Failed to get stream\n");
3817 CloseHandle(the_file);
3818 DeleteFileW(FilePath);
3819 break;
3821 WriteFile(the_file,buffer,sz,&write,NULL);
3822 } while (sz == 1024);
3824 msi_free(FilePath);
3825 CloseHandle(the_file);
3827 return ERROR_SUCCESS;
3830 static UINT msi_publish_icons(MSIPACKAGE *package)
3832 UINT r;
3833 MSIQUERY *view;
3835 static const WCHAR query[]= {
3836 'S','E','L','E','C','T',' ','*',' ',
3837 'F','R','O','M',' ','`','I','c','o','n','`',0};
3839 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3840 if (r == ERROR_SUCCESS)
3842 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3843 msiobj_release(&view->hdr);
3846 return ERROR_SUCCESS;
3849 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3851 UINT r;
3852 HKEY source;
3853 LPWSTR buffer;
3854 MSIMEDIADISK *disk;
3855 MSISOURCELISTINFO *info;
3857 r = RegCreateKeyW(hkey, szSourceList, &source);
3858 if (r != ERROR_SUCCESS)
3859 return r;
3861 RegCloseKey(source);
3863 buffer = strrchrW(package->PackagePath, '\\') + 1;
3864 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3865 package->Context, MSICODE_PRODUCT,
3866 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3867 if (r != ERROR_SUCCESS)
3868 return r;
3870 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3871 package->Context, MSICODE_PRODUCT,
3872 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3873 if (r != ERROR_SUCCESS)
3874 return r;
3876 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3877 package->Context, MSICODE_PRODUCT,
3878 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3879 if (r != ERROR_SUCCESS)
3880 return r;
3882 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3884 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3885 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3886 info->options, info->value);
3887 else
3888 MsiSourceListSetInfoW(package->ProductCode, NULL,
3889 info->context, info->options,
3890 info->property, info->value);
3893 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3895 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3896 disk->context, disk->options,
3897 disk->disk_id, disk->volume_label, disk->disk_prompt);
3900 return ERROR_SUCCESS;
3903 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3905 MSIHANDLE hdb, suminfo;
3906 WCHAR guids[MAX_PATH];
3907 WCHAR packcode[SQUISH_GUID_SIZE];
3908 LPWSTR buffer;
3909 LPWSTR ptr;
3910 DWORD langid;
3911 DWORD size;
3912 UINT r;
3914 static const WCHAR szARPProductIcon[] =
3915 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3916 static const WCHAR szAssignment[] =
3917 {'A','s','s','i','g','n','m','e','n','t',0};
3918 static const WCHAR szAdvertiseFlags[] =
3919 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3920 static const WCHAR szClients[] =
3921 {'C','l','i','e','n','t','s',0};
3922 static const WCHAR szColon[] = {':',0};
3924 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3925 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3926 msi_free(buffer);
3928 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3929 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3931 /* FIXME */
3932 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3934 buffer = msi_dup_property(package->db, szARPProductIcon);
3935 if (buffer)
3937 LPWSTR path = msi_build_icon_path(package, buffer);
3938 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3939 msi_free(path);
3940 msi_free(buffer);
3943 buffer = msi_dup_property(package->db, szProductVersion);
3944 if (buffer)
3946 DWORD verdword = msi_version_str_to_dword(buffer);
3947 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3948 msi_free(buffer);
3951 msi_reg_set_val_dword(hkey, szAssignment, 0);
3952 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3953 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3954 msi_reg_set_val_str(hkey, szClients, szColon);
3956 hdb = alloc_msihandle(&package->db->hdr);
3957 if (!hdb)
3958 return ERROR_NOT_ENOUGH_MEMORY;
3960 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3961 MsiCloseHandle(hdb);
3962 if (r != ERROR_SUCCESS)
3963 goto done;
3965 size = MAX_PATH;
3966 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3967 NULL, guids, &size);
3968 if (r != ERROR_SUCCESS)
3969 goto done;
3971 ptr = strchrW(guids, ';');
3972 if (ptr) *ptr = 0;
3973 squash_guid(guids, packcode);
3974 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3976 done:
3977 MsiCloseHandle(suminfo);
3978 return ERROR_SUCCESS;
3981 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3983 UINT r;
3984 HKEY hkey;
3985 LPWSTR upgrade;
3986 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3988 upgrade = msi_dup_property(package->db, szUpgradeCode);
3989 if (!upgrade)
3990 return ERROR_SUCCESS;
3992 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3993 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3994 else
3995 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3997 if (r != ERROR_SUCCESS)
3999 WARN("failed to open upgrade code key\n");
4000 msi_free(upgrade);
4001 return ERROR_SUCCESS;
4003 squash_guid(package->ProductCode, squashed_pc);
4004 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4005 RegCloseKey(hkey);
4006 msi_free(upgrade);
4007 return ERROR_SUCCESS;
4010 static BOOL msi_check_publish(MSIPACKAGE *package)
4012 MSIFEATURE *feature;
4014 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4016 feature->Action = msi_get_feature_action( package, feature );
4017 if (feature->Action == INSTALLSTATE_LOCAL)
4018 return TRUE;
4021 return FALSE;
4024 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4026 MSIFEATURE *feature;
4028 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4030 feature->Action = msi_get_feature_action( package, feature );
4031 if (feature->Action != INSTALLSTATE_ABSENT)
4032 return FALSE;
4035 return TRUE;
4038 static UINT msi_publish_patches( MSIPACKAGE *package )
4040 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4041 WCHAR patch_squashed[GUID_SIZE];
4042 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4043 LONG res;
4044 MSIPATCHINFO *patch;
4045 UINT r;
4046 WCHAR *p, *all_patches = NULL;
4047 DWORD len = 0;
4049 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4050 if (r != ERROR_SUCCESS)
4051 return ERROR_FUNCTION_FAILED;
4053 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4054 if (res != ERROR_SUCCESS)
4056 r = ERROR_FUNCTION_FAILED;
4057 goto done;
4060 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4061 if (r != ERROR_SUCCESS)
4062 goto done;
4064 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4066 squash_guid( patch->patchcode, patch_squashed );
4067 len += strlenW( patch_squashed ) + 1;
4070 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4071 if (!all_patches)
4072 goto done;
4074 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4076 HKEY patch_key;
4078 squash_guid( patch->patchcode, p );
4079 p += strlenW( p ) + 1;
4081 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4082 (const BYTE *)patch->transforms,
4083 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4084 if (res != ERROR_SUCCESS)
4085 goto done;
4087 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4088 if (r != ERROR_SUCCESS)
4089 goto done;
4091 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4092 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4093 RegCloseKey( patch_key );
4094 if (res != ERROR_SUCCESS)
4095 goto done;
4097 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4099 res = GetLastError();
4100 ERR("Unable to copy patch package %d\n", res);
4101 goto done;
4103 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4104 if (res != ERROR_SUCCESS)
4105 goto done;
4107 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4108 RegCloseKey( patch_key );
4109 if (res != ERROR_SUCCESS)
4110 goto done;
4113 all_patches[len] = 0;
4114 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4115 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4116 if (res != ERROR_SUCCESS)
4117 goto done;
4119 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4120 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4121 if (res != ERROR_SUCCESS)
4122 r = ERROR_FUNCTION_FAILED;
4124 done:
4125 RegCloseKey( product_patches_key );
4126 RegCloseKey( patches_key );
4127 RegCloseKey( product_key );
4128 msi_free( all_patches );
4129 return r;
4132 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4134 UINT rc;
4135 HKEY hukey = NULL, hudkey = NULL;
4136 MSIRECORD *uirow;
4138 if (!list_empty(&package->patches))
4140 rc = msi_publish_patches(package);
4141 if (rc != ERROR_SUCCESS)
4142 goto end;
4145 /* FIXME: also need to publish if the product is in advertise mode */
4146 if (!msi_check_publish(package))
4147 return ERROR_SUCCESS;
4149 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4150 &hukey, TRUE);
4151 if (rc != ERROR_SUCCESS)
4152 goto end;
4154 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4155 NULL, &hudkey, TRUE);
4156 if (rc != ERROR_SUCCESS)
4157 goto end;
4159 rc = msi_publish_upgrade_code(package);
4160 if (rc != ERROR_SUCCESS)
4161 goto end;
4163 rc = msi_publish_product_properties(package, hukey);
4164 if (rc != ERROR_SUCCESS)
4165 goto end;
4167 rc = msi_publish_sourcelist(package, hukey);
4168 if (rc != ERROR_SUCCESS)
4169 goto end;
4171 rc = msi_publish_icons(package);
4173 end:
4174 uirow = MSI_CreateRecord( 1 );
4175 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4176 msi_ui_actiondata( package, szPublishProduct, uirow );
4177 msiobj_release( &uirow->hdr );
4179 RegCloseKey(hukey);
4180 RegCloseKey(hudkey);
4182 return rc;
4185 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4187 WCHAR *filename, *ptr, *folder, *ret;
4188 const WCHAR *dirprop;
4190 filename = msi_dup_record_field( row, 2 );
4191 if (filename && (ptr = strchrW( filename, '|' )))
4192 ptr++;
4193 else
4194 ptr = filename;
4196 dirprop = MSI_RecordGetString( row, 3 );
4197 if (dirprop)
4199 folder = strdupW( msi_get_target_folder( package, dirprop ) );
4200 if (!folder) folder = msi_dup_property( package->db, dirprop );
4202 else
4203 folder = msi_dup_property( package->db, szWindowsFolder );
4205 if (!folder)
4207 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4208 msi_free( filename );
4209 return NULL;
4212 ret = msi_build_directory_name( 2, folder, ptr );
4214 msi_free( filename );
4215 msi_free( folder );
4216 return ret;
4219 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4221 MSIPACKAGE *package = param;
4222 LPCWSTR component, section, key, value, identifier;
4223 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4224 MSIRECORD * uirow;
4225 INT action;
4226 MSICOMPONENT *comp;
4228 component = MSI_RecordGetString(row, 8);
4229 comp = msi_get_loaded_component(package,component);
4230 if (!comp)
4231 return ERROR_SUCCESS;
4233 comp->Action = msi_get_component_action( package, comp );
4234 if (comp->Action != INSTALLSTATE_LOCAL)
4236 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4237 return ERROR_SUCCESS;
4240 identifier = MSI_RecordGetString(row,1);
4241 section = MSI_RecordGetString(row,4);
4242 key = MSI_RecordGetString(row,5);
4243 value = MSI_RecordGetString(row,6);
4244 action = MSI_RecordGetInteger(row,7);
4246 deformat_string(package,section,&deformated_section);
4247 deformat_string(package,key,&deformated_key);
4248 deformat_string(package,value,&deformated_value);
4250 fullname = get_ini_file_name(package, row);
4252 if (action == 0)
4254 TRACE("Adding value %s to section %s in %s\n",
4255 debugstr_w(deformated_key), debugstr_w(deformated_section),
4256 debugstr_w(fullname));
4257 WritePrivateProfileStringW(deformated_section, deformated_key,
4258 deformated_value, fullname);
4260 else if (action == 1)
4262 WCHAR returned[10];
4263 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4264 returned, 10, fullname);
4265 if (returned[0] == 0)
4267 TRACE("Adding value %s to section %s in %s\n",
4268 debugstr_w(deformated_key), debugstr_w(deformated_section),
4269 debugstr_w(fullname));
4271 WritePrivateProfileStringW(deformated_section, deformated_key,
4272 deformated_value, fullname);
4275 else if (action == 3)
4276 FIXME("Append to existing section not yet implemented\n");
4278 uirow = MSI_CreateRecord(4);
4279 MSI_RecordSetStringW(uirow,1,identifier);
4280 MSI_RecordSetStringW(uirow,2,deformated_section);
4281 MSI_RecordSetStringW(uirow,3,deformated_key);
4282 MSI_RecordSetStringW(uirow,4,deformated_value);
4283 msi_ui_actiondata( package, szWriteIniValues, uirow );
4284 msiobj_release( &uirow->hdr );
4286 msi_free(fullname);
4287 msi_free(deformated_key);
4288 msi_free(deformated_value);
4289 msi_free(deformated_section);
4290 return ERROR_SUCCESS;
4293 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4295 UINT rc;
4296 MSIQUERY * view;
4297 static const WCHAR ExecSeqQuery[] =
4298 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4299 '`','I','n','i','F','i','l','e','`',0};
4301 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4302 if (rc != ERROR_SUCCESS)
4304 TRACE("no IniFile table\n");
4305 return ERROR_SUCCESS;
4308 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4309 msiobj_release(&view->hdr);
4310 return rc;
4313 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4315 MSIPACKAGE *package = param;
4316 LPCWSTR component, section, key, value, identifier;
4317 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4318 MSICOMPONENT *comp;
4319 MSIRECORD *uirow;
4320 INT action;
4322 component = MSI_RecordGetString( row, 8 );
4323 comp = msi_get_loaded_component( package, component );
4324 if (!comp)
4325 return ERROR_SUCCESS;
4327 comp->Action = msi_get_component_action( package, comp );
4328 if (comp->Action != INSTALLSTATE_ABSENT)
4330 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4331 return ERROR_SUCCESS;
4334 identifier = MSI_RecordGetString( row, 1 );
4335 section = MSI_RecordGetString( row, 4 );
4336 key = MSI_RecordGetString( row, 5 );
4337 value = MSI_RecordGetString( row, 6 );
4338 action = MSI_RecordGetInteger( row, 7 );
4340 deformat_string( package, section, &deformated_section );
4341 deformat_string( package, key, &deformated_key );
4342 deformat_string( package, value, &deformated_value );
4344 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4346 filename = get_ini_file_name( package, row );
4348 TRACE("Removing key %s from section %s in %s\n",
4349 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4351 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4353 WARN("Unable to remove key %u\n", GetLastError());
4355 msi_free( filename );
4357 else
4358 FIXME("Unsupported action %d\n", action);
4361 uirow = MSI_CreateRecord( 4 );
4362 MSI_RecordSetStringW( uirow, 1, identifier );
4363 MSI_RecordSetStringW( uirow, 2, deformated_section );
4364 MSI_RecordSetStringW( uirow, 3, deformated_key );
4365 MSI_RecordSetStringW( uirow, 4, deformated_value );
4366 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4367 msiobj_release( &uirow->hdr );
4369 msi_free( deformated_key );
4370 msi_free( deformated_value );
4371 msi_free( deformated_section );
4372 return ERROR_SUCCESS;
4375 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4377 MSIPACKAGE *package = param;
4378 LPCWSTR component, section, key, value, identifier;
4379 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4380 MSICOMPONENT *comp;
4381 MSIRECORD *uirow;
4382 INT action;
4384 component = MSI_RecordGetString( row, 8 );
4385 comp = msi_get_loaded_component( package, component );
4386 if (!comp)
4387 return ERROR_SUCCESS;
4389 comp->Action = msi_get_component_action( package, comp );
4390 if (comp->Action != INSTALLSTATE_LOCAL)
4392 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4393 return ERROR_SUCCESS;
4396 identifier = MSI_RecordGetString( row, 1 );
4397 section = MSI_RecordGetString( row, 4 );
4398 key = MSI_RecordGetString( row, 5 );
4399 value = MSI_RecordGetString( row, 6 );
4400 action = MSI_RecordGetInteger( row, 7 );
4402 deformat_string( package, section, &deformated_section );
4403 deformat_string( package, key, &deformated_key );
4404 deformat_string( package, value, &deformated_value );
4406 if (action == msidbIniFileActionRemoveLine)
4408 filename = get_ini_file_name( package, row );
4410 TRACE("Removing key %s from section %s in %s\n",
4411 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4413 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4415 WARN("Unable to remove key %u\n", GetLastError());
4417 msi_free( filename );
4419 else
4420 FIXME("Unsupported action %d\n", action);
4422 uirow = MSI_CreateRecord( 4 );
4423 MSI_RecordSetStringW( uirow, 1, identifier );
4424 MSI_RecordSetStringW( uirow, 2, deformated_section );
4425 MSI_RecordSetStringW( uirow, 3, deformated_key );
4426 MSI_RecordSetStringW( uirow, 4, deformated_value );
4427 msi_ui_actiondata( package, szRemoveIniValues, uirow );
4428 msiobj_release( &uirow->hdr );
4430 msi_free( deformated_key );
4431 msi_free( deformated_value );
4432 msi_free( deformated_section );
4433 return ERROR_SUCCESS;
4436 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4438 UINT rc;
4439 MSIQUERY *view;
4440 static const WCHAR query[] =
4441 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4442 '`','I','n','i','F','i','l','e','`',0};
4443 static const WCHAR remove_query[] =
4444 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4445 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4447 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4448 if (rc == ERROR_SUCCESS)
4450 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4451 msiobj_release( &view->hdr );
4452 if (rc != ERROR_SUCCESS)
4453 return rc;
4456 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4457 if (rc == ERROR_SUCCESS)
4459 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4460 msiobj_release( &view->hdr );
4461 if (rc != ERROR_SUCCESS)
4462 return rc;
4465 return ERROR_SUCCESS;
4468 static void register_dll( const WCHAR *dll, BOOL unregister )
4470 HMODULE hmod;
4472 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4473 if (hmod)
4475 HRESULT (WINAPI *func_ptr)( void );
4476 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4478 func_ptr = (void *)GetProcAddress( hmod, func );
4479 if (func_ptr)
4481 HRESULT hr = func_ptr();
4482 if (FAILED( hr ))
4483 WARN("failed to register dll 0x%08x\n", hr);
4485 else
4486 WARN("entry point %s not found\n", func);
4487 FreeLibrary( hmod );
4488 return;
4490 WARN("failed to load library %u\n", GetLastError());
4493 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4495 MSIPACKAGE *package = param;
4496 LPCWSTR filename;
4497 MSIFILE *file;
4498 MSIRECORD *uirow;
4500 filename = MSI_RecordGetString(row,1);
4501 file = msi_get_loaded_file( package, filename );
4502 if (!file)
4504 WARN("unable to find file %s\n", debugstr_w(filename));
4505 return ERROR_SUCCESS;
4507 file->Component->Action = msi_get_component_action( package, file->Component );
4508 if (file->Component->Action != INSTALLSTATE_LOCAL)
4510 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4511 return ERROR_SUCCESS;
4514 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4515 register_dll( file->TargetPath, FALSE );
4517 uirow = MSI_CreateRecord( 2 );
4518 MSI_RecordSetStringW( uirow, 1, filename );
4519 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4520 msi_ui_actiondata( package, szSelfRegModules, uirow );
4521 msiobj_release( &uirow->hdr );
4523 return ERROR_SUCCESS;
4526 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4528 UINT rc;
4529 MSIQUERY * view;
4530 static const WCHAR ExecSeqQuery[] =
4531 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4532 '`','S','e','l','f','R','e','g','`',0};
4534 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4535 if (rc != ERROR_SUCCESS)
4537 TRACE("no SelfReg table\n");
4538 return ERROR_SUCCESS;
4541 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4542 msiobj_release(&view->hdr);
4544 return ERROR_SUCCESS;
4547 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4549 MSIPACKAGE *package = param;
4550 LPCWSTR filename;
4551 MSIFILE *file;
4552 MSIRECORD *uirow;
4554 filename = MSI_RecordGetString( row, 1 );
4555 file = msi_get_loaded_file( package, filename );
4556 if (!file)
4558 WARN("unable to find file %s\n", debugstr_w(filename));
4559 return ERROR_SUCCESS;
4561 file->Component->Action = msi_get_component_action( package, file->Component );
4562 if (file->Component->Action != INSTALLSTATE_ABSENT)
4564 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4565 return ERROR_SUCCESS;
4568 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4569 register_dll( file->TargetPath, TRUE );
4571 uirow = MSI_CreateRecord( 2 );
4572 MSI_RecordSetStringW( uirow, 1, filename );
4573 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4574 msi_ui_actiondata( package, szSelfUnregModules, uirow );
4575 msiobj_release( &uirow->hdr );
4577 return ERROR_SUCCESS;
4580 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4582 UINT rc;
4583 MSIQUERY *view;
4584 static const WCHAR query[] =
4585 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4586 '`','S','e','l','f','R','e','g','`',0};
4588 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4589 if (rc != ERROR_SUCCESS)
4591 TRACE("no SelfReg table\n");
4592 return ERROR_SUCCESS;
4595 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4596 msiobj_release( &view->hdr );
4598 return ERROR_SUCCESS;
4601 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4603 MSIFEATURE *feature;
4604 UINT rc;
4605 HKEY hkey = NULL, userdata = NULL;
4607 if (!msi_check_publish(package))
4608 return ERROR_SUCCESS;
4610 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4611 &hkey, TRUE);
4612 if (rc != ERROR_SUCCESS)
4613 goto end;
4615 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4616 &userdata, TRUE);
4617 if (rc != ERROR_SUCCESS)
4618 goto end;
4620 /* here the guids are base 85 encoded */
4621 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4623 ComponentList *cl;
4624 LPWSTR data = NULL;
4625 GUID clsid;
4626 INT size;
4627 BOOL absent = FALSE;
4628 MSIRECORD *uirow;
4630 if (feature->Action != INSTALLSTATE_LOCAL &&
4631 feature->Action != INSTALLSTATE_SOURCE &&
4632 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4634 size = 1;
4635 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4637 size += 21;
4639 if (feature->Feature_Parent)
4640 size += strlenW( feature->Feature_Parent )+2;
4642 data = msi_alloc(size * sizeof(WCHAR));
4644 data[0] = 0;
4645 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4647 MSICOMPONENT* component = cl->component;
4648 WCHAR buf[21];
4650 buf[0] = 0;
4651 if (component->ComponentId)
4653 TRACE("From %s\n",debugstr_w(component->ComponentId));
4654 CLSIDFromString(component->ComponentId, &clsid);
4655 encode_base85_guid(&clsid,buf);
4656 TRACE("to %s\n",debugstr_w(buf));
4657 strcatW(data,buf);
4661 if (feature->Feature_Parent)
4663 static const WCHAR sep[] = {'\2',0};
4664 strcatW(data,sep);
4665 strcatW(data,feature->Feature_Parent);
4668 msi_reg_set_val_str( userdata, feature->Feature, data );
4669 msi_free(data);
4671 size = 0;
4672 if (feature->Feature_Parent)
4673 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4674 if (!absent)
4676 size += sizeof(WCHAR);
4677 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4678 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4680 else
4682 size += 2*sizeof(WCHAR);
4683 data = msi_alloc(size);
4684 data[0] = 0x6;
4685 data[1] = 0;
4686 if (feature->Feature_Parent)
4687 strcpyW( &data[1], feature->Feature_Parent );
4688 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4689 (LPBYTE)data,size);
4690 msi_free(data);
4693 /* the UI chunk */
4694 uirow = MSI_CreateRecord( 1 );
4695 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4696 msi_ui_actiondata( package, szPublishFeatures, uirow );
4697 msiobj_release( &uirow->hdr );
4698 /* FIXME: call msi_ui_progress? */
4701 end:
4702 RegCloseKey(hkey);
4703 RegCloseKey(userdata);
4704 return rc;
4707 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4709 UINT r;
4710 HKEY hkey;
4711 MSIRECORD *uirow;
4713 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4715 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4716 &hkey, FALSE);
4717 if (r == ERROR_SUCCESS)
4719 RegDeleteValueW(hkey, feature->Feature);
4720 RegCloseKey(hkey);
4723 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4724 &hkey, FALSE);
4725 if (r == ERROR_SUCCESS)
4727 RegDeleteValueW(hkey, feature->Feature);
4728 RegCloseKey(hkey);
4731 uirow = MSI_CreateRecord( 1 );
4732 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4733 msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4734 msiobj_release( &uirow->hdr );
4736 return ERROR_SUCCESS;
4739 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4741 MSIFEATURE *feature;
4743 if (!msi_check_unpublish(package))
4744 return ERROR_SUCCESS;
4746 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4748 msi_unpublish_feature(package, feature);
4751 return ERROR_SUCCESS;
4754 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4756 SYSTEMTIME systime;
4757 DWORD size, langid;
4758 WCHAR date[9], *val, *buffer;
4759 const WCHAR *prop, *key;
4761 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4762 static const WCHAR modpath_fmt[] =
4763 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4764 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4765 static const WCHAR szModifyPath[] =
4766 {'M','o','d','i','f','y','P','a','t','h',0};
4767 static const WCHAR szUninstallString[] =
4768 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4769 static const WCHAR szEstimatedSize[] =
4770 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4771 static const WCHAR szDisplayVersion[] =
4772 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4773 static const WCHAR szInstallSource[] =
4774 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4775 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4776 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4777 static const WCHAR szAuthorizedCDFPrefix[] =
4778 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4779 static const WCHAR szARPCONTACT[] =
4780 {'A','R','P','C','O','N','T','A','C','T',0};
4781 static const WCHAR szContact[] =
4782 {'C','o','n','t','a','c','t',0};
4783 static const WCHAR szARPCOMMENTS[] =
4784 {'A','R','P','C','O','M','M','E','N','T','S',0};
4785 static const WCHAR szComments[] =
4786 {'C','o','m','m','e','n','t','s',0};
4787 static const WCHAR szProductName[] =
4788 {'P','r','o','d','u','c','t','N','a','m','e',0};
4789 static const WCHAR szDisplayName[] =
4790 {'D','i','s','p','l','a','y','N','a','m','e',0};
4791 static const WCHAR szARPHELPLINK[] =
4792 {'A','R','P','H','E','L','P','L','I','N','K',0};
4793 static const WCHAR szHelpLink[] =
4794 {'H','e','l','p','L','i','n','k',0};
4795 static const WCHAR szARPHELPTELEPHONE[] =
4796 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4797 static const WCHAR szHelpTelephone[] =
4798 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4799 static const WCHAR szARPINSTALLLOCATION[] =
4800 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4801 static const WCHAR szInstallLocation[] =
4802 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4803 static const WCHAR szManufacturer[] =
4804 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4805 static const WCHAR szPublisher[] =
4806 {'P','u','b','l','i','s','h','e','r',0};
4807 static const WCHAR szARPREADME[] =
4808 {'A','R','P','R','E','A','D','M','E',0};
4809 static const WCHAR szReadme[] =
4810 {'R','e','a','d','M','e',0};
4811 static const WCHAR szARPSIZE[] =
4812 {'A','R','P','S','I','Z','E',0};
4813 static const WCHAR szSize[] =
4814 {'S','i','z','e',0};
4815 static const WCHAR szARPURLINFOABOUT[] =
4816 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4817 static const WCHAR szURLInfoAbout[] =
4818 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4819 static const WCHAR szARPURLUPDATEINFO[] =
4820 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4821 static const WCHAR szURLUpdateInfo[] =
4822 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4823 static const WCHAR szARPSYSTEMCOMPONENT[] =
4824 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4825 static const WCHAR szSystemComponent[] =
4826 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4828 static const WCHAR *propval[] = {
4829 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4830 szARPCONTACT, szContact,
4831 szARPCOMMENTS, szComments,
4832 szProductName, szDisplayName,
4833 szARPHELPLINK, szHelpLink,
4834 szARPHELPTELEPHONE, szHelpTelephone,
4835 szARPINSTALLLOCATION, szInstallLocation,
4836 szSourceDir, szInstallSource,
4837 szManufacturer, szPublisher,
4838 szARPREADME, szReadme,
4839 szARPSIZE, szSize,
4840 szARPURLINFOABOUT, szURLInfoAbout,
4841 szARPURLUPDATEINFO, szURLUpdateInfo,
4842 NULL
4844 const WCHAR **p = propval;
4846 while (*p)
4848 prop = *p++;
4849 key = *p++;
4850 val = msi_dup_property(package->db, prop);
4851 msi_reg_set_val_str(hkey, key, val);
4852 msi_free(val);
4855 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4856 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4858 msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4860 size = deformat_string(package, modpath_fmt, &buffer);
4861 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4862 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4863 msi_free(buffer);
4865 /* FIXME: Write real Estimated Size when we have it */
4866 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4868 GetLocalTime(&systime);
4869 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4870 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4872 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4873 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4875 buffer = msi_dup_property(package->db, szProductVersion);
4876 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4877 if (buffer)
4879 DWORD verdword = msi_version_str_to_dword(buffer);
4881 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4882 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4883 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4884 msi_free(buffer);
4887 return ERROR_SUCCESS;
4890 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4892 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4893 MSIRECORD *uirow;
4894 LPWSTR upgrade_code;
4895 HKEY hkey, props, upgrade_key;
4896 UINT rc;
4898 /* FIXME: also need to publish if the product is in advertise mode */
4899 if (!msi_check_publish(package))
4900 return ERROR_SUCCESS;
4902 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4903 if (rc != ERROR_SUCCESS)
4904 return rc;
4906 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4907 if (rc != ERROR_SUCCESS)
4908 goto done;
4910 if (!msi_get_property_int( package->db, szInstalled, 0 ))
4912 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4913 if (!CopyFileW( package->PackagePath, package->localfile, FALSE ))
4915 rc = GetLastError();
4916 ERR("Unable to copy package %u\n", rc);
4917 goto done;
4920 msi_free( package->localfile );
4921 package->localfile = NULL;
4923 rc = msi_publish_install_properties(package, hkey);
4924 if (rc != ERROR_SUCCESS)
4925 goto done;
4927 rc = msi_publish_install_properties(package, props);
4928 if (rc != ERROR_SUCCESS)
4929 goto done;
4931 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4932 if (upgrade_code)
4934 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4935 if (rc == ERROR_SUCCESS)
4937 squash_guid( package->ProductCode, squashed_pc );
4938 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4939 RegCloseKey( upgrade_key );
4941 msi_free( upgrade_code );
4944 done:
4945 uirow = MSI_CreateRecord( 1 );
4946 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4947 msi_ui_actiondata( package, szRegisterProduct, uirow );
4948 msiobj_release( &uirow->hdr );
4950 RegCloseKey(hkey);
4951 return ERROR_SUCCESS;
4954 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4956 return execute_script(package,INSTALL_SCRIPT);
4959 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4961 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4962 WCHAR *upgrade, **features;
4963 BOOL full_uninstall = TRUE;
4964 MSIFEATURE *feature;
4965 MSIPATCHINFO *patch;
4966 UINT i;
4968 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4970 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4972 features = msi_split_string( remove, ',' );
4973 for (i = 0; features && features[i]; i++)
4975 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4977 msi_free(features);
4979 if (!full_uninstall)
4980 return ERROR_SUCCESS;
4982 MSIREG_DeleteProductKey(package->ProductCode);
4983 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4984 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4986 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4987 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4988 MSIREG_DeleteUserProductKey(package->ProductCode);
4989 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4991 upgrade = msi_dup_property(package->db, szUpgradeCode);
4992 if (upgrade)
4994 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4995 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4996 msi_free(upgrade);
4999 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5001 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5002 /* FIXME: remove local patch package if this is the last product */
5005 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5006 DeleteFileW( package->localfile );
5007 msi_free( package->localfile );
5008 package->localfile = NULL;
5010 return ERROR_SUCCESS;
5013 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5015 UINT rc;
5016 WCHAR *remove;
5018 /* turn off scheduling */
5019 package->script->CurrentlyScripting= FALSE;
5021 /* first do the same as an InstallExecute */
5022 rc = ACTION_InstallExecute(package);
5023 if (rc != ERROR_SUCCESS)
5024 return rc;
5026 /* then handle Commit Actions */
5027 rc = execute_script(package,COMMIT_SCRIPT);
5028 if (rc != ERROR_SUCCESS)
5029 return rc;
5031 remove = msi_dup_property(package->db, szRemove);
5032 rc = msi_unpublish_product(package, remove);
5033 msi_free(remove);
5034 return rc;
5037 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5039 static const WCHAR RunOnce[] = {
5040 'S','o','f','t','w','a','r','e','\\',
5041 'M','i','c','r','o','s','o','f','t','\\',
5042 'W','i','n','d','o','w','s','\\',
5043 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5044 'R','u','n','O','n','c','e',0};
5045 static const WCHAR InstallRunOnce[] = {
5046 'S','o','f','t','w','a','r','e','\\',
5047 'M','i','c','r','o','s','o','f','t','\\',
5048 'W','i','n','d','o','w','s','\\',
5049 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5050 'I','n','s','t','a','l','l','e','r','\\',
5051 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5053 static const WCHAR msiexec_fmt[] = {
5054 '%','s',
5055 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5056 '\"','%','s','\"',0};
5057 static const WCHAR install_fmt[] = {
5058 '/','I',' ','\"','%','s','\"',' ',
5059 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5060 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5061 WCHAR buffer[256], sysdir[MAX_PATH];
5062 HKEY hkey;
5063 WCHAR squished_pc[100];
5065 squash_guid(package->ProductCode,squished_pc);
5067 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5068 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5069 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5070 squished_pc);
5072 msi_reg_set_val_str( hkey, squished_pc, buffer );
5073 RegCloseKey(hkey);
5075 TRACE("Reboot command %s\n",debugstr_w(buffer));
5077 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5078 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5080 msi_reg_set_val_str( hkey, squished_pc, buffer );
5081 RegCloseKey(hkey);
5083 return ERROR_INSTALL_SUSPEND;
5086 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5088 static const WCHAR query[] =
5089 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5090 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5091 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5092 MSIRECORD *rec, *row;
5093 DWORD i, size = 0;
5094 va_list va;
5095 const WCHAR *str;
5096 WCHAR *data;
5098 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5100 rec = MSI_CreateRecord( count + 2 );
5101 str = MSI_RecordGetString( row, 1 );
5102 MSI_RecordSetStringW( rec, 0, str );
5103 msiobj_release( &row->hdr );
5104 MSI_RecordSetInteger( rec, 1, error );
5106 va_start( va, count );
5107 for (i = 0; i < count; i++)
5109 str = va_arg( va, const WCHAR *);
5110 MSI_RecordSetStringW( rec, i + 2, str );
5112 va_end( va );
5114 MSI_FormatRecordW( package, rec, NULL, &size );
5115 size++;
5116 data = msi_alloc( size * sizeof(WCHAR) );
5117 if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5118 else data[0] = 0;
5119 msiobj_release( &rec->hdr );
5120 return data;
5123 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5125 DWORD attrib;
5126 UINT rc;
5129 * We are currently doing what should be done here in the top level Install
5130 * however for Administrative and uninstalls this step will be needed
5132 if (!package->PackagePath)
5133 return ERROR_SUCCESS;
5135 msi_set_sourcedir_props(package, TRUE);
5137 attrib = GetFileAttributesW(package->db->path);
5138 if (attrib == INVALID_FILE_ATTRIBUTES)
5140 LPWSTR prompt;
5141 LPWSTR msg;
5142 DWORD size = 0;
5144 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5145 package->Context, MSICODE_PRODUCT,
5146 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5147 if (rc == ERROR_MORE_DATA)
5149 prompt = msi_alloc(size * sizeof(WCHAR));
5150 MsiSourceListGetInfoW(package->ProductCode, NULL,
5151 package->Context, MSICODE_PRODUCT,
5152 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5154 else
5155 prompt = strdupW(package->db->path);
5157 msg = msi_build_error_string(package, 1302, 1, prompt);
5158 while(attrib == INVALID_FILE_ATTRIBUTES)
5160 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5161 if (rc == IDCANCEL)
5163 rc = ERROR_INSTALL_USEREXIT;
5164 break;
5166 attrib = GetFileAttributesW(package->db->path);
5168 msi_free(prompt);
5169 rc = ERROR_SUCCESS;
5171 else
5172 return ERROR_SUCCESS;
5174 return rc;
5177 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5179 HKEY hkey = 0;
5180 LPWSTR buffer, productid = NULL;
5181 UINT i, rc = ERROR_SUCCESS;
5182 MSIRECORD *uirow;
5184 static const WCHAR szPropKeys[][80] =
5186 {'P','r','o','d','u','c','t','I','D',0},
5187 {'U','S','E','R','N','A','M','E',0},
5188 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5189 {0},
5192 static const WCHAR szRegKeys[][80] =
5194 {'P','r','o','d','u','c','t','I','D',0},
5195 {'R','e','g','O','w','n','e','r',0},
5196 {'R','e','g','C','o','m','p','a','n','y',0},
5197 {0},
5200 if (msi_check_unpublish(package))
5202 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5203 goto end;
5206 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5207 if (!productid)
5208 goto end;
5210 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5211 NULL, &hkey, TRUE);
5212 if (rc != ERROR_SUCCESS)
5213 goto end;
5215 for( i = 0; szPropKeys[i][0]; i++ )
5217 buffer = msi_dup_property( package->db, szPropKeys[i] );
5218 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5219 msi_free( buffer );
5222 end:
5223 uirow = MSI_CreateRecord( 1 );
5224 MSI_RecordSetStringW( uirow, 1, productid );
5225 msi_ui_actiondata( package, szRegisterUser, uirow );
5226 msiobj_release( &uirow->hdr );
5228 msi_free(productid);
5229 RegCloseKey(hkey);
5230 return rc;
5234 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5236 UINT rc;
5238 package->script->InWhatSequence |= SEQUENCE_EXEC;
5239 rc = ACTION_ProcessExecSequence(package,FALSE);
5240 return rc;
5243 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5245 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5246 WCHAR productid_85[21], component_85[21], *ret;
5247 GUID clsid;
5248 DWORD sz;
5250 /* > is used if there is a component GUID and < if not. */
5252 productid_85[0] = 0;
5253 component_85[0] = 0;
5254 CLSIDFromString( package->ProductCode, &clsid );
5256 encode_base85_guid( &clsid, productid_85 );
5257 if (component)
5259 CLSIDFromString( component->ComponentId, &clsid );
5260 encode_base85_guid( &clsid, component_85 );
5263 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5264 debugstr_w(component_85));
5266 sz = 20 + strlenW( feature ) + 20 + 3;
5267 ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5268 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5269 return ret;
5272 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5274 MSIPACKAGE *package = param;
5275 LPCWSTR compgroupid, component, feature, qualifier, text;
5276 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5277 HKEY hkey = NULL;
5278 UINT rc;
5279 MSICOMPONENT *comp;
5280 MSIFEATURE *feat;
5281 DWORD sz;
5282 MSIRECORD *uirow;
5283 int len;
5285 feature = MSI_RecordGetString(rec, 5);
5286 feat = msi_get_loaded_feature(package, feature);
5287 if (!feat)
5288 return ERROR_SUCCESS;
5290 feat->Action = msi_get_feature_action( package, feat );
5291 if (feat->Action != INSTALLSTATE_LOCAL &&
5292 feat->Action != INSTALLSTATE_SOURCE &&
5293 feat->Action != INSTALLSTATE_ADVERTISED)
5295 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5296 return ERROR_SUCCESS;
5299 component = MSI_RecordGetString(rec, 3);
5300 comp = msi_get_loaded_component(package, component);
5301 if (!comp)
5302 return ERROR_SUCCESS;
5304 compgroupid = MSI_RecordGetString(rec,1);
5305 qualifier = MSI_RecordGetString(rec,2);
5307 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5308 if (rc != ERROR_SUCCESS)
5309 goto end;
5311 advertise = msi_create_component_advertise_string( package, comp, feature );
5312 text = MSI_RecordGetString( rec, 4 );
5313 if (text)
5315 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5316 strcpyW( p, advertise );
5317 strcatW( p, text );
5318 msi_free( advertise );
5319 advertise = p;
5321 existing = msi_reg_get_val_str( hkey, qualifier );
5323 sz = strlenW( advertise ) + 1;
5324 if (existing)
5326 for (p = existing; *p; p += len)
5328 len = strlenW( p ) + 1;
5329 if (strcmpW( advertise, p )) sz += len;
5332 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5334 rc = ERROR_OUTOFMEMORY;
5335 goto end;
5337 q = output;
5338 if (existing)
5340 for (p = existing; *p; p += len)
5342 len = strlenW( p ) + 1;
5343 if (strcmpW( advertise, p ))
5345 memcpy( q, p, len * sizeof(WCHAR) );
5346 q += len;
5350 strcpyW( q, advertise );
5351 q[strlenW( q ) + 1] = 0;
5353 msi_reg_set_val_multi_str( hkey, qualifier, output );
5355 end:
5356 RegCloseKey(hkey);
5357 msi_free( output );
5358 msi_free( advertise );
5359 msi_free( existing );
5361 /* the UI chunk */
5362 uirow = MSI_CreateRecord( 2 );
5363 MSI_RecordSetStringW( uirow, 1, compgroupid );
5364 MSI_RecordSetStringW( uirow, 2, qualifier);
5365 msi_ui_actiondata( package, szPublishComponents, uirow );
5366 msiobj_release( &uirow->hdr );
5367 /* FIXME: call ui_progress? */
5369 return rc;
5373 * At present I am ignorning the advertised components part of this and only
5374 * focusing on the qualified component sets
5376 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5378 UINT rc;
5379 MSIQUERY * view;
5380 static const WCHAR ExecSeqQuery[] =
5381 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5382 '`','P','u','b','l','i','s','h',
5383 'C','o','m','p','o','n','e','n','t','`',0};
5385 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5386 if (rc != ERROR_SUCCESS)
5387 return ERROR_SUCCESS;
5389 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5390 msiobj_release(&view->hdr);
5392 return rc;
5395 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5397 static const WCHAR szInstallerComponents[] = {
5398 'S','o','f','t','w','a','r','e','\\',
5399 'M','i','c','r','o','s','o','f','t','\\',
5400 'I','n','s','t','a','l','l','e','r','\\',
5401 'C','o','m','p','o','n','e','n','t','s','\\',0};
5403 MSIPACKAGE *package = param;
5404 LPCWSTR compgroupid, component, feature, qualifier;
5405 MSICOMPONENT *comp;
5406 MSIFEATURE *feat;
5407 MSIRECORD *uirow;
5408 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5409 LONG res;
5411 feature = MSI_RecordGetString( rec, 5 );
5412 feat = msi_get_loaded_feature( package, feature );
5413 if (!feat)
5414 return ERROR_SUCCESS;
5416 feat->Action = msi_get_feature_action( package, feat );
5417 if (feat->Action != INSTALLSTATE_ABSENT)
5419 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5420 return ERROR_SUCCESS;
5423 component = MSI_RecordGetString( rec, 3 );
5424 comp = msi_get_loaded_component( package, component );
5425 if (!comp)
5426 return ERROR_SUCCESS;
5428 compgroupid = MSI_RecordGetString( rec, 1 );
5429 qualifier = MSI_RecordGetString( rec, 2 );
5431 squash_guid( compgroupid, squashed );
5432 strcpyW( keypath, szInstallerComponents );
5433 strcatW( keypath, squashed );
5435 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5436 if (res != ERROR_SUCCESS)
5438 WARN("Unable to delete component key %d\n", res);
5441 uirow = MSI_CreateRecord( 2 );
5442 MSI_RecordSetStringW( uirow, 1, compgroupid );
5443 MSI_RecordSetStringW( uirow, 2, qualifier );
5444 msi_ui_actiondata( package, szUnpublishComponents, uirow );
5445 msiobj_release( &uirow->hdr );
5447 return ERROR_SUCCESS;
5450 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5452 UINT rc;
5453 MSIQUERY *view;
5454 static const WCHAR query[] =
5455 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5456 '`','P','u','b','l','i','s','h',
5457 'C','o','m','p','o','n','e','n','t','`',0};
5459 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5460 if (rc != ERROR_SUCCESS)
5461 return ERROR_SUCCESS;
5463 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5464 msiobj_release( &view->hdr );
5466 return rc;
5469 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5471 static const WCHAR query[] =
5472 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5473 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5474 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5475 MSIPACKAGE *package = param;
5476 MSICOMPONENT *component;
5477 MSIRECORD *row;
5478 MSIFILE *file;
5479 SC_HANDLE hscm = NULL, service = NULL;
5480 LPCWSTR comp, key;
5481 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5482 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5483 DWORD serv_type, start_type, err_control;
5484 SERVICE_DESCRIPTIONW sd = {NULL};
5486 comp = MSI_RecordGetString( rec, 12 );
5487 component = msi_get_loaded_component( package, comp );
5488 if (!component)
5490 WARN("service component not found\n");
5491 goto done;
5493 component->Action = msi_get_component_action( package, component );
5494 if (component->Action != INSTALLSTATE_LOCAL)
5496 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5497 goto done;
5499 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5500 if (!hscm)
5502 ERR("Failed to open the SC Manager!\n");
5503 goto done;
5506 start_type = MSI_RecordGetInteger(rec, 5);
5507 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5508 goto done;
5510 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5511 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5512 serv_type = MSI_RecordGetInteger(rec, 4);
5513 err_control = MSI_RecordGetInteger(rec, 6);
5514 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5515 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5516 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5517 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5518 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5519 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5521 /* fetch the service path */
5522 row = MSI_QueryGetRecord(package->db, query, comp);
5523 if (!row)
5525 ERR("Query failed\n");
5526 goto done;
5528 key = MSI_RecordGetString(row, 6);
5529 file = msi_get_loaded_file(package, key);
5530 msiobj_release(&row->hdr);
5531 if (!file)
5533 ERR("Failed to load the service file\n");
5534 goto done;
5537 if (!args || !args[0]) image_path = file->TargetPath;
5538 else
5540 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5541 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5542 return ERROR_OUTOFMEMORY;
5544 strcpyW(image_path, file->TargetPath);
5545 strcatW(image_path, szSpace);
5546 strcatW(image_path, args);
5548 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5549 start_type, err_control, image_path, load_order,
5550 NULL, depends, serv_name, pass);
5552 if (!service)
5554 if (GetLastError() != ERROR_SERVICE_EXISTS)
5555 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5557 else if (sd.lpDescription)
5559 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5560 WARN("failed to set service description %u\n", GetLastError());
5563 if (image_path != file->TargetPath) msi_free(image_path);
5564 done:
5565 CloseServiceHandle(service);
5566 CloseServiceHandle(hscm);
5567 msi_free(name);
5568 msi_free(disp);
5569 msi_free(sd.lpDescription);
5570 msi_free(load_order);
5571 msi_free(serv_name);
5572 msi_free(pass);
5573 msi_free(depends);
5574 msi_free(args);
5576 return ERROR_SUCCESS;
5579 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5581 UINT rc;
5582 MSIQUERY * view;
5583 static const WCHAR ExecSeqQuery[] =
5584 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5585 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5587 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5588 if (rc != ERROR_SUCCESS)
5589 return ERROR_SUCCESS;
5591 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5592 msiobj_release(&view->hdr);
5594 return rc;
5597 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5598 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5600 LPCWSTR *vector, *temp_vector;
5601 LPWSTR p, q;
5602 DWORD sep_len;
5604 static const WCHAR separator[] = {'[','~',']',0};
5606 *numargs = 0;
5607 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5609 if (!args)
5610 return NULL;
5612 vector = msi_alloc(sizeof(LPWSTR));
5613 if (!vector)
5614 return NULL;
5616 p = args;
5619 (*numargs)++;
5620 vector[*numargs - 1] = p;
5622 if ((q = strstrW(p, separator)))
5624 *q = '\0';
5626 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5627 if (!temp_vector)
5629 msi_free(vector);
5630 return NULL;
5632 vector = temp_vector;
5634 p = q + sep_len;
5636 } while (q);
5638 return vector;
5641 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5643 MSIPACKAGE *package = param;
5644 MSICOMPONENT *comp;
5645 MSIRECORD *uirow;
5646 SC_HANDLE scm = NULL, service = NULL;
5647 LPCWSTR component, *vector = NULL;
5648 LPWSTR name, args, display_name = NULL;
5649 DWORD event, numargs, len;
5650 UINT r = ERROR_FUNCTION_FAILED;
5652 component = MSI_RecordGetString(rec, 6);
5653 comp = msi_get_loaded_component(package, component);
5654 if (!comp)
5655 return ERROR_SUCCESS;
5657 comp->Action = msi_get_component_action( package, comp );
5658 if (comp->Action != INSTALLSTATE_LOCAL)
5660 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5661 return ERROR_SUCCESS;
5664 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5665 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5666 event = MSI_RecordGetInteger(rec, 3);
5668 if (!(event & msidbServiceControlEventStart))
5670 r = ERROR_SUCCESS;
5671 goto done;
5674 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5675 if (!scm)
5677 ERR("Failed to open the service control manager\n");
5678 goto done;
5681 len = 0;
5682 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5683 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5685 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5686 GetServiceDisplayNameW( scm, name, display_name, &len );
5689 service = OpenServiceW(scm, name, SERVICE_START);
5690 if (!service)
5692 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5693 goto done;
5696 vector = msi_service_args_to_vector(args, &numargs);
5698 if (!StartServiceW(service, numargs, vector) &&
5699 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5701 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5702 goto done;
5705 r = ERROR_SUCCESS;
5707 done:
5708 uirow = MSI_CreateRecord( 2 );
5709 MSI_RecordSetStringW( uirow, 1, display_name );
5710 MSI_RecordSetStringW( uirow, 2, name );
5711 msi_ui_actiondata( package, szStartServices, uirow );
5712 msiobj_release( &uirow->hdr );
5714 CloseServiceHandle(service);
5715 CloseServiceHandle(scm);
5717 msi_free(name);
5718 msi_free(args);
5719 msi_free(vector);
5720 msi_free(display_name);
5721 return r;
5724 static UINT ACTION_StartServices( MSIPACKAGE *package )
5726 UINT rc;
5727 MSIQUERY *view;
5729 static const WCHAR query[] = {
5730 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5731 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5733 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5734 if (rc != ERROR_SUCCESS)
5735 return ERROR_SUCCESS;
5737 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5738 msiobj_release(&view->hdr);
5740 return rc;
5743 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5745 DWORD i, needed, count;
5746 ENUM_SERVICE_STATUSW *dependencies;
5747 SERVICE_STATUS ss;
5748 SC_HANDLE depserv;
5750 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5751 0, &needed, &count))
5752 return TRUE;
5754 if (GetLastError() != ERROR_MORE_DATA)
5755 return FALSE;
5757 dependencies = msi_alloc(needed);
5758 if (!dependencies)
5759 return FALSE;
5761 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5762 needed, &needed, &count))
5763 goto error;
5765 for (i = 0; i < count; i++)
5767 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5768 SERVICE_STOP | SERVICE_QUERY_STATUS);
5769 if (!depserv)
5770 goto error;
5772 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5773 goto error;
5776 return TRUE;
5778 error:
5779 msi_free(dependencies);
5780 return FALSE;
5783 static UINT stop_service( LPCWSTR name )
5785 SC_HANDLE scm = NULL, service = NULL;
5786 SERVICE_STATUS status;
5787 SERVICE_STATUS_PROCESS ssp;
5788 DWORD needed;
5790 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5791 if (!scm)
5793 WARN("Failed to open the SCM: %d\n", GetLastError());
5794 goto done;
5797 service = OpenServiceW(scm, name,
5798 SERVICE_STOP |
5799 SERVICE_QUERY_STATUS |
5800 SERVICE_ENUMERATE_DEPENDENTS);
5801 if (!service)
5803 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5804 goto done;
5807 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5808 sizeof(SERVICE_STATUS_PROCESS), &needed))
5810 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5811 goto done;
5814 if (ssp.dwCurrentState == SERVICE_STOPPED)
5815 goto done;
5817 stop_service_dependents(scm, service);
5819 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5820 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5822 done:
5823 CloseServiceHandle(service);
5824 CloseServiceHandle(scm);
5826 return ERROR_SUCCESS;
5829 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5831 MSIPACKAGE *package = param;
5832 MSICOMPONENT *comp;
5833 MSIRECORD *uirow;
5834 LPCWSTR component;
5835 LPWSTR name = NULL, display_name = NULL;
5836 DWORD event, len;
5837 SC_HANDLE scm;
5839 event = MSI_RecordGetInteger( rec, 3 );
5840 if (!(event & msidbServiceControlEventStop))
5841 return ERROR_SUCCESS;
5843 component = MSI_RecordGetString( rec, 6 );
5844 comp = msi_get_loaded_component( package, component );
5845 if (!comp)
5846 return ERROR_SUCCESS;
5848 comp->Action = msi_get_component_action( package, comp );
5849 if (comp->Action != INSTALLSTATE_ABSENT)
5851 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5852 return ERROR_SUCCESS;
5855 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5856 if (!scm)
5858 ERR("Failed to open the service control manager\n");
5859 goto done;
5862 len = 0;
5863 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5864 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5866 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5867 GetServiceDisplayNameW( scm, name, display_name, &len );
5869 CloseServiceHandle( scm );
5871 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5872 stop_service( name );
5874 done:
5875 uirow = MSI_CreateRecord( 2 );
5876 MSI_RecordSetStringW( uirow, 1, display_name );
5877 MSI_RecordSetStringW( uirow, 2, name );
5878 msi_ui_actiondata( package, szStopServices, uirow );
5879 msiobj_release( &uirow->hdr );
5881 msi_free( name );
5882 msi_free( display_name );
5883 return ERROR_SUCCESS;
5886 static UINT ACTION_StopServices( MSIPACKAGE *package )
5888 UINT rc;
5889 MSIQUERY *view;
5891 static const WCHAR query[] = {
5892 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5893 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5895 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5896 if (rc != ERROR_SUCCESS)
5897 return ERROR_SUCCESS;
5899 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5900 msiobj_release(&view->hdr);
5902 return rc;
5905 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5907 MSIPACKAGE *package = param;
5908 MSICOMPONENT *comp;
5909 MSIRECORD *uirow;
5910 LPCWSTR component;
5911 LPWSTR name = NULL, display_name = NULL;
5912 DWORD event, len;
5913 SC_HANDLE scm = NULL, service = NULL;
5915 event = MSI_RecordGetInteger( rec, 3 );
5916 if (!(event & msidbServiceControlEventDelete))
5917 return ERROR_SUCCESS;
5919 component = MSI_RecordGetString(rec, 6);
5920 comp = msi_get_loaded_component(package, component);
5921 if (!comp)
5922 return ERROR_SUCCESS;
5924 comp->Action = msi_get_component_action( package, comp );
5925 if (comp->Action != INSTALLSTATE_ABSENT)
5927 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5928 return ERROR_SUCCESS;
5931 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5932 stop_service( name );
5934 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5935 if (!scm)
5937 WARN("Failed to open the SCM: %d\n", GetLastError());
5938 goto done;
5941 len = 0;
5942 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5943 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5945 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5946 GetServiceDisplayNameW( scm, name, display_name, &len );
5949 service = OpenServiceW( scm, name, DELETE );
5950 if (!service)
5952 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5953 goto done;
5956 if (!DeleteService( service ))
5957 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5959 done:
5960 uirow = MSI_CreateRecord( 2 );
5961 MSI_RecordSetStringW( uirow, 1, display_name );
5962 MSI_RecordSetStringW( uirow, 2, name );
5963 msi_ui_actiondata( package, szDeleteServices, uirow );
5964 msiobj_release( &uirow->hdr );
5966 CloseServiceHandle( service );
5967 CloseServiceHandle( scm );
5968 msi_free( name );
5969 msi_free( display_name );
5971 return ERROR_SUCCESS;
5974 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5976 UINT rc;
5977 MSIQUERY *view;
5979 static const WCHAR query[] = {
5980 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5981 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5983 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5984 if (rc != ERROR_SUCCESS)
5985 return ERROR_SUCCESS;
5987 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5988 msiobj_release( &view->hdr );
5990 return rc;
5993 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5995 MSIPACKAGE *package = param;
5996 LPWSTR driver, driver_path, ptr;
5997 WCHAR outpath[MAX_PATH];
5998 MSIFILE *driver_file = NULL, *setup_file = NULL;
5999 MSICOMPONENT *comp;
6000 MSIRECORD *uirow;
6001 LPCWSTR desc, file_key, component;
6002 DWORD len, usage;
6003 UINT r = ERROR_SUCCESS;
6005 static const WCHAR driver_fmt[] = {
6006 'D','r','i','v','e','r','=','%','s',0};
6007 static const WCHAR setup_fmt[] = {
6008 'S','e','t','u','p','=','%','s',0};
6009 static const WCHAR usage_fmt[] = {
6010 'F','i','l','e','U','s','a','g','e','=','1',0};
6012 component = MSI_RecordGetString( rec, 2 );
6013 comp = msi_get_loaded_component( package, component );
6014 if (!comp)
6015 return ERROR_SUCCESS;
6017 comp->Action = msi_get_component_action( package, comp );
6018 if (comp->Action != INSTALLSTATE_LOCAL)
6020 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6021 return ERROR_SUCCESS;
6023 desc = MSI_RecordGetString(rec, 3);
6025 file_key = MSI_RecordGetString( rec, 4 );
6026 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6028 file_key = MSI_RecordGetString( rec, 5 );
6029 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6031 if (!driver_file)
6033 ERR("ODBC Driver entry not found!\n");
6034 return ERROR_FUNCTION_FAILED;
6037 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6038 if (setup_file)
6039 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6040 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6042 driver = msi_alloc(len * sizeof(WCHAR));
6043 if (!driver)
6044 return ERROR_OUTOFMEMORY;
6046 ptr = driver;
6047 lstrcpyW(ptr, desc);
6048 ptr += lstrlenW(ptr) + 1;
6050 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6051 ptr += len + 1;
6053 if (setup_file)
6055 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6056 ptr += len + 1;
6059 lstrcpyW(ptr, usage_fmt);
6060 ptr += lstrlenW(ptr) + 1;
6061 *ptr = '\0';
6063 driver_path = strdupW(driver_file->TargetPath);
6064 ptr = strrchrW(driver_path, '\\');
6065 if (ptr) *ptr = '\0';
6067 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6068 NULL, ODBC_INSTALL_COMPLETE, &usage))
6070 ERR("Failed to install SQL driver!\n");
6071 r = ERROR_FUNCTION_FAILED;
6074 uirow = MSI_CreateRecord( 5 );
6075 MSI_RecordSetStringW( uirow, 1, desc );
6076 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6077 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6078 msi_ui_actiondata( package, szInstallODBC, uirow );
6079 msiobj_release( &uirow->hdr );
6081 msi_free(driver);
6082 msi_free(driver_path);
6084 return r;
6087 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6089 MSIPACKAGE *package = param;
6090 LPWSTR translator, translator_path, ptr;
6091 WCHAR outpath[MAX_PATH];
6092 MSIFILE *translator_file = NULL, *setup_file = NULL;
6093 MSICOMPONENT *comp;
6094 MSIRECORD *uirow;
6095 LPCWSTR desc, file_key, component;
6096 DWORD len, usage;
6097 UINT r = ERROR_SUCCESS;
6099 static const WCHAR translator_fmt[] = {
6100 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6101 static const WCHAR setup_fmt[] = {
6102 'S','e','t','u','p','=','%','s',0};
6104 component = MSI_RecordGetString( rec, 2 );
6105 comp = msi_get_loaded_component( package, component );
6106 if (!comp)
6107 return ERROR_SUCCESS;
6109 comp->Action = msi_get_component_action( package, comp );
6110 if (comp->Action != INSTALLSTATE_LOCAL)
6112 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6113 return ERROR_SUCCESS;
6115 desc = MSI_RecordGetString(rec, 3);
6117 file_key = MSI_RecordGetString( rec, 4 );
6118 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6120 file_key = MSI_RecordGetString( rec, 5 );
6121 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6123 if (!translator_file)
6125 ERR("ODBC Translator entry not found!\n");
6126 return ERROR_FUNCTION_FAILED;
6129 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6130 if (setup_file)
6131 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6133 translator = msi_alloc(len * sizeof(WCHAR));
6134 if (!translator)
6135 return ERROR_OUTOFMEMORY;
6137 ptr = translator;
6138 lstrcpyW(ptr, desc);
6139 ptr += lstrlenW(ptr) + 1;
6141 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6142 ptr += len + 1;
6144 if (setup_file)
6146 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6147 ptr += len + 1;
6149 *ptr = '\0';
6151 translator_path = strdupW(translator_file->TargetPath);
6152 ptr = strrchrW(translator_path, '\\');
6153 if (ptr) *ptr = '\0';
6155 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6156 NULL, ODBC_INSTALL_COMPLETE, &usage))
6158 ERR("Failed to install SQL translator!\n");
6159 r = ERROR_FUNCTION_FAILED;
6162 uirow = MSI_CreateRecord( 5 );
6163 MSI_RecordSetStringW( uirow, 1, desc );
6164 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6165 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6166 msi_ui_actiondata( package, szInstallODBC, uirow );
6167 msiobj_release( &uirow->hdr );
6169 msi_free(translator);
6170 msi_free(translator_path);
6172 return r;
6175 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6177 MSIPACKAGE *package = param;
6178 MSICOMPONENT *comp;
6179 LPWSTR attrs;
6180 LPCWSTR desc, driver, component;
6181 WORD request = ODBC_ADD_SYS_DSN;
6182 INT registration;
6183 DWORD len;
6184 UINT r = ERROR_SUCCESS;
6185 MSIRECORD *uirow;
6187 static const WCHAR attrs_fmt[] = {
6188 'D','S','N','=','%','s',0 };
6190 component = MSI_RecordGetString( rec, 2 );
6191 comp = msi_get_loaded_component( package, component );
6192 if (!comp)
6193 return ERROR_SUCCESS;
6195 comp->Action = msi_get_component_action( package, comp );
6196 if (comp->Action != INSTALLSTATE_LOCAL)
6198 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6199 return ERROR_SUCCESS;
6202 desc = MSI_RecordGetString(rec, 3);
6203 driver = MSI_RecordGetString(rec, 4);
6204 registration = MSI_RecordGetInteger(rec, 5);
6206 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6207 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6209 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6210 attrs = msi_alloc(len * sizeof(WCHAR));
6211 if (!attrs)
6212 return ERROR_OUTOFMEMORY;
6214 len = sprintfW(attrs, attrs_fmt, desc);
6215 attrs[len + 1] = 0;
6217 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6219 ERR("Failed to install SQL data source!\n");
6220 r = ERROR_FUNCTION_FAILED;
6223 uirow = MSI_CreateRecord( 5 );
6224 MSI_RecordSetStringW( uirow, 1, desc );
6225 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6226 MSI_RecordSetInteger( uirow, 3, request );
6227 msi_ui_actiondata( package, szInstallODBC, uirow );
6228 msiobj_release( &uirow->hdr );
6230 msi_free(attrs);
6232 return r;
6235 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6237 UINT rc;
6238 MSIQUERY *view;
6240 static const WCHAR driver_query[] = {
6241 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6242 'O','D','B','C','D','r','i','v','e','r',0 };
6244 static const WCHAR translator_query[] = {
6245 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6246 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6248 static const WCHAR source_query[] = {
6249 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6250 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6252 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6253 if (rc != ERROR_SUCCESS)
6254 return ERROR_SUCCESS;
6256 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6257 msiobj_release(&view->hdr);
6259 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6260 if (rc != ERROR_SUCCESS)
6261 return ERROR_SUCCESS;
6263 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6264 msiobj_release(&view->hdr);
6266 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6267 if (rc != ERROR_SUCCESS)
6268 return ERROR_SUCCESS;
6270 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6271 msiobj_release(&view->hdr);
6273 return rc;
6276 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6278 MSIPACKAGE *package = param;
6279 MSICOMPONENT *comp;
6280 MSIRECORD *uirow;
6281 DWORD usage;
6282 LPCWSTR desc, component;
6284 component = MSI_RecordGetString( rec, 2 );
6285 comp = msi_get_loaded_component( package, component );
6286 if (!comp)
6287 return ERROR_SUCCESS;
6289 comp->Action = msi_get_component_action( package, comp );
6290 if (comp->Action != INSTALLSTATE_ABSENT)
6292 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6293 return ERROR_SUCCESS;
6296 desc = MSI_RecordGetString( rec, 3 );
6297 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6299 WARN("Failed to remove ODBC driver\n");
6301 else if (!usage)
6303 FIXME("Usage count reached 0\n");
6306 uirow = MSI_CreateRecord( 2 );
6307 MSI_RecordSetStringW( uirow, 1, desc );
6308 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6309 msi_ui_actiondata( package, szRemoveODBC, uirow );
6310 msiobj_release( &uirow->hdr );
6312 return ERROR_SUCCESS;
6315 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6317 MSIPACKAGE *package = param;
6318 MSICOMPONENT *comp;
6319 MSIRECORD *uirow;
6320 DWORD usage;
6321 LPCWSTR desc, component;
6323 component = MSI_RecordGetString( rec, 2 );
6324 comp = msi_get_loaded_component( package, component );
6325 if (!comp)
6326 return ERROR_SUCCESS;
6328 comp->Action = msi_get_component_action( package, comp );
6329 if (comp->Action != INSTALLSTATE_ABSENT)
6331 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6332 return ERROR_SUCCESS;
6335 desc = MSI_RecordGetString( rec, 3 );
6336 if (!SQLRemoveTranslatorW( desc, &usage ))
6338 WARN("Failed to remove ODBC translator\n");
6340 else if (!usage)
6342 FIXME("Usage count reached 0\n");
6345 uirow = MSI_CreateRecord( 2 );
6346 MSI_RecordSetStringW( uirow, 1, desc );
6347 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6348 msi_ui_actiondata( package, szRemoveODBC, uirow );
6349 msiobj_release( &uirow->hdr );
6351 return ERROR_SUCCESS;
6354 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6356 MSIPACKAGE *package = param;
6357 MSICOMPONENT *comp;
6358 MSIRECORD *uirow;
6359 LPWSTR attrs;
6360 LPCWSTR desc, driver, component;
6361 WORD request = ODBC_REMOVE_SYS_DSN;
6362 INT registration;
6363 DWORD len;
6365 static const WCHAR attrs_fmt[] = {
6366 'D','S','N','=','%','s',0 };
6368 component = MSI_RecordGetString( rec, 2 );
6369 comp = msi_get_loaded_component( package, component );
6370 if (!comp)
6371 return ERROR_SUCCESS;
6373 comp->Action = msi_get_component_action( package, comp );
6374 if (comp->Action != INSTALLSTATE_ABSENT)
6376 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6377 return ERROR_SUCCESS;
6380 desc = MSI_RecordGetString( rec, 3 );
6381 driver = MSI_RecordGetString( rec, 4 );
6382 registration = MSI_RecordGetInteger( rec, 5 );
6384 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6385 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6387 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6388 attrs = msi_alloc( len * sizeof(WCHAR) );
6389 if (!attrs)
6390 return ERROR_OUTOFMEMORY;
6392 FIXME("Use ODBCSourceAttribute table\n");
6394 len = sprintfW( attrs, attrs_fmt, desc );
6395 attrs[len + 1] = 0;
6397 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6399 WARN("Failed to remove ODBC data source\n");
6401 msi_free( attrs );
6403 uirow = MSI_CreateRecord( 3 );
6404 MSI_RecordSetStringW( uirow, 1, desc );
6405 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6406 MSI_RecordSetInteger( uirow, 3, request );
6407 msi_ui_actiondata( package, szRemoveODBC, uirow );
6408 msiobj_release( &uirow->hdr );
6410 return ERROR_SUCCESS;
6413 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6415 UINT rc;
6416 MSIQUERY *view;
6418 static const WCHAR driver_query[] = {
6419 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6420 'O','D','B','C','D','r','i','v','e','r',0 };
6422 static const WCHAR translator_query[] = {
6423 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6424 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6426 static const WCHAR source_query[] = {
6427 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6428 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6430 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6431 if (rc != ERROR_SUCCESS)
6432 return ERROR_SUCCESS;
6434 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6435 msiobj_release( &view->hdr );
6437 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6438 if (rc != ERROR_SUCCESS)
6439 return ERROR_SUCCESS;
6441 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6442 msiobj_release( &view->hdr );
6444 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6445 if (rc != ERROR_SUCCESS)
6446 return ERROR_SUCCESS;
6448 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6449 msiobj_release( &view->hdr );
6451 return rc;
6454 #define ENV_ACT_SETALWAYS 0x1
6455 #define ENV_ACT_SETABSENT 0x2
6456 #define ENV_ACT_REMOVE 0x4
6457 #define ENV_ACT_REMOVEMATCH 0x8
6459 #define ENV_MOD_MACHINE 0x20000000
6460 #define ENV_MOD_APPEND 0x40000000
6461 #define ENV_MOD_PREFIX 0x80000000
6462 #define ENV_MOD_MASK 0xC0000000
6464 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6466 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6468 LPCWSTR cptr = *name;
6470 static const WCHAR prefix[] = {'[','~',']',0};
6471 static const int prefix_len = 3;
6473 *flags = 0;
6474 while (*cptr)
6476 if (*cptr == '=')
6477 *flags |= ENV_ACT_SETALWAYS;
6478 else if (*cptr == '+')
6479 *flags |= ENV_ACT_SETABSENT;
6480 else if (*cptr == '-')
6481 *flags |= ENV_ACT_REMOVE;
6482 else if (*cptr == '!')
6483 *flags |= ENV_ACT_REMOVEMATCH;
6484 else if (*cptr == '*')
6485 *flags |= ENV_MOD_MACHINE;
6486 else
6487 break;
6489 cptr++;
6490 (*name)++;
6493 if (!*cptr)
6495 ERR("Missing environment variable\n");
6496 return ERROR_FUNCTION_FAILED;
6499 if (*value)
6501 LPCWSTR ptr = *value;
6502 if (!strncmpW(ptr, prefix, prefix_len))
6504 if (ptr[prefix_len] == szSemiColon[0])
6506 *flags |= ENV_MOD_APPEND;
6507 *value += lstrlenW(prefix);
6509 else
6511 *value = NULL;
6514 else if (lstrlenW(*value) >= prefix_len)
6516 ptr += lstrlenW(ptr) - prefix_len;
6517 if (!strcmpW( ptr, prefix ))
6519 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6521 *flags |= ENV_MOD_PREFIX;
6522 /* the "[~]" will be removed by deformat_string */;
6524 else
6526 *value = NULL;
6532 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6533 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6534 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6535 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6537 ERR("Invalid flags: %08x\n", *flags);
6538 return ERROR_FUNCTION_FAILED;
6541 if (!*flags)
6542 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6544 return ERROR_SUCCESS;
6547 static UINT open_env_key( DWORD flags, HKEY *key )
6549 static const WCHAR user_env[] =
6550 {'E','n','v','i','r','o','n','m','e','n','t',0};
6551 static const WCHAR machine_env[] =
6552 {'S','y','s','t','e','m','\\',
6553 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6554 'C','o','n','t','r','o','l','\\',
6555 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6556 'E','n','v','i','r','o','n','m','e','n','t',0};
6557 const WCHAR *env;
6558 HKEY root;
6559 LONG res;
6561 if (flags & ENV_MOD_MACHINE)
6563 env = machine_env;
6564 root = HKEY_LOCAL_MACHINE;
6566 else
6568 env = user_env;
6569 root = HKEY_CURRENT_USER;
6572 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6573 if (res != ERROR_SUCCESS)
6575 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6576 return ERROR_FUNCTION_FAILED;
6579 return ERROR_SUCCESS;
6582 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6584 MSIPACKAGE *package = param;
6585 LPCWSTR name, value, component;
6586 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6587 DWORD flags, type, size;
6588 UINT res;
6589 HKEY env = NULL;
6590 MSICOMPONENT *comp;
6591 MSIRECORD *uirow;
6592 int action = 0;
6594 component = MSI_RecordGetString(rec, 4);
6595 comp = msi_get_loaded_component(package, component);
6596 if (!comp)
6597 return ERROR_SUCCESS;
6599 comp->Action = msi_get_component_action( package, comp );
6600 if (comp->Action != INSTALLSTATE_LOCAL)
6602 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6603 return ERROR_SUCCESS;
6605 name = MSI_RecordGetString(rec, 2);
6606 value = MSI_RecordGetString(rec, 3);
6608 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6610 res = env_parse_flags(&name, &value, &flags);
6611 if (res != ERROR_SUCCESS || !value)
6612 goto done;
6614 if (value && !deformat_string(package, value, &deformatted))
6616 res = ERROR_OUTOFMEMORY;
6617 goto done;
6620 value = deformatted;
6622 res = open_env_key( flags, &env );
6623 if (res != ERROR_SUCCESS)
6624 goto done;
6626 if (flags & ENV_MOD_MACHINE)
6627 action |= 0x20000000;
6629 size = 0;
6630 type = REG_SZ;
6631 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6632 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6633 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6634 goto done;
6636 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6638 action = 0x2;
6640 /* Nothing to do. */
6641 if (!value)
6643 res = ERROR_SUCCESS;
6644 goto done;
6647 /* If we are appending but the string was empty, strip ; */
6648 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6650 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6651 newval = strdupW(value);
6652 if (!newval)
6654 res = ERROR_OUTOFMEMORY;
6655 goto done;
6658 else
6660 action = 0x1;
6662 /* Contrary to MSDN, +-variable to [~];path works */
6663 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6665 res = ERROR_SUCCESS;
6666 goto done;
6669 data = msi_alloc(size);
6670 if (!data)
6672 RegCloseKey(env);
6673 return ERROR_OUTOFMEMORY;
6676 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6677 if (res != ERROR_SUCCESS)
6678 goto done;
6680 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6682 action = 0x4;
6683 res = RegDeleteValueW(env, name);
6684 if (res != ERROR_SUCCESS)
6685 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6686 goto done;
6689 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6690 if (flags & ENV_MOD_MASK)
6692 DWORD mod_size;
6693 int multiplier = 0;
6694 if (flags & ENV_MOD_APPEND) multiplier++;
6695 if (flags & ENV_MOD_PREFIX) multiplier++;
6696 mod_size = lstrlenW(value) * multiplier;
6697 size += mod_size * sizeof(WCHAR);
6700 newval = msi_alloc(size);
6701 ptr = newval;
6702 if (!newval)
6704 res = ERROR_OUTOFMEMORY;
6705 goto done;
6708 if (flags & ENV_MOD_PREFIX)
6710 lstrcpyW(newval, value);
6711 ptr = newval + lstrlenW(value);
6712 action |= 0x80000000;
6715 lstrcpyW(ptr, data);
6717 if (flags & ENV_MOD_APPEND)
6719 lstrcatW(newval, value);
6720 action |= 0x40000000;
6723 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6724 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6725 if (res)
6727 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6730 done:
6731 uirow = MSI_CreateRecord( 3 );
6732 MSI_RecordSetStringW( uirow, 1, name );
6733 MSI_RecordSetStringW( uirow, 2, newval );
6734 MSI_RecordSetInteger( uirow, 3, action );
6735 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6736 msiobj_release( &uirow->hdr );
6738 if (env) RegCloseKey(env);
6739 msi_free(deformatted);
6740 msi_free(data);
6741 msi_free(newval);
6742 return res;
6745 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6747 UINT rc;
6748 MSIQUERY * view;
6749 static const WCHAR ExecSeqQuery[] =
6750 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6751 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6752 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6753 if (rc != ERROR_SUCCESS)
6754 return ERROR_SUCCESS;
6756 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6757 msiobj_release(&view->hdr);
6759 return rc;
6762 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6764 MSIPACKAGE *package = param;
6765 LPCWSTR name, value, component;
6766 LPWSTR deformatted = NULL;
6767 DWORD flags;
6768 HKEY env;
6769 MSICOMPONENT *comp;
6770 MSIRECORD *uirow;
6771 int action = 0;
6772 LONG res;
6773 UINT r;
6775 component = MSI_RecordGetString( rec, 4 );
6776 comp = msi_get_loaded_component( package, component );
6777 if (!comp)
6778 return ERROR_SUCCESS;
6780 comp->Action = msi_get_component_action( package, comp );
6781 if (comp->Action != INSTALLSTATE_ABSENT)
6783 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6784 return ERROR_SUCCESS;
6786 name = MSI_RecordGetString( rec, 2 );
6787 value = MSI_RecordGetString( rec, 3 );
6789 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6791 r = env_parse_flags( &name, &value, &flags );
6792 if (r != ERROR_SUCCESS)
6793 return r;
6795 if (!(flags & ENV_ACT_REMOVE))
6797 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6798 return ERROR_SUCCESS;
6801 if (value && !deformat_string( package, value, &deformatted ))
6802 return ERROR_OUTOFMEMORY;
6804 value = deformatted;
6806 r = open_env_key( flags, &env );
6807 if (r != ERROR_SUCCESS)
6809 r = ERROR_SUCCESS;
6810 goto done;
6813 if (flags & ENV_MOD_MACHINE)
6814 action |= 0x20000000;
6816 TRACE("Removing %s\n", debugstr_w(name));
6818 res = RegDeleteValueW( env, name );
6819 if (res != ERROR_SUCCESS)
6821 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6822 r = ERROR_SUCCESS;
6825 done:
6826 uirow = MSI_CreateRecord( 3 );
6827 MSI_RecordSetStringW( uirow, 1, name );
6828 MSI_RecordSetStringW( uirow, 2, value );
6829 MSI_RecordSetInteger( uirow, 3, action );
6830 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6831 msiobj_release( &uirow->hdr );
6833 if (env) RegCloseKey( env );
6834 msi_free( deformatted );
6835 return r;
6838 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6840 UINT rc;
6841 MSIQUERY *view;
6842 static const WCHAR query[] =
6843 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6844 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6846 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6847 if (rc != ERROR_SUCCESS)
6848 return ERROR_SUCCESS;
6850 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6851 msiobj_release( &view->hdr );
6853 return rc;
6856 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6858 LPWSTR key, template, id;
6859 UINT r = ERROR_SUCCESS;
6861 id = msi_dup_property( package->db, szProductID );
6862 if (id)
6864 msi_free( id );
6865 return ERROR_SUCCESS;
6867 template = msi_dup_property( package->db, szPIDTemplate );
6868 key = msi_dup_property( package->db, szPIDKEY );
6870 if (key && template)
6872 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6873 r = msi_set_property( package->db, szProductID, key );
6875 msi_free( template );
6876 msi_free( key );
6877 return r;
6880 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6882 TRACE("\n");
6883 package->need_reboot = 1;
6884 return ERROR_SUCCESS;
6887 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6889 static const WCHAR szAvailableFreeReg[] =
6890 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6891 MSIRECORD *uirow;
6892 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6894 TRACE("%p %d kilobytes\n", package, space);
6896 uirow = MSI_CreateRecord( 1 );
6897 MSI_RecordSetInteger( uirow, 1, space );
6898 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6899 msiobj_release( &uirow->hdr );
6901 return ERROR_SUCCESS;
6904 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6906 TRACE("%p\n", package);
6908 msi_set_property( package->db, szRollbackDisabled, szOne );
6909 return ERROR_SUCCESS;
6912 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6914 FIXME("%p\n", package);
6915 return ERROR_SUCCESS;
6918 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6920 UINT r, count;
6921 MSIQUERY *view;
6923 static const WCHAR driver_query[] = {
6924 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6925 'O','D','B','C','D','r','i','v','e','r',0 };
6927 static const WCHAR translator_query[] = {
6928 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6929 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6931 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6932 if (r == ERROR_SUCCESS)
6934 count = 0;
6935 r = MSI_IterateRecords( view, &count, NULL, package );
6936 msiobj_release( &view->hdr );
6937 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6940 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6941 if (r == ERROR_SUCCESS)
6943 count = 0;
6944 r = MSI_IterateRecords( view, &count, NULL, package );
6945 msiobj_release( &view->hdr );
6946 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6949 return ERROR_SUCCESS;
6952 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6954 MSIPACKAGE *package = param;
6955 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6956 WCHAR *value;
6958 if ((value = msi_dup_property( package->db, property )))
6960 FIXME("remove %s\n", debugstr_w(value));
6961 msi_free( value );
6963 return ERROR_SUCCESS;
6966 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6968 UINT r;
6969 MSIQUERY *view;
6971 static const WCHAR query[] =
6972 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
6973 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
6975 r = MSI_DatabaseOpenViewW( package->db, query, &view );
6976 if (r == ERROR_SUCCESS)
6978 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
6979 msiobj_release( &view->hdr );
6980 return r;
6982 return ERROR_SUCCESS;
6985 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
6987 MSIPACKAGE *package = param;
6988 int attributes = MSI_RecordGetInteger( rec, 5 );
6990 if (attributes & msidbUpgradeAttributesMigrateFeatures)
6992 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
6993 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
6994 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
6995 const WCHAR *language = MSI_RecordGetString( rec, 4 );
6996 HKEY hkey;
6997 UINT r;
6999 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7001 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7002 if (r != ERROR_SUCCESS)
7003 return ERROR_SUCCESS;
7005 else
7007 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7008 if (r != ERROR_SUCCESS)
7009 return ERROR_SUCCESS;
7011 RegCloseKey( hkey );
7013 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7014 debugstr_w(upgrade_code), debugstr_w(version_min),
7015 debugstr_w(version_max), debugstr_w(language));
7017 return ERROR_SUCCESS;
7020 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7022 UINT r;
7023 MSIQUERY *view;
7024 static const WCHAR query[] =
7025 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7027 if (msi_get_property_int( package->db, szInstalled, 0 ))
7029 TRACE("product is installed, skipping action\n");
7030 return ERROR_SUCCESS;
7032 if (msi_get_property_int( package->db, szPreselected, 0 ))
7034 TRACE("Preselected property is set, not migrating feature states\n");
7035 return ERROR_SUCCESS;
7038 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7039 if (r == ERROR_SUCCESS)
7041 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7042 msiobj_release( &view->hdr );
7044 return ERROR_SUCCESS;
7047 static void bind_image( const char *filename, const char *path )
7049 if (!BindImageEx( 0, filename, path, NULL, NULL ))
7051 WARN("failed to bind image %u\n", GetLastError());
7055 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7057 UINT i;
7058 MSIFILE *file;
7059 MSIPACKAGE *package = param;
7060 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7061 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7062 char *filenameA, *pathA;
7063 WCHAR *pathW, **path_list;
7065 if (!(file = msi_get_loaded_file( package, key )))
7067 WARN("file %s not found\n", debugstr_w(key));
7068 return ERROR_SUCCESS;
7070 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7071 path_list = msi_split_string( paths, ';' );
7072 if (!path_list) bind_image( filenameA, NULL );
7073 else
7075 for (i = 0; path_list[i] && path_list[i][0]; i++)
7077 deformat_string( package, path_list[i], &pathW );
7078 if ((pathA = strdupWtoA( pathW )))
7080 bind_image( filenameA, pathA );
7081 msi_free( pathA );
7083 msi_free( pathW );
7086 msi_free( path_list );
7087 msi_free( filenameA );
7088 return ERROR_SUCCESS;
7091 static UINT ACTION_BindImage( MSIPACKAGE *package )
7093 UINT r;
7094 MSIQUERY *view;
7095 static const WCHAR query[] =
7096 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','B','i','n','d','I','m','a','g','e',0};
7098 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7099 if (r == ERROR_SUCCESS)
7101 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7102 msiobj_release( &view->hdr );
7104 return ERROR_SUCCESS;
7107 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7108 LPCSTR action, LPCWSTR table )
7110 static const WCHAR query[] = {
7111 'S','E','L','E','C','T',' ','*',' ',
7112 'F','R','O','M',' ','`','%','s','`',0 };
7113 MSIQUERY *view = NULL;
7114 DWORD count = 0;
7115 UINT r;
7117 r = MSI_OpenQuery( package->db, &view, query, table );
7118 if (r == ERROR_SUCCESS)
7120 r = MSI_IterateRecords(view, &count, NULL, package);
7121 msiobj_release(&view->hdr);
7124 if (count)
7125 FIXME("%s -> %u ignored %s table values\n",
7126 action, count, debugstr_w(table));
7128 return ERROR_SUCCESS;
7131 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7133 static const WCHAR table[] = {
7134 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7135 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7138 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7140 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7141 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7144 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7146 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7147 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7150 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7152 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7153 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7156 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7158 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7159 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7162 static const struct
7164 const WCHAR *action;
7165 UINT (*handler)(MSIPACKAGE *);
7166 const WCHAR *action_rollback;
7168 StandardActions[] =
7170 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7171 { szAppSearch, ACTION_AppSearch, NULL },
7172 { szBindImage, ACTION_BindImage, NULL },
7173 { szCCPSearch, ACTION_CCPSearch, NULL },
7174 { szCostFinalize, ACTION_CostFinalize, NULL },
7175 { szCostInitialize, ACTION_CostInitialize, NULL },
7176 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7177 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7178 { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7179 { szDisableRollback, ACTION_DisableRollback, NULL },
7180 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7181 { szExecuteAction, ACTION_ExecuteAction, NULL },
7182 { szFileCost, ACTION_FileCost, NULL },
7183 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7184 { szForceReboot, ACTION_ForceReboot, NULL },
7185 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7186 { szInstallExecute, ACTION_InstallExecute, NULL },
7187 { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7188 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7189 { szInstallFinalize, ACTION_InstallFinalize, NULL },
7190 { szInstallInitialize, ACTION_InstallInitialize, NULL },
7191 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7192 { szInstallServices, ACTION_InstallServices, szDeleteServices },
7193 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7194 { szInstallValidate, ACTION_InstallValidate, NULL },
7195 { szIsolateComponents, ACTION_IsolateComponents, NULL },
7196 { szLaunchConditions, ACTION_LaunchConditions, NULL },
7197 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7198 { szMoveFiles, ACTION_MoveFiles, NULL },
7199 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7200 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7201 { szPatchFiles, ACTION_PatchFiles, NULL },
7202 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7203 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7204 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7205 { szPublishProduct, ACTION_PublishProduct, NULL },
7206 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7207 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7208 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7209 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7210 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7211 { szRegisterProduct, ACTION_RegisterProduct, NULL },
7212 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7213 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7214 { szRegisterUser, ACTION_RegisterUser, NULL },
7215 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7216 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7217 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7218 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7219 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7220 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7221 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7222 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7223 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7224 { szResolveSource, ACTION_ResolveSource, NULL },
7225 { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7226 { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7227 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7228 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfUnregModules },
7229 { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7230 { szStartServices, ACTION_StartServices, szStopServices },
7231 { szStopServices, ACTION_StopServices, szStartServices },
7232 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7233 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7234 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7235 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7236 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7237 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7238 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7239 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7240 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7241 { szValidateProductID, ACTION_ValidateProductID, NULL },
7242 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7243 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7244 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7245 { NULL, NULL, NULL }
7248 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7250 BOOL ret = FALSE;
7251 UINT i;
7253 i = 0;
7254 while (StandardActions[i].action != NULL)
7256 if (!strcmpW( StandardActions[i].action, action ))
7258 ui_actionstart( package, action );
7259 if (StandardActions[i].handler)
7261 ui_actioninfo( package, action, TRUE, 0 );
7262 *rc = StandardActions[i].handler( package );
7263 ui_actioninfo( package, action, FALSE, *rc );
7265 if (StandardActions[i].action_rollback && !package->need_rollback)
7267 TRACE("scheduling rollback action\n");
7268 msi_schedule_action( package, ROLLBACK_SCRIPT, StandardActions[i].action_rollback );
7271 else
7273 FIXME("unhandled standard action %s\n", debugstr_w(action));
7274 *rc = ERROR_SUCCESS;
7276 ret = TRUE;
7277 break;
7279 i++;
7281 return ret;
7284 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7286 UINT rc = ERROR_SUCCESS;
7287 BOOL handled;
7289 TRACE("Performing action (%s)\n", debugstr_w(action));
7291 handled = ACTION_HandleStandardAction(package, action, &rc);
7293 if (!handled)
7294 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7296 if (!handled)
7298 WARN("unhandled msi action %s\n", debugstr_w(action));
7299 rc = ERROR_FUNCTION_NOT_CALLED;
7302 return rc;
7305 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7307 UINT rc = ERROR_SUCCESS;
7308 BOOL handled = FALSE;
7310 TRACE("Performing action (%s)\n", debugstr_w(action));
7312 handled = ACTION_HandleStandardAction(package, action, &rc);
7314 if (!handled)
7315 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7317 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7318 handled = TRUE;
7320 if (!handled)
7322 WARN("unhandled msi action %s\n", debugstr_w(action));
7323 rc = ERROR_FUNCTION_NOT_CALLED;
7326 return rc;
7329 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7331 UINT rc = ERROR_SUCCESS;
7332 MSIRECORD *row;
7334 static const WCHAR ExecSeqQuery[] =
7335 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7336 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7337 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7338 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7339 static const WCHAR UISeqQuery[] =
7340 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7341 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7342 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7343 ' ', '=',' ','%','i',0};
7345 if (needs_ui_sequence(package))
7346 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7347 else
7348 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7350 if (row)
7352 LPCWSTR action, cond;
7354 TRACE("Running the actions\n");
7356 /* check conditions */
7357 cond = MSI_RecordGetString(row, 2);
7359 /* this is a hack to skip errors in the condition code */
7360 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7362 msiobj_release(&row->hdr);
7363 return ERROR_SUCCESS;
7366 action = MSI_RecordGetString(row, 1);
7367 if (!action)
7369 ERR("failed to fetch action\n");
7370 msiobj_release(&row->hdr);
7371 return ERROR_FUNCTION_FAILED;
7374 if (needs_ui_sequence(package))
7375 rc = ACTION_PerformUIAction(package, action, -1);
7376 else
7377 rc = ACTION_PerformAction(package, action, -1);
7379 msiobj_release(&row->hdr);
7382 return rc;
7385 /****************************************************
7386 * TOP level entry points
7387 *****************************************************/
7389 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7390 LPCWSTR szCommandLine )
7392 UINT rc;
7393 BOOL ui_exists;
7394 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7395 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7396 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7398 msi_set_property( package->db, szAction, szInstall );
7400 package->script->InWhatSequence = SEQUENCE_INSTALL;
7402 if (szPackagePath)
7404 LPWSTR p, dir;
7405 LPCWSTR file;
7407 dir = strdupW(szPackagePath);
7408 p = strrchrW(dir, '\\');
7409 if (p)
7411 *(++p) = 0;
7412 file = szPackagePath + (p - dir);
7414 else
7416 msi_free(dir);
7417 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7418 GetCurrentDirectoryW(MAX_PATH, dir);
7419 lstrcatW(dir, szBackSlash);
7420 file = szPackagePath;
7423 msi_free( package->PackagePath );
7424 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7425 if (!package->PackagePath)
7427 msi_free(dir);
7428 return ERROR_OUTOFMEMORY;
7431 lstrcpyW(package->PackagePath, dir);
7432 lstrcatW(package->PackagePath, file);
7433 msi_free(dir);
7435 msi_set_sourcedir_props(package, FALSE);
7438 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7439 if (rc != ERROR_SUCCESS)
7440 return rc;
7442 msi_apply_transforms( package );
7443 msi_apply_patches( package );
7445 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7447 TRACE("setting reinstall property\n");
7448 msi_set_property( package->db, szReinstall, szAll );
7451 /* properties may have been added by a transform */
7452 msi_clone_properties( package );
7454 msi_parse_command_line( package, szCommandLine, FALSE );
7455 msi_adjust_privilege_properties( package );
7456 msi_set_context( package );
7458 if (msi_get_property_int( package->db, szInstalled, 0 ))
7460 HKEY hkey;
7461 DeleteFileW( package->localfile );
7462 msi_free( package->localfile );
7463 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
7464 package->localfile = msi_reg_get_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW );
7465 RegCloseKey( hkey );
7467 if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7469 TRACE("disabling rollback\n");
7470 msi_set_property( package->db, szRollbackDisabled, szOne );
7473 if (needs_ui_sequence( package))
7475 package->script->InWhatSequence |= SEQUENCE_UI;
7476 rc = ACTION_ProcessUISequence(package);
7477 ui_exists = ui_sequence_exists(package);
7478 if (rc == ERROR_SUCCESS || !ui_exists)
7480 package->script->InWhatSequence |= SEQUENCE_EXEC;
7481 rc = ACTION_ProcessExecSequence(package, ui_exists);
7484 else
7485 rc = ACTION_ProcessExecSequence(package, FALSE);
7487 package->script->CurrentlyScripting = FALSE;
7489 /* process the ending type action */
7490 if (rc == ERROR_SUCCESS)
7491 ACTION_PerformActionSequence(package, -1);
7492 else if (rc == ERROR_INSTALL_USEREXIT)
7493 ACTION_PerformActionSequence(package, -2);
7494 else if (rc == ERROR_INSTALL_SUSPEND)
7495 ACTION_PerformActionSequence(package, -4);
7496 else /* failed */
7498 ACTION_PerformActionSequence(package, -3);
7499 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7501 package->need_rollback = TRUE;
7505 /* finish up running custom actions */
7506 ACTION_FinishCustomActions(package);
7508 if (package->need_rollback)
7510 WARN("installation failed, running rollback script\n");
7511 execute_script( package, ROLLBACK_SCRIPT );
7514 if (rc == ERROR_SUCCESS && package->need_reboot)
7515 return ERROR_SUCCESS_REBOOT_REQUIRED;
7517 return rc;