[MSI]
[reactos.git] / reactos / 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 *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 *)&ret, &sz ))
2006 {
2007 msi_free( version );
2008 return NULL;
2009 }
2010
2011 msi_free( version );
2012 return ret;
2013 }
2014
2015 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2016 {
2017 DWORD ms, ls;
2018
2019 msi_parse_version_string( version, &ms, &ls );
2020
2021 if (fi->dwFileVersionMS > ms) return 1;
2022 else if (fi->dwFileVersionMS < ms) return -1;
2023 else if (fi->dwFileVersionLS > ls) return 1;
2024 else if (fi->dwFileVersionLS < ls) return -1;
2025 return 0;
2026 }
2027
2028 static DWORD get_disk_file_size( LPCWSTR filename )
2029 {
2030 HANDLE file;
2031 DWORD size;
2032
2033 TRACE("%s\n", debugstr_w(filename));
2034
2035 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2036 if (file == INVALID_HANDLE_VALUE)
2037 return INVALID_FILE_SIZE;
2038
2039 size = GetFileSize( file, NULL );
2040 CloseHandle( file );
2041 return size;
2042 }
2043
2044 static BOOL hash_matches( MSIFILE *file )
2045 {
2046 UINT r;
2047 MSIFILEHASHINFO hash;
2048
2049 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2050 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2051 if (r != ERROR_SUCCESS)
2052 return FALSE;
2053
2054 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2055 }
2056
2057 static UINT set_file_install_states( MSIPACKAGE *package )
2058 {
2059 VS_FIXEDFILEINFO *file_version;
2060 MSIFILE *file;
2061
2062 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2063 {
2064 MSICOMPONENT* comp = file->Component;
2065 DWORD file_size;
2066 LPWSTR p;
2067
2068 if (!comp)
2069 continue;
2070
2071 if (file->IsCompressed)
2072 comp->ForceLocalState = TRUE;
2073
2074 /* calculate target */
2075 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2076 msi_free(file->TargetPath);
2077
2078 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2079
2080 file->TargetPath = build_directory_name(2, p, file->FileName);
2081 msi_free(p);
2082
2083 TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
2084
2085 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2086 {
2087 file->state = msifs_missing;
2088 comp->Cost += file->FileSize;
2089 continue;
2090 }
2091 if (file->Version && (file_version = msi_get_disk_file_version( file->TargetPath )))
2092 {
2093 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2094 HIWORD(file_version->dwFileVersionMS),
2095 LOWORD(file_version->dwFileVersionMS),
2096 HIWORD(file_version->dwFileVersionLS),
2097 LOWORD(file_version->dwFileVersionLS));
2098
2099 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2100 {
2101 file->state = msifs_overwrite;
2102 comp->Cost += file->FileSize;
2103 }
2104 else
2105 {
2106 TRACE("Destination file version equal or greater, not overwriting\n");
2107 file->state = msifs_present;
2108 }
2109 msi_free( file_version );
2110 continue;
2111 }
2112 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2113 {
2114 file->state = msifs_overwrite;
2115 comp->Cost += file->FileSize - file_size;
2116 continue;
2117 }
2118 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2119 {
2120 TRACE("File hashes match, not overwriting\n");
2121 file->state = msifs_present;
2122 continue;
2123 }
2124 file->state = msifs_overwrite;
2125 comp->Cost += file->FileSize - file_size;
2126 }
2127
2128 return ERROR_SUCCESS;
2129 }
2130
2131 /*
2132 * A lot is done in this function aside from just the costing.
2133 * The costing needs to be implemented at some point but for now I am going
2134 * to focus on the directory building
2135 *
2136 */
2137 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2138 {
2139 static const WCHAR ExecSeqQuery[] =
2140 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2141 '`','D','i','r','e','c','t','o','r','y','`',0};
2142 static const WCHAR ConditionQuery[] =
2143 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2144 '`','C','o','n','d','i','t','i','o','n','`',0};
2145 static const WCHAR szCosting[] =
2146 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2147 static const WCHAR szlevel[] =
2148 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2149 static const WCHAR szOutOfDiskSpace[] =
2150 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2151 MSICOMPONENT *comp;
2152 UINT rc = ERROR_SUCCESS;
2153 MSIQUERY * view;
2154 LPWSTR level;
2155
2156 TRACE("Building Directory properties\n");
2157
2158 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2159 if (rc == ERROR_SUCCESS)
2160 {
2161 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2162 package);
2163 msiobj_release(&view->hdr);
2164 }
2165
2166 /* read components states from the registry */
2167 ACTION_GetComponentInstallStates(package);
2168 ACTION_GetFeatureInstallStates(package);
2169
2170 TRACE("Calculating file install states\n");
2171 set_file_install_states( package );
2172
2173 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2174 {
2175 TRACE("Evaluating feature conditions\n");
2176
2177 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2178 if (rc == ERROR_SUCCESS)
2179 {
2180 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2181 msiobj_release( &view->hdr );
2182 }
2183 }
2184 TRACE("Evaluating component conditions\n");
2185
2186 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2187 {
2188 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2189 {
2190 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2191 comp->Enabled = FALSE;
2192 }
2193 else
2194 comp->Enabled = TRUE;
2195 }
2196
2197 msi_set_property( package->db, szCosting, szOne );
2198 /* set default run level if not set */
2199 level = msi_dup_property( package->db, szlevel );
2200 if (!level)
2201 msi_set_property( package->db, szlevel, szOne );
2202 msi_free(level);
2203
2204 /* FIXME: check volume disk space */
2205 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2206
2207 return MSI_SetFeatureStates(package);
2208 }
2209
2210 /* OK this value is "interpreted" and then formatted based on the
2211 first few characters */
2212 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2213 DWORD *size)
2214 {
2215 LPSTR data = NULL;
2216
2217 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2218 {
2219 if (value[1]=='x')
2220 {
2221 LPWSTR ptr;
2222 CHAR byte[5];
2223 LPWSTR deformated = NULL;
2224 int count;
2225
2226 deformat_string(package, &value[2], &deformated);
2227
2228 /* binary value type */
2229 ptr = deformated;
2230 *type = REG_BINARY;
2231 if (strlenW(ptr)%2)
2232 *size = (strlenW(ptr)/2)+1;
2233 else
2234 *size = strlenW(ptr)/2;
2235
2236 data = msi_alloc(*size);
2237
2238 byte[0] = '0';
2239 byte[1] = 'x';
2240 byte[4] = 0;
2241 count = 0;
2242 /* if uneven pad with a zero in front */
2243 if (strlenW(ptr)%2)
2244 {
2245 byte[2]= '0';
2246 byte[3]= *ptr;
2247 ptr++;
2248 data[count] = (BYTE)strtol(byte,NULL,0);
2249 count ++;
2250 TRACE("Uneven byte count\n");
2251 }
2252 while (*ptr)
2253 {
2254 byte[2]= *ptr;
2255 ptr++;
2256 byte[3]= *ptr;
2257 ptr++;
2258 data[count] = (BYTE)strtol(byte,NULL,0);
2259 count ++;
2260 }
2261 msi_free(deformated);
2262
2263 TRACE("Data %i bytes(%i)\n",*size,count);
2264 }
2265 else
2266 {
2267 LPWSTR deformated;
2268 LPWSTR p;
2269 DWORD d = 0;
2270 deformat_string(package, &value[1], &deformated);
2271
2272 *type=REG_DWORD;
2273 *size = sizeof(DWORD);
2274 data = msi_alloc(*size);
2275 p = deformated;
2276 if (*p == '-')
2277 p++;
2278 while (*p)
2279 {
2280 if ( (*p < '0') || (*p > '9') )
2281 break;
2282 d *= 10;
2283 d += (*p - '0');
2284 p++;
2285 }
2286 if (deformated[0] == '-')
2287 d = -d;
2288 *(LPDWORD)data = d;
2289 TRACE("DWORD %i\n",*(LPDWORD)data);
2290
2291 msi_free(deformated);
2292 }
2293 }
2294 else
2295 {
2296 static const WCHAR szMulti[] = {'[','~',']',0};
2297 LPCWSTR ptr;
2298 *type=REG_SZ;
2299
2300 if (value[0]=='#')
2301 {
2302 if (value[1]=='%')
2303 {
2304 ptr = &value[2];
2305 *type=REG_EXPAND_SZ;
2306 }
2307 else
2308 ptr = &value[1];
2309 }
2310 else
2311 ptr=value;
2312
2313 if (strstrW(value,szMulti))
2314 *type = REG_MULTI_SZ;
2315
2316 /* remove initial delimiter */
2317 if (!strncmpW(value, szMulti, 3))
2318 ptr = value + 3;
2319
2320 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2321
2322 /* add double NULL terminator */
2323 if (*type == REG_MULTI_SZ)
2324 {
2325 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2326 data = msi_realloc_zero(data, *size);
2327 }
2328 }
2329 return data;
2330 }
2331
2332 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2333 {
2334 const WCHAR *ret;
2335
2336 switch (root)
2337 {
2338 case -1:
2339 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2340 {
2341 *root_key = HKEY_LOCAL_MACHINE;
2342 ret = szHLM;
2343 }
2344 else
2345 {
2346 *root_key = HKEY_CURRENT_USER;
2347 ret = szHCU;
2348 }
2349 break;
2350 case 0:
2351 *root_key = HKEY_CLASSES_ROOT;
2352 ret = szHCR;
2353 break;
2354 case 1:
2355 *root_key = HKEY_CURRENT_USER;
2356 ret = szHCU;
2357 break;
2358 case 2:
2359 *root_key = HKEY_LOCAL_MACHINE;
2360 ret = szHLM;
2361 break;
2362 case 3:
2363 *root_key = HKEY_USERS;
2364 ret = szHU;
2365 break;
2366 default:
2367 ERR("Unknown root %i\n", root);
2368 return NULL;
2369 }
2370
2371 return ret;
2372 }
2373
2374 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2375 {
2376 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2377 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2378
2379 if (is_64bit && package->platform == PLATFORM_INTEL &&
2380 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2381 {
2382 UINT size;
2383 WCHAR *path_32node;
2384
2385 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2386 path_32node = msi_alloc( size );
2387 if (!path_32node)
2388 return NULL;
2389
2390 memcpy( path_32node, path, len * sizeof(WCHAR) );
2391 path_32node[len] = 0;
2392 strcatW( path_32node, szWow6432Node );
2393 strcatW( path_32node, szBackSlash );
2394 strcatW( path_32node, path + len );
2395 return path_32node;
2396 }
2397
2398 return strdupW( path );
2399 }
2400
2401 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2402 {
2403 MSIPACKAGE *package = param;
2404 LPSTR value_data = NULL;
2405 HKEY root_key, hkey;
2406 DWORD type,size;
2407 LPWSTR deformated, uikey, keypath;
2408 LPCWSTR szRoot, component, name, key, value;
2409 MSICOMPONENT *comp;
2410 MSIRECORD * uirow;
2411 INT root;
2412 BOOL check_first = FALSE;
2413 UINT rc;
2414
2415 ui_progress(package,2,0,0,0);
2416
2417 component = MSI_RecordGetString(row, 6);
2418 comp = get_loaded_component(package,component);
2419 if (!comp)
2420 return ERROR_SUCCESS;
2421
2422 if (!comp->Enabled)
2423 {
2424 TRACE("component is disabled\n");
2425 return ERROR_SUCCESS;
2426 }
2427
2428 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2429 {
2430 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2431 comp->Action = comp->Installed;
2432 return ERROR_SUCCESS;
2433 }
2434 comp->Action = INSTALLSTATE_LOCAL;
2435
2436 name = MSI_RecordGetString(row, 4);
2437 if( MSI_RecordIsNull(row,5) && name )
2438 {
2439 /* null values can have special meanings */
2440 if (name[0]=='-' && name[1] == 0)
2441 return ERROR_SUCCESS;
2442 else if ((name[0]=='+' && name[1] == 0) ||
2443 (name[0] == '*' && name[1] == 0))
2444 name = NULL;
2445 check_first = TRUE;
2446 }
2447
2448 root = MSI_RecordGetInteger(row,2);
2449 key = MSI_RecordGetString(row, 3);
2450
2451 szRoot = get_root_key( package, root, &root_key );
2452 if (!szRoot)
2453 return ERROR_SUCCESS;
2454
2455 deformat_string(package, key , &deformated);
2456 size = strlenW(deformated) + strlenW(szRoot) + 1;
2457 uikey = msi_alloc(size*sizeof(WCHAR));
2458 strcpyW(uikey,szRoot);
2459 strcatW(uikey,deformated);
2460
2461 keypath = get_keypath( package, root_key, deformated );
2462 msi_free( deformated );
2463 if (RegCreateKeyW( root_key, keypath, &hkey ))
2464 {
2465 ERR("Could not create key %s\n", debugstr_w(keypath));
2466 msi_free(uikey);
2467 return ERROR_SUCCESS;
2468 }
2469
2470 value = MSI_RecordGetString(row,5);
2471 if (value)
2472 value_data = parse_value(package, value, &type, &size);
2473 else
2474 {
2475 value_data = (LPSTR)strdupW(szEmpty);
2476 size = sizeof(szEmpty);
2477 type = REG_SZ;
2478 }
2479
2480 deformat_string(package, name, &deformated);
2481
2482 if (!check_first)
2483 {
2484 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2485 debugstr_w(uikey));
2486 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2487 }
2488 else
2489 {
2490 DWORD sz = 0;
2491 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2492 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2493 {
2494 TRACE("value %s of %s checked already exists\n",
2495 debugstr_w(deformated), debugstr_w(uikey));
2496 }
2497 else
2498 {
2499 TRACE("Checked and setting value %s of %s\n",
2500 debugstr_w(deformated), debugstr_w(uikey));
2501 if (deformated || size)
2502 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2503 }
2504 }
2505 RegCloseKey(hkey);
2506
2507 uirow = MSI_CreateRecord(3);
2508 MSI_RecordSetStringW(uirow,2,deformated);
2509 MSI_RecordSetStringW(uirow,1,uikey);
2510 if (type == REG_SZ || type == REG_EXPAND_SZ)
2511 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2512 ui_actiondata(package,szWriteRegistryValues,uirow);
2513 msiobj_release( &uirow->hdr );
2514
2515 msi_free(value_data);
2516 msi_free(deformated);
2517 msi_free(uikey);
2518
2519 return ERROR_SUCCESS;
2520 }
2521
2522 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2523 {
2524 UINT rc;
2525 MSIQUERY * view;
2526 static const WCHAR ExecSeqQuery[] =
2527 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2528 '`','R','e','g','i','s','t','r','y','`',0 };
2529
2530 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2531 if (rc != ERROR_SUCCESS)
2532 return ERROR_SUCCESS;
2533
2534 /* increment progress bar each time action data is sent */
2535 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2536
2537 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2538
2539 msiobj_release(&view->hdr);
2540 return rc;
2541 }
2542
2543 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2544 {
2545 LONG res;
2546 HKEY hkey;
2547 DWORD num_subkeys, num_values;
2548
2549 if (delete_key)
2550 {
2551 if ((res = RegDeleteTreeW( hkey_root, key )))
2552 {
2553 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2554 }
2555 return;
2556 }
2557
2558 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2559 {
2560 if ((res = RegDeleteValueW( hkey, value )))
2561 {
2562 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2563 }
2564 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2565 NULL, NULL, NULL, NULL );
2566 RegCloseKey( hkey );
2567
2568 if (!res && !num_subkeys && !num_values)
2569 {
2570 TRACE("Removing empty key %s\n", debugstr_w(key));
2571 RegDeleteKeyW( hkey_root, key );
2572 }
2573 return;
2574 }
2575 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2576 }
2577
2578
2579 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2580 {
2581 MSIPACKAGE *package = param;
2582 LPCWSTR component, name, key_str, root_key_str;
2583 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2584 MSICOMPONENT *comp;
2585 MSIRECORD *uirow;
2586 BOOL delete_key = FALSE;
2587 HKEY hkey_root;
2588 UINT size;
2589 INT root;
2590
2591 ui_progress( package, 2, 0, 0, 0 );
2592
2593 component = MSI_RecordGetString( row, 6 );
2594 comp = get_loaded_component( package, component );
2595 if (!comp)
2596 return ERROR_SUCCESS;
2597
2598 if (!comp->Enabled)
2599 {
2600 TRACE("component is disabled\n");
2601 return ERROR_SUCCESS;
2602 }
2603
2604 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2605 {
2606 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2607 comp->Action = comp->Installed;
2608 return ERROR_SUCCESS;
2609 }
2610 comp->Action = INSTALLSTATE_ABSENT;
2611
2612 name = MSI_RecordGetString( row, 4 );
2613 if (MSI_RecordIsNull( row, 5 ) && name )
2614 {
2615 if (name[0] == '+' && !name[1])
2616 return ERROR_SUCCESS;
2617 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2618 {
2619 delete_key = TRUE;
2620 name = NULL;
2621 }
2622 }
2623
2624 root = MSI_RecordGetInteger( row, 2 );
2625 key_str = MSI_RecordGetString( row, 3 );
2626
2627 root_key_str = get_root_key( package, root, &hkey_root );
2628 if (!root_key_str)
2629 return ERROR_SUCCESS;
2630
2631 deformat_string( package, key_str, &deformated_key );
2632 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2633 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2634 strcpyW( ui_key_str, root_key_str );
2635 strcatW( ui_key_str, deformated_key );
2636
2637 deformat_string( package, name, &deformated_name );
2638
2639 keypath = get_keypath( package, hkey_root, deformated_key );
2640 msi_free( deformated_key );
2641 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2642 msi_free( keypath );
2643
2644 uirow = MSI_CreateRecord( 2 );
2645 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2646 MSI_RecordSetStringW( uirow, 2, deformated_name );
2647
2648 ui_actiondata( package, szRemoveRegistryValues, uirow );
2649 msiobj_release( &uirow->hdr );
2650
2651 msi_free( ui_key_str );
2652 msi_free( deformated_name );
2653 return ERROR_SUCCESS;
2654 }
2655
2656 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2657 {
2658 MSIPACKAGE *package = param;
2659 LPCWSTR component, name, key_str, root_key_str;
2660 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2661 MSICOMPONENT *comp;
2662 MSIRECORD *uirow;
2663 BOOL delete_key = FALSE;
2664 HKEY hkey_root;
2665 UINT size;
2666 INT root;
2667
2668 ui_progress( package, 2, 0, 0, 0 );
2669
2670 component = MSI_RecordGetString( row, 5 );
2671 comp = get_loaded_component( package, component );
2672 if (!comp)
2673 return ERROR_SUCCESS;
2674
2675 if (!comp->Enabled)
2676 {
2677 TRACE("component is disabled\n");
2678 return ERROR_SUCCESS;
2679 }
2680
2681 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2682 {
2683 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2684 comp->Action = comp->Installed;
2685 return ERROR_SUCCESS;
2686 }
2687 comp->Action = INSTALLSTATE_LOCAL;
2688
2689 if ((name = MSI_RecordGetString( row, 4 )))
2690 {
2691 if (name[0] == '-' && !name[1])
2692 {
2693 delete_key = TRUE;
2694 name = NULL;
2695 }
2696 }
2697
2698 root = MSI_RecordGetInteger( row, 2 );
2699 key_str = MSI_RecordGetString( row, 3 );
2700
2701 root_key_str = get_root_key( package, root, &hkey_root );
2702 if (!root_key_str)
2703 return ERROR_SUCCESS;
2704
2705 deformat_string( package, key_str, &deformated_key );
2706 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2707 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2708 strcpyW( ui_key_str, root_key_str );
2709 strcatW( ui_key_str, deformated_key );
2710
2711 deformat_string( package, name, &deformated_name );
2712
2713 keypath = get_keypath( package, hkey_root, deformated_key );
2714 msi_free( deformated_key );
2715 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2716 msi_free( keypath );
2717
2718 uirow = MSI_CreateRecord( 2 );
2719 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2720 MSI_RecordSetStringW( uirow, 2, deformated_name );
2721
2722 ui_actiondata( package, szRemoveRegistryValues, uirow );
2723 msiobj_release( &uirow->hdr );
2724
2725 msi_free( ui_key_str );
2726 msi_free( deformated_name );
2727 return ERROR_SUCCESS;
2728 }
2729
2730 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2731 {
2732 UINT rc;
2733 MSIQUERY *view;
2734 static const WCHAR registry_query[] =
2735 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2736 '`','R','e','g','i','s','t','r','y','`',0 };
2737 static const WCHAR remove_registry_query[] =
2738 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2739 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2740
2741 /* increment progress bar each time action data is sent */
2742 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2743
2744 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2745 if (rc == ERROR_SUCCESS)
2746 {
2747 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2748 msiobj_release( &view->hdr );
2749 if (rc != ERROR_SUCCESS)
2750 return rc;
2751 }
2752
2753 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2754 if (rc == ERROR_SUCCESS)
2755 {
2756 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2757 msiobj_release( &view->hdr );
2758 if (rc != ERROR_SUCCESS)
2759 return rc;
2760 }
2761
2762 return ERROR_SUCCESS;
2763 }
2764
2765 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2766 {
2767 package->script->CurrentlyScripting = TRUE;
2768
2769 return ERROR_SUCCESS;
2770 }
2771
2772
2773 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2774 {
2775 MSICOMPONENT *comp;
2776 DWORD progress = 0;
2777 DWORD total = 0;
2778 static const WCHAR q1[]=
2779 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2780 '`','R','e','g','i','s','t','r','y','`',0};
2781 UINT rc;
2782 MSIQUERY * view;
2783 MSIFEATURE *feature;
2784 MSIFILE *file;
2785
2786 TRACE("InstallValidate\n");
2787
2788 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2789 if (rc == ERROR_SUCCESS)
2790 {
2791 MSI_IterateRecords( view, &progress, NULL, package );
2792 msiobj_release( &view->hdr );
2793 total += progress * REG_PROGRESS_VALUE;
2794 }
2795
2796 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2797 total += COMPONENT_PROGRESS_VALUE;
2798
2799 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2800 total += file->FileSize;
2801
2802 ui_progress(package,0,total,0,0);
2803
2804 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2805 {
2806 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2807 debugstr_w(feature->Feature), feature->Installed,
2808 feature->ActionRequest, feature->Action);
2809 }
2810
2811 return ERROR_SUCCESS;
2812 }
2813
2814 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2815 {
2816 MSIPACKAGE* package = param;
2817 LPCWSTR cond = NULL;
2818 LPCWSTR message = NULL;
2819 UINT r;
2820
2821 static const WCHAR title[]=
2822 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2823
2824 cond = MSI_RecordGetString(row,1);
2825
2826 r = MSI_EvaluateConditionW(package,cond);
2827 if (r == MSICONDITION_FALSE)
2828 {
2829 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2830 {
2831 LPWSTR deformated;
2832 message = MSI_RecordGetString(row,2);
2833 deformat_string(package,message,&deformated);
2834 MessageBoxW(NULL,deformated,title,MB_OK);
2835 msi_free(deformated);
2836 }
2837
2838 return ERROR_INSTALL_FAILURE;
2839 }
2840
2841 return ERROR_SUCCESS;
2842 }
2843
2844 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2845 {
2846 UINT rc;
2847 MSIQUERY * view = NULL;
2848 static const WCHAR ExecSeqQuery[] =
2849 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2850 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2851
2852 TRACE("Checking launch conditions\n");
2853
2854 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2855 if (rc != ERROR_SUCCESS)
2856 return ERROR_SUCCESS;
2857
2858 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2859 msiobj_release(&view->hdr);
2860
2861 return rc;
2862 }
2863
2864 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2865 {
2866
2867 if (!cmp->KeyPath)
2868 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2869
2870 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2871 {
2872 MSIRECORD * row = 0;
2873 UINT root,len;
2874 LPWSTR deformated,buffer,deformated_name;
2875 LPCWSTR key,name;
2876 static const WCHAR ExecSeqQuery[] =
2877 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2878 '`','R','e','g','i','s','t','r','y','`',' ',
2879 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2880 ' ','=',' ' ,'\'','%','s','\'',0 };
2881 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2882 static const WCHAR fmt2[]=
2883 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2884
2885 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2886 if (!row)
2887 return NULL;
2888
2889 root = MSI_RecordGetInteger(row,2);
2890 key = MSI_RecordGetString(row, 3);
2891 name = MSI_RecordGetString(row, 4);
2892 deformat_string(package, key , &deformated);
2893 deformat_string(package, name, &deformated_name);
2894
2895 len = strlenW(deformated) + 6;
2896 if (deformated_name)
2897 len+=strlenW(deformated_name);
2898
2899 buffer = msi_alloc( len *sizeof(WCHAR));
2900
2901 if (deformated_name)
2902 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2903 else
2904 sprintfW(buffer,fmt,root,deformated);
2905
2906 msi_free(deformated);
2907 msi_free(deformated_name);
2908 msiobj_release(&row->hdr);
2909
2910 return buffer;
2911 }
2912 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2913 {
2914 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2915 return NULL;
2916 }
2917 else
2918 {
2919 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2920
2921 if (file)
2922 return strdupW( file->TargetPath );
2923 }
2924 return NULL;
2925 }
2926
2927 static HKEY openSharedDLLsKey(void)
2928 {
2929 HKEY hkey=0;
2930 static const WCHAR path[] =
2931 {'S','o','f','t','w','a','r','e','\\',
2932 'M','i','c','r','o','s','o','f','t','\\',
2933 'W','i','n','d','o','w','s','\\',
2934 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2935 'S','h','a','r','e','d','D','L','L','s',0};
2936
2937 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2938 return hkey;
2939 }
2940
2941 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2942 {
2943 HKEY hkey;
2944 DWORD count=0;
2945 DWORD type;
2946 DWORD sz = sizeof(count);
2947 DWORD rc;
2948
2949 hkey = openSharedDLLsKey();
2950 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2951 if (rc != ERROR_SUCCESS)
2952 count = 0;
2953 RegCloseKey(hkey);
2954 return count;
2955 }
2956
2957 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2958 {
2959 HKEY hkey;
2960
2961 hkey = openSharedDLLsKey();
2962 if (count > 0)
2963 msi_reg_set_val_dword( hkey, path, count );
2964 else
2965 RegDeleteValueW(hkey,path);
2966 RegCloseKey(hkey);
2967 return count;
2968 }
2969
2970 /*
2971 * Return TRUE if the count should be written out and FALSE if not
2972 */
2973 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2974 {
2975 MSIFEATURE *feature;
2976 INT count = 0;
2977 BOOL write = FALSE;
2978
2979 /* only refcount DLLs */
2980 if (comp->KeyPath == NULL ||
2981 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2982 comp->Attributes & msidbComponentAttributesODBCDataSource)
2983 write = FALSE;
2984 else
2985 {
2986 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2987 write = (count > 0);
2988
2989 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2990 write = TRUE;
2991 }
2992
2993 /* increment counts */
2994 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2995 {
2996 ComponentList *cl;
2997
2998 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2999 continue;
3000
3001 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3002 {
3003 if ( cl->component == comp )
3004 count++;
3005 }
3006 }
3007
3008 /* decrement counts */
3009 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3010 {
3011 ComponentList *cl;
3012
3013 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3014 continue;
3015
3016 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3017 {
3018 if ( cl->component == comp )
3019 count--;
3020 }
3021 }
3022
3023 /* ref count all the files in the component */
3024 if (write)
3025 {
3026 MSIFILE *file;
3027
3028 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3029 {
3030 if (file->Component == comp)
3031 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3032 }
3033 }
3034
3035 /* add a count for permanent */
3036 if (comp->Attributes & msidbComponentAttributesPermanent)
3037 count ++;
3038
3039 comp->RefCount = count;
3040
3041 if (write)
3042 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3043 }
3044
3045 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3046 {
3047 WCHAR squished_pc[GUID_SIZE];
3048 WCHAR squished_cc[GUID_SIZE];
3049 UINT rc;
3050 MSICOMPONENT *comp;
3051 HKEY hkey;
3052
3053 TRACE("\n");
3054
3055 squash_guid(package->ProductCode,squished_pc);
3056 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3057
3058 msi_set_sourcedir_props(package, FALSE);
3059
3060 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3061 {
3062 MSIRECORD * uirow;
3063
3064 ui_progress(package,2,0,0,0);
3065 if (!comp->ComponentId)
3066 continue;
3067
3068 squash_guid(comp->ComponentId,squished_cc);
3069
3070 msi_free(comp->FullKeypath);
3071 comp->FullKeypath = resolve_keypath( package, comp );
3072
3073 ACTION_RefCountComponent( package, comp );
3074
3075 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3076 debugstr_w(comp->Component),
3077 debugstr_w(squished_cc),
3078 debugstr_w(comp->FullKeypath),
3079 comp->RefCount,
3080 comp->ActionRequest);
3081
3082 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3083 comp->ActionRequest == INSTALLSTATE_SOURCE)
3084 {
3085 if (!comp->FullKeypath)
3086 continue;
3087
3088 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3089 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3090 &hkey, TRUE);
3091 else
3092 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3093 &hkey, TRUE);
3094
3095 if (rc != ERROR_SUCCESS)
3096 continue;
3097
3098 if (comp->Attributes & msidbComponentAttributesPermanent)
3099 {
3100 static const WCHAR szPermKey[] =
3101 { '0','0','0','0','0','0','0','0','0','0','0','0',
3102 '0','0','0','0','0','0','0','0','0','0','0','0',
3103 '0','0','0','0','0','0','0','0',0 };
3104
3105 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3106 }
3107
3108 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3109 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3110 else
3111 {
3112 MSIFILE *file;
3113 MSIRECORD *row;
3114 LPWSTR ptr, ptr2;
3115 WCHAR source[MAX_PATH];
3116 WCHAR base[MAX_PATH];
3117 LPWSTR sourcepath;
3118
3119 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3120 static const WCHAR query[] = {
3121 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3122 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3123 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3124 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3125 '`','D','i','s','k','I','d','`',0};
3126
3127 file = get_loaded_file(package, comp->KeyPath);
3128 if (!file)
3129 continue;
3130
3131 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3132 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3133 ptr2 = strrchrW(source, '\\') + 1;
3134 msiobj_release(&row->hdr);
3135
3136 lstrcpyW(base, package->PackagePath);
3137 ptr = strrchrW(base, '\\');
3138 *(ptr + 1) = '\0';
3139
3140 sourcepath = resolve_file_source(package, file);
3141 ptr = sourcepath + lstrlenW(base);
3142 lstrcpyW(ptr2, ptr);
3143 msi_free(sourcepath);
3144
3145 msi_reg_set_val_str(hkey, squished_pc, source);
3146 }
3147 RegCloseKey(hkey);
3148 }
3149 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3150 {
3151 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3152 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3153 else
3154 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3155 }
3156 comp->Action = comp->ActionRequest;
3157
3158 /* UI stuff */
3159 uirow = MSI_CreateRecord(3);
3160 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3161 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3162 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3163 ui_actiondata(package,szProcessComponents,uirow);
3164 msiobj_release( &uirow->hdr );
3165 }
3166
3167 return ERROR_SUCCESS;
3168 }
3169
3170 typedef struct {
3171 CLSID clsid;
3172 LPWSTR source;
3173
3174 LPWSTR path;
3175 ITypeLib *ptLib;
3176 } typelib_struct;
3177
3178 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3179 LPWSTR lpszName, LONG_PTR lParam)
3180 {
3181 TLIBATTR *attr;
3182 typelib_struct *tl_struct = (typelib_struct*) lParam;
3183 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3184 int sz;
3185 HRESULT res;
3186
3187 if (!IS_INTRESOURCE(lpszName))
3188 {
3189 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3190 return TRUE;
3191 }
3192
3193 sz = strlenW(tl_struct->source)+4;
3194 sz *= sizeof(WCHAR);
3195
3196 if ((INT_PTR)lpszName == 1)
3197 tl_struct->path = strdupW(tl_struct->source);
3198 else
3199 {
3200 tl_struct->path = msi_alloc(sz);
3201 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3202 }
3203
3204 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3205 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3206 if (FAILED(res))
3207 {
3208 msi_free(tl_struct->path);
3209 tl_struct->path = NULL;
3210
3211 return TRUE;
3212 }
3213
3214 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3215 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3216 {
3217 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3218 return FALSE;
3219 }
3220
3221 msi_free(tl_struct->path);
3222 tl_struct->path = NULL;
3223
3224 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3225 ITypeLib_Release(tl_struct->ptLib);
3226
3227 return TRUE;
3228 }
3229
3230 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3231 {
3232 MSIPACKAGE* package = param;
3233 LPCWSTR component;
3234 MSICOMPONENT *comp;
3235 MSIFILE *file;
3236 typelib_struct tl_struct;
3237 ITypeLib *tlib;
3238 HMODULE module;
3239 HRESULT hr;
3240
3241 component = MSI_RecordGetString(row,3);
3242 comp = get_loaded_component(package,component);
3243 if (!comp)
3244 return ERROR_SUCCESS;
3245
3246 if (!comp->Enabled)
3247 {
3248 TRACE("component is disabled\n");
3249 return ERROR_SUCCESS;
3250 }
3251
3252 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3253 {
3254 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3255 comp->Action = comp->Installed;
3256 return ERROR_SUCCESS;
3257 }
3258 comp->Action = INSTALLSTATE_LOCAL;
3259
3260 file = get_loaded_file( package, comp->KeyPath );
3261 if (!file)
3262 return ERROR_SUCCESS;
3263
3264 ui_actiondata( package, szRegisterTypeLibraries, row );
3265
3266 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3267 if (module)
3268 {
3269 LPCWSTR guid;
3270 guid = MSI_RecordGetString(row,1);
3271 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3272 tl_struct.source = strdupW( file->TargetPath );
3273 tl_struct.path = NULL;
3274
3275 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3276 (LONG_PTR)&tl_struct);
3277
3278 if (tl_struct.path)
3279 {
3280 LPWSTR help = NULL;
3281 LPCWSTR helpid;
3282 HRESULT res;
3283
3284 helpid = MSI_RecordGetString(row,6);
3285
3286 if (helpid)
3287 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3288 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3289 msi_free(help);
3290
3291 if (FAILED(res))
3292 ERR("Failed to register type library %s\n",
3293 debugstr_w(tl_struct.path));
3294 else
3295 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3296
3297 ITypeLib_Release(tl_struct.ptLib);
3298 msi_free(tl_struct.path);
3299 }
3300 else
3301 ERR("Failed to load type library %s\n",
3302 debugstr_w(tl_struct.source));
3303
3304 FreeLibrary(module);
3305 msi_free(tl_struct.source);
3306 }
3307 else
3308 {
3309 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3310 if (FAILED(hr))
3311 {
3312 ERR("Failed to load type library: %08x\n", hr);
3313 return ERROR_INSTALL_FAILURE;
3314 }
3315
3316 ITypeLib_Release(tlib);
3317 }
3318
3319 return ERROR_SUCCESS;
3320 }
3321
3322 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3323 {
3324 /*
3325 * OK this is a bit confusing.. I am given a _Component key and I believe
3326 * that the file that is being registered as a type library is the "key file
3327 * of that component" which I interpret to mean "The file in the KeyPath of
3328 * that component".
3329 */
3330 UINT rc;
3331 MSIQUERY * view;
3332 static const WCHAR Query[] =
3333 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3334 '`','T','y','p','e','L','i','b','`',0};
3335
3336 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3337 if (rc != ERROR_SUCCESS)
3338 return ERROR_SUCCESS;
3339
3340 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3341 msiobj_release(&view->hdr);
3342 return rc;
3343 }
3344
3345 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3346 {
3347 MSIPACKAGE *package = param;
3348 LPCWSTR component, guid;
3349 MSICOMPONENT *comp;
3350 GUID libid;
3351 UINT version;
3352 LCID language;
3353 SYSKIND syskind;
3354 HRESULT hr;
3355
3356 component = MSI_RecordGetString( row, 3 );
3357 comp = get_loaded_component( package, component );
3358 if (!comp)
3359 return ERROR_SUCCESS;
3360
3361 if (!comp->Enabled)
3362 {
3363 TRACE("component is disabled\n");
3364 return ERROR_SUCCESS;
3365 }
3366
3367 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3368 {
3369 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3370 comp->Action = comp->Installed;
3371 return ERROR_SUCCESS;
3372 }
3373 comp->Action = INSTALLSTATE_ABSENT;
3374
3375 ui_actiondata( package, szUnregisterTypeLibraries, row );
3376
3377 guid = MSI_RecordGetString( row, 1 );
3378 CLSIDFromString( (LPCWSTR)guid, &libid );
3379 version = MSI_RecordGetInteger( row, 4 );
3380 language = MSI_RecordGetInteger( row, 2 );
3381
3382 #ifdef _WIN64
3383 syskind = SYS_WIN64;
3384 #else
3385 syskind = SYS_WIN32;
3386 #endif
3387
3388 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3389 if (FAILED(hr))
3390 {
3391 WARN("Failed to unregister typelib: %08x\n", hr);
3392 }
3393
3394 return ERROR_SUCCESS;
3395 }
3396
3397 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3398 {
3399 UINT rc;
3400 MSIQUERY *view;
3401 static const WCHAR query[] =
3402 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3403 '`','T','y','p','e','L','i','b','`',0};
3404
3405 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3406 if (rc != ERROR_SUCCESS)
3407 return ERROR_SUCCESS;
3408
3409 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3410 msiobj_release( &view->hdr );
3411 return rc;
3412 }
3413
3414 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3415 {
3416 static const WCHAR szlnk[] = {'.','l','n','k',0};
3417 LPCWSTR directory, extension;
3418 LPWSTR link_folder, link_file, filename;
3419
3420 directory = MSI_RecordGetString( row, 2 );
3421 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3422
3423 /* may be needed because of a bug somewhere else */
3424 create_full_pathW( link_folder );
3425
3426 filename = msi_dup_record_field( row, 3 );
3427 reduce_to_longfilename( filename );
3428
3429 extension = strchrW( filename, '.' );
3430 if (!extension || strcmpiW( extension, szlnk ))
3431 {
3432 int len = strlenW( filename );
3433 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3434 memcpy( filename + len, szlnk, sizeof(szlnk) );
3435 }
3436 link_file = build_directory_name( 2, link_folder, filename );
3437 msi_free( link_folder );
3438 msi_free( filename );
3439
3440 return link_file;
3441 }
3442
3443 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3444 {
3445 MSIPACKAGE *package = param;
3446 LPWSTR link_file, deformated, path;
3447 LPCWSTR component, target;
3448 MSICOMPONENT *comp;
3449 IShellLinkW *sl = NULL;
3450 IPersistFile *pf = NULL;
3451 HRESULT res;
3452
3453 component = MSI_RecordGetString(row, 4);
3454 comp = get_loaded_component(package, component);
3455 if (!comp)
3456 return ERROR_SUCCESS;
3457
3458 if (!comp->Enabled)
3459 {
3460 TRACE("component is disabled\n");
3461 return ERROR_SUCCESS;
3462 }
3463
3464 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3465 {
3466 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3467 comp->Action = comp->Installed;
3468 return ERROR_SUCCESS;
3469 }
3470 comp->Action = INSTALLSTATE_LOCAL;
3471
3472 ui_actiondata(package,szCreateShortcuts,row);
3473
3474 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3475 &IID_IShellLinkW, (LPVOID *) &sl );
3476
3477 if (FAILED( res ))
3478 {
3479 ERR("CLSID_ShellLink not available\n");
3480 goto err;
3481 }
3482
3483 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3484 if (FAILED( res ))
3485 {
3486 ERR("QueryInterface(IID_IPersistFile) failed\n");
3487 goto err;
3488 }
3489
3490 target = MSI_RecordGetString(row, 5);
3491 if (strchrW(target, '['))
3492 {
3493 deformat_string(package, target, &deformated);
3494 IShellLinkW_SetPath(sl,deformated);
3495 msi_free(deformated);
3496 }
3497 else
3498 {
3499 FIXME("poorly handled shortcut format, advertised shortcut\n");
3500 IShellLinkW_SetPath(sl,comp->FullKeypath);
3501 }
3502
3503 if (!MSI_RecordIsNull(row,6))
3504 {
3505 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3506 deformat_string(package, arguments, &deformated);
3507 IShellLinkW_SetArguments(sl,deformated);
3508 msi_free(deformated);
3509 }
3510
3511 if (!MSI_RecordIsNull(row,7))
3512 {
3513 LPCWSTR description = MSI_RecordGetString(row, 7);
3514 IShellLinkW_SetDescription(sl, description);
3515 }
3516
3517 if (!MSI_RecordIsNull(row,8))
3518 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3519
3520 if (!MSI_RecordIsNull(row,9))
3521 {
3522 INT index;
3523 LPCWSTR icon = MSI_RecordGetString(row, 9);
3524
3525 path = build_icon_path(package, icon);
3526 index = MSI_RecordGetInteger(row,10);
3527
3528 /* no value means 0 */
3529 if (index == MSI_NULL_INTEGER)
3530 index = 0;
3531
3532 IShellLinkW_SetIconLocation(sl, path, index);
3533 msi_free(path);
3534 }
3535
3536 if (!MSI_RecordIsNull(row,11))
3537 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3538
3539 if (!MSI_RecordIsNull(row,12))
3540 {
3541 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3542 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3543 if (path)
3544 IShellLinkW_SetWorkingDirectory(sl, path);
3545 msi_free(path);
3546 }
3547
3548 link_file = get_link_file(package, row);
3549
3550 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3551 IPersistFile_Save(pf, link_file, FALSE);
3552
3553 msi_free(link_file);
3554
3555 err:
3556 if (pf)
3557 IPersistFile_Release( pf );
3558 if (sl)
3559 IShellLinkW_Release( sl );
3560
3561 return ERROR_SUCCESS;
3562 }
3563
3564 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3565 {
3566 UINT rc;
3567 HRESULT res;
3568 MSIQUERY * view;
3569 static const WCHAR Query[] =
3570 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3571 '`','S','h','o','r','t','c','u','t','`',0};
3572
3573 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3574 if (rc != ERROR_SUCCESS)
3575 return ERROR_SUCCESS;
3576
3577 res = CoInitialize( NULL );
3578
3579 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3580 msiobj_release(&view->hdr);
3581
3582 if (SUCCEEDED(res))
3583 CoUninitialize();
3584
3585 return rc;
3586 }
3587
3588 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3589 {
3590 MSIPACKAGE *package = param;
3591 LPWSTR link_file;
3592 LPCWSTR component;
3593 MSICOMPONENT *comp;
3594
3595 component = MSI_RecordGetString( row, 4 );
3596 comp = get_loaded_component( package, component );
3597 if (!comp)
3598 return ERROR_SUCCESS;
3599
3600 if (!comp->Enabled)
3601 {
3602 TRACE("component is disabled\n");
3603 return ERROR_SUCCESS;
3604 }
3605
3606 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3607 {
3608 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3609 comp->Action = comp->Installed;
3610 return ERROR_SUCCESS;
3611 }
3612 comp->Action = INSTALLSTATE_ABSENT;
3613
3614 ui_actiondata( package, szRemoveShortcuts, row );
3615
3616 link_file = get_link_file( package, row );
3617
3618 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3619 if (!DeleteFileW( link_file ))
3620 {
3621 WARN("Failed to remove shortcut file %u\n", GetLastError());
3622 }
3623 msi_free( link_file );
3624
3625 return ERROR_SUCCESS;
3626 }
3627
3628 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3629 {
3630 UINT rc;
3631 MSIQUERY *view;
3632 static const WCHAR query[] =
3633 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3634 '`','S','h','o','r','t','c','u','t','`',0};
3635
3636 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3637 if (rc != ERROR_SUCCESS)
3638 return ERROR_SUCCESS;
3639
3640 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3641 msiobj_release( &view->hdr );
3642
3643 return rc;
3644 }
3645
3646 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3647 {
3648 MSIPACKAGE* package = param;
3649 HANDLE the_file;
3650 LPWSTR FilePath;
3651 LPCWSTR FileName;
3652 CHAR buffer[1024];
3653 DWORD sz;
3654 UINT rc;
3655
3656 FileName = MSI_RecordGetString(row,1);
3657 if (!FileName)
3658 {
3659 ERR("Unable to get FileName\n");
3660 return ERROR_SUCCESS;
3661 }
3662
3663 FilePath = build_icon_path(package,FileName);
3664
3665 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3666
3667 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3668 FILE_ATTRIBUTE_NORMAL, NULL);
3669
3670 if (the_file == INVALID_HANDLE_VALUE)
3671 {
3672 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3673 msi_free(FilePath);
3674 return ERROR_SUCCESS;
3675 }
3676
3677 do
3678 {
3679 DWORD write;
3680 sz = 1024;
3681 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3682 if (rc != ERROR_SUCCESS)
3683 {
3684 ERR("Failed to get stream\n");
3685 CloseHandle(the_file);
3686 DeleteFileW(FilePath);
3687 break;
3688 }
3689 WriteFile(the_file,buffer,sz,&write,NULL);
3690 } while (sz == 1024);
3691
3692 msi_free(FilePath);
3693 CloseHandle(the_file);
3694
3695 return ERROR_SUCCESS;
3696 }
3697
3698 static UINT msi_publish_icons(MSIPACKAGE *package)
3699 {
3700 UINT r;
3701 MSIQUERY *view;
3702
3703 static const WCHAR query[]= {
3704 'S','E','L','E','C','T',' ','*',' ',
3705 'F','R','O','M',' ','`','I','c','o','n','`',0};
3706
3707 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3708 if (r == ERROR_SUCCESS)
3709 {
3710 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3711 msiobj_release(&view->hdr);
3712 }
3713
3714 return ERROR_SUCCESS;
3715 }
3716
3717 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3718 {
3719 UINT r;
3720 HKEY source;
3721 LPWSTR buffer;
3722 MSIMEDIADISK *disk;
3723 MSISOURCELISTINFO *info;
3724
3725 r = RegCreateKeyW(hkey, szSourceList, &source);
3726 if (r != ERROR_SUCCESS)
3727 return r;
3728
3729 RegCloseKey(source);
3730
3731 buffer = strrchrW(package->PackagePath, '\\') + 1;
3732 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3733 package->Context, MSICODE_PRODUCT,
3734 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3735 if (r != ERROR_SUCCESS)
3736 return r;
3737
3738 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3739 package->Context, MSICODE_PRODUCT,
3740 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3741 if (r != ERROR_SUCCESS)
3742 return r;
3743
3744 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3745 package->Context, MSICODE_PRODUCT,
3746 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3747 if (r != ERROR_SUCCESS)
3748 return r;
3749
3750 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3751 {
3752 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3753 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3754 info->options, info->value);
3755 else
3756 MsiSourceListSetInfoW(package->ProductCode, NULL,
3757 info->context, info->options,
3758 info->property, info->value);
3759 }
3760
3761 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3762 {
3763 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3764 disk->context, disk->options,
3765 disk->disk_id, disk->volume_label, disk->disk_prompt);
3766 }
3767
3768 return ERROR_SUCCESS;
3769 }
3770
3771 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3772 {
3773 MSIHANDLE hdb, suminfo;
3774 WCHAR guids[MAX_PATH];
3775 WCHAR packcode[SQUISH_GUID_SIZE];
3776 LPWSTR buffer;
3777 LPWSTR ptr;
3778 DWORD langid;
3779 DWORD size;
3780 UINT r;
3781
3782 static const WCHAR szProductLanguage[] =
3783 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3784 static const WCHAR szARPProductIcon[] =
3785 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3786 static const WCHAR szProductVersion[] =
3787 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3788 static const WCHAR szAssignment[] =
3789 {'A','s','s','i','g','n','m','e','n','t',0};
3790 static const WCHAR szAdvertiseFlags[] =
3791 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3792 static const WCHAR szClients[] =
3793 {'C','l','i','e','n','t','s',0};
3794 static const WCHAR szColon[] = {':',0};
3795
3796 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3797 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3798 msi_free(buffer);
3799
3800 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3801 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3802
3803 /* FIXME */
3804 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3805
3806 buffer = msi_dup_property(package->db, szARPProductIcon);
3807 if (buffer)
3808 {
3809 LPWSTR path = build_icon_path(package,buffer);
3810 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3811 msi_free(path);
3812 msi_free(buffer);
3813 }
3814
3815 buffer = msi_dup_property(package->db, szProductVersion);
3816 if (buffer)
3817 {
3818 DWORD verdword = msi_version_str_to_dword(buffer);
3819 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3820 msi_free(buffer);
3821 }
3822
3823 msi_reg_set_val_dword(hkey, szAssignment, 0);
3824 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3825 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3826 msi_reg_set_val_str(hkey, szClients, szColon);
3827
3828 hdb = alloc_msihandle(&package->db->hdr);
3829 if (!hdb)
3830 return ERROR_NOT_ENOUGH_MEMORY;
3831
3832 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3833 MsiCloseHandle(hdb);
3834 if (r != ERROR_SUCCESS)
3835 goto done;
3836
3837 size = MAX_PATH;
3838 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3839 NULL, guids, &size);
3840 if (r != ERROR_SUCCESS)
3841 goto done;
3842
3843 ptr = strchrW(guids, ';');
3844 if (ptr) *ptr = 0;
3845 squash_guid(guids, packcode);
3846 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3847
3848 done:
3849 MsiCloseHandle(suminfo);
3850 return ERROR_SUCCESS;
3851 }
3852
3853 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3854 {
3855 UINT r;
3856 HKEY hkey;
3857 LPWSTR upgrade;
3858 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3859
3860 upgrade = msi_dup_property(package->db, szUpgradeCode);
3861 if (!upgrade)
3862 return ERROR_SUCCESS;
3863
3864 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3865 {
3866 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3867 if (r != ERROR_SUCCESS)
3868 goto done;
3869 }
3870 else
3871 {
3872 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3873 if (r != ERROR_SUCCESS)
3874 goto done;
3875 }
3876
3877 squash_guid(package->ProductCode, squashed_pc);
3878 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3879
3880 RegCloseKey(hkey);
3881
3882 done:
3883 msi_free(upgrade);
3884 return r;
3885 }
3886
3887 static BOOL msi_check_publish(MSIPACKAGE *package)
3888 {
3889 MSIFEATURE *feature;
3890
3891 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3892 {
3893 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3894 return TRUE;
3895 }
3896
3897 return FALSE;
3898 }
3899
3900 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3901 {
3902 MSIFEATURE *feature;
3903
3904 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3905 {
3906 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3907 return FALSE;
3908 }
3909
3910 return TRUE;
3911 }
3912
3913 static UINT msi_publish_patches( MSIPACKAGE *package )
3914 {
3915 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
3916 WCHAR patch_squashed[GUID_SIZE];
3917 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
3918 LONG res;
3919 MSIPATCHINFO *patch;
3920 UINT r;
3921 WCHAR *p, *all_patches = NULL;
3922 DWORD len = 0;
3923
3924 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
3925 if (r != ERROR_SUCCESS)
3926 return ERROR_FUNCTION_FAILED;
3927
3928 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
3929 if (res != ERROR_SUCCESS)
3930 {
3931 r = ERROR_FUNCTION_FAILED;
3932 goto done;
3933 }
3934
3935 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
3936 if (r != ERROR_SUCCESS)
3937 goto done;
3938
3939 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3940 {
3941 squash_guid( patch->patchcode, patch_squashed );
3942 len += strlenW( patch_squashed ) + 1;
3943 }
3944
3945 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
3946 if (!all_patches)
3947 goto done;
3948
3949 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3950 {
3951 HKEY patch_key;
3952
3953 squash_guid( patch->patchcode, p );
3954 p += strlenW( p ) + 1;
3955
3956 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
3957 (const BYTE *)patch->transforms,
3958 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
3959 if (res != ERROR_SUCCESS)
3960 goto done;
3961
3962 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
3963 if (r != ERROR_SUCCESS)
3964 goto done;
3965
3966 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
3967 (const BYTE *)patch->localfile,
3968 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
3969 RegCloseKey( patch_key );
3970 if (res != ERROR_SUCCESS)
3971 goto done;
3972
3973 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
3974 if (res != ERROR_SUCCESS)
3975 goto done;
3976
3977 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
3978 RegCloseKey( patch_key );
3979 if (res != ERROR_SUCCESS)
3980 goto done;
3981 }
3982
3983 all_patches[len] = 0;
3984 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
3985 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3986 if (res != ERROR_SUCCESS)
3987 goto done;
3988
3989 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
3990 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3991 if (res != ERROR_SUCCESS)
3992 r = ERROR_FUNCTION_FAILED;
3993
3994 done:
3995 RegCloseKey( product_patches_key );
3996 RegCloseKey( patches_key );
3997 RegCloseKey( product_key );
3998 msi_free( all_patches );
3999 return r;
4000 }
4001
4002 /*
4003 * 99% of the work done here is only done for
4004 * advertised installs. However this is where the
4005 * Icon table is processed and written out
4006 * so that is what I am going to do here.
4007 */
4008 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4009 {
4010 UINT rc;
4011 HKEY hukey = NULL, hudkey = NULL;
4012 MSIRECORD *uirow;
4013
4014 if (!list_empty(&package->patches))
4015 {
4016 rc = msi_publish_patches(package);
4017 if (rc != ERROR_SUCCESS)
4018 goto end;
4019 }
4020
4021 /* FIXME: also need to publish if the product is in advertise mode */
4022 if (!msi_check_publish(package))
4023 return ERROR_SUCCESS;
4024
4025 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4026 &hukey, TRUE);
4027 if (rc != ERROR_SUCCESS)
4028 goto end;
4029
4030 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4031 NULL, &hudkey, TRUE);
4032 if (rc != ERROR_SUCCESS)
4033 goto end;
4034
4035 rc = msi_publish_upgrade_code(package);
4036 if (rc != ERROR_SUCCESS)
4037 goto end;
4038
4039 rc = msi_publish_product_properties(package, hukey);
4040 if (rc != ERROR_SUCCESS)
4041 goto end;
4042
4043 rc = msi_publish_sourcelist(package, hukey);
4044 if (rc != ERROR_SUCCESS)
4045 goto end;
4046
4047 rc = msi_publish_icons(package);
4048
4049 end:
4050 uirow = MSI_CreateRecord( 1 );
4051 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4052 ui_actiondata( package, szPublishProduct, uirow );
4053 msiobj_release( &uirow->hdr );
4054
4055 RegCloseKey(hukey);
4056 RegCloseKey(hudkey);
4057
4058 return rc;
4059 }
4060
4061 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4062 {
4063 WCHAR *filename, *ptr, *folder, *ret;
4064 const WCHAR *dirprop;
4065
4066 filename = msi_dup_record_field( row, 2 );
4067 if (filename && (ptr = strchrW( filename, '|' )))
4068 ptr++;
4069 else
4070 ptr = filename;
4071
4072 dirprop = MSI_RecordGetString( row, 3 );
4073 if (dirprop)
4074 {
4075 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4076 if (!folder)
4077 folder = msi_dup_property( package->db, dirprop );
4078 }
4079 else
4080 folder = msi_dup_property( package->db, szWindowsFolder );
4081
4082 if (!folder)
4083 {
4084 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4085 msi_free( filename );
4086 return NULL;
4087 }
4088
4089 ret = build_directory_name( 2, folder, ptr );
4090
4091 msi_free( filename );
4092 msi_free( folder );
4093 return ret;
4094 }
4095
4096 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4097 {
4098 MSIPACKAGE *package = param;
4099 LPCWSTR component, section, key, value, identifier;
4100 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4101 MSIRECORD * uirow;
4102 INT action;
4103 MSICOMPONENT *comp;
4104
4105 component = MSI_RecordGetString(row, 8);
4106 comp = get_loaded_component(package,component);
4107 if (!comp)
4108 return ERROR_SUCCESS;
4109
4110 if (!comp->Enabled)
4111 {
4112 TRACE("component is disabled\n");
4113 return ERROR_SUCCESS;
4114 }
4115
4116 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4117 {
4118 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4119 comp->Action = comp->Installed;
4120 return ERROR_SUCCESS;
4121 }
4122 comp->Action = INSTALLSTATE_LOCAL;
4123
4124 identifier = MSI_RecordGetString(row,1);
4125 section = MSI_RecordGetString(row,4);
4126 key = MSI_RecordGetString(row,5);
4127 value = MSI_RecordGetString(row,6);
4128 action = MSI_RecordGetInteger(row,7);
4129
4130 deformat_string(package,section,&deformated_section);
4131 deformat_string(package,key,&deformated_key);
4132 deformat_string(package,value,&deformated_value);
4133
4134 fullname = get_ini_file_name(package, row);
4135
4136 if (action == 0)
4137 {
4138 TRACE("Adding value %s to section %s in %s\n",
4139 debugstr_w(deformated_key), debugstr_w(deformated_section),
4140 debugstr_w(fullname));
4141 WritePrivateProfileStringW(deformated_section, deformated_key,
4142 deformated_value, fullname);
4143 }
4144 else if (action == 1)
4145 {
4146 WCHAR returned[10];
4147 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4148 returned, 10, fullname);
4149 if (returned[0] == 0)
4150 {
4151 TRACE("Adding value %s to section %s in %s\n",
4152 debugstr_w(deformated_key), debugstr_w(deformated_section),
4153 debugstr_w(fullname));
4154
4155 WritePrivateProfileStringW(deformated_section, deformated_key,
4156 deformated_value, fullname);
4157 }
4158 }
4159 else if (action == 3)
4160 FIXME("Append to existing section not yet implemented\n");
4161
4162 uirow = MSI_CreateRecord(4);
4163 MSI_RecordSetStringW(uirow,1,identifier);
4164 MSI_RecordSetStringW(uirow,2,deformated_section);
4165 MSI_RecordSetStringW(uirow,3,deformated_key);
4166 MSI_RecordSetStringW(uirow,4,deformated_value);
4167 ui_actiondata(package,szWriteIniValues,uirow);
4168 msiobj_release( &uirow->hdr );
4169
4170 msi_free(fullname);
4171 msi_free(deformated_key);
4172 msi_free(deformated_value);
4173 msi_free(deformated_section);
4174 return ERROR_SUCCESS;
4175 }
4176
4177 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4178 {
4179 UINT rc;
4180 MSIQUERY * view;
4181 static const WCHAR ExecSeqQuery[] =
4182 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4183 '`','I','n','i','F','i','l','e','`',0};
4184
4185 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4186 if (rc != ERROR_SUCCESS)
4187 {
4188 TRACE("no IniFile table\n");
4189 return ERROR_SUCCESS;
4190 }
4191
4192 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4193 msiobj_release(&view->hdr);
4194 return rc;
4195 }
4196
4197 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4198 {
4199 MSIPACKAGE *package = param;
4200 LPCWSTR component, section, key, value, identifier;
4201 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4202 MSICOMPONENT *comp;
4203 MSIRECORD *uirow;
4204 INT action;
4205
4206 component = MSI_RecordGetString( row, 8 );
4207 comp = get_loaded_component( package, component );
4208 if (!comp)
4209 return ERROR_SUCCESS;
4210
4211 if (!comp->Enabled)
4212 {
4213 TRACE("component is disabled\n");
4214 return ERROR_SUCCESS;
4215 }
4216
4217 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4218 {
4219 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4220 comp->Action = comp->Installed;
4221 return ERROR_SUCCESS;
4222 }
4223 comp->Action = INSTALLSTATE_ABSENT;
4224
4225 identifier = MSI_RecordGetString( row, 1 );
4226 section = MSI_RecordGetString( row, 4 );
4227 key = MSI_RecordGetString( row, 5 );
4228 value = MSI_RecordGetString( row, 6 );
4229 action = MSI_RecordGetInteger( row, 7 );
4230
4231 deformat_string( package, section, &deformated_section );
4232 deformat_string( package, key, &deformated_key );
4233 deformat_string( package, value, &deformated_value );
4234
4235 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4236 {
4237 filename = get_ini_file_name( package, row );
4238
4239 TRACE("Removing key %s from section %s in %s\n",
4240 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4241
4242 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4243 {
4244 WARN("Unable to remove key %u\n", GetLastError());
4245 }
4246 msi_free( filename );
4247 }
4248 else
4249 FIXME("Unsupported action %d\n", action);
4250
4251
4252 uirow = MSI_CreateRecord( 4 );
4253 MSI_RecordSetStringW( uirow, 1, identifier );
4254 MSI_RecordSetStringW( uirow, 2, deformated_section );
4255 MSI_RecordSetStringW( uirow, 3, deformated_key );
4256 MSI_RecordSetStringW( uirow, 4, deformated_value );
4257 ui_actiondata( package, szRemoveIniValues, uirow );
4258 msiobj_release( &uirow->hdr );
4259
4260 msi_free( deformated_key );
4261 msi_free( deformated_value );
4262 msi_free( deformated_section );
4263 return ERROR_SUCCESS;
4264 }
4265
4266 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4267 {
4268 MSIPACKAGE *package = param;
4269 LPCWSTR component, section, key, value, identifier;
4270 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4271 MSICOMPONENT *comp;
4272 MSIRECORD *uirow;
4273 INT action;
4274
4275 component = MSI_RecordGetString( row, 8 );
4276 comp = get_loaded_component( package, component );
4277 if (!comp)
4278 return ERROR_SUCCESS;
4279
4280 if (!comp->Enabled)
4281 {
4282 TRACE("component is disabled\n");
4283 return ERROR_SUCCESS;
4284 }
4285
4286 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4287 {
4288 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4289 comp->Action = comp->Installed;
4290 return ERROR_SUCCESS;
4291 }
4292 comp->Action = INSTALLSTATE_LOCAL;
4293
4294 identifier = MSI_RecordGetString( row, 1 );
4295 section = MSI_RecordGetString( row, 4 );
4296 key = MSI_RecordGetString( row, 5 );
4297 value = MSI_RecordGetString( row, 6 );
4298 action = MSI_RecordGetInteger( row, 7 );
4299
4300 deformat_string( package, section, &deformated_section );
4301 deformat_string( package, key, &deformated_key );
4302 deformat_string( package, value, &deformated_value );
4303
4304 if (action == msidbIniFileActionRemoveLine)
4305 {
4306 filename = get_ini_file_name( package, row );
4307
4308 TRACE("Removing key %s from section %s in %s\n",
4309 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4310
4311 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4312 {
4313 WARN("Unable to remove key %u\n", GetLastError());
4314 }
4315 msi_free( filename );
4316 }
4317 else
4318 FIXME("Unsupported action %d\n", action);
4319
4320 uirow = MSI_CreateRecord( 4 );
4321 MSI_RecordSetStringW( uirow, 1, identifier );
4322 MSI_RecordSetStringW( uirow, 2, deformated_section );
4323 MSI_RecordSetStringW( uirow, 3, deformated_key );
4324 MSI_RecordSetStringW( uirow, 4, deformated_value );
4325 ui_actiondata( package, szRemoveIniValues, uirow );
4326 msiobj_release( &uirow->hdr );
4327
4328 msi_free( deformated_key );
4329 msi_free( deformated_value );
4330 msi_free( deformated_section );
4331 return ERROR_SUCCESS;
4332 }
4333
4334 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4335 {
4336 UINT rc;
4337 MSIQUERY *view;
4338 static const WCHAR query[] =
4339 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4340 '`','I','n','i','F','i','l','e','`',0};
4341 static const WCHAR remove_query[] =
4342 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4343 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4344
4345 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4346 if (rc == ERROR_SUCCESS)
4347 {
4348 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4349 msiobj_release( &view->hdr );
4350 if (rc != ERROR_SUCCESS)
4351 return rc;
4352 }
4353
4354 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4355 if (rc == ERROR_SUCCESS)
4356 {
4357 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4358 msiobj_release( &view->hdr );
4359 if (rc != ERROR_SUCCESS)
4360 return rc;
4361 }
4362
4363 return ERROR_SUCCESS;
4364 }
4365
4366 static void register_dll( const WCHAR *dll, BOOL unregister )
4367 {
4368 HMODULE hmod;
4369
4370 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4371 if (hmod)
4372 {
4373 HRESULT (WINAPI *func_ptr)( void );
4374 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4375
4376 func_ptr = (void *)GetProcAddress( hmod, func );
4377 if (func_ptr)
4378 {
4379 HRESULT hr = func_ptr();
4380 if (FAILED( hr ))
4381 WARN("failed to register dll 0x%08x\n", hr);
4382 }
4383 else
4384 WARN("entry point %s not found\n", func);
4385 FreeLibrary( hmod );
4386 return;
4387 }
4388 WARN("failed to load library %u\n", GetLastError());
4389 }
4390
4391 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4392 {
4393 MSIPACKAGE *package = param;
4394 LPCWSTR filename;
4395 MSIFILE *file;
4396 MSIRECORD *uirow;
4397
4398 filename = MSI_RecordGetString(row,1);
4399 file = get_loaded_file( package, filename );
4400
4401 if (!file)
4402 {
4403 ERR("Unable to find file id %s\n",debugstr_w(filename));
4404 return ERROR_SUCCESS;
4405 }
4406
4407 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4408
4409 register_dll( file->TargetPath, FALSE );
4410
4411 uirow = MSI_CreateRecord( 2 );
4412 MSI_RecordSetStringW( uirow, 1, filename );
4413 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4414 ui_actiondata( package, szSelfRegModules, uirow );
4415 msiobj_release( &uirow->hdr );
4416
4417 return ERROR_SUCCESS;
4418 }
4419
4420 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4421 {
4422 UINT rc;
4423 MSIQUERY * view;
4424 static const WCHAR ExecSeqQuery[] =
4425 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4426 '`','S','e','l','f','R','e','g','`',0};
4427
4428 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4429 if (rc != ERROR_SUCCESS)
4430 {
4431 TRACE("no SelfReg table\n");
4432 return ERROR_SUCCESS;
4433 }
4434
4435 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4436 msiobj_release(&view->hdr);
4437
4438 return ERROR_SUCCESS;
4439 }
4440
4441 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4442 {
4443 MSIPACKAGE *package = param;
4444 LPCWSTR filename;
4445 MSIFILE *file;
4446 MSIRECORD *uirow;
4447
4448 filename = MSI_RecordGetString( row, 1 );
4449 file = get_loaded_file( package, filename );
4450
4451 if (!file)
4452 {
4453 ERR("Unable to find file id %s\n", debugstr_w(filename));
4454 return ERROR_SUCCESS;
4455 }
4456
4457 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4458
4459 register_dll( file->TargetPath, TRUE );
4460
4461 uirow = MSI_CreateRecord( 2 );
4462 MSI_RecordSetStringW( uirow, 1, filename );
4463 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4464 ui_actiondata( package, szSelfUnregModules, uirow );
4465 msiobj_release( &uirow->hdr );
4466
4467 return ERROR_SUCCESS;
4468 }
4469
4470 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4471 {
4472 UINT rc;
4473 MSIQUERY *view;
4474 static const WCHAR query[] =
4475 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4476 '`','S','e','l','f','R','e','g','`',0};
4477
4478 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4479 if (rc != ERROR_SUCCESS)
4480 {
4481 TRACE("no SelfReg table\n");
4482 return ERROR_SUCCESS;
4483 }
4484
4485 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4486 msiobj_release( &view->hdr );
4487
4488 return ERROR_SUCCESS;
4489 }
4490
4491 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4492 {
4493 MSIFEATURE *feature;
4494 UINT rc;
4495 HKEY hkey = NULL, userdata = NULL;
4496
4497 if (!msi_check_publish(package))
4498 return ERROR_SUCCESS;
4499
4500 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4501 &hkey, TRUE);
4502 if (rc != ERROR_SUCCESS)
4503 goto end;
4504
4505 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4506 &userdata, TRUE);
4507 if (rc != ERROR_SUCCESS)
4508 goto end;
4509
4510 /* here the guids are base 85 encoded */
4511 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4512 {
4513 ComponentList *cl;
4514 LPWSTR data = NULL;
4515 GUID clsid;
4516 INT size;
4517 BOOL absent = FALSE;
4518 MSIRECORD *uirow;
4519
4520 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4521 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4522 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4523
4524 size = 1;
4525 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4526 {
4527 size += 21;
4528 }
4529 if (feature->Feature_Parent)
4530 size += strlenW( feature->Feature_Parent )+2;
4531
4532 data = msi_alloc(size * sizeof(WCHAR));
4533
4534 data[0] = 0;
4535 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4536 {
4537 MSICOMPONENT* component = cl->component;
4538 WCHAR buf[21];
4539
4540 buf[0] = 0;
4541 if (component->ComponentId)
4542 {
4543 TRACE("From %s\n",debugstr_w(component->ComponentId));
4544 CLSIDFromString(component->ComponentId, &clsid);
4545 encode_base85_guid(&clsid,buf);
4546 TRACE("to %s\n",debugstr_w(buf));
4547 strcatW(data,buf);
4548 }
4549 }
4550
4551 if (feature->Feature_Parent)
4552 {
4553 static const WCHAR sep[] = {'\2',0};
4554 strcatW(data,sep);
4555 strcatW(data,feature->Feature_Parent);
4556 }
4557
4558 msi_reg_set_val_str( userdata, feature->Feature, data );
4559 msi_free(data);
4560
4561 size = 0;
4562 if (feature->Feature_Parent)
4563 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4564 if (!absent)
4565 {
4566 size += sizeof(WCHAR);
4567 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4568 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4569 }
4570 else
4571 {
4572 size += 2*sizeof(WCHAR);
4573 data = msi_alloc(size);
4574 data[0] = 0x6;
4575 data[1] = 0;
4576 if (feature->Feature_Parent)
4577 strcpyW( &data[1], feature->Feature_Parent );
4578 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4579 (LPBYTE)data,size);
4580 msi_free(data);
4581 }
4582
4583 /* the UI chunk */
4584 uirow = MSI_CreateRecord( 1 );
4585 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4586 ui_actiondata( package, szPublishFeatures, uirow);
4587 msiobj_release( &uirow->hdr );
4588 /* FIXME: call ui_progress? */
4589 }
4590
4591 end:
4592 RegCloseKey(hkey);
4593 RegCloseKey(userdata);
4594 return rc;
4595 }
4596
4597 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4598 {
4599 UINT r;
4600 HKEY hkey;
4601 MSIRECORD *uirow;
4602
4603 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4604
4605 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4606 &hkey, FALSE);
4607 if (r == ERROR_SUCCESS)
4608 {
4609 RegDeleteValueW(hkey, feature->Feature);
4610 RegCloseKey(hkey);
4611 }
4612
4613 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4614 &hkey, FALSE);
4615 if (r == ERROR_SUCCESS)
4616 {
4617 RegDeleteValueW(hkey, feature->Feature);
4618 RegCloseKey(hkey);
4619 }
4620
4621 uirow = MSI_CreateRecord( 1 );
4622 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4623 ui_actiondata( package, szUnpublishFeatures, uirow );
4624 msiobj_release( &uirow->hdr );
4625
4626 return ERROR_SUCCESS;
4627 }
4628
4629 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4630 {
4631 MSIFEATURE *feature;
4632
4633 if (!msi_check_unpublish(package))
4634 return ERROR_SUCCESS;
4635
4636 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4637 {
4638 msi_unpublish_feature(package, feature);
4639 }
4640
4641 return ERROR_SUCCESS;
4642 }
4643
4644 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4645 {
4646 SYSTEMTIME systime;
4647 DWORD size, langid;
4648 WCHAR date[9], *val, *buffer;
4649 const WCHAR *prop, *key;
4650
4651 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4652 static const WCHAR szWindowsInstaller[] =
4653 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4654 static const WCHAR modpath_fmt[] =
4655 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4656 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4657 static const WCHAR szModifyPath[] =
4658 {'M','o','d','i','f','y','P','a','t','h',0};
4659 static const WCHAR szUninstallString[] =
4660 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4661 static const WCHAR szEstimatedSize[] =
4662 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4663 static const WCHAR szProductLanguage[] =
4664 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4665 static const WCHAR szProductVersion[] =
4666 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4667 static const WCHAR szDisplayVersion[] =
4668 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4669 static const WCHAR szInstallSource[] =
4670 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4671 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4672 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4673 static const WCHAR szAuthorizedCDFPrefix[] =
4674 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4675 static const WCHAR szARPCONTACT[] =
4676 {'A','R','P','C','O','N','T','A','C','T',0};
4677 static const WCHAR szContact[] =
4678 {'C','o','n','t','a','c','t',0};
4679 static const WCHAR szARPCOMMENTS[] =
4680 {'A','R','P','C','O','M','M','E','N','T','S',0};
4681 static const WCHAR szComments[] =
4682 {'C','o','m','m','e','n','t','s',0};
4683 static const WCHAR szProductName[] =
4684 {'P','r','o','d','u','c','t','N','a','m','e',0};
4685 static const WCHAR szDisplayName[] =
4686 {'D','i','s','p','l','a','y','N','a','m','e',0};
4687 static const WCHAR szARPHELPLINK[] =
4688 {'A','R','P','H','E','L','P','L','I','N','K',0};
4689 static const WCHAR szHelpLink[] =
4690 {'H','e','l','p','L','i','n','k',0};
4691 static const WCHAR szARPHELPTELEPHONE[] =
4692 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4693 static const WCHAR szHelpTelephone[] =
4694 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4695 static const WCHAR szARPINSTALLLOCATION[] =
4696 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4697 static const WCHAR szInstallLocation[] =
4698 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4699 static const WCHAR szManufacturer[] =
4700 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4701 static const WCHAR szPublisher[] =
4702 {'P','u','b','l','i','s','h','e','r',0};
4703 static const WCHAR szARPREADME[] =
4704 {'A','R','P','R','E','A','D','M','E',0};
4705 static const WCHAR szReadme[] =
4706 {'R','e','a','d','M','e',0};
4707 static const WCHAR szARPSIZE[] =
4708 {'A','R','P','S','I','Z','E',0};
4709 static const WCHAR szSize[] =
4710 {'S','i','z','e',0};
4711 static const WCHAR szARPURLINFOABOUT[] =
4712 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4713 static const WCHAR szURLInfoAbout[] =
4714 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4715 static const WCHAR szARPURLUPDATEINFO[] =
4716 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4717 static const WCHAR szURLUpdateInfo[] =
4718 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4719
4720 static const WCHAR *propval[] = {
4721 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4722 szARPCONTACT, szContact,
4723 szARPCOMMENTS, szComments,
4724 szProductName, szDisplayName,
4725 szARPHELPLINK, szHelpLink,
4726 szARPHELPTELEPHONE, szHelpTelephone,
4727 szARPINSTALLLOCATION, szInstallLocation,
4728 cszSourceDir, szInstallSource,
4729 szManufacturer, szPublisher,
4730 szARPREADME, szReadme,
4731 szARPSIZE, szSize,
4732 szARPURLINFOABOUT, szURLInfoAbout,
4733 szARPURLUPDATEINFO, szURLUpdateInfo,
4734 NULL
4735 };
4736 const WCHAR **p = propval;
4737
4738 while (*p)
4739 {
4740 prop = *p++;
4741 key = *p++;
4742 val = msi_dup_property(package->db, prop);
4743 msi_reg_set_val_str(hkey, key, val);
4744 msi_free(val);
4745 }
4746
4747 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4748
4749 size = deformat_string(package, modpath_fmt, &buffer);
4750 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4751 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4752 msi_free(buffer);
4753
4754 /* FIXME: Write real Estimated Size when we have it */
4755 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4756
4757 GetLocalTime(&systime);
4758 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4759 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4760
4761 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4762 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4763
4764 buffer = msi_dup_property(package->db, szProductVersion);
4765 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4766 if (buffer)
4767 {
4768 DWORD verdword = msi_version_str_to_dword(buffer);
4769
4770 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4771 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4772 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4773 msi_free(buffer);
4774 }
4775
4776 return ERROR_SUCCESS;
4777 }
4778
4779 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4780 {
4781 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4782 MSIRECORD *uirow;
4783 LPWSTR upgrade_code;
4784 HKEY hkey, props;
4785 HKEY upgrade;
4786 UINT rc;
4787
4788 /* FIXME: also need to publish if the product is in advertise mode */
4789 if (!msi_check_publish(package))
4790 return ERROR_SUCCESS;
4791
4792 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
4793 if (rc != ERROR_SUCCESS)
4794 return rc;
4795
4796 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4797 NULL, &props, TRUE);
4798 if (rc != ERROR_SUCCESS)
4799 goto done;
4800
4801 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4802 msi_free( package->db->localfile );
4803 package->db->localfile = NULL;
4804
4805 rc = msi_publish_install_properties(package, hkey);
4806 if (rc != ERROR_SUCCESS)
4807 goto done;
4808
4809 rc = msi_publish_install_properties(package, props);
4810 if (rc != ERROR_SUCCESS)
4811 goto done;
4812
4813 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4814 if (upgrade_code)
4815 {
4816 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4817 squash_guid(package->ProductCode, squashed_pc);
4818 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4819 RegCloseKey(upgrade);
4820 msi_free(upgrade_code);
4821 }
4822
4823 done:
4824 uirow = MSI_CreateRecord( 1 );
4825 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4826 ui_actiondata( package, szRegisterProduct, uirow );
4827 msiobj_release( &uirow->hdr );
4828
4829 RegCloseKey(hkey);
4830 return ERROR_SUCCESS;
4831 }
4832
4833 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4834 {
4835 return execute_script(package,INSTALL_SCRIPT);
4836 }
4837
4838 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
4839 {
4840 WCHAR *upgrade, **features;
4841 BOOL full_uninstall = TRUE;
4842 MSIFEATURE *feature;
4843 MSIPATCHINFO *patch;
4844
4845 static const WCHAR szUpgradeCode[] =
4846 {'U','p','g','r','a','d','e','C','o','d','e',0};
4847
4848 features = msi_split_string(remove, ',');
4849 if (!features)
4850 {
4851 ERR("REMOVE feature list is empty!\n");
4852 return ERROR_FUNCTION_FAILED;
4853 }
4854
4855 if (!lstrcmpW(features[0], szAll))
4856 full_uninstall = TRUE;
4857 else
4858 {
4859 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4860 {
4861 if (feature->Action != INSTALLSTATE_ABSENT)
4862 full_uninstall = FALSE;
4863 }
4864 }
4865 msi_free(features);
4866
4867 if (!full_uninstall)
4868 return ERROR_SUCCESS;
4869
4870 MSIREG_DeleteProductKey(package->ProductCode);
4871 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4872 MSIREG_DeleteUninstallKey(package);
4873
4874 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4875 {
4876 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4877 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4878 }
4879 else
4880 {
4881 MSIREG_DeleteUserProductKey(package->ProductCode);
4882 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4883 }
4884
4885 upgrade = msi_dup_property(package->db, szUpgradeCode);
4886 if (upgrade)
4887 {
4888 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4889 msi_free(upgrade);
4890 }
4891
4892 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4893 {
4894 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4895 }
4896
4897 return ERROR_SUCCESS;
4898 }
4899
4900 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4901 {
4902 UINT rc;
4903 WCHAR *remove;
4904
4905 /* turn off scheduling */
4906 package->script->CurrentlyScripting= FALSE;
4907
4908 /* first do the same as an InstallExecute */
4909 rc = ACTION_InstallExecute(package);
4910 if (rc != ERROR_SUCCESS)
4911 return rc;
4912
4913 /* then handle Commit Actions */
4914 rc = execute_script(package,COMMIT_SCRIPT);
4915 if (rc != ERROR_SUCCESS)
4916 return rc;
4917
4918 remove = msi_dup_property(package->db, szRemove);
4919 if (remove)
4920 rc = msi_unpublish_product(package, remove);
4921
4922 msi_free(remove);
4923 return rc;
4924 }
4925
4926 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4927 {
4928 static const WCHAR RunOnce[] = {
4929 'S','o','f','t','w','a','r','e','\\',
4930 'M','i','c','r','o','s','o','f','t','\\',
4931 'W','i','n','d','o','w','s','\\',
4932 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4933 'R','u','n','O','n','c','e',0};
4934 static const WCHAR InstallRunOnce[] = {
4935 'S','o','f','t','w','a','r','e','\\',
4936 'M','i','c','r','o','s','o','f','t','\\',
4937 'W','i','n','d','o','w','s','\\',
4938 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4939 'I','n','s','t','a','l','l','e','r','\\',
4940 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4941
4942 static const WCHAR msiexec_fmt[] = {
4943 '%','s',
4944 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4945 '\"','%','s','\"',0};
4946 static const WCHAR install_fmt[] = {
4947 '/','I',' ','\"','%','s','\"',' ',
4948 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4949 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4950 WCHAR buffer[256], sysdir[MAX_PATH];
4951 HKEY hkey;
4952 WCHAR squished_pc[100];
4953
4954 squash_guid(package->ProductCode,squished_pc);
4955
4956 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4957 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4958 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4959 squished_pc);
4960
4961 msi_reg_set_val_str( hkey, squished_pc, buffer );
4962 RegCloseKey(hkey);
4963
4964 TRACE("Reboot command %s\n",debugstr_w(buffer));
4965
4966 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4967 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4968
4969 msi_reg_set_val_str( hkey, squished_pc, buffer );
4970 RegCloseKey(hkey);
4971
4972 return ERROR_INSTALL_SUSPEND;
4973 }
4974
4975 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4976 {
4977 DWORD attrib;
4978 UINT rc;
4979
4980 /*
4981 * We are currently doing what should be done here in the top level Install
4982 * however for Administrative and uninstalls this step will be needed
4983 */
4984 if (!package->PackagePath)
4985 return ERROR_SUCCESS;
4986
4987 msi_set_sourcedir_props(package, TRUE);
4988
4989 attrib = GetFileAttributesW(package->db->path);
4990 if (attrib == INVALID_FILE_ATTRIBUTES)
4991 {
4992 LPWSTR prompt;
4993 LPWSTR msg;
4994 DWORD size = 0;
4995
4996 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4997 package->Context, MSICODE_PRODUCT,
4998 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4999 if (rc == ERROR_MORE_DATA)
5000 {
5001 prompt = msi_alloc(size * sizeof(WCHAR));
5002 MsiSourceListGetInfoW(package->ProductCode, NULL,
5003 package->Context, MSICODE_PRODUCT,
5004 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5005 }
5006 else
5007 prompt = strdupW(package->db->path);
5008
5009 msg = generate_error_string(package,1302,1,prompt);
5010 while(attrib == INVALID_FILE_ATTRIBUTES)
5011 {
5012 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5013 if (rc == IDCANCEL)
5014 {
5015 rc = ERROR_INSTALL_USEREXIT;
5016 break;
5017 }
5018 attrib = GetFileAttributesW(package->db->path);
5019 }
5020 msi_free(prompt);
5021 rc = ERROR_SUCCESS;
5022 }
5023 else
5024 return ERROR_SUCCESS;
5025
5026 return rc;
5027 }
5028
5029 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5030 {
5031 HKEY hkey = 0;
5032 LPWSTR buffer, productid = NULL;
5033 UINT i, rc = ERROR_SUCCESS;
5034 MSIRECORD *uirow;
5035
5036 static const WCHAR szPropKeys[][80] =
5037 {
5038 {'P','r','o','d','u','c','t','I','D',0},
5039 {'U','S','E','R','N','A','M','E',0},
5040 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5041 {0},
5042 };
5043
5044 static const WCHAR szRegKeys[][80] =
5045 {
5046 {'P','r','o','d','u','c','t','I','D',0},
5047 {'R','e','g','O','w','n','e','r',0},
5048 {'R','e','g','C','o','m','p','a','n','y',0},
5049 {0},
5050 };
5051
5052 if (msi_check_unpublish(package))
5053 {
5054 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5055 goto end;
5056 }
5057
5058 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5059 if (!productid)
5060 goto end;
5061
5062 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5063 NULL, &hkey, TRUE);
5064 if (rc != ERROR_SUCCESS)
5065 goto end;
5066
5067 for( i = 0; szPropKeys[i][0]; i++ )
5068 {
5069 buffer = msi_dup_property( package->db, szPropKeys[i] );
5070 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5071 msi_free( buffer );
5072 }
5073
5074 end:
5075 uirow = MSI_CreateRecord( 1 );
5076 MSI_RecordSetStringW( uirow, 1, productid );
5077 ui_actiondata( package, szRegisterUser, uirow );
5078 msiobj_release( &uirow->hdr );
5079
5080 msi_free(productid);
5081 RegCloseKey(hkey);
5082 return rc;
5083 }
5084
5085
5086 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5087 {
5088 UINT rc;
5089
5090 package->script->InWhatSequence |= SEQUENCE_EXEC;
5091 rc = ACTION_ProcessExecSequence(package,FALSE);
5092 return rc;
5093 }
5094
5095
5096 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5097 {
5098 MSIPACKAGE *package = param;
5099 LPCWSTR compgroupid, component, feature, qualifier, text;
5100 LPWSTR advertise = NULL, output = NULL;
5101 HKEY hkey = NULL;
5102 UINT rc;
5103 MSICOMPONENT *comp;
5104 MSIFEATURE *feat;
5105 DWORD sz;
5106 MSIRECORD *uirow;
5107
5108 feature = MSI_RecordGetString(rec, 5);
5109 feat = get_loaded_feature(package, feature);
5110 if (!feat)
5111 return ERROR_SUCCESS;
5112
5113 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5114 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5115 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5116 {
5117 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5118 feat->Action = feat->Installed;
5119 return ERROR_SUCCESS;
5120 }
5121
5122 component = MSI_RecordGetString(rec, 3);
5123 comp = get_loaded_component(package, component);
5124 if (!comp)
5125 return ERROR_SUCCESS;
5126
5127 compgroupid = MSI_RecordGetString(rec,1);
5128 qualifier = MSI_RecordGetString(rec,2);
5129
5130 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5131 if (rc != ERROR_SUCCESS)
5132 goto end;
5133
5134 text = MSI_RecordGetString(rec,4);
5135 advertise = create_component_advertise_string(package, comp, feature);
5136
5137 sz = strlenW(advertise);
5138
5139 if (text)
5140 sz += lstrlenW(text);
5141
5142 sz+=3;
5143 sz *= sizeof(WCHAR);
5144
5145 output = msi_alloc_zero(sz);
5146 strcpyW(output,advertise);
5147 msi_free(advertise);
5148
5149 if (text)
5150 strcatW(output,text);
5151
5152 msi_reg_set_val_multi_str( hkey, qualifier, output );
5153
5154 end:
5155 RegCloseKey(hkey);
5156 msi_free(output);
5157
5158 /* the UI chunk */
5159 uirow = MSI_CreateRecord( 2 );
5160 MSI_RecordSetStringW( uirow, 1, compgroupid );
5161 MSI_RecordSetStringW( uirow, 2, qualifier);
5162 ui_actiondata( package, szPublishComponents, uirow);
5163 msiobj_release( &uirow->hdr );
5164 /* FIXME: call ui_progress? */
5165
5166 return rc;
5167 }
5168
5169 /*
5170 * At present I am ignorning the advertised components part of this and only
5171 * focusing on the qualified component sets
5172 */
5173 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5174 {
5175 UINT rc;
5176 MSIQUERY * view;
5177 static const WCHAR ExecSeqQuery[] =
5178 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5179 '`','P','u','b','l','i','s','h',
5180 'C','o','m','p','o','n','e','n','t','`',0};
5181
5182 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5183 if (rc != ERROR_SUCCESS)
5184 return ERROR_SUCCESS;
5185
5186 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5187 msiobj_release(&view->hdr);
5188
5189 return rc;
5190 }
5191
5192 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5193 {
5194 static const WCHAR szInstallerComponents[] = {
5195 'S','o','f','t','w','a','r','e','\\',
5196 'M','i','c','r','o','s','o','f','t','\\',
5197 'I','n','s','t','a','l','l','e','r','\\',
5198 'C','o','m','p','o','n','e','n','t','s','\\',0};
5199
5200 MSIPACKAGE *package = param;
5201 LPCWSTR compgroupid, component, feature, qualifier;
5202 MSICOMPONENT *comp;
5203 MSIFEATURE *feat;
5204 MSIRECORD *uirow;
5205 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5206 LONG res;
5207
5208 feature = MSI_RecordGetString( rec, 5 );
5209 feat = get_loaded_feature( package, feature );
5210 if (!feat)
5211 return ERROR_SUCCESS;
5212
5213 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5214 {
5215 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5216 feat->Action = feat->Installed;
5217 return ERROR_SUCCESS;
5218 }
5219
5220 component = MSI_RecordGetString( rec, 3 );
5221 comp = get_loaded_component( package, component );
5222 if (!comp)
5223 return ERROR_SUCCESS;
5224
5225 compgroupid = MSI_RecordGetString( rec, 1 );
5226 qualifier = MSI_RecordGetString( rec, 2 );
5227
5228 squash_guid( compgroupid, squashed );
5229 strcpyW( keypath, szInstallerComponents );
5230 strcatW( keypath, squashed );
5231
5232 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5233 if (res != ERROR_SUCCESS)
5234 {
5235 WARN("Unable to delete component key %d\n", res);
5236 }
5237
5238 uirow = MSI_CreateRecord( 2 );
5239 MSI_RecordSetStringW( uirow, 1, compgroupid );
5240 MSI_RecordSetStringW( uirow, 2, qualifier );
5241 ui_actiondata( package, szUnpublishComponents, uirow );
5242 msiobj_release( &uirow->hdr );
5243
5244 return ERROR_SUCCESS;
5245 }
5246
5247 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5248 {
5249 UINT rc;
5250 MSIQUERY *view;
5251 static const WCHAR query[] =
5252 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5253 '`','P','u','b','l','i','s','h',
5254 'C','o','m','p','o','n','e','n','t','`',0};
5255
5256 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5257 if (rc != ERROR_SUCCESS)
5258 return ERROR_SUCCESS;
5259
5260 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5261 msiobj_release( &view->hdr );
5262
5263 return rc;
5264 }
5265
5266 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5267 {
5268 MSIPACKAGE *package = param;
5269 MSIRECORD *row;
5270 MSIFILE *file;
5271 SC_HANDLE hscm, service = NULL;
5272 LPCWSTR comp, depends, pass;
5273 LPWSTR name = NULL, disp = NULL;
5274 LPCWSTR load_order, serv_name, key;
5275 DWORD serv_type, start_type;
5276 DWORD err_control;
5277
5278 static const WCHAR query[] =
5279 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5280 '`','C','o','m','p','o','n','e','n','t','`',' ',
5281 'W','H','E','R','E',' ',
5282 '`','C','o','m','p','o','n','e','n','t','`',' ',
5283 '=','\'','%','s','\'',0};
5284
5285 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5286 if (!hscm)
5287 {
5288 ERR("Failed to open the SC Manager!\n");
5289 goto done;
5290 }
5291
5292 start_type = MSI_RecordGetInteger(rec, 5);
5293 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5294 goto done;
5295
5296 depends = MSI_RecordGetString(rec, 8);
5297 if (depends && *depends)
5298 FIXME("Dependency list unhandled!\n");
5299
5300 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5301 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5302 serv_type = MSI_RecordGetInteger(rec, 4);
5303 err_control = MSI_RecordGetInteger(rec, 6);
5304 load_order = MSI_RecordGetString(rec, 7);
5305 serv_name = MSI_RecordGetString(rec, 9);
5306 pass = MSI_RecordGetString(rec, 10);
5307 comp = MSI_RecordGetString(rec, 12);
5308
5309 /* fetch the service path */
5310 row = MSI_QueryGetRecord(package->db, query, comp);
5311 if (!row)
5312 {
5313 ERR("Control query failed!\n");
5314 goto done;
5315 }
5316
5317 key = MSI_RecordGetString(row, 6);
5318
5319 file = get_loaded_file(package, key);
5320 msiobj_release(&row->hdr);
5321 if (!file)
5322 {
5323 ERR("Failed to load the service file\n");
5324 goto done;
5325 }
5326
5327 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5328 start_type, err_control, file->TargetPath,
5329 load_order, NULL, NULL, serv_name, pass);
5330 if (!service)
5331 {
5332 if (GetLastError() != ERROR_SERVICE_EXISTS)
5333 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5334 }
5335
5336 done:
5337 CloseServiceHandle(service);
5338 CloseServiceHandle(hscm);
5339 msi_free(name);
5340 msi_free(disp);
5341
5342 return ERROR_SUCCESS;
5343 }
5344
5345 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5346 {
5347 UINT rc;
5348 MSIQUERY * view;
5349 static const WCHAR ExecSeqQuery[] =
5350 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5351 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5352
5353 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5354 if (rc != ERROR_SUCCESS)
5355 return ERROR_SUCCESS;
5356
5357 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5358 msiobj_release(&view->hdr);
5359
5360 return rc;
5361 }
5362
5363 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5364 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5365 {
5366 LPCWSTR *vector, *temp_vector;
5367 LPWSTR p, q;
5368 DWORD sep_len;
5369
5370 static const WCHAR separator[] = {'[','~',']',0};
5371
5372 *numargs = 0;
5373 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5374
5375 if (!args)
5376 return NULL;
5377
5378 vector = msi_alloc(sizeof(LPWSTR));
5379 if (!vector)
5380 return NULL;
5381
5382 p = args;
5383 do
5384 {
5385 (*numargs)++;
5386 vector[*numargs - 1] = p;
5387
5388 if ((q = strstrW(p, separator)))
5389 {
5390 *q = '\0';
5391
5392 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5393 if (!temp_vector)
5394 {
5395 msi_free(vector);
5396 return NULL;
5397 }
5398 vector = temp_vector;
5399
5400 p = q + sep_len;
5401 }
5402 } while (q);
5403
5404 return vector;
5405 }
5406
5407 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5408 {
5409 MSIPACKAGE *package = param;
5410 MSICOMPONENT *comp;
5411 MSIRECORD *uirow;
5412 SC_HANDLE scm = NULL, service = NULL;
5413 LPCWSTR component, *vector = NULL;
5414 LPWSTR name, args, display_name = NULL;
5415 DWORD event, numargs, len;
5416 UINT r = ERROR_FUNCTION_FAILED;
5417
5418 component = MSI_RecordGetString(rec, 6);
5419 comp = get_loaded_component(package, component);
5420 if (!comp)
5421 return ERROR_SUCCESS;
5422
5423 if (!comp->Enabled)
5424 {
5425 TRACE("component is disabled\n");
5426 return ERROR_SUCCESS;
5427 }
5428
5429 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5430 {
5431 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5432 comp->Action = comp->Installed;
5433 return ERROR_SUCCESS;
5434 }
5435 comp->Action = INSTALLSTATE_LOCAL;
5436
5437 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5438 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5439 event = MSI_RecordGetInteger(rec, 3);
5440
5441 if (!(event & msidbServiceControlEventStart))
5442 {
5443 r = ERROR_SUCCESS;
5444 goto done;
5445 }
5446
5447 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5448 if (!scm)
5449 {
5450 ERR("Failed to open the service control manager\n");
5451 goto done;
5452 }
5453
5454 len = 0;
5455 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5456 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5457 {
5458 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5459 GetServiceDisplayNameW( scm, name, display_name, &len );
5460 }
5461
5462 service = OpenServiceW(scm, name, SERVICE_START);
5463 if (!service)
5464 {
5465 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5466 goto done;
5467 }
5468
5469 vector = msi_service_args_to_vector(args, &numargs);
5470
5471 if (!StartServiceW(service, numargs, vector) &&
5472 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5473 {
5474 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5475 goto done;
5476 }
5477
5478 r = ERROR_SUCCESS;
5479
5480 done:
5481 uirow = MSI_CreateRecord( 2 );
5482 MSI_RecordSetStringW( uirow, 1, display_name );
5483 MSI_RecordSetStringW( uirow, 2, name );
5484 ui_actiondata( package, szStartServices, uirow );
5485 msiobj_release( &uirow->hdr );
5486
5487 CloseServiceHandle(service);
5488 CloseServiceHandle(scm);
5489
5490 msi_free(name);
5491 msi_free(args);
5492 msi_free(vector);
5493 msi_free(display_name);
5494 return r;
5495 }
5496
5497 static UINT ACTION_StartServices( MSIPACKAGE *package )
5498 {
5499 UINT rc;
5500 MSIQUERY *view;
5501
5502 static const WCHAR query[] = {
5503 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5504 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5505
5506 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5507 if (rc != ERROR_SUCCESS)
5508 return ERROR_SUCCESS;
5509
5510 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5511 msiobj_release(&view->hdr);
5512
5513 return rc;
5514 }
5515
5516 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5517 {
5518 DWORD i, needed, count;
5519 ENUM_SERVICE_STATUSW *dependencies;
5520 SERVICE_STATUS ss;
5521 SC_HANDLE depserv;
5522
5523 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5524 0, &needed, &count))
5525 return TRUE;
5526
5527 if (GetLastError() != ERROR_MORE_DATA)
5528 return FALSE;
5529
5530 dependencies = msi_alloc(needed);
5531 if (!dependencies)
5532 return FALSE;
5533
5534 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5535 needed, &needed, &count))
5536 goto error;
5537
5538 for (i = 0; i < count; i++)
5539 {
5540 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5541 SERVICE_STOP | SERVICE_QUERY_STATUS);
5542 if (!depserv)
5543 goto error;
5544
5545 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5546 goto error;
5547 }
5548
5549 return TRUE;
5550
5551 error:
5552 msi_free(dependencies);
5553 return FALSE;
5554 }
5555
5556 static UINT stop_service( LPCWSTR name )
5557 {
5558 SC_HANDLE scm = NULL, service = NULL;
5559 SERVICE_STATUS status;
5560 SERVICE_STATUS_PROCESS ssp;
5561 DWORD needed;
5562
5563 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5564 if (!scm)
5565 {
5566 WARN("Failed to open the SCM: %d\n", GetLastError());
5567 goto done;
5568 }
5569
5570 service = OpenServiceW(scm, name,
5571 SERVICE_STOP |
5572 SERVICE_QUERY_STATUS |
5573 SERVICE_ENUMERATE_DEPENDENTS);
5574 if (!service)
5575 {
5576 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5577 goto done;
5578 }
5579
5580 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5581 sizeof(SERVICE_STATUS_PROCESS), &needed))
5582 {
5583 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5584 goto done;
5585 }
5586
5587 if (ssp.dwCurrentState == SERVICE_STOPPED)
5588 goto done;
5589
5590 stop_service_dependents(scm, service);
5591
5592 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5593 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5594
5595 done:
5596 CloseServiceHandle(service);
5597 CloseServiceHandle(scm);
5598
5599 return ERROR_SUCCESS;
5600 }
5601
5602 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5603 {
5604 MSIPACKAGE *package = param;
5605 MSICOMPONENT *comp;
5606 MSIRECORD *uirow;
5607 LPCWSTR component;
5608 LPWSTR name = NULL, display_name = NULL;
5609 DWORD event, len;
5610 SC_HANDLE scm;
5611
5612 event = MSI_RecordGetInteger( rec, 3 );
5613 if (!(event & msidbServiceControlEventStop))
5614 return ERROR_SUCCESS;
5615
5616 component = MSI_RecordGetString( rec, 6 );
5617 comp = get_loaded_component( package, component );
5618 if (!comp)
5619 return ERROR_SUCCESS;
5620
5621 if (!comp->Enabled)
5622 {
5623 TRACE("component is disabled\n");
5624 return ERROR_SUCCESS;
5625 }
5626
5627 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5628 {
5629 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5630 comp->Action = comp->Installed;
5631 return ERROR_SUCCESS;
5632 }
5633 comp->Action = INSTALLSTATE_ABSENT;
5634
5635 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5636 if (!scm)
5637 {
5638 ERR("Failed to open the service control manager\n");
5639 goto done;
5640 }
5641
5642 len = 0;
5643 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5644 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5645 {
5646 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5647 GetServiceDisplayNameW( scm, name, display_name, &len );
5648 }
5649 CloseServiceHandle( scm );
5650
5651 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5652 stop_service( name );
5653
5654 done:
5655 uirow = MSI_CreateRecord( 2 );
5656 MSI_RecordSetStringW( uirow, 1, display_name );
5657 MSI_RecordSetStringW( uirow, 2, name );
5658 ui_actiondata( package, szStopServices, uirow );
5659 msiobj_release( &uirow->hdr );
5660
5661 msi_free( name );
5662 msi_free( display_name );
5663 return ERROR_SUCCESS;
5664 }
5665
5666 static UINT ACTION_StopServices( MSIPACKAGE *package )
5667 {
5668 UINT rc;
5669 MSIQUERY *view;
5670
5671 static const WCHAR query[] = {
5672 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5673 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5674
5675 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5676 if (rc != ERROR_SUCCESS)
5677 return ERROR_SUCCESS;
5678
5679 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5680 msiobj_release(&view->hdr);
5681
5682 return rc;
5683 }
5684
5685 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5686 {
5687 MSIPACKAGE *package = param;
5688 MSICOMPONENT *comp;
5689 MSIRECORD *uirow;
5690 LPCWSTR component;
5691 LPWSTR name = NULL, display_name = NULL;
5692 DWORD event, len;
5693 SC_HANDLE scm = NULL, service = NULL;
5694
5695 event = MSI_RecordGetInteger( rec, 3 );
5696 if (!(event & msidbServiceControlEventDelete))
5697 return ERROR_SUCCESS;
5698
5699 component = MSI_RecordGetString(rec, 6);
5700 comp = get_loaded_component(package, component);
5701 if (!comp)
5702 return ERROR_SUCCESS;
5703
5704 if (!comp->Enabled)
5705 {
5706 TRACE("component is disabled\n");
5707 return ERROR_SUCCESS;
5708 }
5709
5710 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5711 {
5712 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5713 comp->Action = comp->Installed;
5714 return ERROR_SUCCESS;
5715 }
5716 comp->Action = INSTALLSTATE_ABSENT;
5717
5718 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5719 stop_service( name );
5720
5721 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5722 if (!scm)
5723 {
5724 WARN("Failed to open the SCM: %d\n", GetLastError());
5725 goto done;
5726 }
5727
5728 len = 0;
5729 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5730 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5731 {
5732 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5733 GetServiceDisplayNameW( scm, name, display_name, &len );
5734 }
5735
5736 service = OpenServiceW( scm, name, DELETE );
5737 if (!service)
5738 {
5739 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5740 goto done;
5741 }
5742
5743 if (!DeleteService( service ))
5744 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5745
5746 done:
5747 uirow = MSI_CreateRecord( 2 );
5748 MSI_RecordSetStringW( uirow, 1, display_name );
5749 MSI_RecordSetStringW( uirow, 2, name );
5750 ui_actiondata( package, szDeleteServices, uirow );
5751 msiobj_release( &uirow->hdr );
5752
5753 CloseServiceHandle( service );
5754 CloseServiceHandle( scm );
5755 msi_free( name );
5756 msi_free( display_name );
5757
5758 return ERROR_SUCCESS;
5759 }
5760
5761 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5762 {
5763 UINT rc;
5764 MSIQUERY *view;
5765
5766 static const WCHAR query[] = {
5767 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5768 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5769
5770 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5771 if (rc != ERROR_SUCCESS)
5772 return ERROR_SUCCESS;
5773
5774 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5775 msiobj_release( &view->hdr );
5776
5777 return rc;
5778 }
5779
5780 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5781 {
5782 MSIFILE *file;
5783
5784 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5785 {
5786 if (!lstrcmpW(file->File, filename))
5787 return file;
5788 }
5789
5790 return NULL;
5791 }
5792
5793 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5794 {
5795 MSIPACKAGE *package = param;
5796 LPWSTR driver, driver_path, ptr;
5797 WCHAR outpath[MAX_PATH];
5798 MSIFILE *driver_file, *setup_file;
5799 MSIRECORD *uirow;
5800 LPCWSTR desc;
5801 DWORD len, usage;
5802 UINT r = ERROR_SUCCESS;
5803
5804 static const WCHAR driver_fmt[] = {
5805 'D','r','i','v','e','r','=','%','s',0};
5806 static const WCHAR setup_fmt[] = {
5807 'S','e','t','u','p','=','%','s',0};
5808 static const WCHAR usage_fmt[] = {
5809 'F','i','l','e','U','s','a','g','e','=','1',0};
5810
5811 desc = MSI_RecordGetString(rec, 3);
5812
5813 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5814 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5815
5816 if (!driver_file)
5817 {
5818 ERR("ODBC Driver entry not found!\n");
5819 return ERROR_FUNCTION_FAILED;
5820 }
5821
5822 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5823 if (setup_file)
5824 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5825 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5826
5827 driver = msi_alloc(len * sizeof(WCHAR));
5828 if (!driver)
5829 return ERROR_OUTOFMEMORY;
5830
5831 ptr = driver;
5832 lstrcpyW(ptr, desc);
5833 ptr += lstrlenW(ptr) + 1;
5834
5835 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5836 ptr += len + 1;
5837
5838 if (setup_file)
5839 {
5840 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5841 ptr += len + 1;
5842 }
5843
5844 lstrcpyW(ptr, usage_fmt);
5845 ptr += lstrlenW(ptr) + 1;
5846 *ptr = '\0';
5847
5848 driver_path = strdupW(driver_file->TargetPath);
5849 ptr = strrchrW(driver_path, '\\');
5850 if (ptr) *ptr = '\0';
5851
5852 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5853 NULL, ODBC_INSTALL_COMPLETE, &usage))
5854 {
5855 ERR("Failed to install SQL driver!\n");
5856 r = ERROR_FUNCTION_FAILED;
5857 }
5858
5859 uirow = MSI_CreateRecord( 5 );
5860 MSI_RecordSetStringW( uirow, 1, desc );
5861 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5862 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
5863 ui_actiondata( package, szInstallODBC, uirow );
5864 msiobj_release( &uirow->hdr );
5865
5866 msi_free(driver);
5867 msi_free(driver_path);
5868
5869 return r;
5870 }
5871
5872 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5873 {
5874 MSIPACKAGE *package = param;
5875 LPWSTR translator, translator_path, ptr;
5876 WCHAR outpath[MAX_PATH];
5877 MSIFILE *translator_file, *setup_file;
5878 MSIRECORD *uirow;
5879 LPCWSTR desc;
5880 DWORD len, usage;
5881 UINT r = ERROR_SUCCESS;
5882
5883 static const WCHAR translator_fmt[] = {
5884 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5885 static const WCHAR setup_fmt[] = {
5886 'S','e','t','u','p','=','%','s',0};
5887
5888 desc = MSI_RecordGetString(rec, 3);
5889
5890 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5891 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5892
5893 if (!translator_file)
5894 {
5895 ERR("ODBC Translator entry not found!\n");
5896 return ERROR_FUNCTION_FAILED;
5897 }
5898
5899 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5900 if (setup_file)
5901 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5902
5903 translator = msi_alloc(len * sizeof(WCHAR));
5904 if (!translator)
5905 return ERROR_OUTOFMEMORY;
5906
5907 ptr = translator;
5908 lstrcpyW(ptr, desc);
5909 ptr += lstrlenW(ptr) + 1;
5910
5911 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5912 ptr += len + 1;
5913
5914 if (setup_file)
5915 {
5916 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5917 ptr += len + 1;
5918 }
5919 *ptr = '\0';
5920
5921 translator_path = strdupW(translator_file->TargetPath);
5922 ptr = strrchrW(translator_path, '\\');
5923 if (ptr) *ptr = '\0';
5924
5925 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5926 NULL, ODBC_INSTALL_COMPLETE, &usage))
5927 {
5928 ERR("Failed to install SQL translator!\n");
5929 r = ERROR_FUNCTION_FAILED;
5930 }
5931
5932 uirow = MSI_CreateRecord( 5 );
5933 MSI_RecordSetStringW( uirow, 1, desc );
5934 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5935 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
5936 ui_actiondata( package, szInstallODBC, uirow );
5937 msiobj_release( &uirow->hdr );
5938
5939 msi_free(translator);
5940 msi_free(translator_path);
5941
5942 return r;
5943 }
5944
5945 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5946 {
5947 MSIPACKAGE *package = param;
5948 LPWSTR attrs;
5949 LPCWSTR desc, driver;
5950 WORD request = ODBC_ADD_SYS_DSN;
5951 INT registration;
5952 DWORD len;
5953 UINT r = ERROR_SUCCESS;
5954 MSIRECORD *uirow;
5955
5956 static const WCHAR attrs_fmt[] = {
5957 'D','S','N','=','%','s',0 };
5958
5959 desc = MSI_RecordGetString(rec, 3);
5960 driver = MSI_RecordGetString(rec, 4);
5961 registration = MSI_RecordGetInteger(rec, 5);
5962
5963 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5964 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5965
5966 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5967 attrs = msi_alloc(len * sizeof(WCHAR));
5968 if (!attrs)
5969 return ERROR_OUTOFMEMORY;
5970
5971 len = sprintfW(attrs, attrs_fmt, desc);
5972 attrs[len + 1] = 0;
5973
5974 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5975 {
5976 ERR("Failed to install SQL data source!\n");
5977 r = ERROR_FUNCTION_FAILED;
5978 }
5979
5980 uirow = MSI_CreateRecord( 5 );
5981 MSI_RecordSetStringW( uirow, 1, desc );
5982 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5983 MSI_RecordSetInteger( uirow, 3, request );
5984 ui_actiondata( package, szInstallODBC, uirow );
5985 msiobj_release( &uirow->hdr );
5986
5987 msi_free(attrs);
5988
5989 return r;
5990 }
5991
5992 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5993 {
5994 UINT rc;
5995 MSIQUERY *view;
5996
5997 static const WCHAR driver_query[] = {
5998 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5999 'O','D','B','C','D','r','i','v','e','r',0 };
6000
6001 static const WCHAR translator_query[] = {
6002 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6003 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6004
6005 static const WCHAR source_query[] = {
6006 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6007 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6008
6009 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6010 if (rc != ERROR_SUCCESS)
6011 return ERROR_SUCCESS;
6012
6013 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6014 msiobj_release(&view->hdr);
6015
6016 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6017 if (rc != ERROR_SUCCESS)
6018 return ERROR_SUCCESS;
6019
6020 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6021 msiobj_release(&view->hdr);
6022
6023 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6024 if (rc != ERROR_SUCCESS)
6025 return ERROR_SUCCESS;
6026
6027 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6028 msiobj_release(&view->hdr);
6029
6030 return rc;
6031 }
6032
6033 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6034 {
6035 MSIPACKAGE *package = param;
6036 MSIRECORD *uirow;
6037 DWORD usage;
6038 LPCWSTR desc;
6039
6040 desc = MSI_RecordGetString( rec, 3 );
6041 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6042 {
6043 WARN("Failed to remove ODBC driver\n");
6044 }
6045 else if (!usage)
6046 {
6047 FIXME("Usage count reached 0\n");
6048 }
6049
6050 uirow = MSI_CreateRecord( 2 );
6051 MSI_RecordSetStringW( uirow, 1, desc );
6052 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6053 ui_actiondata( package, szRemoveODBC, uirow );
6054 msiobj_release( &uirow->hdr );
6055
6056 return ERROR_SUCCESS;
6057 }
6058
6059 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6060 {
6061 MSIPACKAGE *package = param;
6062 MSIRECORD *uirow;
6063 DWORD usage;
6064 LPCWSTR desc;
6065
6066 desc = MSI_RecordGetString( rec, 3 );
6067 if (!SQLRemoveTranslatorW( desc, &usage ))
6068 {
6069 WARN("Failed to remove ODBC translator\n");
6070 }
6071 else if (!usage)
6072 {
6073 FIXME("Usage count reached 0\n");
6074 }
6075
6076 uirow = MSI_CreateRecord( 2 );
6077 MSI_RecordSetStringW( uirow, 1, desc );
6078 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6079 ui_actiondata( package, szRemoveODBC, uirow );
6080 msiobj_release( &uirow->hdr );
6081
6082 return ERROR_SUCCESS;
6083 }
6084
6085 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6086 {
6087 MSIPACKAGE *package = param;
6088 MSIRECORD *uirow;
6089 LPWSTR attrs;
6090 LPCWSTR desc, driver;
6091 WORD request = ODBC_REMOVE_SYS_DSN;
6092 INT registration;
6093 DWORD len;
6094
6095 static const WCHAR attrs_fmt[] = {
6096 'D','S','N','=','%','s',0 };
6097
6098 desc = MSI_RecordGetString( rec, 3 );
6099 driver = MSI_RecordGetString( rec, 4 );
6100 registration = MSI_RecordGetInteger( rec, 5 );
6101
6102 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6103 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6104
6105 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6106 attrs = msi_alloc( len * sizeof(WCHAR) );
6107 if (!attrs)
6108 return ERROR_OUTOFMEMORY;
6109
6110 FIXME("Use ODBCSourceAttribute table\n");
6111
6112 len = sprintfW( attrs, attrs_fmt, desc );
6113 attrs[len + 1] = 0;
6114
6115 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6116 {
6117 WARN("Failed to remove ODBC data source\n");
6118 }
6119 msi_free( attrs );
6120
6121 uirow = MSI_CreateRecord( 3 );
6122 MSI_RecordSetStringW( uirow, 1, desc );
6123 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6124 MSI_RecordSetInteger( uirow, 3, request );
6125 ui_actiondata( package, szRemoveODBC, uirow );
6126 msiobj_release( &uirow->hdr );
6127
6128 return ERROR_SUCCESS;
6129 }
6130
6131 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6132 {
6133 UINT rc;
6134 MSIQUERY *view;
6135
6136 static const WCHAR driver_query[] = {
6137 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6138 'O','D','B','C','D','r','i','v','e','r',0 };
6139
6140 static const WCHAR translator_query[] = {
6141 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6142 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6143
6144 static const WCHAR source_query[] = {
6145 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6146 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6147
6148 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6149 if (rc != ERROR_SUCCESS)
6150 return ERROR_SUCCESS;
6151
6152 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6153 msiobj_release( &view->hdr );
6154
6155 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6156 if (rc != ERROR_SUCCESS)
6157 return ERROR_SUCCESS;
6158
6159 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6160 msiobj_release( &view->hdr );
6161
6162 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6163 if (rc != ERROR_SUCCESS)
6164 return ERROR_SUCCESS;
6165
6166 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6167 msiobj_release( &view->hdr );
6168
6169 return rc;
6170 }
6171
6172 #define ENV_ACT_SETALWAYS 0x1
6173 #define ENV_ACT_SETABSENT 0x2
6174 #define ENV_ACT_REMOVE 0x4
6175 #define ENV_ACT_REMOVEMATCH 0x8
6176
6177 #define ENV_MOD_MACHINE 0x20000000
6178 #define ENV_MOD_APPEND 0x40000000
6179 #define ENV_MOD_PREFIX 0x80000000
6180 #define ENV_MOD_MASK 0xC0000000
6181
6182 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6183
6184 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6185 {
6186 LPCWSTR cptr = *name;
6187
6188 static const WCHAR prefix[] = {'[','~',']',0};
6189 static const int prefix_len = 3;
6190
6191 *flags = 0;
6192 while (*cptr)
6193 {
6194 if (*cptr == '=')
6195 *flags |= ENV_ACT_SETALWAYS;
6196 else if (*cptr == '+')
6197 *flags |= ENV_ACT_SETABSENT;
6198 else if (*cptr == '-')
6199 *flags |= ENV_ACT_REMOVE;
6200 else if (*cptr == '!')
6201 *flags |= ENV_ACT_REMOVEMATCH;
6202 else if (*cptr == '*')
6203 *flags |= ENV_MOD_MACHINE;
6204 else
6205 break;
6206
6207 cptr++;
6208 (*name)++;
6209 }
6210
6211 if (!*cptr)
6212 {
6213 ERR("Missing environment variable\n");
6214 return ERROR_FUNCTION_FAILED;
6215 }
6216
6217 if (*value)
6218 {
6219 LPCWSTR ptr = *value;
6220 if (!strncmpW(ptr, prefix, prefix_len))
6221 {
6222 if (ptr[prefix_len] == szSemiColon[0])
6223 {
6224 *flags |= ENV_MOD_APPEND;
6225 *value += lstrlenW(prefix);
6226 }
6227 else
6228 {
6229 *value = NULL;
6230 }
6231 }
6232 else if (lstrlenW(*value) >= prefix_len)
6233 {
6234 ptr += lstrlenW(ptr) - prefix_len;
6235 if (!lstrcmpW(ptr, prefix))
6236 {
6237 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6238 {
6239 *flags |= ENV_MOD_PREFIX;
6240 /* the "[~]" will be removed by deformat_string */;
6241 }
6242 else
6243 {
6244 *value = NULL;
6245 }
6246 }
6247 }
6248 }
6249
6250 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6251 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6252 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6253 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6254 {
6255 ERR("Invalid flags: %08x\n", *flags);
6256 return ERROR_FUNCTION_FAILED;
6257 }
6258
6259 if (!*flags)
6260 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6261
6262 return ERROR_SUCCESS;
6263 }
6264
6265 static UINT open_env_key( DWORD flags, HKEY *key )
6266 {
6267 static const WCHAR user_env[] =
6268 {'E','n','v','i','r','o','n','m','e','n','t',0};
6269 static const WCHAR machine_env[] =
6270 {'S','y','s','t','e','m','\\',
6271 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6272 'C','o','n','t','r','o','l','\\',
6273 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6274 'E','n','v','i','r','o','n','m','e','n','t',0};
6275 const WCHAR *env;
6276 HKEY root;
6277 LONG res;
6278
6279 if (flags & ENV_MOD_MACHINE)
6280 {
6281 env = machine_env;
6282 root = HKEY_LOCAL_MACHINE;
6283 }
6284 else
6285 {
6286 env = user_env;
6287 root = HKEY_CURRENT_USER;
6288 }
6289
6290 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6291 if (res != ERROR_SUCCESS)
6292 {
6293 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6294 return ERROR_FUNCTION_FAILED;
6295 }
6296
6297 return ERROR_SUCCESS;
6298 }
6299
6300 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6301 {
6302 MSIPACKAGE *package = param;
6303 LPCWSTR name, value, component;
6304 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6305 DWORD flags, type, size;
6306 UINT res;
6307 HKEY env = NULL;
6308 MSICOMPONENT *comp;
6309 MSIRECORD *uirow;
6310 int action = 0;
6311
6312 component = MSI_RecordGetString(rec, 4);
6313 comp = get_loaded_component(package, component);
6314 if (!comp)
6315 return ERROR_SUCCESS;
6316
6317 if (!comp->Enabled)
6318 {
6319 TRACE("component is disabled\n");
6320 return ERROR_SUCCESS;
6321 }
6322
6323 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6324 {
6325 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6326 comp->Action = comp->Installed;
6327 return ERROR_SUCCESS;
6328 }
6329 comp->Action = INSTALLSTATE_LOCAL;
6330
6331 name = MSI_RecordGetString(rec, 2);
6332 value = MSI_RecordGetString(rec, 3);
6333
6334 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6335
6336 res = env_parse_flags(&name, &value, &flags);
6337 if (res != ERROR_SUCCESS || !value)
6338 goto done;
6339
6340 if (value && !deformat_string(package, value, &deformatted))
6341 {
6342 res = ERROR_OUTOFMEMORY;
6343 goto done;
6344 }
6345
6346 value = deformatted;
6347
6348 res = open_env_key( flags, &env );
6349 if (res != ERROR_SUCCESS)
6350 goto done;
6351
6352 if (flags & ENV_MOD_MACHINE)
6353 action |= 0x20000000;
6354
6355 size = 0;
6356 type = REG_SZ;
6357 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6358 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6359 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6360 goto done;
6361
6362 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6363 {
6364 action = 0x2;
6365
6366 /* Nothing to do. */
6367 if (!value)
6368 {
6369 res = ERROR_SUCCESS;
6370 goto done;
6371 }
6372
6373 /* If we are appending but the string was empty, strip ; */
6374 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6375
6376 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6377 newval = strdupW(value);
6378 if (!newval)
6379 {
6380 res = ERROR_OUTOFMEMORY;
6381 goto done;
6382 }
6383 }
6384 else
6385 {
6386 action = 0x1;
6387
6388 /* Contrary to MSDN, +-variable to [~];path works */
6389 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6390 {
6391 res = ERROR_SUCCESS;
6392 goto done;
6393 }
6394
6395 data = msi_alloc(size);
6396 if (!data)
6397 {
6398 RegCloseKey(env);
6399 return ERROR_OUTOFMEMORY;
6400 }
6401
6402 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6403 if (res != ERROR_SUCCESS)
6404 goto done;
6405
6406 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6407 {
6408 action = 0x4;
6409 res = RegDeleteValueW(env, name);
6410 if (res != ERROR_SUCCESS)
6411 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6412 goto done;
6413 }
6414
6415 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6416 if (flags & ENV_MOD_MASK)
6417 {
6418 DWORD mod_size;
6419 int multiplier = 0;
6420 if (flags & ENV_MOD_APPEND) multiplier++;
6421 if (flags & ENV_MOD_PREFIX) multiplier++;
6422 mod_size = lstrlenW(value) * multiplier;
6423 size += mod_size * sizeof(WCHAR);
6424 }
6425
6426 newval = msi_alloc(size);
6427 ptr = newval;
6428 if (!newval)
6429 {
6430 res = ERROR_OUTOFMEMORY;
6431 goto done;
6432 }
6433
6434 if (flags & ENV_MOD_PREFIX)
6435 {
6436 lstrcpyW(newval, value);
6437 ptr = newval + lstrlenW(value);
6438 action |= 0x80000000;
6439 }
6440
6441 lstrcpyW(ptr, data);
6442
6443 if (flags & ENV_MOD_APPEND)
6444 {
6445 lstrcatW(newval, value);
6446 action |= 0x40000000;
6447 }
6448 }
6449 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6450 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6451 if (res)
6452 {
6453 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6454 }
6455
6456 done:
6457 uirow = MSI_CreateRecord( 3 );
6458 MSI_RecordSetStringW( uirow, 1, name );
6459 MSI_RecordSetStringW( uirow, 2, newval );
6460 MSI_RecordSetInteger( uirow, 3, action );
6461 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6462 msiobj_release( &uirow->hdr );
6463
6464 if (env) RegCloseKey(env);
6465 msi_free(deformatted);
6466 msi_free(data);
6467 msi_free(newval);
6468 return res;
6469 }
6470
6471 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6472 {
6473 UINT rc;
6474 MSIQUERY * view;
6475 static const WCHAR ExecSeqQuery[] =
6476 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6477 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6478 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6479 if (rc != ERROR_SUCCESS)
6480 return ERROR_SUCCESS;
6481
6482 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6483 msiobj_release(&view->hdr);
6484
6485 return rc;
6486 }
6487
6488 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6489 {
6490 MSIPACKAGE *package = param;
6491 LPCWSTR name, value, component;
6492 LPWSTR deformatted = NULL;
6493 DWORD flags;
6494 HKEY env;
6495 MSICOMPONENT *comp;
6496 MSIRECORD *uirow;
6497 int action = 0;
6498 LONG res;
6499 UINT r;
6500
6501 component = MSI_RecordGetString( rec, 4 );
6502 comp = get_loaded_component( package, component );
6503 if (!comp)
6504 return ERROR_SUCCESS;
6505
6506 if (!comp->Enabled)
6507 {
6508 TRACE("component is disabled\n");
6509 return ERROR_SUCCESS;
6510 }
6511
6512 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6513 {
6514 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6515 comp->Action = comp->Installed;
6516 return ERROR_SUCCESS;
6517 }
6518 comp->Action = INSTALLSTATE_ABSENT;
6519
6520 name = MSI_RecordGetString( rec, 2 );
6521 value = MSI_RecordGetString( rec, 3 );
6522
6523 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6524
6525 r = env_parse_flags( &name, &value, &flags );
6526 if (r != ERROR_SUCCESS)
6527 return r;
6528
6529 if (!(flags & ENV_ACT_REMOVE))
6530 {
6531 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6532 return ERROR_SUCCESS;
6533 }
6534
6535 if (value && !deformat_string( package, value, &deformatted ))
6536 return ERROR_OUTOFMEMORY;
6537
6538 value = deformatted;
6539
6540 r = open_env_key( flags, &env );
6541 if (r != ERROR_SUCCESS)
6542 {
6543 r = ERROR_SUCCESS;
6544 goto done;
6545 }
6546
6547 if (flags & ENV_MOD_MACHINE)
6548 action |= 0x20000000;
6549
6550 TRACE("Removing %s\n", debugstr_w(name));
6551
6552 res = RegDeleteValueW( env, name );
6553 if (res != ERROR_SUCCESS)
6554 {
6555 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6556 r = ERROR_SUCCESS;
6557 }
6558
6559 done:
6560 uirow = MSI_CreateRecord( 3 );
6561 MSI_RecordSetStringW( uirow, 1, name );
6562 MSI_RecordSetStringW( uirow, 2, value );
6563 MSI_RecordSetInteger( uirow, 3, action );
6564 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6565 msiobj_release( &uirow->hdr );
6566
6567 if (env) RegCloseKey( env );
6568 msi_free( deformatted );
6569 return r;
6570 }
6571
6572 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6573 {
6574 UINT rc;
6575 MSIQUERY *view;
6576 static const WCHAR query[] =
6577 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6578 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6579
6580 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6581 if (rc != ERROR_SUCCESS)
6582 return ERROR_SUCCESS;
6583
6584 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6585 msiobj_release( &view->hdr );
6586
6587 return rc;
6588 }
6589
6590 typedef struct tagMSIASSEMBLY
6591 {
6592 struct list entry;
6593 MSICOMPONENT *component;
6594 MSIFEATURE *feature;
6595 MSIFILE *file;
6596 LPWSTR manifest;
6597 LPWSTR application;
6598 LPWSTR display_name;
6599 DWORD attributes;
6600 BOOL installed;
6601 } MSIASSEMBLY;
6602
6603 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6604 DWORD dwReserved);
6605 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6606 LPVOID pvReserved, HMODULE *phModDll);
6607
6608 static BOOL init_functionpointers(void)
6609 {
6610 HRESULT hr;
6611 HMODULE hfusion;
6612 HMODULE hmscoree;
6613
6614 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6615
6616 hmscoree = LoadLibraryA("mscoree.dll");
6617 if (!hmscoree)
6618 {
6619 WARN("mscoree.dll not available\n");
6620 return FALSE;
6621 }
6622
6623 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6624 if (!pLoadLibraryShim)
6625 {
6626 WARN("LoadLibraryShim not available\n");
6627 FreeLibrary(hmscoree);
6628 return FALSE;
6629 }
6630
6631 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6632 if (FAILED(hr))
6633 {
6634 WARN("fusion.dll not available\n");
6635 FreeLibrary(hmscoree);
6636 return FALSE;
6637 }
6638
6639 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6640
6641 FreeLibrary(hmscoree);
6642 return TRUE;
6643 }
6644
6645 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6646 LPWSTR path)
6647 {
6648 IAssemblyCache *cache;
6649 MSIRECORD *uirow;
6650 HRESULT hr;
6651 UINT r = ERROR_FUNCTION_FAILED;
6652
6653 TRACE("installing assembly: %s\n", debugstr_w(path));
6654
6655 uirow = MSI_CreateRecord( 2 );
6656 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6657 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6658 msiobj_release( &uirow->hdr );
6659
6660 if (assembly->feature)
6661 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6662
6663 if (assembly->manifest)
6664 FIXME("Manifest unhandled\n");
6665
6666 if (assembly->application)
6667 {
6668 FIXME("Assembly should be privately installed\n");
6669 return ERROR_SUCCESS;
6670 }
6671
6672 if (assembly->attributes == msidbAssemblyAttributesWin32)
6673 {
6674 FIXME("Win32 assemblies not handled\n");
6675 return ERROR_SUCCESS;
6676 }
6677
6678 hr = pCreateAssemblyCache(&cache, 0);
6679 if (FAILED(hr))
6680 goto done;
6681
6682 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6683 if (FAILED(hr))
6684 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6685
6686 r = ERROR_SUCCESS;
6687
6688 done:
6689 IAssemblyCache_Release(cache);
6690 return r;
6691 }
6692
6693 typedef struct tagASSEMBLY_LIST
6694 {
6695 MSIPACKAGE *package;
6696 IAssemblyCache *cache;
6697 struct list *assemblies;
6698 } ASSEMBLY_LIST;
6699
6700 typedef struct tagASSEMBLY_NAME
6701 {
6702 LPWSTR name;
6703 LPWSTR version;
6704 LPWSTR culture;
6705 LPWSTR pubkeytoken;
6706 } ASSEMBLY_NAME;
6707
6708 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6709 {
6710 ASSEMBLY_NAME *asmname = param;
6711 LPCWSTR name = MSI_RecordGetString(rec, 2);
6712 LPWSTR val = msi_dup_record_field(rec, 3);
6713
6714 static const WCHAR Name[] = {'N','a','m','e',0};
6715 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6716 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6717 static const WCHAR PublicKeyToken[] = {
6718 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6719
6720 if (!strcmpiW(name, Name))
6721 asmname->name = val;
6722 else if (!strcmpiW(name, Version))
6723 asmname->version = val;
6724 else if (!strcmpiW(name, Culture))
6725 asmname->culture = val;
6726 else if (!strcmpiW(name, PublicKeyToken))
6727 asmname->pubkeytoken = val;
6728 else
6729 msi_free(val);
6730
6731 return ERROR_SUCCESS;
6732 }
6733
6734 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6735 {
6736 if (!*str)
6737 {
6738 *size = lstrlenW(append) + 1;
6739 *str = msi_alloc((*size) * sizeof(WCHAR));
6740 lstrcpyW(*str, append);
6741 return;
6742 }
6743
6744 (*size) += lstrlenW(append);
6745 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6746 lstrcatW(*str, append);
6747 }
6748
6749 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6750 {
6751 static const WCHAR separator[] = {',',' ',0};
6752 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6753 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6754 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6755 static const WCHAR query[] = {
6756 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6757 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6758 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6759 '=','\'','%','s','\'',0};
6760 ASSEMBLY_NAME name;
6761 MSIQUERY *view;
6762 LPWSTR display_name;
6763 DWORD size;
6764 UINT r;
6765
6766 display_name = NULL;
6767 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6768
6769 r = MSI_OpenQuery( db, &view, query, comp->Component );
6770 if (r != ERROR_SUCCESS)
6771 return NULL;
6772
6773 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6774 msiobj_release( &view->hdr );
6775
6776 if (!name.name)
6777 {
6778 ERR("No assembly name specified!\n");
6779 return NULL;
6780 }
6781
6782 append_str( &display_name, &size, name.name );
6783
6784 if (name.version)
6785 {
6786 append_str( &display_name, &size, separator );
6787 append_str( &display_name, &size, Version );
6788 append_str( &display_name, &size, name.version );
6789 }
6790 if (name.culture)
6791 {
6792 append_str( &display_name, &size, separator );
6793 append_str( &display_name, &size, Culture );
6794 append_str( &display_name, &size, name.culture );
6795 }
6796 if (name.pubkeytoken)
6797 {
6798 append_str( &display_name, &size, separator );
6799 append_str( &display_name, &size, PublicKeyToken );
6800 append_str( &display_name, &size, name.pubkeytoken );
6801 }
6802
6803 msi_free( name.name );
6804 msi_free( name.version );
6805 msi_free( name.culture );
6806 msi_free( name.pubkeytoken );
6807
6808 return display_name;
6809 }
6810
6811 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6812 {
6813 ASSEMBLY_INFO asminfo;
6814 LPWSTR disp;
6815 BOOL found = FALSE;
6816 HRESULT hr;
6817
6818 disp = get_assembly_display_name( db, comp );
6819 if (!disp)
6820 return FALSE;
6821
6822 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6823 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6824
6825 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6826 if (SUCCEEDED(hr))
6827 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6828
6829 msi_free( disp );
6830 return found;
6831 }
6832
6833 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6834 {
6835 ASSEMBLY_LIST *list = param;
6836 MSIASSEMBLY *assembly;
6837 LPCWSTR component;
6838
6839 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6840 if (!assembly)
6841 return ERROR_OUTOFMEMORY;
6842
6843 component = MSI_RecordGetString(rec, 1);
6844 assembly->component = get_loaded_component(list->package, component);
6845 if (!assembly->component)
6846 return ERROR_SUCCESS;
6847
6848 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6849 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6850 {
6851 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6852 assembly->component->Action = assembly->component->Installed;
6853 return ERROR_SUCCESS;
6854 }
6855 assembly->component->Action = assembly->component->ActionRequest;
6856
6857 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6858 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6859
6860 if (!assembly->file)
6861 {
6862 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6863 return ERROR_FUNCTION_FAILED;
6864 }
6865
6866 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6867 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6868 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6869
6870 if (assembly->application)
6871 {
6872 WCHAR version[24];
6873 DWORD size = sizeof(version)/sizeof(WCHAR);
6874
6875 /* FIXME: we should probably check the manifest file here */
6876
6877 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6878 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6879 {
6880 assembly->installed = TRUE;
6881 }
6882 }
6883 else
6884 assembly->installed = check_assembly_installed(list->package->db,
6885 list->cache,
6886 assembly->component);
6887
6888 list_add_head(list->assemblies, &assembly->entry);
6889 return ERROR_SUCCESS;
6890 }
6891
6892 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6893 {
6894 IAssemblyCache *cache = NULL;
6895 ASSEMBLY_LIST list;
6896 MSIQUERY *view;
6897 HRESULT hr;
6898 UINT r;
6899
6900 static const WCHAR query[] =
6901 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6902 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6903
6904 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6905 if (r != ERROR_SUCCESS)
6906 return ERROR_SUCCESS;
6907
6908 hr = pCreateAssemblyCache(&cache, 0);
6909 if (FAILED(hr))
6910 return ERROR_FUNCTION_FAILED;
6911
6912 list.package = package;
6913 list.cache = cache;
6914 list.assemblies = assemblies;
6915
6916 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6917 msiobj_release(&view->hdr);
6918
6919 IAssemblyCache_Release(cache);
6920
6921 return r;
6922 }
6923
6924 static void free_assemblies(struct list *assemblies)
6925 {
6926 struct list *item, *cursor;
6927
6928 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6929 {
6930 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6931
6932 list_remove(&assembly->entry);
6933 msi_free(assembly->application);
6934 msi_free(assembly->manifest);
6935 msi_free(assembly->display_name);
6936 msi_free(assembly);
6937 }
6938 }
6939
6940 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6941 {
6942 MSIASSEMBLY *assembly;
6943
6944 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6945 {
6946 if (!lstrcmpW(assembly->file->File, file))
6947 {
6948 *out = assembly;
6949 return TRUE;
6950 }
6951 }
6952
6953 return FALSE;
6954 }
6955
6956 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6957 LPWSTR *path, DWORD *attrs, PVOID user)
6958 {
6959 MSIASSEMBLY *assembly;
6960 WCHAR temppath[MAX_PATH];
6961 struct list *assemblies = user;
6962 UINT r;
6963
6964 if (!find_assembly(assemblies, file, &assembly))
6965 return FALSE;
6966
6967 GetTempPathW(MAX_PATH, temppath);
6968 PathAddBackslashW(temppath);
6969 lstrcatW(temppath, assembly->file->FileName);
6970
6971 if (action == MSICABEXTRACT_BEGINEXTRACT)
6972 {
6973 if (assembly->installed)
6974 return FALSE;
6975
6976 *path = strdupW(temppath);
6977 *attrs = assembly->file->Attributes;
6978 }
6979 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6980 {
6981 assembly->installed = TRUE;
6982
6983 r = install_assembly(package, assembly, temppath);
6984 if (r != ERROR_SUCCESS)
6985 ERR("Failed to install assembly\n");
6986 }
6987
6988 return TRUE;
6989 }
6990
6991 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6992 {
6993 UINT r;
6994 struct list assemblies = LIST_INIT(assemblies);
6995 MSIASSEMBLY *assembly;
6996 MSIMEDIAINFO *mi;
6997
6998 if (!init_functionpointers() || !pCreateAssemblyCache)
6999 return ERROR_FUNCTION_FAILED;
7000
7001 r = load_assemblies(package, &assemblies);
7002 if (r != ERROR_SUCCESS)
7003 goto done;
7004
7005 if (list_empty(&assemblies))
7006 goto done;
7007
7008 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
7009 if (!mi)
7010 {
7011 r = ERROR_OUTOFMEMORY;
7012 goto done;
7013 }
7014
7015 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
7016 {
7017 if (assembly->installed && !mi->is_continuous)
7018 continue;
7019
7020 if (assembly->file->IsCompressed)
7021 {
7022 if (assembly->file->disk_id != mi->disk_id || mi->is_continuous)
7023 {
7024 MSICABDATA data;
7025
7026 r = ready_media(package, assembly->file, mi);
7027 if (r != ERROR_SUCCESS)
7028 {
7029 ERR("Failed to ready media\n");
7030 break;
7031 }
7032
7033 data.mi = mi;
7034 data.package = package;
7035 data.cb = installassembly_cb;
7036 data.user = &assemblies;
7037
7038 if (!msi_cabextract(package, mi, &data))
7039 {
7040 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
7041 r = ERROR_FUNCTION_FAILED;
7042 break;
7043 }
7044 }
7045 }
7046 else
7047 {
7048 LPWSTR source = resolve_file_source(package, assembly->file);
7049
7050 r = install_assembly(package, assembly, source);
7051 if (r != ERROR_SUCCESS)
7052 ERR("Failed to install assembly\n");
7053
7054 msi_free(source);
7055 }
7056
7057 /* FIXME: write Installer assembly reg values */
7058 }
7059
7060 done:
7061 free_assemblies(&assemblies);
7062 return r;
7063 }
7064
7065 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7066 {
7067 LPWSTR key, template, id;
7068 UINT r = ERROR_SUCCESS;
7069
7070 id = msi_dup_property( package->db, szProductID );
7071 if (id)
7072 {
7073 msi_free( id );
7074 return ERROR_SUCCESS;
7075 }
7076 template = msi_dup_property( package->db, szPIDTemplate );
7077 key = msi_dup_property( package->db, szPIDKEY );
7078
7079 if (key && template)
7080 {
7081 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7082 r = msi_set_property( package->db, szProductID, key );
7083 }
7084 msi_free( template );
7085 msi_free( key );
7086 return r;
7087 }
7088
7089 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7090 {
7091 TRACE("\n");
7092 package->need_reboot = 1;
7093 return ERROR_SUCCESS;
7094 }
7095
7096 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7097 {
7098 static const WCHAR szAvailableFreeReg[] =
7099 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7100 MSIRECORD *uirow;
7101 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7102
7103 TRACE("%p %d kilobytes\n", package, space);
7104
7105 uirow = MSI_CreateRecord( 1 );
7106 MSI_RecordSetInteger( uirow, 1, space );
7107 ui_actiondata( package, szAllocateRegistrySpace, uirow );
7108 msiobj_release( &uirow->hdr );
7109
7110 return ERROR_SUCCESS;
7111 }
7112
7113 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7114 {
7115 FIXME("%p\n", package);
7116 return ERROR_SUCCESS;
7117 }
7118
7119 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7120 {
7121 FIXME("%p\n", package);
7122 return ERROR_SUCCESS;
7123 }
7124
7125 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7126 {
7127 UINT r, count;
7128 MSIQUERY *view;
7129
7130 static const WCHAR driver_query[] = {
7131 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7132 'O','D','B','C','D','r','i','v','e','r',0 };
7133
7134 static const WCHAR translator_query[] = {
7135 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7136 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7137
7138 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7139 if (r == ERROR_SUCCESS)
7140 {
7141 count = 0;
7142 r = MSI_IterateRecords( view, &count, NULL, package );
7143 msiobj_release( &view->hdr );
7144 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7145 }
7146
7147 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7148 if (r == ERROR_SUCCESS)
7149 {
7150 count = 0;
7151 r = MSI_IterateRecords( view, &count, NULL, package );
7152 msiobj_release( &view->hdr );
7153 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7154 }
7155
7156 return ERROR_SUCCESS;
7157 }
7158
7159 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7160 LPCSTR action, LPCWSTR table )
7161 {
7162 static const WCHAR query[] = {
7163 'S','E','L','E','C','T',' ','*',' ',
7164 'F','R','O','M',' ','`','%','s','`',0 };
7165 MSIQUERY *view = NULL;
7166 DWORD count = 0;
7167 UINT r;
7168
7169 r = MSI_OpenQuery( package->db, &view, query, table );
7170 if (r == ERROR_SUCCESS)
7171 {
7172 r = MSI_IterateRecords(view, &count, NULL, package);
7173 msiobj_release(&view->hdr);
7174 }
7175
7176 if (count)
7177 FIXME("%s -> %u ignored %s table values\n",
7178 action, count, debugstr_w(table));
7179
7180 return ERROR_SUCCESS;
7181 }
7182
7183 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7184 {
7185 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7186 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7187 }
7188
7189 static UINT ACTION_BindImage( MSIPACKAGE *package )
7190 {
7191 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7192 return msi_unimplemented_action_stub( package, "BindImage", table );
7193 }
7194
7195 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7196 {
7197 static const WCHAR table[] = {
7198 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7199 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7200 }
7201
7202 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7203 {
7204 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7205 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
7206 }
7207
7208 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7209 {
7210 static const WCHAR table[] = {
7211 'M','s','i','A','s','s','e','m','b','l','y',0 };
7212 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7213 }
7214
7215 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7216 {
7217 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7218 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7219 }
7220
7221 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7222 {
7223 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7224 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7225 }
7226
7227 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7228 {
7229 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7230 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7231 }
7232
7233 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7234 {
7235 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7236 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7237 }
7238
7239 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7240 {
7241 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7242 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
7243 }
7244
7245 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7246
7247 static const struct
7248 {
7249 const WCHAR *action;
7250 UINT (*handler)(MSIPACKAGE *);
7251 }
7252 StandardActions[] =
7253 {
7254 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7255 { szAppSearch, ACTION_AppSearch },
7256 { szBindImage, ACTION_BindImage },
7257 { szCCPSearch, ACTION_CCPSearch },
7258 { szCostFinalize, ACTION_CostFinalize },
7259 { szCostInitialize, ACTION_CostInitialize },
7260 { szCreateFolders, ACTION_CreateFolders },
7261 { szCreateShortcuts, ACTION_CreateShortcuts },
7262 { szDeleteServices, ACTION_DeleteServices },
7263 { szDisableRollback, ACTION_DisableRollback },
7264 { szDuplicateFiles, ACTION_DuplicateFiles },
7265 { szExecuteAction, ACTION_ExecuteAction },
7266 { szFileCost, ACTION_FileCost },
7267 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7268 { szForceReboot, ACTION_ForceReboot },
7269 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7270 { szInstallExecute, ACTION_InstallExecute },
7271 { szInstallExecuteAgain, ACTION_InstallExecute },
7272 { szInstallFiles, ACTION_InstallFiles},
7273 { szInstallFinalize, ACTION_InstallFinalize },
7274 { szInstallInitialize, ACTION_InstallInitialize },
7275 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7276 { szInstallValidate, ACTION_InstallValidate },
7277 { szIsolateComponents, ACTION_IsolateComponents },
7278 { szLaunchConditions, ACTION_LaunchConditions },
7279 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7280 { szMoveFiles, ACTION_MoveFiles },
7281 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7282 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7283 { szInstallODBC, ACTION_InstallODBC },
7284 { szInstallServices, ACTION_InstallServices },
7285 { szPatchFiles, ACTION_PatchFiles },
7286 { szProcessComponents, ACTION_ProcessComponents },
7287 { szPublishComponents, ACTION_PublishComponents },
7288 { szPublishFeatures, ACTION_PublishFeatures },
7289 { szPublishProduct, ACTION_PublishProduct },
7290 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7291 { szRegisterComPlus, ACTION_RegisterComPlus},
7292 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7293 { szRegisterFonts, ACTION_RegisterFonts },
7294 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7295 { szRegisterProduct, ACTION_RegisterProduct },
7296 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7297 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7298 { szRegisterUser, ACTION_RegisterUser },
7299 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7300 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7301 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7302 { szRemoveFiles, ACTION_RemoveFiles },
7303 { szRemoveFolders, ACTION_RemoveFolders },
7304 { szRemoveIniValues, ACTION_RemoveIniValues },
7305 { szRemoveODBC, ACTION_RemoveODBC },
7306 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7307 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7308 { szResolveSource, ACTION_ResolveSource },
7309 { szRMCCPSearch, ACTION_RMCCPSearch },
7310 { szScheduleReboot, ACTION_ScheduleReboot },
7311 { szSelfRegModules, ACTION_SelfRegModules },
7312 { szSelfUnregModules, ACTION_SelfUnregModules },
7313 { szSetODBCFolders, ACTION_SetODBCFolders },
7314 { szStartServices, ACTION_StartServices },
7315 { szStopServices, ACTION_StopServices },
7316 { szUnpublishComponents, ACTION_UnpublishComponents },
7317 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7318 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7319 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7320 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7321 { szUnregisterFonts, ACTION_UnregisterFonts },
7322 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7323 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7324 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7325 { szValidateProductID, ACTION_ValidateProductID },
7326 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7327 { szWriteIniValues, ACTION_WriteIniValues },
7328 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7329 { NULL, NULL },
7330 };
7331
7332 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7333 {
7334 BOOL ret = FALSE;
7335 UINT i;
7336
7337 i = 0;
7338 while (StandardActions[i].action != NULL)
7339 {
7340 if (!strcmpW( StandardActions[i].action, action ))
7341 {
7342 ui_actionstart( package, action );
7343 if (StandardActions[i].handler)
7344 {
7345 ui_actioninfo( package, action, TRUE, 0 );
7346 *rc = StandardActions[i].handler( package );
7347 ui_actioninfo( package, action, FALSE, *rc );
7348 }
7349 else
7350 {
7351 FIXME("unhandled standard action %s\n", debugstr_w(action));
7352 *rc = ERROR_SUCCESS;
7353 }
7354 ret = TRUE;
7355 break;
7356 }
7357 i++;
7358 }
7359 return ret;
7360 }
7361
7362 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7363 {
7364 UINT rc = ERROR_SUCCESS;
7365 BOOL handled;
7366
7367 TRACE("Performing action (%s)\n", debugstr_w(action));
7368
7369 handled = ACTION_HandleStandardAction(package, action, &rc);
7370
7371 if (!handled)
7372 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7373
7374 if (!handled)
7375 {
7376 WARN("unhandled msi action %s\n", debugstr_w(action));
7377 rc = ERROR_FUNCTION_NOT_CALLED;
7378 }
7379
7380 return rc;
7381 }
7382
7383 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7384 {
7385 UINT rc = ERROR_SUCCESS;
7386 BOOL handled = FALSE;
7387
7388 TRACE("Performing action (%s)\n", debugstr_w(action));
7389
7390 handled = ACTION_HandleStandardAction(package, action, &rc);
7391
7392 if (!handled)
7393 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7394
7395 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7396 handled = TRUE;
7397
7398 if (!handled)
7399 {
7400 WARN("unhandled msi action %s\n", debugstr_w(action));
7401 rc = ERROR_FUNCTION_NOT_CALLED;
7402 }
7403
7404 return rc;
7405 }
7406
7407 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7408 {
7409 UINT rc = ERROR_SUCCESS;
7410 MSIRECORD *row;
7411
7412 static const WCHAR ExecSeqQuery[] =
7413 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7414 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7415 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7416 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7417 static const WCHAR UISeqQuery[] =
7418 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7419 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7420 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7421 ' ', '=',' ','%','i',0};
7422
7423 if (needs_ui_sequence(package))
7424 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7425 else
7426 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7427
7428 if (row)
7429 {
7430 LPCWSTR action, cond;
7431
7432 TRACE("Running the actions\n");
7433
7434 /* check conditions */
7435 cond = MSI_RecordGetString(row, 2);
7436
7437 /* this is a hack to skip errors in the condition code */
7438 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7439 {
7440 msiobj_release(&row->hdr);
7441 return ERROR_SUCCESS;
7442 }
7443
7444 action = MSI_RecordGetString(row, 1);
7445 if (!action)
7446 {
7447 ERR("failed to fetch action\n");
7448 msiobj_release(&row->hdr);
7449 return ERROR_FUNCTION_FAILED;
7450 }
7451
7452 if (needs_ui_sequence(package))
7453 rc = ACTION_PerformUIAction(package, action, -1);
7454 else
7455 rc = ACTION_PerformAction(package, action, -1);
7456
7457 msiobj_release(&row->hdr);
7458 }
7459
7460 return rc;
7461 }
7462
7463 /****************************************************
7464 * TOP level entry points
7465 *****************************************************/
7466
7467 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7468 LPCWSTR szCommandLine )
7469 {
7470 UINT rc;
7471 BOOL ui_exists;
7472
7473 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7474 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7475
7476 msi_set_property( package->db, szAction, szInstall );
7477
7478 package->script->InWhatSequence = SEQUENCE_INSTALL;
7479
7480 if (szPackagePath)
7481 {
7482 LPWSTR p, dir;
7483 LPCWSTR file;
7484
7485 dir = strdupW(szPackagePath);
7486 p = strrchrW(dir, '\\');
7487 if (p)
7488 {
7489 *(++p) = 0;
7490 file = szPackagePath + (p - dir);
7491 }
7492 else
7493 {
7494 msi_free(dir);
7495 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7496 GetCurrentDirectoryW(MAX_PATH, dir);
7497 lstrcatW(dir, szBackSlash);
7498 file = szPackagePath;
7499 }
7500
7501 msi_free( package->PackagePath );
7502 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7503 if (!package->PackagePath)
7504 {
7505 msi_free(dir);
7506 return ERROR_OUTOFMEMORY;
7507 }
7508
7509 lstrcpyW(package->PackagePath, dir);
7510 lstrcatW(package->PackagePath, file);
7511 msi_free(dir);
7512
7513 msi_set_sourcedir_props(package, FALSE);
7514 }
7515
7516 msi_parse_command_line( package, szCommandLine, FALSE );
7517
7518 msi_apply_transforms( package );
7519 msi_apply_patches( package );
7520
7521 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7522 {
7523 TRACE("setting reinstall property\n");
7524 msi_set_property( package->db, szReinstall, szAll );
7525 }
7526
7527 /* properties may have been added by a transform */
7528 msi_clone_properties( package );
7529
7530 msi_parse_command_line( package, szCommandLine, FALSE );
7531 msi_adjust_privilege_properties( package );
7532 msi_set_context( package );
7533
7534 if (needs_ui_sequence( package))
7535 {
7536 package->script->InWhatSequence |= SEQUENCE_UI;
7537 rc = ACTION_ProcessUISequence(package);
7538 ui_exists = ui_sequence_exists(package);
7539 if (rc == ERROR_SUCCESS || !ui_exists)
7540 {
7541 package->script->InWhatSequence |= SEQUENCE_EXEC;
7542 rc = ACTION_ProcessExecSequence(package, ui_exists);
7543 }
7544 }
7545 else
7546 rc = ACTION_ProcessExecSequence(package, FALSE);
7547
7548 package->script->CurrentlyScripting = FALSE;
7549
7550 /* process the ending type action */
7551 if (rc == ERROR_SUCCESS)
7552 ACTION_PerformActionSequence(package, -1);
7553 else if (rc == ERROR_INSTALL_USEREXIT)
7554 ACTION_PerformActionSequence(package, -2);
7555 else if (rc == ERROR_INSTALL_SUSPEND)
7556 ACTION_PerformActionSequence(package, -4);
7557 else /* failed */
7558 ACTION_PerformActionSequence(package, -3);
7559
7560 /* finish up running custom actions */
7561 ACTION_FinishCustomActions(package);
7562
7563 if (rc == ERROR_SUCCESS && package->need_reboot)
7564 return ERROR_SUCCESS_REBOOT_REQUIRED;
7565
7566 return rc;
7567 }