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