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