Sync to Wine-0_9_1:
[reactos.git] / reactos / lib / 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 /*
22 * Pages I need
23 *
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
25
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
27 */
28
29 #include <stdarg.h>
30
31 #define COBJMACROS
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36 #include "winreg.h"
37 #include "wine/debug.h"
38 #include "msidefs.h"
39 #include "msipriv.h"
40 #include "winuser.h"
41 #include "shlobj.h"
42 #include "wine/unicode.h"
43 #include "winver.h"
44 #include "action.h"
45
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
48
49 WINE_DEFAULT_DEBUG_CHANNEL(msi);
50
51 /*
52 * Prototypes
53 */
54 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
55 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
56 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
57
58 /*
59 * consts and values used
60 */
61 static const WCHAR c_colon[] = {'C',':','\\',0};
62
63 static const WCHAR szCreateFolders[] =
64 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 static const WCHAR szCostFinalize[] =
66 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
67 const WCHAR szInstallFiles[] =
68 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
69 const WCHAR szDuplicateFiles[] =
70 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
71 static const WCHAR szWriteRegistryValues[] =
72 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
73 'V','a','l','u','e','s',0};
74 static const WCHAR szCostInitialize[] =
75 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 static const WCHAR szFileCost[] =
77 {'F','i','l','e','C','o','s','t',0};
78 static const WCHAR szInstallInitialize[] =
79 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 static const WCHAR szInstallValidate[] =
81 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 static const WCHAR szLaunchConditions[] =
83 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 static const WCHAR szProcessComponents[] =
85 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 static const WCHAR szRegisterTypeLibraries[] =
87 {'R','e','g','i','s','t','e','r','T','y','p','e',
88 'L','i','b','r','a','r','i','e','s',0};
89 const WCHAR szRegisterClassInfo[] =
90 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
91 const WCHAR szRegisterProgIdInfo[] =
92 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
93 static const WCHAR szCreateShortcuts[] =
94 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 static const WCHAR szPublishProduct[] =
96 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 static const WCHAR szWriteIniValues[] =
98 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 static const WCHAR szSelfRegModules[] =
100 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 static const WCHAR szPublishFeatures[] =
102 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 static const WCHAR szRegisterProduct[] =
104 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 static const WCHAR szInstallExecute[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 static const WCHAR szInstallExecuteAgain[] =
108 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
109 'A','g','a','i','n',0};
110 static const WCHAR szInstallFinalize[] =
111 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 static const WCHAR szForceReboot[] =
113 {'F','o','r','c','e','R','e','b','o','o','t',0};
114 static const WCHAR szResolveSource[] =
115 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
116 const WCHAR szAppSearch[] =
117 {'A','p','p','S','e','a','r','c','h',0};
118 static const WCHAR szAllocateRegistrySpace[] =
119 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
120 'S','p','a','c','e',0};
121 static const WCHAR szBindImage[] =
122 {'B','i','n','d','I','m','a','g','e',0};
123 static const WCHAR szCCPSearch[] =
124 {'C','C','P','S','e','a','r','c','h',0};
125 static const WCHAR szDeleteServices[] =
126 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szDisableRollback[] =
128 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 static const WCHAR szExecuteAction[] =
130 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
131 const WCHAR szFindRelatedProducts[] =
132 {'F','i','n','d','R','e','l','a','t','e','d',
133 'P','r','o','d','u','c','t','s',0};
134 static const WCHAR szInstallAdminPackage[] =
135 {'I','n','s','t','a','l','l','A','d','m','i','n',
136 'P','a','c','k','a','g','e',0};
137 static const WCHAR szInstallSFPCatalogFile[] =
138 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
139 'F','i','l','e',0};
140 static const WCHAR szIsolateComponents[] =
141 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
142 const WCHAR szMigrateFeatureStates[] =
143 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
144 'S','t','a','t','e','s',0};
145 const WCHAR szMoveFiles[] =
146 {'M','o','v','e','F','i','l','e','s',0};
147 static const WCHAR szMsiPublishAssemblies[] =
148 {'M','s','i','P','u','b','l','i','s','h',
149 'A','s','s','e','m','b','l','i','e','s',0};
150 static const WCHAR szMsiUnpublishAssemblies[] =
151 {'M','s','i','U','n','p','u','b','l','i','s','h',
152 'A','s','s','e','m','b','l','i','e','s',0};
153 static const WCHAR szInstallODBC[] =
154 {'I','n','s','t','a','l','l','O','D','B','C',0};
155 static const WCHAR szInstallServices[] =
156 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
157 const WCHAR szPatchFiles[] =
158 {'P','a','t','c','h','F','i','l','e','s',0};
159 static const WCHAR szPublishComponents[] =
160 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szRegisterComPlus[] =
162 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 const WCHAR szRegisterExtensionInfo[] =
164 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
165 'I','n','f','o',0};
166 static const WCHAR szRegisterFonts[] =
167 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
168 const WCHAR szRegisterMIMEInfo[] =
169 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
170 static const WCHAR szRegisterUser[] =
171 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
172 const WCHAR szRemoveDuplicateFiles[] =
173 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
174 'F','i','l','e','s',0};
175 static const WCHAR szRemoveEnvironmentStrings[] =
176 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
177 'S','t','r','i','n','g','s',0};
178 const WCHAR szRemoveExistingProducts[] =
179 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
180 'P','r','o','d','u','c','t','s',0};
181 const WCHAR szRemoveFiles[] =
182 {'R','e','m','o','v','e','F','i','l','e','s',0};
183 static const WCHAR szRemoveFolders[] =
184 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 static const WCHAR szRemoveIniValues[] =
186 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 static const WCHAR szRemoveODBC[] =
188 {'R','e','m','o','v','e','O','D','B','C',0};
189 static const WCHAR szRemoveRegistryValues[] =
190 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
191 'V','a','l','u','e','s',0};
192 static const WCHAR szRemoveShortcuts[] =
193 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 static const WCHAR szRMCCPSearch[] =
195 {'R','M','C','C','P','S','e','a','r','c','h',0};
196 static const WCHAR szScheduleReboot[] =
197 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 static const WCHAR szSelfUnregModules[] =
199 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 static const WCHAR szSetODBCFolders[] =
201 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 static const WCHAR szStartServices[] =
203 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szStopServices[] =
205 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 static const WCHAR szUnpublishComponents[] =
207 {'U','n','p','u','b','l','i','s','h',
208 'C','o','m','p','o','n','e','n','t','s',0};
209 static const WCHAR szUnpublishFeatures[] =
210 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
211 const WCHAR szUnregisterClassInfo[] =
212 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
213 'I','n','f','o',0};
214 static const WCHAR szUnregisterComPlus[] =
215 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
216 const WCHAR szUnregisterExtensionInfo[] =
217 {'U','n','r','e','g','i','s','t','e','r',
218 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
219 static const WCHAR szUnregisterFonts[] =
220 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
221 const WCHAR szUnregisterMIMEInfo[] =
222 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
223 const WCHAR szUnregisterProgIdInfo[] =
224 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
225 'I','n','f','o',0};
226 static const WCHAR szUnregisterTypeLibraries[] =
227 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
228 'L','i','b','r','a','r','i','e','s',0};
229 static const WCHAR szValidateProductID[] =
230 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 static const WCHAR szWriteEnvironmentStrings[] =
232 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
233 'S','t','r','i','n','g','s',0};
234
235 /* action handlers */
236 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
237
238 struct _actions {
239 LPCWSTR action;
240 STANDARDACTIONHANDLER handler;
241 };
242
243 static struct _actions StandardActions[];
244
245
246 /********************************************************
247 * helper functions
248 ********************************************************/
249
250 static void ce_actiontext(MSIPACKAGE* package, LPCWSTR action)
251 {
252 static const WCHAR szActionText[] =
253 {'A','c','t','i','o','n','T','e','x','t',0};
254 MSIRECORD *row;
255
256 row = MSI_CreateRecord(1);
257 MSI_RecordSetStringW(row,1,action);
258 ControlEvent_FireSubscribedEvent(package,szActionText, row);
259 msiobj_release(&row->hdr);
260 }
261
262 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
263 {
264 static const WCHAR template_s[]=
265 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
266 '.',0};
267 static const WCHAR format[] =
268 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
269 static const WCHAR Query_t[] =
270 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
271 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
272 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
273 ' ','\'','%','s','\'',0};
274 WCHAR message[1024];
275 WCHAR timet[0x100];
276 MSIRECORD * row = 0;
277 LPCWSTR ActionText;
278 LPWSTR deformated;
279
280 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
281
282 row = MSI_QueryGetRecord( package->db, Query_t, action );
283 if (!row)
284 return;
285
286 ActionText = MSI_RecordGetString(row,2);
287 deformat_string(package, ActionText, &deformated);
288
289 sprintfW(message,template_s,timet,action,deformated);
290 ce_actiontext(package, deformated);
291 msiobj_release(&row->hdr);
292
293 row = MSI_CreateRecord(1);
294 MSI_RecordSetStringW(row,1,message);
295
296 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
297 msiobj_release(&row->hdr);
298 msi_free(deformated);
299 }
300
301 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
302 UINT rc)
303 {
304 MSIRECORD * row;
305 static const WCHAR template_s[]=
306 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
307 '%','s', '.',0};
308 static const WCHAR template_e[]=
309 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
310 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
311 '%','i','.',0};
312 static const WCHAR format[] =
313 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
314 WCHAR message[1024];
315 WCHAR timet[0x100];
316
317 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
318 if (start)
319 sprintfW(message,template_s,timet,action);
320 else
321 sprintfW(message,template_e,timet,action,rc);
322
323 row = MSI_CreateRecord(1);
324 MSI_RecordSetStringW(row,1,message);
325
326 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
327 msiobj_release(&row->hdr);
328 }
329
330 static int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def )
331 {
332 LPWSTR str = msi_dup_property( package, prop );
333 int val = str ? atoiW( str ) : def;
334 msi_free( str );
335 return val;
336 }
337
338 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
339 {
340 LPCWSTR ptr,ptr2;
341 BOOL quote;
342 DWORD len;
343 LPWSTR prop = NULL, val = NULL;
344
345 if (!szCommandLine)
346 return ERROR_SUCCESS;
347
348 ptr = szCommandLine;
349
350 while (*ptr)
351 {
352 if (*ptr==' ')
353 {
354 ptr++;
355 continue;
356 }
357
358 TRACE("Looking at %s\n",debugstr_w(ptr));
359
360 ptr2 = strchrW(ptr,'=');
361 if (!ptr2)
362 {
363 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
364 break;
365 }
366
367 quote = FALSE;
368
369 len = ptr2-ptr;
370 prop = msi_alloc((len+1)*sizeof(WCHAR));
371 memcpy(prop,ptr,len*sizeof(WCHAR));
372 prop[len]=0;
373 ptr2++;
374
375 len = 0;
376 ptr = ptr2;
377 while (*ptr && (quote || (!quote && *ptr!=' ')))
378 {
379 if (*ptr == '"')
380 quote = !quote;
381 ptr++;
382 len++;
383 }
384
385 if (*ptr2=='"')
386 {
387 ptr2++;
388 len -= 2;
389 }
390 val = msi_alloc((len+1)*sizeof(WCHAR));
391 memcpy(val,ptr2,len*sizeof(WCHAR));
392 val[len] = 0;
393
394 if (lstrlenW(prop) > 0)
395 {
396 TRACE("Found commandline property (%s) = (%s)\n",
397 debugstr_w(prop), debugstr_w(val));
398 MSI_SetPropertyW(package,prop,val);
399 }
400 msi_free(val);
401 msi_free(prop);
402 }
403
404 return ERROR_SUCCESS;
405 }
406
407
408 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
409 {
410 LPWSTR p, *ret = NULL;
411 UINT count = 0;
412
413 if (!str)
414 return ret;
415
416 /* count the number of substrings */
417 for ( p = (LPWSTR)str, count = 0; p; count++ )
418 {
419 p = strchrW( p, sep );
420 if (p)
421 p++;
422 }
423
424 /* allocate space for an array of substring pointers and the substrings */
425 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
426 (lstrlenW(str)+1) * sizeof(WCHAR) );
427 if (!ret)
428 return ret;
429
430 /* copy the string and set the pointers */
431 p = (LPWSTR) &ret[count+1];
432 lstrcpyW( p, str );
433 for( count = 0; (ret[count] = p); count++ )
434 {
435 p = strchrW( p, sep );
436 if (p)
437 *p++ = 0;
438 }
439
440 return ret;
441 }
442
443 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
444 MSIDATABASE *patch_db, LPCWSTR name )
445 {
446 UINT ret = ERROR_FUNCTION_FAILED;
447 IStorage *stg = NULL;
448 HRESULT r;
449
450 TRACE("%p %s\n", package, debugstr_w(name) );
451
452 if (*name++ != ':')
453 {
454 ERR("expected a colon in %s\n", debugstr_w(name));
455 return ERROR_FUNCTION_FAILED;
456 }
457
458 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
459 if (SUCCEEDED(r))
460 {
461 ret = msi_table_apply_transform( package->db, stg );
462 IStorage_Release( stg );
463 ret = ERROR_SUCCESS;
464 }
465 else
466 ERR("failed to open substorage %s\n", debugstr_w(name));
467
468 return ret;
469 }
470
471 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
472 {
473 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
474 LPWSTR guid_list, *guids, product_id;
475 UINT i, ret = ERROR_FUNCTION_FAILED;
476
477 product_id = msi_dup_property( package, szProdID );
478 if (!product_id)
479 {
480 /* FIXME: the property ProductID should be written into the DB somewhere */
481 ERR("no product ID to check\n");
482 return ERROR_SUCCESS;
483 }
484
485 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
486 guids = msi_split_string( guid_list, ';' );
487 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
488 {
489 if (!lstrcmpW( guids[i], product_id ))
490 ret = ERROR_SUCCESS;
491 }
492 msi_free( guids );
493 msi_free( guid_list );
494 msi_free( product_id );
495
496 return ret;
497 }
498
499 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
500 {
501 MSISUMMARYINFO *si;
502 LPWSTR str, *substorage;
503 UINT i, r = ERROR_SUCCESS;
504
505 si = MSI_GetSummaryInformationW( patch_db, 0 );
506 if (!si)
507 return ERROR_FUNCTION_FAILED;
508
509 msi_check_patch_applicable( package, si );
510
511 /* enumerate the substorage */
512 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
513 substorage = msi_split_string( str, ';' );
514 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
515 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
516 msi_free( substorage );
517 msi_free( str );
518
519 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
520
521 msiobj_release( &si->hdr );
522
523 return r;
524 }
525
526 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
527 {
528 MSIDATABASE *patch_db = NULL;
529 UINT r;
530
531 TRACE("%p %s\n", package, debugstr_w( file ) );
532
533 /* FIXME:
534 * We probably want to make sure we only open a patch collection here.
535 * Patch collections (.msp) and databases (.msi) have different GUIDs
536 * but currently MSI_OpenDatabaseW will accept both.
537 */
538 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
539 if ( r != ERROR_SUCCESS )
540 {
541 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
542 return r;
543 }
544
545 msi_parse_patch_summary( package, patch_db );
546 msiobj_release( &patch_db->hdr );
547
548 return ERROR_SUCCESS;
549 }
550
551 /* get the PATCH property, and apply all the patches it specifies */
552 static UINT msi_apply_patches( MSIPACKAGE *package )
553 {
554 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
555 LPWSTR patch_list, *patches;
556 UINT i, r = ERROR_SUCCESS;
557
558 patch_list = msi_dup_property( package, szPatch );
559
560 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
561
562 patches = msi_split_string( patch_list, ';' );
563 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
564 r = msi_apply_patch_package( package, patches[i] );
565
566 msi_free( patches );
567 msi_free( patch_list );
568
569 return r;
570 }
571
572 /****************************************************
573 * TOP level entry points
574 *****************************************************/
575
576 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
577 LPCWSTR szCommandLine )
578 {
579 UINT rc;
580 BOOL ui = FALSE;
581 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
582 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
583 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
584
585 MSI_SetPropertyW(package, szAction, szInstall);
586
587 package->script = msi_alloc(sizeof(MSISCRIPT));
588 memset(package->script,0,sizeof(MSISCRIPT));
589
590 package->script->InWhatSequence = SEQUENCE_INSTALL;
591
592 if (szPackagePath)
593 {
594 LPWSTR p, check, path;
595
596 package->PackagePath = strdupW(szPackagePath);
597 path = strdupW(szPackagePath);
598 p = strrchrW(path,'\\');
599 if (p)
600 {
601 p++;
602 *p=0;
603 }
604 else
605 {
606 msi_free(path);
607 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
608 GetCurrentDirectoryW(MAX_PATH,path);
609 strcatW(path,cszbs);
610 }
611
612 check = msi_dup_property( package, cszSourceDir );
613 if (!check)
614 MSI_SetPropertyW(package, cszSourceDir, path);
615 msi_free(check);
616 msi_free(path);
617 }
618
619 msi_parse_command_line( package, szCommandLine );
620
621 msi_apply_patches( package );
622
623 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
624 {
625 package->script->InWhatSequence |= SEQUENCE_UI;
626 rc = ACTION_ProcessUISequence(package);
627 ui = TRUE;
628 if (rc == ERROR_SUCCESS)
629 {
630 package->script->InWhatSequence |= SEQUENCE_EXEC;
631 rc = ACTION_ProcessExecSequence(package,TRUE);
632 }
633 }
634 else
635 rc = ACTION_ProcessExecSequence(package,FALSE);
636
637 if (rc == -1)
638 {
639 /* install was halted but should be considered a success */
640 rc = ERROR_SUCCESS;
641 }
642
643 package->script->CurrentlyScripting= FALSE;
644
645 /* process the ending type action */
646 if (rc == ERROR_SUCCESS)
647 ACTION_PerformActionSequence(package,-1,ui);
648 else if (rc == ERROR_INSTALL_USEREXIT)
649 ACTION_PerformActionSequence(package,-2,ui);
650 else if (rc == ERROR_INSTALL_SUSPEND)
651 ACTION_PerformActionSequence(package,-4,ui);
652 else /* failed */
653 ACTION_PerformActionSequence(package,-3,ui);
654
655 /* finish up running custom actions */
656 ACTION_FinishCustomActions(package);
657
658 return rc;
659 }
660
661 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
662 {
663 UINT rc = ERROR_SUCCESS;
664 MSIRECORD * row = 0;
665 static const WCHAR ExecSeqQuery[] =
666 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
667 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
668 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
669 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
670
671 static const WCHAR UISeqQuery[] =
672 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
673 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
674 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
675 ' ', '=',' ','%','i',0};
676
677 if (UI)
678 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
679 else
680 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
681
682 if (row)
683 {
684 LPCWSTR action, cond;
685
686 TRACE("Running the actions\n");
687
688 /* check conditions */
689 cond = MSI_RecordGetString(row,2);
690 if (cond)
691 {
692 /* this is a hack to skip errors in the condition code */
693 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
694 goto end;
695 }
696
697 action = MSI_RecordGetString(row,1);
698 if (!action)
699 {
700 ERR("failed to fetch action\n");
701 rc = ERROR_FUNCTION_FAILED;
702 goto end;
703 }
704
705 if (UI)
706 rc = ACTION_PerformUIAction(package,action);
707 else
708 rc = ACTION_PerformAction(package,action,FALSE);
709 end:
710 msiobj_release(&row->hdr);
711 }
712 else
713 rc = ERROR_SUCCESS;
714
715 return rc;
716 }
717
718 typedef struct {
719 MSIPACKAGE* package;
720 BOOL UI;
721 } iterate_action_param;
722
723 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
724 {
725 iterate_action_param *iap= (iterate_action_param*)param;
726 UINT rc;
727 LPCWSTR cond, action;
728
729 action = MSI_RecordGetString(row,1);
730 if (!action)
731 {
732 ERR("Error is retrieving action name\n");
733 return ERROR_FUNCTION_FAILED;
734 }
735
736 /* check conditions */
737 cond = MSI_RecordGetString(row,2);
738 if (cond)
739 {
740 /* this is a hack to skip errors in the condition code */
741 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
742 {
743 TRACE("Skipping action: %s (condition is false)\n",
744 debugstr_w(action));
745 return ERROR_SUCCESS;
746 }
747 }
748
749 if (iap->UI)
750 rc = ACTION_PerformUIAction(iap->package,action);
751 else
752 rc = ACTION_PerformAction(iap->package,action,FALSE);
753
754 msi_dialog_check_messages( NULL );
755
756 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
757 rc = iap->package->CurrentInstallState;
758
759 if (rc == ERROR_FUNCTION_NOT_CALLED)
760 rc = ERROR_SUCCESS;
761
762 if (rc != ERROR_SUCCESS)
763 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
764
765 return rc;
766 }
767
768 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
769 {
770 MSIQUERY * view;
771 UINT r;
772 static const WCHAR query[] =
773 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
774 '`','%','s','`',
775 ' ','W','H','E','R','E',' ',
776 '`','S','e','q','u','e','n','c','e','`',' ',
777 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
778 '`','S','e','q','u','e','n','c','e','`',0};
779 iterate_action_param iap;
780
781 /*
782 * FIXME: probably should be checking UILevel in the
783 * ACTION_PerformUIAction/ACTION_PerformAction
784 * rather than saving the UI level here. Those
785 * two functions can be merged too.
786 */
787 iap.package = package;
788 iap.UI = TRUE;
789
790 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
791
792 r = MSI_OpenQuery( package->db, &view, query, szTable );
793 if (r == ERROR_SUCCESS)
794 {
795 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
796 msiobj_release(&view->hdr);
797 }
798
799 return r;
800 }
801
802 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
803 {
804 MSIQUERY * view;
805 UINT rc;
806 static const WCHAR ExecSeqQuery[] =
807 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
808 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
809 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
810 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
811 'O','R','D','E','R',' ', 'B','Y',' ',
812 '`','S','e','q','u','e','n','c','e','`',0 };
813 MSIRECORD * row = 0;
814 static const WCHAR IVQuery[] =
815 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
816 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
817 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
818 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
819 ' ','\'', 'I','n','s','t','a','l','l',
820 'V','a','l','i','d','a','t','e','\'', 0};
821 INT seq = 0;
822 iterate_action_param iap;
823
824 iap.package = package;
825 iap.UI = FALSE;
826
827 if (package->script->ExecuteSequenceRun)
828 {
829 TRACE("Execute Sequence already Run\n");
830 return ERROR_SUCCESS;
831 }
832
833 package->script->ExecuteSequenceRun = TRUE;
834
835 /* get the sequence number */
836 if (UIran)
837 {
838 row = MSI_QueryGetRecord(package->db, IVQuery);
839 if( !row )
840 return ERROR_FUNCTION_FAILED;
841 seq = MSI_RecordGetInteger(row,1);
842 msiobj_release(&row->hdr);
843 }
844
845 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
846 if (rc == ERROR_SUCCESS)
847 {
848 TRACE("Running the actions\n");
849
850 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
851 msiobj_release(&view->hdr);
852 }
853
854 return rc;
855 }
856
857 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
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',
864 'U','I','S','e','q','u','e','n','c','e','`',
865 ' ','W','H','E','R','E',' ',
866 '`','S','e','q','u','e','n','c','e','`',' ',
867 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
868 '`','S','e','q','u','e','n','c','e','`',0};
869 iterate_action_param iap;
870
871 iap.package = package;
872 iap.UI = TRUE;
873
874 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
875
876 if (rc == ERROR_SUCCESS)
877 {
878 TRACE("Running the actions\n");
879
880 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
881 msiobj_release(&view->hdr);
882 }
883
884 return rc;
885 }
886
887 /********************************************************
888 * ACTION helper functions and functions that perform the actions
889 *******************************************************/
890 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
891 UINT* rc, BOOL force )
892 {
893 BOOL ret = FALSE;
894 BOOL run = force;
895 int i;
896
897 if (!package)
898 {
899 ERR("package was null!\n");
900 return FALSE;
901 }
902
903 if (!run && !package->script->CurrentlyScripting)
904 run = TRUE;
905
906 if (!run)
907 {
908 if (strcmpW(action,szInstallFinalize) == 0 ||
909 strcmpW(action,szInstallExecute) == 0 ||
910 strcmpW(action,szInstallExecuteAgain) == 0)
911 run = TRUE;
912 }
913
914 i = 0;
915 while (StandardActions[i].action != NULL)
916 {
917 if (strcmpW(StandardActions[i].action, action)==0)
918 {
919 if (!run)
920 {
921 ui_actioninfo(package, action, TRUE, 0);
922 *rc = schedule_action(package,INSTALL_SCRIPT,action);
923 ui_actioninfo(package, action, FALSE, *rc);
924 }
925 else
926 {
927 ui_actionstart(package, action);
928 if (StandardActions[i].handler)
929 {
930 *rc = StandardActions[i].handler(package);
931 }
932 else
933 {
934 FIXME("unhandled standard action %s\n",debugstr_w(action));
935 *rc = ERROR_SUCCESS;
936 }
937 }
938 ret = TRUE;
939 break;
940 }
941 i++;
942 }
943 return ret;
944 }
945
946 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
947 UINT* rc, BOOL force )
948 {
949 BOOL ret=FALSE;
950 UINT arc;
951
952 arc = ACTION_CustomAction(package,action, force);
953
954 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
955 {
956 *rc = arc;
957 ret = TRUE;
958 }
959 return ret;
960 }
961
962 /*
963 * A lot of actions are really important even if they don't do anything
964 * explicit... Lots of properties are set at the beginning of the installation
965 * CostFinalize does a bunch of work to translate the directories and such
966 *
967 * But until I get write access to the database that is hard, so I am going to
968 * hack it to see if I can get something to run.
969 */
970 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
971 {
972 UINT rc = ERROR_SUCCESS;
973 BOOL handled;
974
975 TRACE("Performing action (%s)\n",debugstr_w(action));
976
977 handled = ACTION_HandleStandardAction(package, action, &rc, force);
978
979 if (!handled)
980 handled = ACTION_HandleCustomAction(package, action, &rc, force);
981
982 if (!handled)
983 {
984 FIXME("unhandled msi action %s\n",debugstr_w(action));
985 rc = ERROR_FUNCTION_NOT_CALLED;
986 }
987
988 return rc;
989 }
990
991 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
992 {
993 UINT rc = ERROR_SUCCESS;
994 BOOL handled = FALSE;
995
996 TRACE("Performing action (%s)\n",debugstr_w(action));
997
998 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
999
1000 if (!handled)
1001 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1002
1003 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1004 handled = TRUE;
1005
1006 if (!handled)
1007 {
1008 FIXME("unhandled msi action %s\n",debugstr_w(action));
1009 rc = ERROR_FUNCTION_NOT_CALLED;
1010 }
1011
1012 return rc;
1013 }
1014
1015
1016 /*
1017 * Actual Action Handlers
1018 */
1019
1020 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1021 {
1022 MSIPACKAGE *package = (MSIPACKAGE*)param;
1023 LPCWSTR dir;
1024 LPWSTR full_path;
1025 MSIRECORD *uirow;
1026 MSIFOLDER *folder;
1027
1028 dir = MSI_RecordGetString(row,1);
1029 if (!dir)
1030 {
1031 ERR("Unable to get folder id\n");
1032 return ERROR_SUCCESS;
1033 }
1034
1035 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1036 if (!full_path)
1037 {
1038 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1039 return ERROR_SUCCESS;
1040 }
1041
1042 TRACE("Folder is %s\n",debugstr_w(full_path));
1043
1044 /* UI stuff */
1045 uirow = MSI_CreateRecord(1);
1046 MSI_RecordSetStringW(uirow,1,full_path);
1047 ui_actiondata(package,szCreateFolders,uirow);
1048 msiobj_release( &uirow->hdr );
1049
1050 if (folder->State == 0)
1051 create_full_pathW(full_path);
1052
1053 folder->State = 3;
1054
1055 msi_free(full_path);
1056 return ERROR_SUCCESS;
1057 }
1058
1059 /* FIXME: probably should merge this with the above function */
1060 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1061 {
1062 UINT rc = ERROR_SUCCESS;
1063 MSIFOLDER *folder;
1064 LPWSTR install_path;
1065
1066 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1067 if (!install_path)
1068 return ERROR_FUNCTION_FAILED;
1069
1070 /* create the path */
1071 if (folder->State == 0)
1072 {
1073 create_full_pathW(install_path);
1074 folder->State = 2;
1075 }
1076 msi_free(install_path);
1077
1078 return rc;
1079 }
1080
1081 UINT msi_create_component_directories( MSIPACKAGE *package )
1082 {
1083 MSICOMPONENT *comp;
1084
1085 /* create all the folders required by the components are going to install */
1086 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1087 {
1088 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1089 continue;
1090 msi_create_directory( package, comp->Directory );
1091 }
1092
1093 return ERROR_SUCCESS;
1094 }
1095
1096 /*
1097 * Also we cannot enable/disable components either, so for now I am just going
1098 * to do all the directories for all the components.
1099 */
1100 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1101 {
1102 static const WCHAR ExecSeqQuery[] =
1103 {'S','E','L','E','C','T',' ',
1104 '`','D','i','r','e','c','t','o','r','y','_','`',
1105 ' ','F','R','O','M',' ',
1106 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1107 UINT rc;
1108 MSIQUERY *view;
1109
1110 /* create all the empty folders specified in the CreateFolder table */
1111 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1112 if (rc != ERROR_SUCCESS)
1113 return ERROR_SUCCESS;
1114
1115 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1116 msiobj_release(&view->hdr);
1117
1118 msi_create_component_directories( package );
1119
1120 return rc;
1121 }
1122
1123 static MSICOMPONENT* load_component( MSIRECORD * row )
1124 {
1125 MSICOMPONENT *comp;
1126
1127 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1128 if (!comp)
1129 return comp;
1130
1131 /* fill in the data */
1132 comp->Component = msi_dup_record_field( row, 1 );
1133
1134 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1135
1136 comp->ComponentId = msi_dup_record_field( row, 2 );
1137 comp->Directory = msi_dup_record_field( row, 3 );
1138 comp->Attributes = MSI_RecordGetInteger(row,4);
1139 comp->Condition = msi_dup_record_field( row, 5 );
1140 comp->KeyPath = msi_dup_record_field( row, 6 );
1141
1142 comp->Installed = INSTALLSTATE_ABSENT;
1143 comp->Action = INSTALLSTATE_UNKNOWN;
1144 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1145
1146 comp->Enabled = TRUE;
1147
1148 return comp;
1149 }
1150
1151 typedef struct {
1152 MSIPACKAGE *package;
1153 MSIFEATURE *feature;
1154 } _ilfs;
1155
1156 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1157 {
1158 ComponentList *cl;
1159
1160 cl = msi_alloc( sizeof (*cl) );
1161 if ( !cl )
1162 return ERROR_NOT_ENOUGH_MEMORY;
1163 cl->component = comp;
1164 list_add_tail( &feature->Components, &cl->entry );
1165
1166 return ERROR_SUCCESS;
1167 }
1168
1169 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1170 {
1171 _ilfs* ilfs= (_ilfs*)param;
1172 MSIPACKAGE *package = ilfs->package;
1173 MSIFEATURE *feature = ilfs->feature;
1174 MSICOMPONENT *comp;
1175
1176 comp = load_component( row );
1177 if (!comp)
1178 return ERROR_FUNCTION_FAILED;
1179
1180 list_add_tail( &package->components, &comp->entry );
1181 add_feature_component( feature, comp );
1182
1183 TRACE("Loaded new component %p\n", comp);
1184
1185 return ERROR_SUCCESS;
1186 }
1187
1188 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1189 {
1190 _ilfs* ilfs= (_ilfs*)param;
1191 LPCWSTR component;
1192 DWORD rc;
1193 MSICOMPONENT *comp;
1194 MSIQUERY * view;
1195 static const WCHAR Query[] =
1196 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1197 '`','C','o','m','p','o','n','e','n','t','`',' ',
1198 'W','H','E','R','E',' ',
1199 '`','C','o','m','p','o','n','e','n','t','`',' ',
1200 '=','\'','%','s','\'',0};
1201
1202 component = MSI_RecordGetString(row,1);
1203
1204 /* check to see if the component is already loaded */
1205 comp = get_loaded_component( ilfs->package, component );
1206 if (comp)
1207 {
1208 TRACE("Component %s already loaded\n", debugstr_w(component) );
1209 add_feature_component( ilfs->feature, comp );
1210 return ERROR_SUCCESS;
1211 }
1212
1213 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1214 if (rc != ERROR_SUCCESS)
1215 return ERROR_SUCCESS;
1216
1217 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1218 msiobj_release( &view->hdr );
1219
1220 return ERROR_SUCCESS;
1221 }
1222
1223 static UINT load_feature(MSIRECORD * row, LPVOID param)
1224 {
1225 MSIPACKAGE* package = (MSIPACKAGE*)param;
1226 MSIFEATURE* feature;
1227 static const WCHAR Query1[] =
1228 {'S','E','L','E','C','T',' ',
1229 '`','C','o','m','p','o','n','e','n','t','_','`',
1230 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1231 'C','o','m','p','o','n','e','n','t','s','`',' ',
1232 'W','H','E','R','E',' ',
1233 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1234 MSIQUERY * view;
1235 UINT rc;
1236 _ilfs ilfs;
1237
1238 /* fill in the data */
1239
1240 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1241 if (!feature)
1242 return ERROR_NOT_ENOUGH_MEMORY;
1243
1244 list_init( &feature->Components );
1245
1246 feature->Feature = msi_dup_record_field( row, 1 );
1247
1248 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1249
1250 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1251 feature->Title = msi_dup_record_field( row, 3 );
1252 feature->Description = msi_dup_record_field( row, 4 );
1253
1254 if (!MSI_RecordIsNull(row,5))
1255 feature->Display = MSI_RecordGetInteger(row,5);
1256
1257 feature->Level= MSI_RecordGetInteger(row,6);
1258 feature->Directory = msi_dup_record_field( row, 7 );
1259 feature->Attributes = MSI_RecordGetInteger(row,8);
1260
1261 feature->Installed = INSTALLSTATE_ABSENT;
1262 feature->Action = INSTALLSTATE_UNKNOWN;
1263 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1264
1265 list_add_tail( &package->features, &feature->entry );
1266
1267 /* load feature components */
1268
1269 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1270 if (rc != ERROR_SUCCESS)
1271 return ERROR_SUCCESS;
1272
1273 ilfs.package = package;
1274 ilfs.feature = feature;
1275
1276 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1277 msiobj_release(&view->hdr);
1278
1279 return ERROR_SUCCESS;
1280 }
1281
1282 static UINT load_file(MSIRECORD *row, LPVOID param)
1283 {
1284 MSIPACKAGE* package = (MSIPACKAGE*)param;
1285 LPCWSTR component;
1286 MSIFILE *file;
1287
1288 /* fill in the data */
1289
1290 file = msi_alloc_zero( sizeof (MSIFILE) );
1291 if (!file)
1292 return ERROR_NOT_ENOUGH_MEMORY;
1293
1294 file->File = msi_dup_record_field( row, 1 );
1295
1296 component = MSI_RecordGetString( row, 2 );
1297 file->Component = get_loaded_component( package, component );
1298
1299 if (!file->Component)
1300 ERR("Unfound Component %s\n",debugstr_w(component));
1301
1302 file->FileName = msi_dup_record_field( row, 3 );
1303 reduce_to_longfilename( file->FileName );
1304
1305 file->ShortName = msi_dup_record_field( row, 3 );
1306 reduce_to_shortfilename( file->ShortName );
1307
1308 file->FileSize = MSI_RecordGetInteger( row, 4 );
1309 file->Version = msi_dup_record_field( row, 5 );
1310 file->Language = msi_dup_record_field( row, 6 );
1311 file->Attributes = MSI_RecordGetInteger( row, 7 );
1312 file->Sequence = MSI_RecordGetInteger( row, 8 );
1313
1314 file->state = msifs_invalid;
1315
1316 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1317
1318 list_add_tail( &package->files, &file->entry );
1319
1320 return ERROR_SUCCESS;
1321 }
1322
1323 static UINT load_all_files(MSIPACKAGE *package)
1324 {
1325 MSIQUERY * view;
1326 UINT rc;
1327 static const WCHAR Query[] =
1328 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1329 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1330 '`','S','e','q','u','e','n','c','e','`', 0};
1331
1332 if (!package)
1333 return ERROR_INVALID_HANDLE;
1334
1335 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1336 if (rc != ERROR_SUCCESS)
1337 return ERROR_SUCCESS;
1338
1339 rc = MSI_IterateRecords(view, NULL, load_file, package);
1340 msiobj_release(&view->hdr);
1341
1342 return ERROR_SUCCESS;
1343 }
1344
1345
1346 /*
1347 * I am not doing any of the costing functionality yet.
1348 * Mostly looking at doing the Component and Feature loading
1349 *
1350 * The native MSI does A LOT of modification to tables here. Mostly adding
1351 * a lot of temporary columns to the Feature and Component tables.
1352 *
1353 * note: Native msi also tracks the short filename. But I am only going to
1354 * track the long ones. Also looking at this directory table
1355 * it appears that the directory table does not get the parents
1356 * resolved base on property only based on their entries in the
1357 * directory table.
1358 */
1359 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1360 {
1361 MSIQUERY * view;
1362 UINT rc;
1363 static const WCHAR Query_all[] =
1364 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1365 '`','F','e','a','t','u','r','e','`',0};
1366 static const WCHAR szCosting[] =
1367 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1368 static const WCHAR szZero[] = { '0', 0 };
1369
1370 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1371 return ERROR_SUCCESS;
1372
1373 MSI_SetPropertyW(package, szCosting, szZero);
1374 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1375
1376 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1377 if (rc != ERROR_SUCCESS)
1378 return rc;
1379
1380 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1381 msiobj_release(&view->hdr);
1382
1383 load_all_files(package);
1384
1385 return ERROR_SUCCESS;
1386 }
1387
1388 static UINT execute_script(MSIPACKAGE *package, UINT script )
1389 {
1390 int i;
1391 UINT rc = ERROR_SUCCESS;
1392
1393 TRACE("Executing Script %i\n",script);
1394
1395 for (i = 0; i < package->script->ActionCount[script]; i++)
1396 {
1397 LPWSTR action;
1398 action = package->script->Actions[script][i];
1399 ui_actionstart(package, action);
1400 TRACE("Executing Action (%s)\n",debugstr_w(action));
1401 rc = ACTION_PerformAction(package, action, TRUE);
1402 msi_free(package->script->Actions[script][i]);
1403 if (rc != ERROR_SUCCESS)
1404 break;
1405 }
1406 msi_free(package->script->Actions[script]);
1407
1408 package->script->ActionCount[script] = 0;
1409 package->script->Actions[script] = NULL;
1410 return rc;
1411 }
1412
1413 static UINT ACTION_FileCost(MSIPACKAGE *package)
1414 {
1415 return ERROR_SUCCESS;
1416 }
1417
1418
1419 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1420 {
1421 static const WCHAR Query[] =
1422 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1423 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1424 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1425 ' ','=',' ','\'','%','s','\'',
1426 0};
1427 LPWSTR ptargetdir, targetdir, srcdir;
1428 LPCWSTR parent;
1429 LPWSTR shortname = NULL;
1430 MSIRECORD * row = 0;
1431 MSIFOLDER *folder;
1432
1433 TRACE("Looking for dir %s\n",debugstr_w(dir));
1434
1435 folder = get_loaded_folder( package, dir );
1436 if (folder)
1437 return folder;
1438
1439 TRACE("Working to load %s\n",debugstr_w(dir));
1440
1441 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1442 if (!folder)
1443 return NULL;
1444
1445 folder->Directory = strdupW(dir);
1446
1447 row = MSI_QueryGetRecord(package->db, Query, dir);
1448 if (!row)
1449 return NULL;
1450
1451 ptargetdir = targetdir = msi_dup_record_field(row,3);
1452
1453 /* split src and target dir */
1454 if (strchrW(targetdir,':'))
1455 {
1456 srcdir=strchrW(targetdir,':');
1457 *srcdir=0;
1458 srcdir ++;
1459 }
1460 else
1461 srcdir=NULL;
1462
1463 /* for now only pick long filename versions */
1464 if (strchrW(targetdir,'|'))
1465 {
1466 shortname = targetdir;
1467 targetdir = strchrW(targetdir,'|');
1468 *targetdir = 0;
1469 targetdir ++;
1470 }
1471 /* for the sourcedir pick the short filename */
1472 if (srcdir && strchrW(srcdir,'|'))
1473 {
1474 LPWSTR p = strchrW(srcdir,'|');
1475 *p = 0;
1476 }
1477
1478 /* now check for root dirs */
1479 if (targetdir[0] == '.' && targetdir[1] == 0)
1480 targetdir = NULL;
1481
1482 if (targetdir)
1483 {
1484 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
1485 msi_free( folder->TargetDefault);
1486 folder->TargetDefault = strdupW(targetdir);
1487 }
1488
1489 if (srcdir)
1490 folder->SourceDefault = strdupW(srcdir);
1491 else if (shortname)
1492 folder->SourceDefault = strdupW(shortname);
1493 else if (targetdir)
1494 folder->SourceDefault = strdupW(targetdir);
1495 msi_free(ptargetdir);
1496 TRACE(" SourceDefault = %s\n", debugstr_w( folder->SourceDefault ));
1497
1498 parent = MSI_RecordGetString(row,2);
1499 if (parent)
1500 {
1501 folder->Parent = load_folder( package, parent );
1502 if ( folder->Parent )
1503 TRACE("loaded parent %p %s\n", folder->Parent,
1504 debugstr_w(folder->Parent->Directory));
1505 else
1506 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1507 }
1508
1509 folder->Property = msi_dup_property( package, dir );
1510
1511 msiobj_release(&row->hdr);
1512
1513 list_add_tail( &package->folders, &folder->entry );
1514
1515 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1516
1517 return folder;
1518 }
1519
1520 /* scan for and update current install states */
1521 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1522 {
1523 MSICOMPONENT *comp;
1524 MSIFEATURE *feature;
1525
1526 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1527 {
1528 INSTALLSTATE res;
1529 res = MsiGetComponentPathW( package->ProductCode,
1530 comp->ComponentId, NULL, NULL);
1531 if (res < 0)
1532 res = INSTALLSTATE_ABSENT;
1533 comp->Installed = res;
1534 }
1535
1536 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1537 {
1538 ComponentList *cl;
1539 INSTALLSTATE res = -10;
1540
1541 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1542 {
1543 comp= cl->component;
1544
1545 if (res == -10)
1546 res = comp->Installed;
1547 else
1548 {
1549 if (res == comp->Installed)
1550 continue;
1551
1552 if (res != comp->Installed)
1553 res = INSTALLSTATE_INCOMPLETE;
1554 }
1555 }
1556 feature->Installed = res;
1557 }
1558 }
1559
1560 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1561 INSTALLSTATE state)
1562 {
1563 static const WCHAR all[]={'A','L','L',0};
1564 LPWSTR override;
1565 MSIFEATURE *feature;
1566
1567 override = msi_dup_property( package, property );
1568 if (!override)
1569 return FALSE;
1570
1571 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1572 {
1573 if (strcmpiW(override,all)==0)
1574 {
1575 feature->ActionRequest= state;
1576 feature->Action = state;
1577 }
1578 else
1579 {
1580 LPWSTR ptr = override;
1581 LPWSTR ptr2 = strchrW(override,',');
1582
1583 while (ptr)
1584 {
1585 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1586 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1587 {
1588 feature->ActionRequest= state;
1589 feature->Action = state;
1590 break;
1591 }
1592 if (ptr2)
1593 {
1594 ptr=ptr2+1;
1595 ptr2 = strchrW(ptr,',');
1596 }
1597 else
1598 break;
1599 }
1600 }
1601 }
1602 msi_free(override);
1603
1604 return TRUE;
1605 }
1606
1607 static UINT SetFeatureStates(MSIPACKAGE *package)
1608 {
1609 int install_level;
1610 static const WCHAR szlevel[] =
1611 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1612 static const WCHAR szAddLocal[] =
1613 {'A','D','D','L','O','C','A','L',0};
1614 static const WCHAR szRemove[] =
1615 {'R','E','M','O','V','E',0};
1616 static const WCHAR szReinstall[] =
1617 {'R','E','I','N','S','T','A','L','L',0};
1618 BOOL override = FALSE;
1619 MSICOMPONENT* component;
1620 MSIFEATURE *feature;
1621
1622
1623 /* I do not know if this is where it should happen.. but */
1624
1625 TRACE("Checking Install Level\n");
1626
1627 install_level = msi_get_property_int( package, szlevel, 1 );
1628
1629 /* ok hereis the _real_ rub
1630 * all these activation/deactivation things happen in order and things
1631 * later on the list override things earlier on the list.
1632 * 1) INSTALLLEVEL processing
1633 * 2) ADDLOCAL
1634 * 3) REMOVE
1635 * 4) ADDSOURCE
1636 * 5) ADDDEFAULT
1637 * 6) REINSTALL
1638 * 7) COMPADDLOCAL
1639 * 8) COMPADDSOURCE
1640 * 9) FILEADDLOCAL
1641 * 10) FILEADDSOURCE
1642 * 11) FILEADDDEFAULT
1643 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1644 * ignored for all the features. seems strange, especially since it is not
1645 * documented anywhere, but it is how it works.
1646 *
1647 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1648 * REMOVE are the big ones, since we don't handle administrative installs
1649 * yet anyway.
1650 */
1651 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1652 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1653 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1654
1655 if (!override)
1656 {
1657 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1658 {
1659 BOOL feature_state = ((feature->Level > 0) &&
1660 (feature->Level <= install_level));
1661
1662 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1663 {
1664 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1665 {
1666 feature->ActionRequest = INSTALLSTATE_SOURCE;
1667 feature->Action = INSTALLSTATE_SOURCE;
1668 }
1669 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1670 {
1671 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1672 feature->Action = INSTALLSTATE_ADVERTISED;
1673 }
1674 else
1675 {
1676 feature->ActionRequest = INSTALLSTATE_LOCAL;
1677 feature->Action = INSTALLSTATE_LOCAL;
1678 }
1679 }
1680 }
1681 }
1682 else
1683 {
1684 /* set the Preselected Property */
1685 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1686 static const WCHAR szOne[] = { '1', 0 };
1687
1688 MSI_SetPropertyW(package,szPreselected,szOne);
1689 }
1690
1691 /*
1692 * now we want to enable or disable components base on feature
1693 */
1694
1695 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1696 {
1697 ComponentList *cl;
1698
1699 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1700 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1701 feature->ActionRequest);
1702
1703 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1704 {
1705 component = cl->component;
1706
1707 if (!component->Enabled)
1708 {
1709 component->Action = INSTALLSTATE_UNKNOWN;
1710 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1711 }
1712 else
1713 {
1714 if (feature->Action == INSTALLSTATE_LOCAL)
1715 {
1716 component->Action = INSTALLSTATE_LOCAL;
1717 component->ActionRequest = INSTALLSTATE_LOCAL;
1718 }
1719 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1720 {
1721 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1722 (component->Action == INSTALLSTATE_ABSENT) ||
1723 (component->Action == INSTALLSTATE_ADVERTISED))
1724
1725 {
1726 component->Action = INSTALLSTATE_SOURCE;
1727 component->ActionRequest = INSTALLSTATE_SOURCE;
1728 }
1729 }
1730 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1731 {
1732 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1733 (component->Action == INSTALLSTATE_ABSENT))
1734
1735 {
1736 component->Action = INSTALLSTATE_ADVERTISED;
1737 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1738 }
1739 }
1740 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1741 {
1742 if (component->Action == INSTALLSTATE_UNKNOWN)
1743 {
1744 component->Action = INSTALLSTATE_ABSENT;
1745 component->ActionRequest = INSTALLSTATE_ABSENT;
1746 }
1747 }
1748 }
1749 }
1750 }
1751
1752 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1753 {
1754 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1755 debugstr_w(component->Component), component->Installed,
1756 component->Action, component->ActionRequest);
1757 }
1758
1759
1760 return ERROR_SUCCESS;
1761 }
1762
1763 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1764 {
1765 MSIPACKAGE *package = (MSIPACKAGE*)param;
1766 LPCWSTR name;
1767 LPWSTR path;
1768
1769 name = MSI_RecordGetString(row,1);
1770
1771 /* This helper function now does ALL the work */
1772 TRACE("Dir %s ...\n",debugstr_w(name));
1773 load_folder(package,name);
1774 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1775 TRACE("resolves to %s\n",debugstr_w(path));
1776 msi_free(path);
1777
1778 return ERROR_SUCCESS;
1779 }
1780
1781 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1782 {
1783 MSIPACKAGE *package = (MSIPACKAGE*)param;
1784 LPCWSTR name;
1785 MSIFEATURE *feature;
1786
1787 name = MSI_RecordGetString( row, 1 );
1788
1789 feature = get_loaded_feature( package, name );
1790 if (!feature)
1791 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1792 else
1793 {
1794 LPCWSTR Condition;
1795 Condition = MSI_RecordGetString(row,3);
1796
1797 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1798 {
1799 int level = MSI_RecordGetInteger(row,2);
1800 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1801 feature->Level = level;
1802 }
1803 }
1804 return ERROR_SUCCESS;
1805 }
1806
1807
1808 /*
1809 * A lot is done in this function aside from just the costing.
1810 * The costing needs to be implemented at some point but for now I am going
1811 * to focus on the directory building
1812 *
1813 */
1814 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1815 {
1816 static const WCHAR ExecSeqQuery[] =
1817 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1818 '`','D','i','r','e','c','t','o','r','y','`',0};
1819 static const WCHAR ConditionQuery[] =
1820 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1821 '`','C','o','n','d','i','t','i','o','n','`',0};
1822 static const WCHAR szCosting[] =
1823 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1824 static const WCHAR szlevel[] =
1825 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1826 static const WCHAR szOne[] = { '1', 0 };
1827 MSICOMPONENT *comp;
1828 MSIFILE *file;
1829 UINT rc;
1830 MSIQUERY * view;
1831 LPWSTR level;
1832
1833 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1834 return ERROR_SUCCESS;
1835
1836 TRACE("Building Directory properties\n");
1837
1838 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1839 if (rc == ERROR_SUCCESS)
1840 {
1841 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1842 package);
1843 msiobj_release(&view->hdr);
1844 }
1845
1846 TRACE("File calculations\n");
1847
1848 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1849 {
1850 MSICOMPONENT* comp = file->Component;
1851 LPWSTR p;
1852
1853 if (!comp)
1854 continue;
1855
1856 /* calculate target */
1857 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1858
1859 msi_free(file->TargetPath);
1860
1861 TRACE("file %s is named %s\n",
1862 debugstr_w(file->File),debugstr_w(file->FileName));
1863
1864 file->TargetPath = build_directory_name(2, p, file->FileName);
1865
1866 msi_free(p);
1867
1868 TRACE("file %s resolves to %s\n",
1869 debugstr_w(file->File),debugstr_w(file->TargetPath));
1870
1871 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1872 {
1873 file->state = msifs_missing;
1874 comp->Cost += file->FileSize;
1875 continue;
1876 }
1877
1878 if (file->Version)
1879 {
1880 DWORD handle;
1881 DWORD versize;
1882 UINT sz;
1883 LPVOID version;
1884 static WCHAR name[] = {'\\',0};
1885 static const WCHAR name_fmt[] =
1886 {'%','u','.','%','u','.','%','u','.','%','u',0};
1887 WCHAR filever[0x100];
1888 VS_FIXEDFILEINFO *lpVer;
1889
1890 TRACE("Version comparison..\n");
1891 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1892 version = msi_alloc(versize);
1893 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1894
1895 VerQueryValueW(version, (LPWSTR)name, (LPVOID*)&lpVer, &sz);
1896
1897 sprintfW(filever,name_fmt,
1898 HIWORD(lpVer->dwFileVersionMS),
1899 LOWORD(lpVer->dwFileVersionMS),
1900 HIWORD(lpVer->dwFileVersionLS),
1901 LOWORD(lpVer->dwFileVersionLS));
1902
1903 TRACE("new %s old %s\n", debugstr_w(file->Version),
1904 debugstr_w(filever));
1905 if (strcmpiW(filever,file->Version)<0)
1906 {
1907 file->state = msifs_overwrite;
1908 /* FIXME: cost should be diff in size */
1909 comp->Cost += file->FileSize;
1910 }
1911 else
1912 file->state = msifs_present;
1913 msi_free(version);
1914 }
1915 else
1916 file->state = msifs_present;
1917 }
1918
1919 TRACE("Evaluating Condition Table\n");
1920
1921 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1922 if (rc == ERROR_SUCCESS)
1923 {
1924 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1925 package);
1926 msiobj_release(&view->hdr);
1927 }
1928
1929 TRACE("Enabling or Disabling Components\n");
1930 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1931 {
1932 if (comp->Condition)
1933 {
1934 if (MSI_EvaluateConditionW(package,
1935 comp->Condition) == MSICONDITION_FALSE)
1936 {
1937 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1938 comp->Enabled = FALSE;
1939 }
1940 }
1941 }
1942
1943 MSI_SetPropertyW(package,szCosting,szOne);
1944 /* set default run level if not set */
1945 level = msi_dup_property( package, szlevel );
1946 if (!level)
1947 MSI_SetPropertyW(package,szlevel, szOne);
1948 msi_free(level);
1949
1950 ACTION_UpdateInstallStates(package);
1951
1952 return SetFeatureStates(package);
1953 }
1954
1955 /* OK this value is "interpreted" and then formatted based on the
1956 first few characters */
1957 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1958 DWORD *size)
1959 {
1960 LPSTR data = NULL;
1961 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1962 {
1963 if (value[1]=='x')
1964 {
1965 LPWSTR ptr;
1966 CHAR byte[5];
1967 LPWSTR deformated = NULL;
1968 int count;
1969
1970 deformat_string(package, &value[2], &deformated);
1971
1972 /* binary value type */
1973 ptr = deformated;
1974 *type = REG_BINARY;
1975 if (strlenW(ptr)%2)
1976 *size = (strlenW(ptr)/2)+1;
1977 else
1978 *size = strlenW(ptr)/2;
1979
1980 data = msi_alloc(*size);
1981
1982 byte[0] = '0';
1983 byte[1] = 'x';
1984 byte[4] = 0;
1985 count = 0;
1986 /* if uneven pad with a zero in front */
1987 if (strlenW(ptr)%2)
1988 {
1989 byte[2]= '0';
1990 byte[3]= *ptr;
1991 ptr++;
1992 data[count] = (BYTE)strtol(byte,NULL,0);
1993 count ++;
1994 TRACE("Uneven byte count\n");
1995 }
1996 while (*ptr)
1997 {
1998 byte[2]= *ptr;
1999 ptr++;
2000 byte[3]= *ptr;
2001 ptr++;
2002 data[count] = (BYTE)strtol(byte,NULL,0);
2003 count ++;
2004 }
2005 msi_free(deformated);
2006
2007 TRACE("Data %li bytes(%i)\n",*size,count);
2008 }
2009 else
2010 {
2011 LPWSTR deformated;
2012 LPWSTR p;
2013 DWORD d = 0;
2014 deformat_string(package, &value[1], &deformated);
2015
2016 *type=REG_DWORD;
2017 *size = sizeof(DWORD);
2018 data = msi_alloc(*size);
2019 p = deformated;
2020 if (*p == '-')
2021 p++;
2022 while (*p)
2023 {
2024 if ( (*p < '0') || (*p > '9') )
2025 break;
2026 d *= 10;
2027 d += (*p - '0');
2028 p++;
2029 }
2030 if (deformated[0] == '-')
2031 d = -d;
2032 *(LPDWORD)data = d;
2033 TRACE("DWORD %li\n",*(LPDWORD)data);
2034
2035 msi_free(deformated);
2036 }
2037 }
2038 else
2039 {
2040 static const WCHAR szMulti[] = {'[','~',']',0};
2041 LPCWSTR ptr;
2042 *type=REG_SZ;
2043
2044 if (value[0]=='#')
2045 {
2046 if (value[1]=='%')
2047 {
2048 ptr = &value[2];
2049 *type=REG_EXPAND_SZ;
2050 }
2051 else
2052 ptr = &value[1];
2053 }
2054 else
2055 ptr=value;
2056
2057 if (strstrW(value,szMulti))
2058 *type = REG_MULTI_SZ;
2059
2060 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2061 }
2062 return data;
2063 }
2064
2065 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2066 {
2067 MSIPACKAGE *package = (MSIPACKAGE*)param;
2068 static const WCHAR szHCR[] =
2069 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2070 'R','O','O','T','\\',0};
2071 static const WCHAR szHCU[] =
2072 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2073 'U','S','E','R','\\',0};
2074 static const WCHAR szHLM[] =
2075 {'H','K','E','Y','_','L','O','C','A','L','_',
2076 'M','A','C','H','I','N','E','\\',0};
2077 static const WCHAR szHU[] =
2078 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2079
2080 LPSTR value_data = NULL;
2081 HKEY root_key, hkey;
2082 DWORD type,size;
2083 LPWSTR deformated;
2084 LPCWSTR szRoot, component, name, key, value;
2085 MSICOMPONENT *comp;
2086 MSIRECORD * uirow;
2087 LPWSTR uikey;
2088 INT root;
2089 BOOL check_first = FALSE;
2090 UINT rc;
2091
2092 ui_progress(package,2,0,0,0);
2093
2094 value = NULL;
2095 key = NULL;
2096 uikey = NULL;
2097 name = NULL;
2098
2099 component = MSI_RecordGetString(row, 6);
2100 comp = get_loaded_component(package,component);
2101 if (!comp)
2102 return ERROR_SUCCESS;
2103
2104 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2105 {
2106 TRACE("Skipping write due to disabled component %s\n",
2107 debugstr_w(component));
2108
2109 comp->Action = comp->Installed;
2110
2111 return ERROR_SUCCESS;
2112 }
2113
2114 comp->Action = INSTALLSTATE_LOCAL;
2115
2116 name = MSI_RecordGetString(row, 4);
2117 if( MSI_RecordIsNull(row,5) && name )
2118 {
2119 /* null values can have special meanings */
2120 if (name[0]=='-' && name[1] == 0)
2121 return ERROR_SUCCESS;
2122 else if ((name[0]=='+' && name[1] == 0) ||
2123 (name[0] == '*' && name[1] == 0))
2124 name = NULL;
2125 check_first = TRUE;
2126 }
2127
2128 root = MSI_RecordGetInteger(row,2);
2129 key = MSI_RecordGetString(row, 3);
2130
2131 /* get the root key */
2132 switch (root)
2133 {
2134 case -1:
2135 {
2136 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2137 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2138 if (all_users && all_users[0] == '1')
2139 {
2140 root_key = HKEY_LOCAL_MACHINE;
2141 szRoot = szHLM;
2142 }
2143 else
2144 {
2145 root_key = HKEY_CURRENT_USER;
2146 szRoot = szHCU;
2147 }
2148 msi_free(all_users);
2149 }
2150 break;
2151 case 0: root_key = HKEY_CLASSES_ROOT;
2152 szRoot = szHCR;
2153 break;
2154 case 1: root_key = HKEY_CURRENT_USER;
2155 szRoot = szHCU;
2156 break;
2157 case 2: root_key = HKEY_LOCAL_MACHINE;
2158 szRoot = szHLM;
2159 break;
2160 case 3: root_key = HKEY_USERS;
2161 szRoot = szHU;
2162 break;
2163 default:
2164 ERR("Unknown root %i\n",root);
2165 root_key=NULL;
2166 szRoot = NULL;
2167 break;
2168 }
2169 if (!root_key)
2170 return ERROR_SUCCESS;
2171
2172 deformat_string(package, key , &deformated);
2173 size = strlenW(deformated) + strlenW(szRoot) + 1;
2174 uikey = msi_alloc(size*sizeof(WCHAR));
2175 strcpyW(uikey,szRoot);
2176 strcatW(uikey,deformated);
2177
2178 if (RegCreateKeyW( root_key, deformated, &hkey))
2179 {
2180 ERR("Could not create key %s\n",debugstr_w(deformated));
2181 msi_free(deformated);
2182 msi_free(uikey);
2183 return ERROR_SUCCESS;
2184 }
2185 msi_free(deformated);
2186
2187 value = MSI_RecordGetString(row,5);
2188 if (value)
2189 value_data = parse_value(package, value, &type, &size);
2190 else
2191 {
2192 static const WCHAR szEmpty[] = {0};
2193 value_data = (LPSTR)strdupW(szEmpty);
2194 size = 0;
2195 type = REG_SZ;
2196 }
2197
2198 deformat_string(package, name, &deformated);
2199
2200 /* get the double nulls to terminate SZ_MULTI */
2201 if (type == REG_MULTI_SZ)
2202 size +=sizeof(WCHAR);
2203
2204 if (!check_first)
2205 {
2206 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2207 debugstr_w(uikey));
2208 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2209 }
2210 else
2211 {
2212 DWORD sz = 0;
2213 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2214 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2215 {
2216 TRACE("value %s of %s checked already exists\n",
2217 debugstr_w(deformated), debugstr_w(uikey));
2218 }
2219 else
2220 {
2221 TRACE("Checked and setting value %s of %s\n",
2222 debugstr_w(deformated), debugstr_w(uikey));
2223 if (deformated || size)
2224 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2225 }
2226 }
2227 RegCloseKey(hkey);
2228
2229 uirow = MSI_CreateRecord(3);
2230 MSI_RecordSetStringW(uirow,2,deformated);
2231 MSI_RecordSetStringW(uirow,1,uikey);
2232
2233 if (type == REG_SZ)
2234 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2235 else
2236 MSI_RecordSetStringW(uirow,3,value);
2237
2238 ui_actiondata(package,szWriteRegistryValues,uirow);
2239 msiobj_release( &uirow->hdr );
2240
2241 msi_free(value_data);
2242 msi_free(deformated);
2243 msi_free(uikey);
2244
2245 return ERROR_SUCCESS;
2246 }
2247
2248 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2249 {
2250 UINT rc;
2251 MSIQUERY * view;
2252 static const WCHAR ExecSeqQuery[] =
2253 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2254 '`','R','e','g','i','s','t','r','y','`',0 };
2255
2256 if (!package)
2257 return ERROR_INVALID_HANDLE;
2258
2259 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2260 if (rc != ERROR_SUCCESS)
2261 return ERROR_SUCCESS;
2262
2263 /* increment progress bar each time action data is sent */
2264 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2265
2266 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2267
2268 msiobj_release(&view->hdr);
2269 return rc;
2270 }
2271
2272 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2273 {
2274 package->script->CurrentlyScripting = TRUE;
2275
2276 return ERROR_SUCCESS;
2277 }
2278
2279
2280 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2281 {
2282 MSICOMPONENT *comp;
2283 DWORD progress = 0;
2284 DWORD total = 0;
2285 static const WCHAR q1[]=
2286 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2287 '`','R','e','g','i','s','t','r','y','`',0};
2288 UINT rc;
2289 MSIQUERY * view;
2290 MSIFEATURE *feature;
2291 MSIFILE *file;
2292
2293 TRACE("InstallValidate\n");
2294
2295 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2296 if (rc == ERROR_SUCCESS)
2297 {
2298 MSI_IterateRecords( view, &progress, NULL, package );
2299 msiobj_release( &view->hdr );
2300 total += progress * REG_PROGRESS_VALUE;
2301 }
2302
2303 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2304 total += COMPONENT_PROGRESS_VALUE;
2305
2306 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2307 total += file->FileSize;
2308
2309 ui_progress(package,0,total,0,0);
2310
2311 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2312 {
2313 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2314 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2315 feature->ActionRequest);
2316 }
2317
2318 return ERROR_SUCCESS;
2319 }
2320
2321 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2322 {
2323 MSIPACKAGE* package = (MSIPACKAGE*)param;
2324 LPCWSTR cond = NULL;
2325 LPCWSTR message = NULL;
2326 static const WCHAR title[]=
2327 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2328
2329 cond = MSI_RecordGetString(row,1);
2330
2331 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2332 {
2333 LPWSTR deformated;
2334 message = MSI_RecordGetString(row,2);
2335 deformat_string(package,message,&deformated);
2336 MessageBoxW(NULL,deformated,title,MB_OK);
2337 msi_free(deformated);
2338 return ERROR_FUNCTION_FAILED;
2339 }
2340
2341 return ERROR_SUCCESS;
2342 }
2343
2344 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2345 {
2346 UINT rc;
2347 MSIQUERY * view = NULL;
2348 static const WCHAR ExecSeqQuery[] =
2349 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2350 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2351
2352 TRACE("Checking launch conditions\n");
2353
2354 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2355 if (rc != ERROR_SUCCESS)
2356 return ERROR_SUCCESS;
2357
2358 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2359 msiobj_release(&view->hdr);
2360
2361 return rc;
2362 }
2363
2364 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2365 {
2366
2367 if (!cmp->KeyPath)
2368 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2369
2370 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2371 {
2372 MSIRECORD * row = 0;
2373 UINT root,len;
2374 LPWSTR deformated,buffer,deformated_name;
2375 LPCWSTR key,name;
2376 static const WCHAR ExecSeqQuery[] =
2377 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2378 '`','R','e','g','i','s','t','r','y','`',' ',
2379 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2380 ' ','=',' ' ,'\'','%','s','\'',0 };
2381 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2382 static const WCHAR fmt2[]=
2383 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2384
2385 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2386 if (!row)
2387 return NULL;
2388
2389 root = MSI_RecordGetInteger(row,2);
2390 key = MSI_RecordGetString(row, 3);
2391 name = MSI_RecordGetString(row, 4);
2392 deformat_string(package, key , &deformated);
2393 deformat_string(package, name, &deformated_name);
2394
2395 len = strlenW(deformated) + 6;
2396 if (deformated_name)
2397 len+=strlenW(deformated_name);
2398
2399 buffer = msi_alloc( len *sizeof(WCHAR));
2400
2401 if (deformated_name)
2402 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2403 else
2404 sprintfW(buffer,fmt,root,deformated);
2405
2406 msi_free(deformated);
2407 msi_free(deformated_name);
2408 msiobj_release(&row->hdr);
2409
2410 return buffer;
2411 }
2412 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2413 {
2414 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2415 return NULL;
2416 }
2417 else
2418 {
2419 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2420
2421 if (file)
2422 return strdupW( file->TargetPath );
2423 }
2424 return NULL;
2425 }
2426
2427 static HKEY openSharedDLLsKey(void)
2428 {
2429 HKEY hkey=0;
2430 static const WCHAR path[] =
2431 {'S','o','f','t','w','a','r','e','\\',
2432 'M','i','c','r','o','s','o','f','t','\\',
2433 'W','i','n','d','o','w','s','\\',
2434 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2435 'S','h','a','r','e','d','D','L','L','s',0};
2436
2437 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2438 return hkey;
2439 }
2440
2441 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2442 {
2443 HKEY hkey;
2444 DWORD count=0;
2445 DWORD type;
2446 DWORD sz = sizeof(count);
2447 DWORD rc;
2448
2449 hkey = openSharedDLLsKey();
2450 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2451 if (rc != ERROR_SUCCESS)
2452 count = 0;
2453 RegCloseKey(hkey);
2454 return count;
2455 }
2456
2457 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2458 {
2459 HKEY hkey;
2460
2461 hkey = openSharedDLLsKey();
2462 if (count > 0)
2463 msi_reg_set_val_dword( hkey, path, count );
2464 else
2465 RegDeleteValueW(hkey,path);
2466 RegCloseKey(hkey);
2467 return count;
2468 }
2469
2470 /*
2471 * Return TRUE if the count should be written out and FALSE if not
2472 */
2473 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2474 {
2475 MSIFEATURE *feature;
2476 INT count = 0;
2477 BOOL write = FALSE;
2478
2479 /* only refcount DLLs */
2480 if (comp->KeyPath == NULL ||
2481 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2482 comp->Attributes & msidbComponentAttributesODBCDataSource)
2483 write = FALSE;
2484 else
2485 {
2486 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2487 write = (count > 0);
2488
2489 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2490 write = TRUE;
2491 }
2492
2493 /* increment counts */
2494 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2495 {
2496 ComponentList *cl;
2497
2498 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2499 continue;
2500
2501 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2502 {
2503 if ( cl->component == comp )
2504 count++;
2505 }
2506 }
2507
2508 /* decrement counts */
2509 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2510 {
2511 ComponentList *cl;
2512
2513 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2514 continue;
2515
2516 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2517 {
2518 if ( cl->component == comp )
2519 count--;
2520 }
2521 }
2522
2523 /* ref count all the files in the component */
2524 if (write)
2525 {
2526 MSIFILE *file;
2527
2528 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2529 {
2530 if (file->Component == comp)
2531 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2532 }
2533 }
2534
2535 /* add a count for permenent */
2536 if (comp->Attributes & msidbComponentAttributesPermanent)
2537 count ++;
2538
2539 comp->RefCount = count;
2540
2541 if (write)
2542 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2543 }
2544
2545 /*
2546 * Ok further analysis makes me think that this work is
2547 * actually done in the PublishComponents and PublishFeatures
2548 * step, and not here. It appears like the keypath and all that is
2549 * resolved in this step, however actually written in the Publish steps.
2550 * But we will leave it here for now because it is unclear
2551 */
2552 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2553 {
2554 WCHAR squished_pc[GUID_SIZE];
2555 WCHAR squished_cc[GUID_SIZE];
2556 UINT rc;
2557 MSICOMPONENT *comp;
2558 HKEY hkey=0,hkey2=0;
2559
2560 /* writes the Component and Features values to the registry */
2561
2562 rc = MSIREG_OpenComponents(&hkey);
2563 if (rc != ERROR_SUCCESS)
2564 goto end;
2565
2566 squash_guid(package->ProductCode,squished_pc);
2567 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2568
2569 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2570 {
2571 ui_progress(package,2,0,0,0);
2572 if (comp->ComponentId)
2573 {
2574 MSIRECORD * uirow;
2575
2576 squash_guid(comp->ComponentId,squished_cc);
2577
2578 msi_free(comp->FullKeypath);
2579 comp->FullKeypath = resolve_keypath( package, comp );
2580
2581 /* do the refcounting */
2582 ACTION_RefCountComponent( package, comp );
2583
2584 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2585 debugstr_w(comp->Component),
2586 debugstr_w(squished_cc),
2587 debugstr_w(comp->FullKeypath),
2588 comp->RefCount);
2589 /*
2590 * Write the keypath out if the component is to be registered
2591 * and delete the key if the component is to be deregistered
2592 */
2593 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2594 {
2595 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2596 if (rc != ERROR_SUCCESS)
2597 continue;
2598
2599 if (comp->FullKeypath)
2600 {
2601 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2602
2603 if (comp->Attributes & msidbComponentAttributesPermanent)
2604 {
2605 static const WCHAR szPermKey[] =
2606 { '0','0','0','0','0','0','0','0','0','0','0','0',
2607 '0','0','0','0','0','0','0','0','0','0','0','0',
2608 '0','0','0','0','0','0','0','0',0};
2609
2610 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2611 }
2612
2613 RegCloseKey(hkey2);
2614
2615 /* UI stuff */
2616 uirow = MSI_CreateRecord(3);
2617 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2618 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2619 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2620 ui_actiondata(package,szProcessComponents,uirow);
2621 msiobj_release( &uirow->hdr );
2622 }
2623 }
2624 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2625 {
2626 DWORD res;
2627
2628 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2629 if (rc != ERROR_SUCCESS)
2630 continue;
2631
2632 RegDeleteValueW(hkey2,squished_pc);
2633
2634 /* if the key is empty delete it */
2635 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2636 RegCloseKey(hkey2);
2637 if (res == ERROR_NO_MORE_ITEMS)
2638 RegDeleteKeyW(hkey,squished_cc);
2639
2640 /* UI stuff */
2641 uirow = MSI_CreateRecord(2);
2642 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2643 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2644 ui_actiondata(package,szProcessComponents,uirow);
2645 msiobj_release( &uirow->hdr );
2646 }
2647 }
2648 }
2649 end:
2650 RegCloseKey(hkey);
2651 return rc;
2652 }
2653
2654 typedef struct {
2655 CLSID clsid;
2656 LPWSTR source;
2657
2658 LPWSTR path;
2659 ITypeLib *ptLib;
2660 } typelib_struct;
2661
2662 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2663 LPWSTR lpszName, LONG_PTR lParam)
2664 {
2665 TLIBATTR *attr;
2666 typelib_struct *tl_struct = (typelib_struct*) lParam;
2667 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2668 int sz;
2669 HRESULT res;
2670
2671 if (!IS_INTRESOURCE(lpszName))
2672 {
2673 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2674 return TRUE;
2675 }
2676
2677 sz = strlenW(tl_struct->source)+4;
2678 sz *= sizeof(WCHAR);
2679
2680 if ((INT)lpszName == 1)
2681 tl_struct->path = strdupW(tl_struct->source);
2682 else
2683 {
2684 tl_struct->path = msi_alloc(sz);
2685 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2686 }
2687
2688 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2689 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2690 if (!SUCCEEDED(res))
2691 {
2692 msi_free(tl_struct->path);
2693 tl_struct->path = NULL;
2694
2695 return TRUE;
2696 }
2697
2698 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2699 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2700 {
2701 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2702 return FALSE;
2703 }
2704
2705 msi_free(tl_struct->path);
2706 tl_struct->path = NULL;
2707
2708 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2709 ITypeLib_Release(tl_struct->ptLib);
2710
2711 return TRUE;
2712 }
2713
2714 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2715 {
2716 MSIPACKAGE* package = (MSIPACKAGE*)param;
2717 LPCWSTR component;
2718 MSICOMPONENT *comp;
2719 MSIFILE *file;
2720 typelib_struct tl_struct;
2721 HMODULE module;
2722 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2723
2724 component = MSI_RecordGetString(row,3);
2725 comp = get_loaded_component(package,component);
2726 if (!comp)
2727 return ERROR_SUCCESS;
2728
2729 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2730 {
2731 TRACE("Skipping typelib reg due to disabled component\n");
2732
2733 comp->Action = comp->Installed;
2734
2735 return ERROR_SUCCESS;
2736 }
2737
2738 comp->Action = INSTALLSTATE_LOCAL;
2739
2740 file = get_loaded_file( package, comp->KeyPath );
2741 if (!file)
2742 return ERROR_SUCCESS;
2743
2744 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2745 if (module)
2746 {
2747 LPCWSTR guid;
2748 guid = MSI_RecordGetString(row,1);
2749 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2750 tl_struct.source = strdupW( file->TargetPath );
2751 tl_struct.path = NULL;
2752
2753 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2754 (LONG_PTR)&tl_struct);
2755
2756 if (tl_struct.path)
2757 {
2758 LPWSTR help = NULL;
2759 LPCWSTR helpid;
2760 HRESULT res;
2761
2762 helpid = MSI_RecordGetString(row,6);
2763
2764 if (helpid)
2765 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2766 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2767 msi_free(help);
2768
2769 if (!SUCCEEDED(res))
2770 ERR("Failed to register type library %s\n",
2771 debugstr_w(tl_struct.path));
2772 else
2773 {
2774 ui_actiondata(package,szRegisterTypeLibraries,row);
2775
2776 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2777 }
2778
2779 ITypeLib_Release(tl_struct.ptLib);
2780 msi_free(tl_struct.path);
2781 }
2782 else
2783 ERR("Failed to load type library %s\n",
2784 debugstr_w(tl_struct.source));
2785
2786 FreeLibrary(module);
2787 msi_free(tl_struct.source);
2788 }
2789 else
2790 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2791
2792 return ERROR_SUCCESS;
2793 }
2794
2795 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2796 {
2797 /*
2798 * OK this is a bit confusing.. I am given a _Component key and I believe
2799 * that the file that is being registered as a type library is the "key file
2800 * of that component" which I interpret to mean "The file in the KeyPath of
2801 * that component".
2802 */
2803 UINT rc;
2804 MSIQUERY * view;
2805 static const WCHAR Query[] =
2806 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2807 '`','T','y','p','e','L','i','b','`',0};
2808
2809 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2810 if (rc != ERROR_SUCCESS)
2811 return ERROR_SUCCESS;
2812
2813 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2814 msiobj_release(&view->hdr);
2815 return rc;
2816 }
2817
2818 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2819 {
2820 MSIPACKAGE *package = (MSIPACKAGE*)param;
2821 LPWSTR target_file, target_folder;
2822 LPCWSTR buffer;
2823 WCHAR filename[0x100];
2824 DWORD sz;
2825 MSICOMPONENT *comp;
2826 static const WCHAR szlnk[]={'.','l','n','k',0};
2827 IShellLinkW *sl;
2828 IPersistFile *pf;
2829 HRESULT res;
2830
2831 buffer = MSI_RecordGetString(row,4);
2832 comp = get_loaded_component(package,buffer);
2833 if (!comp)
2834 return ERROR_SUCCESS;
2835
2836 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2837 {
2838 TRACE("Skipping shortcut creation due to disabled component\n");
2839
2840 comp->Action = comp->Installed;
2841
2842 return ERROR_SUCCESS;
2843 }
2844
2845 comp->Action = INSTALLSTATE_LOCAL;
2846
2847 ui_actiondata(package,szCreateShortcuts,row);
2848
2849 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2850 &IID_IShellLinkW, (LPVOID *) &sl );
2851
2852 if (FAILED(res))
2853 {
2854 ERR("Is IID_IShellLink\n");
2855 return ERROR_SUCCESS;
2856 }
2857
2858 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2859 if( FAILED( res ) )
2860 {
2861 ERR("Is IID_IPersistFile\n");
2862 return ERROR_SUCCESS;
2863 }
2864
2865 buffer = MSI_RecordGetString(row,2);
2866 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2867
2868 /* may be needed because of a bug somehwere else */
2869 create_full_pathW(target_folder);
2870
2871 sz = 0x100;
2872 MSI_RecordGetStringW(row,3,filename,&sz);
2873 reduce_to_longfilename(filename);
2874 if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk))
2875 strcatW(filename,szlnk);
2876 target_file = build_directory_name(2, target_folder, filename);
2877 msi_free(target_folder);
2878
2879 buffer = MSI_RecordGetString(row,5);
2880 if (strchrW(buffer,'['))
2881 {
2882 LPWSTR deformated;
2883 deformat_string(package,buffer,&deformated);
2884 IShellLinkW_SetPath(sl,deformated);
2885 msi_free(deformated);
2886 }
2887 else
2888 {
2889 FIXME("poorly handled shortcut format, advertised shortcut\n");
2890 IShellLinkW_SetPath(sl,comp->FullKeypath);
2891 }
2892
2893 if (!MSI_RecordIsNull(row,6))
2894 {
2895 LPWSTR deformated;
2896 buffer = MSI_RecordGetString(row,6);
2897 deformat_string(package,buffer,&deformated);
2898 IShellLinkW_SetArguments(sl,deformated);
2899 msi_free(deformated);
2900 }
2901
2902 if (!MSI_RecordIsNull(row,7))
2903 {
2904 buffer = MSI_RecordGetString(row,7);
2905 IShellLinkW_SetDescription(sl,buffer);
2906 }
2907
2908 if (!MSI_RecordIsNull(row,8))
2909 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2910
2911 if (!MSI_RecordIsNull(row,9))
2912 {
2913 LPWSTR Path;
2914 INT index;
2915
2916 buffer = MSI_RecordGetString(row,9);
2917
2918 Path = build_icon_path(package,buffer);
2919 index = MSI_RecordGetInteger(row,10);
2920
2921 IShellLinkW_SetIconLocation(sl,Path,index);
2922 msi_free(Path);
2923 }
2924
2925 if (!MSI_RecordIsNull(row,11))
2926 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2927
2928 if (!MSI_RecordIsNull(row,12))
2929 {
2930 LPWSTR Path;
2931 buffer = MSI_RecordGetString(row,12);
2932 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2933 IShellLinkW_SetWorkingDirectory(sl,Path);
2934 msi_free(Path);
2935 }
2936
2937 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2938 IPersistFile_Save(pf,target_file,FALSE);
2939
2940 msi_free(target_file);
2941
2942 IPersistFile_Release( pf );
2943 IShellLinkW_Release( sl );
2944
2945 return ERROR_SUCCESS;
2946 }
2947
2948 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2949 {
2950 UINT rc;
2951 HRESULT res;
2952 MSIQUERY * view;
2953 static const WCHAR Query[] =
2954 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2955 '`','S','h','o','r','t','c','u','t','`',0};
2956
2957 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2958 if (rc != ERROR_SUCCESS)
2959 return ERROR_SUCCESS;
2960
2961 res = CoInitialize( NULL );
2962 if (FAILED (res))
2963 {
2964 ERR("CoInitialize failed\n");
2965 return ERROR_FUNCTION_FAILED;
2966 }
2967
2968 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2969 msiobj_release(&view->hdr);
2970
2971 CoUninitialize();
2972
2973 return rc;
2974 }
2975
2976 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2977 {
2978 MSIPACKAGE* package = (MSIPACKAGE*)param;
2979 HANDLE the_file;
2980 LPWSTR FilePath;
2981 LPCWSTR FileName;
2982 CHAR buffer[1024];
2983 DWORD sz;
2984 UINT rc;
2985
2986 FileName = MSI_RecordGetString(row,1);
2987 if (!FileName)
2988 {
2989 ERR("Unable to get FileName\n");
2990 return ERROR_SUCCESS;
2991 }
2992
2993 FilePath = build_icon_path(package,FileName);
2994
2995 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
2996
2997 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2998 FILE_ATTRIBUTE_NORMAL, NULL);
2999
3000 if (the_file == INVALID_HANDLE_VALUE)
3001 {
3002 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3003 msi_free(FilePath);
3004 return ERROR_SUCCESS;
3005 }
3006
3007 do
3008 {
3009 DWORD write;
3010 sz = 1024;
3011 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3012 if (rc != ERROR_SUCCESS)
3013 {
3014 ERR("Failed to get stream\n");
3015 CloseHandle(the_file);
3016 DeleteFileW(FilePath);
3017 break;
3018 }
3019 WriteFile(the_file,buffer,sz,&write,NULL);
3020 } while (sz == 1024);
3021
3022 msi_free(FilePath);
3023
3024 CloseHandle(the_file);
3025 return ERROR_SUCCESS;
3026 }
3027
3028 /*
3029 * 99% of the work done here is only done for
3030 * advertised installs. However this is where the
3031 * Icon table is processed and written out
3032 * so that is what I am going to do here.
3033 */
3034 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3035 {
3036 UINT rc;
3037 MSIQUERY * view;
3038 static const WCHAR Query[]=
3039 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3040 '`','I','c','o','n','`',0};
3041 /* for registry stuff */
3042 HKEY hkey=0;
3043 HKEY hukey=0;
3044 static const WCHAR szProductLanguage[] =
3045 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3046 static const WCHAR szARPProductIcon[] =
3047 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3048 static const WCHAR szProductVersion[] =
3049 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3050 DWORD langid;
3051 LPWSTR buffer;
3052 DWORD size;
3053 MSIHANDLE hDb, hSumInfo;
3054
3055 /* write out icon files */
3056
3057 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3058 if (rc == ERROR_SUCCESS)
3059 {
3060 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3061 msiobj_release(&view->hdr);
3062 }
3063
3064 /* ok there is a lot more done here but i need to figure out what */
3065
3066 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3067 if (rc != ERROR_SUCCESS)
3068 goto end;
3069
3070 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3071 if (rc != ERROR_SUCCESS)
3072 goto end;
3073
3074
3075 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3076 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3077 msi_free(buffer);
3078
3079 langid = msi_get_property_int( package, szProductLanguage, 0 );
3080 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3081
3082 buffer = msi_dup_property( package, szARPProductIcon );
3083 if (buffer)
3084 {
3085 LPWSTR path = build_icon_path(package,buffer);
3086 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3087 msi_free( path );
3088 }
3089 msi_free(buffer);
3090
3091 buffer = msi_dup_property( package, szProductVersion );
3092 if (buffer)
3093 {
3094 DWORD verdword = build_version_dword(buffer);
3095 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3096 }
3097 msi_free(buffer);
3098
3099 FIXME("Need to write more keys to the user registry\n");
3100
3101 hDb= alloc_msihandle( &package->db->hdr );
3102 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3103 MsiCloseHandle(hDb);
3104 if (rc == ERROR_SUCCESS)
3105 {
3106 WCHAR guidbuffer[0x200];
3107 size = 0x200;
3108 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3109 guidbuffer, &size);
3110 if (rc == ERROR_SUCCESS)
3111 {
3112 WCHAR squashed[GUID_SIZE];
3113 /* for now we only care about the first guid */
3114 LPWSTR ptr = strchrW(guidbuffer,';');
3115 if (ptr) *ptr = 0;
3116 squash_guid(guidbuffer,squashed);
3117 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3118 }
3119 else
3120 {
3121 ERR("Unable to query Revision_Number...\n");
3122 rc = ERROR_SUCCESS;
3123 }
3124 MsiCloseHandle(hSumInfo);
3125 }
3126 else
3127 {
3128 ERR("Unable to open Summary Information\n");
3129 rc = ERROR_SUCCESS;
3130 }
3131
3132 end:
3133
3134 RegCloseKey(hkey);
3135 RegCloseKey(hukey);
3136
3137 return rc;
3138 }
3139
3140 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3141 {
3142 MSIPACKAGE *package = (MSIPACKAGE*)param;
3143 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3144 LPWSTR deformated_section, deformated_key, deformated_value;
3145 LPWSTR folder, fullname = NULL;
3146 MSIRECORD * uirow;
3147 INT action;
3148 MSICOMPONENT *comp;
3149 static const WCHAR szWindowsFolder[] =
3150 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3151
3152 component = MSI_RecordGetString(row, 8);
3153 comp = get_loaded_component(package,component);
3154
3155 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3156 {
3157 TRACE("Skipping ini file due to disabled component %s\n",
3158 debugstr_w(component));
3159
3160 comp->Action = comp->Installed;
3161
3162 return ERROR_SUCCESS;
3163 }
3164
3165 comp->Action = INSTALLSTATE_LOCAL;
3166
3167 identifier = MSI_RecordGetString(row,1);
3168 filename = MSI_RecordGetString(row,2);
3169 dirproperty = MSI_RecordGetString(row,3);
3170 section = MSI_RecordGetString(row,4);
3171 key = MSI_RecordGetString(row,5);
3172 value = MSI_RecordGetString(row,6);
3173 action = MSI_RecordGetInteger(row,7);
3174
3175 deformat_string(package,section,&deformated_section);
3176 deformat_string(package,key,&deformated_key);
3177 deformat_string(package,value,&deformated_value);
3178
3179 if (dirproperty)
3180 {
3181 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3182 if (!folder)
3183 folder = msi_dup_property( package, dirproperty );
3184 }
3185 else
3186 folder = msi_dup_property( package, szWindowsFolder );
3187
3188 if (!folder)
3189 {
3190 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3191 goto cleanup;
3192 }
3193
3194 fullname = build_directory_name(2, folder, filename);
3195
3196 if (action == 0)
3197 {
3198 TRACE("Adding value %s to section %s in %s\n",
3199 debugstr_w(deformated_key), debugstr_w(deformated_section),
3200 debugstr_w(fullname));
3201 WritePrivateProfileStringW(deformated_section, deformated_key,
3202 deformated_value, fullname);
3203 }
3204 else if (action == 1)
3205 {
3206 WCHAR returned[10];
3207 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3208 returned, 10, fullname);
3209 if (returned[0] == 0)
3210 {
3211 TRACE("Adding value %s to section %s in %s\n",
3212 debugstr_w(deformated_key), debugstr_w(deformated_section),
3213 debugstr_w(fullname));
3214
3215 WritePrivateProfileStringW(deformated_section, deformated_key,
3216 deformated_value, fullname);
3217 }
3218 }
3219 else if (action == 3)
3220 FIXME("Append to existing section not yet implemented\n");
3221
3222 uirow = MSI_CreateRecord(4);
3223 MSI_RecordSetStringW(uirow,1,identifier);
3224 MSI_RecordSetStringW(uirow,2,deformated_section);
3225 MSI_RecordSetStringW(uirow,3,deformated_key);
3226 MSI_RecordSetStringW(uirow,4,deformated_value);
3227 ui_actiondata(package,szWriteIniValues,uirow);
3228 msiobj_release( &uirow->hdr );
3229 cleanup:
3230 msi_free(fullname);
3231 msi_free(folder);
3232 msi_free(deformated_key);
3233 msi_free(deformated_value);
3234 msi_free(deformated_section);
3235 return ERROR_SUCCESS;
3236 }
3237
3238 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3239 {
3240 UINT rc;
3241 MSIQUERY * view;
3242 static const WCHAR ExecSeqQuery[] =
3243 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3244 '`','I','n','i','F','i','l','e','`',0};
3245
3246 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3247 if (rc != ERROR_SUCCESS)
3248 {
3249 TRACE("no IniFile table\n");
3250 return ERROR_SUCCESS;
3251 }
3252
3253 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3254 msiobj_release(&view->hdr);
3255 return rc;
3256 }
3257
3258 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3259 {
3260 MSIPACKAGE *package = (MSIPACKAGE*)param;
3261 LPCWSTR filename;
3262 LPWSTR FullName;
3263 MSIFILE *file;
3264 DWORD len;
3265 static const WCHAR ExeStr[] =
3266 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3267 static const WCHAR close[] = {'\"',0};
3268 STARTUPINFOW si;
3269 PROCESS_INFORMATION info;
3270 BOOL brc;
3271
3272 memset(&si,0,sizeof(STARTUPINFOW));
3273
3274 filename = MSI_RecordGetString(row,1);
3275 file = get_loaded_file( package, filename );
3276
3277 if (!file)
3278 {
3279 ERR("Unable to find file id %s\n",debugstr_w(filename));
3280 return ERROR_SUCCESS;
3281 }
3282
3283 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3284
3285 FullName = msi_alloc(len*sizeof(WCHAR));
3286 strcpyW(FullName,ExeStr);
3287 strcatW( FullName, file->TargetPath );
3288 strcatW(FullName,close);
3289
3290 TRACE("Registering %s\n",debugstr_w(FullName));
3291 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3292 &si, &info);
3293
3294 if (brc)
3295 msi_dialog_check_messages(info.hProcess);
3296
3297 msi_free(FullName);
3298 return ERROR_SUCCESS;
3299 }
3300
3301 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3302 {
3303 UINT rc;
3304 MSIQUERY * view;
3305 static const WCHAR ExecSeqQuery[] =
3306 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3307 '`','S','e','l','f','R','e','g','`',0};
3308
3309 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3310 if (rc != ERROR_SUCCESS)
3311 {
3312 TRACE("no SelfReg table\n");
3313 return ERROR_SUCCESS;
3314 }
3315
3316 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3317 msiobj_release(&view->hdr);
3318
3319 return ERROR_SUCCESS;
3320 }
3321
3322 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3323 {
3324 MSIFEATURE *feature;
3325 UINT rc;
3326 HKEY hkey=0;
3327 HKEY hukey=0;
3328
3329 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3330 if (rc != ERROR_SUCCESS)
3331 goto end;
3332
3333 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3334 if (rc != ERROR_SUCCESS)
3335 goto end;
3336
3337 /* here the guids are base 85 encoded */
3338 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3339 {
3340 ComponentList *cl;
3341 LPWSTR data = NULL;
3342 GUID clsid;
3343 INT size;
3344 BOOL absent = FALSE;
3345
3346 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3347 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3348 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3349 absent = TRUE;
3350
3351 size = 1;
3352 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3353 {
3354 size += 21;
3355 }
3356 if (feature->Feature_Parent)
3357 size += strlenW( feature->Feature_Parent )+2;
3358
3359 data = msi_alloc(size * sizeof(WCHAR));
3360
3361 data[0] = 0;
3362 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3363 {
3364 MSICOMPONENT* component = cl->component;
3365 WCHAR buf[21];
3366
3367 memset(buf,0,sizeof(buf));
3368 if (component->ComponentId)
3369 {
3370 TRACE("From %s\n",debugstr_w(component->ComponentId));
3371 CLSIDFromString(component->ComponentId, &clsid);
3372 encode_base85_guid(&clsid,buf);
3373 TRACE("to %s\n",debugstr_w(buf));
3374 strcatW(data,buf);
3375 }
3376 }
3377 if (feature->Feature_Parent)
3378 {
3379 static const WCHAR sep[] = {'\2',0};
3380 strcatW(data,sep);
3381 strcatW(data,feature->Feature_Parent);
3382 }
3383
3384 msi_reg_set_val_str( hkey, feature->Feature, data );
3385 msi_free(data);
3386
3387 size = 0;
3388 if (feature->Feature_Parent)
3389 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3390 if (!absent)
3391 {
3392 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3393 (LPBYTE)feature->Feature_Parent,size);
3394 }
3395 else
3396 {
3397 size += 2*sizeof(WCHAR);
3398 data = msi_alloc(size);
3399 data[0] = 0x6;
3400 data[1] = 0;
3401 if (feature->Feature_Parent)
3402 strcpyW( &data[1], feature->Feature_Parent );
3403 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3404 (LPBYTE)data,size);
3405 msi_free(data);
3406 }
3407 }
3408
3409 end:
3410 RegCloseKey(hkey);
3411 RegCloseKey(hukey);
3412 return rc;
3413 }
3414
3415 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3416 {
3417 static const WCHAR installerPathFmt[] = {
3418 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3419 static const WCHAR fmt[] = {
3420 '%','s','\\',
3421 'I','n','s','t','a','l','l','e','r','\\',
3422 '%','x','.','m','s','i',0};
3423 static const WCHAR szOriginalDatabase[] =
3424 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3425 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3426 INT num, start;
3427 LPWSTR msiFilePath;
3428 BOOL r;
3429
3430 /* copy the package locally */
3431 num = GetTickCount() & 0xffff;
3432 if (!num)
3433 num = 1;
3434 start = num;
3435 GetWindowsDirectoryW( windir, MAX_PATH );
3436 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3437 do
3438 {
3439 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3440 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3441 if (handle != INVALID_HANDLE_VALUE)
3442 {
3443 CloseHandle(handle);
3444 break;
3445 }
3446 if (GetLastError() != ERROR_FILE_EXISTS &&
3447 GetLastError() != ERROR_SHARING_VIOLATION)
3448 break;
3449 if (!(++num & 0xffff)) num = 1;
3450 sprintfW(packagefile,fmt,num);
3451 } while (num != start);
3452
3453 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3454 create_full_pathW(path);
3455
3456 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3457
3458 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3459 r = CopyFileW( msiFilePath, packagefile, FALSE);
3460 msi_free( msiFilePath );
3461
3462 if (!r)
3463 {
3464 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3465 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3466 return ERROR_FUNCTION_FAILED;
3467 }
3468
3469 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3470 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3471 return ERROR_SUCCESS;
3472 }
3473
3474 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3475 {
3476 LPWSTR prop, val, key;
3477 static const LPCSTR propval[] = {
3478 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3479 "ARPCONTACT", "Contact",
3480 "ARPCOMMENTS", "Comments",
3481 "ProductName", "DisplayName",
3482 "ProductVersion", "DisplayVersion",
3483 "ARPHELPLINK", "HelpLink",
3484 "ARPHELPTELEPHONE", "HelpTelephone",
3485 "ARPINSTALLLOCATION", "InstallLocation",
3486 "SourceDir", "InstallSource",
3487 "Manufacturer", "Publisher",
3488 "ARPREADME", "Readme",
3489 "ARPSIZE", "Size",
3490 "ARPURLINFOABOUT", "URLInfoAbout",
3491 "ARPURLUPDATEINFO", "URLUpdateInfo",
3492 NULL,
3493 };
3494 const LPCSTR *p = propval;
3495
3496 while( *p )
3497 {
3498 prop = strdupAtoW( *p++ );
3499 key = strdupAtoW( *p++ );
3500 val = msi_dup_property( package, prop );
3501 msi_reg_set_val_str( hkey, key, val );
3502 msi_free(val);
3503 msi_free(key);
3504 msi_free(prop);
3505 }
3506 return ERROR_SUCCESS;
3507 }
3508
3509 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3510 {
3511 HKEY hkey=0;
3512 LPWSTR buffer = NULL;
3513 UINT rc;
3514 DWORD size, langid;
3515 static const WCHAR szWindowsInstaller[] =
3516 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3517 static const WCHAR szUpgradeCode[] =
3518 {'U','p','g','r','a','d','e','C','o','d','e',0};
3519 static const WCHAR modpath_fmt[] =
3520 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3521 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3522 static const WCHAR szModifyPath[] =
3523 {'M','o','d','i','f','y','P','a','t','h',0};
3524 static const WCHAR szUninstallString[] =
3525 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3526 static const WCHAR szEstimatedSize[] =
3527 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3528 static const WCHAR szProductLanguage[] =
3529 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3530 static const WCHAR szProductVersion[] =
3531 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3532
3533 SYSTEMTIME systime;
3534 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3535 LPWSTR upgrade_code;
3536 WCHAR szDate[9];
3537
3538 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3539 if (rc != ERROR_SUCCESS)
3540 return rc;
3541
3542 /* dump all the info i can grab */
3543 FIXME("Flesh out more information\n");
3544
3545 msi_write_uninstall_property_vals( package, hkey );
3546
3547 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3548
3549 msi_make_package_local( package, hkey );
3550
3551 /* do ModifyPath and UninstallString */
3552 size = deformat_string(package,modpath_fmt,&buffer);
3553 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3554 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3555 msi_free(buffer);
3556
3557 FIXME("Write real Estimated Size when we have it\n");
3558 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3559
3560 GetLocalTime(&systime);
3561 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3562 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3563
3564 langid = msi_get_property_int( package, szProductLanguage, 0 );
3565 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3566
3567 buffer = msi_dup_property( package, szProductVersion );
3568 if (buffer)
3569 {
3570 DWORD verdword = build_version_dword(buffer);
3571
3572 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3573 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3574 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3575 }
3576 msi_free(buffer);
3577
3578 /* Handle Upgrade Codes */
3579 upgrade_code = msi_dup_property( package, szUpgradeCode );
3580 if (upgrade_code)
3581 {
3582 HKEY hkey2;
3583 WCHAR squashed[33];
3584 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3585 squash_guid(package->ProductCode,squashed);
3586 msi_reg_set_val_str( hkey2, squashed, NULL );
3587 RegCloseKey(hkey2);
3588 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3589 squash_guid(package->ProductCode,squashed);
3590 msi_reg_set_val_str( hkey2, squashed, NULL );
3591 RegCloseKey(hkey2);
3592
3593 msi_free(upgrade_code);
3594 }
3595
3596 RegCloseKey(hkey);
3597
3598 return ERROR_SUCCESS;
3599 }
3600
3601 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3602 {
3603 return execute_script(package,INSTALL_SCRIPT);
3604 }
3605
3606 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3607 {
3608 UINT rc;
3609
3610 /* turn off scheduleing */
3611 package->script->CurrentlyScripting= FALSE;
3612
3613 /* first do the same as an InstallExecute */
3614 rc = ACTION_InstallExecute(package);
3615 if (rc != ERROR_SUCCESS)
3616 return rc;
3617
3618 /* then handle Commit Actions */
3619 rc = execute_script(package,COMMIT_SCRIPT);
3620
3621 return rc;
3622 }
3623
3624 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3625 {
3626 static const WCHAR RunOnce[] = {
3627 'S','o','f','t','w','a','r','e','\\',
3628 'M','i','c','r','o','s','o','f','t','\\',
3629 'W','i','n','d','o','w','s','\\',
3630 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3631 'R','u','n','O','n','c','e',0};
3632 static const WCHAR InstallRunOnce[] = {
3633 'S','o','f','t','w','a','r','e','\\',
3634 'M','i','c','r','o','s','o','f','t','\\',
3635 'W','i','n','d','o','w','s','\\',
3636 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3637 'I','n','s','t','a','l','l','e','r','\\',
3638 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3639
3640 static const WCHAR msiexec_fmt[] = {
3641 '%','s',
3642 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3643 '\"','%','s','\"',0};
3644 static const WCHAR install_fmt[] = {
3645 '/','I',' ','\"','%','s','\"',' ',
3646 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3647 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3648 WCHAR buffer[256], sysdir[MAX_PATH];
3649 HKEY hkey;
3650 WCHAR squished_pc[100];
3651
3652 squash_guid(package->ProductCode,squished_pc);
3653
3654 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3655 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3656 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3657 squished_pc);
3658
3659 msi_reg_set_val_str( hkey, squished_pc, buffer );
3660 RegCloseKey(hkey);
3661
3662 TRACE("Reboot command %s\n",debugstr_w(buffer));
3663
3664 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3665 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3666
3667 msi_reg_set_val_str( hkey, squished_pc, buffer );
3668 RegCloseKey(hkey);
3669
3670 return ERROR_INSTALL_SUSPEND;
3671 }
3672
3673 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3674 {
3675 DWORD attrib;
3676 UINT rc;
3677 /*
3678 * we are currently doing what should be done here in the top level Install
3679 * however for Adminastrative and uninstalls this step will be needed
3680 */
3681 if (!package->PackagePath)
3682 return ERROR_SUCCESS;
3683
3684 attrib = GetFileAttributesW(package->PackagePath);
3685 if (attrib == INVALID_FILE_ATTRIBUTES)
3686 {
3687 LPWSTR prompt;
3688 LPWSTR msg;
3689 DWORD size = 0;
3690
3691 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3692 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3693 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3694 if (rc == ERROR_MORE_DATA)
3695 {
3696 prompt = msi_alloc(size * sizeof(WCHAR));
3697 MsiSourceListGetInfoW(package->ProductCode, NULL,
3698 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3699 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3700 }
3701 else
3702 prompt = strdupW(package->PackagePath);
3703
3704 msg = generate_error_string(package,1302,1,prompt);
3705 while(attrib == INVALID_FILE_ATTRIBUTES)
3706 {
3707 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3708 if (rc == IDCANCEL)
3709 {
3710 rc = ERROR_INSTALL_USEREXIT;
3711 break;
3712 }
3713 attrib = GetFileAttributesW(package->PackagePath);
3714 }
3715 msi_free(prompt);
3716 rc = ERROR_SUCCESS;
3717 }
3718 else
3719 return ERROR_SUCCESS;
3720
3721 return rc;
3722 }
3723
3724 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3725 {
3726 HKEY hkey=0;
3727 LPWSTR buffer;
3728 LPWSTR productid;
3729 UINT rc,i;
3730
3731 static const WCHAR szPropKeys[][80] =
3732 {
3733 {'P','r','o','d','u','c','t','I','D',0},
3734 {'U','S','E','R','N','A','M','E',0},
3735 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3736 {0},
3737 };
3738
3739 static const WCHAR szRegKeys[][80] =
3740 {
3741 {'P','r','o','d','u','c','t','I','D',0},
3742 {'R','e','g','O','w','n','e','r',0},
3743 {'R','e','g','C','o','m','p','a','n','y',0},
3744 {0},
3745 };
3746
3747 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3748 if (!productid)
3749 return ERROR_SUCCESS;
3750
3751 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3752 if (rc != ERROR_SUCCESS)
3753 goto end;
3754
3755 for( i = 0; szPropKeys[i][0]; i++ )
3756 {
3757 buffer = msi_dup_property( package, szPropKeys[i] );
3758 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3759 msi_free( buffer );
3760 }
3761
3762 end:
3763 msi_free(productid);
3764 RegCloseKey(hkey);
3765
3766 return ERROR_SUCCESS;
3767 }
3768
3769
3770 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3771 {
3772 UINT rc;
3773
3774 package->script->InWhatSequence |= SEQUENCE_EXEC;
3775 rc = ACTION_ProcessExecSequence(package,FALSE);
3776 return rc;
3777 }
3778
3779
3780 /*
3781 * Code based off of code located here
3782 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3783 *
3784 * Using string index 4 (full font name) instead of 1 (family name)
3785 */
3786 static LPWSTR load_ttfname_from(LPCWSTR filename)
3787 {
3788 HANDLE handle;
3789 LPWSTR ret = NULL;
3790 int i;
3791
3792 typedef struct _tagTT_OFFSET_TABLE{
3793 USHORT uMajorVersion;
3794 USHORT uMinorVersion;
3795 USHORT uNumOfTables;
3796 USHORT uSearchRange;
3797 USHORT uEntrySelector;
3798 USHORT uRangeShift;
3799 }TT_OFFSET_TABLE;
3800
3801 typedef struct _tagTT_TABLE_DIRECTORY{
3802 char szTag[4]; /* table name */
3803 ULONG uCheckSum; /* Check sum */
3804 ULONG uOffset; /* Offset from beginning of file */
3805 ULONG uLength; /* length of the table in bytes */
3806 }TT_TABLE_DIRECTORY;
3807
3808 typedef struct _tagTT_NAME_TABLE_HEADER{
3809 USHORT uFSelector; /* format selector. Always 0 */
3810 USHORT uNRCount; /* Name Records count */
3811 USHORT uStorageOffset; /* Offset for strings storage,
3812 * from start of the table */
3813 }TT_NAME_TABLE_HEADER;
3814
3815 typedef struct _tagTT_NAME_RECORD{
3816 USHORT uPlatformID;
3817 USHORT uEncodingID;
3818 USHORT uLanguageID;
3819 USHORT uNameID;
3820 USHORT uStringLength;
3821 USHORT uStringOffset; /* from start of storage area */
3822 }TT_NAME_RECORD;
3823
3824 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3825 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3826
3827 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3828 FILE_ATTRIBUTE_NORMAL, 0 );
3829 if (handle != INVALID_HANDLE_VALUE)
3830 {
3831 TT_TABLE_DIRECTORY tblDir;
3832 BOOL bFound = FALSE;
3833 TT_OFFSET_TABLE ttOffsetTable;
3834 DWORD dwRead;
3835
3836 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3837 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3838 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3839 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3840
3841 if (ttOffsetTable.uMajorVersion != 1 ||
3842 ttOffsetTable.uMinorVersion != 0)
3843 return NULL;
3844
3845 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3846 {
3847 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3848 if (strncmp(tblDir.szTag,"name",4)==0)
3849 {
3850 bFound = TRUE;
3851 tblDir.uLength = SWAPLONG(tblDir.uLength);
3852 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3853 break;
3854 }
3855 }
3856
3857 if (bFound)
3858 {
3859 TT_NAME_TABLE_HEADER ttNTHeader;
3860 TT_NAME_RECORD ttRecord;
3861
3862 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3863 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3864 &dwRead,NULL);
3865
3866 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3867 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3868 bFound = FALSE;
3869 for(i=0; i<ttNTHeader.uNRCount; i++)
3870 {
3871 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3872 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3873 /* 4 is the Full Font Name */
3874 if(ttRecord.uNameID == 4)
3875 {
3876 int nPos;
3877 LPSTR buf;
3878 static LPCSTR tt = " (TrueType)";
3879
3880 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3881 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3882 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3883 SetFilePointer(handle, tblDir.uOffset +
3884 ttRecord.uStringOffset +
3885 ttNTHeader.uStorageOffset,
3886 NULL, FILE_BEGIN);
3887 buf = msi_alloc( ttRecord.uStringLength + 1 + strlen(tt) );
3888 memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
3889 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3890 if (strlen(buf) > 0)
3891 {
3892 strcat(buf,tt);
3893 ret = strdupAtoW(buf);
3894 msi_free(buf);
3895 break;
3896 }
3897
3898 msi_free(buf);
3899 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3900 }
3901 }
3902 }
3903 CloseHandle(handle);
3904 }
3905 else
3906 ERR("Unable to open font file %s\n", debugstr_w(filename));
3907
3908 TRACE("Returning fontname %s\n",debugstr_w(ret));
3909 return ret;
3910 }
3911
3912 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3913 {
3914 MSIPACKAGE *package = (MSIPACKAGE*)param;
3915 LPWSTR name;
3916 LPCWSTR filename;
3917 MSIFILE *file;
3918 static const WCHAR regfont1[] =
3919 {'S','o','f','t','w','a','r','e','\\',
3920 'M','i','c','r','o','s','o','f','t','\\',
3921 'W','i','n','d','o','w','s',' ','N','T','\\',
3922 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3923 'F','o','n','t','s',0};
3924 static const WCHAR regfont2[] =
3925 {'S','o','f','t','w','a','r','e','\\',
3926 'M','i','c','r','o','s','o','f','t','\\',
3927 'W','i','n','d','o','w','s','\\',
3928 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3929 'F','o','n','t','s',0};
3930 HKEY hkey1;
3931 HKEY hkey2;
3932
3933 filename = MSI_RecordGetString( row, 1 );
3934 file = get_loaded_file( package, filename );
3935 if (!file)
3936 {
3937 ERR("Unable to load file\n");
3938 return ERROR_SUCCESS;
3939 }
3940
3941 /* check to make sure that component is installed */
3942 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3943 {
3944 TRACE("Skipping: Component not scheduled for install\n");
3945 return ERROR_SUCCESS;
3946 }
3947
3948 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3949 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3950
3951 if (MSI_RecordIsNull(row,2))
3952 name = load_ttfname_from( file->TargetPath );
3953 else
3954 name = msi_dup_record_field(row,2);
3955
3956 if (name)
3957 {
3958 msi_reg_set_val_str( hkey1, name, file->FileName );
3959 msi_reg_set_val_str( hkey2, name, file->FileName );
3960 }
3961
3962 msi_free(name);
3963 RegCloseKey(hkey1);
3964 RegCloseKey(hkey2);
3965 return ERROR_SUCCESS;
3966 }
3967
3968 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
3969 {
3970 UINT rc;
3971 MSIQUERY * view;
3972 static const WCHAR ExecSeqQuery[] =
3973 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3974 '`','F','o','n','t','`',0};
3975
3976 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3977 if (rc != ERROR_SUCCESS)
3978 {
3979 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
3980 return ERROR_SUCCESS;
3981 }
3982
3983 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
3984 msiobj_release(&view->hdr);
3985
3986 return ERROR_SUCCESS;
3987 }
3988
3989 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3990 {
3991 MSIPACKAGE *package = (MSIPACKAGE*)param;
3992 LPCWSTR compgroupid=NULL;
3993 LPCWSTR feature=NULL;
3994 LPCWSTR text = NULL;
3995 LPCWSTR qualifier = NULL;
3996 LPCWSTR component = NULL;
3997 LPWSTR advertise = NULL;
3998 LPWSTR output = NULL;
3999 HKEY hkey;
4000 UINT rc = ERROR_SUCCESS;
4001 MSICOMPONENT *comp;
4002 DWORD sz = 0;
4003
4004 component = MSI_RecordGetString(rec,3);
4005 comp = get_loaded_component(package,component);
4006
4007 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4008 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4009 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4010 {
4011 TRACE("Skipping: Component %s not scheduled for install\n",
4012 debugstr_w(component));
4013
4014 return ERROR_SUCCESS;
4015 }
4016
4017 compgroupid = MSI_RecordGetString(rec,1);
4018
4019 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4020 if (rc != ERROR_SUCCESS)
4021 goto end;
4022
4023 text = MSI_RecordGetString(rec,4);
4024 qualifier = MSI_RecordGetString(rec,2);
4025 feature = MSI_RecordGetString(rec,5);
4026
4027 advertise = create_component_advertise_string(package, comp, feature);
4028
4029 sz = strlenW(advertise);
4030
4031 if (text)
4032 sz += lstrlenW(text);
4033
4034 sz+=3;
4035 sz *= sizeof(WCHAR);
4036
4037 output = msi_alloc(sz);
4038 memset(output,0,sz);
4039 strcpyW(output,advertise);
4040 msi_free(advertise);
4041
4042 if (text)
4043 strcatW(output,text);
4044
4045 msi_reg_set_val_multi_str( hkey, qualifier, output );
4046
4047 end:
4048 RegCloseKey(hkey);
4049 msi_free(output);
4050
4051 return rc;
4052 }
4053
4054 /*
4055 * At present I am ignorning the advertised components part of this and only
4056 * focusing on the qualified component sets
4057 */
4058 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4059 {
4060 UINT rc;
4061 MSIQUERY * view;
4062 static const WCHAR ExecSeqQuery[] =
4063 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4064 '`','P','u','b','l','i','s','h',
4065 'C','o','m','p','o','n','e','n','t','`',0};
4066
4067 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4068 if (rc != ERROR_SUCCESS)
4069 return ERROR_SUCCESS;
4070
4071 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4072 msiobj_release(&view->hdr);
4073
4074 return rc;
4075 }
4076
4077 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4078 LPCSTR action, LPCWSTR table )
4079 {
4080 static const WCHAR query[] = {
4081 'S','E','L','E','C','T',' ','*',' ',
4082 'F','R','O','M',' ','`','%','s','`',0 };
4083 MSIQUERY *view = NULL;
4084 DWORD count = 0;
4085 UINT r;
4086
4087 r = MSI_OpenQuery( package->db, &view, query, table );
4088 if (r == ERROR_SUCCESS)
4089 {
4090 r = MSI_IterateRecords(view, &count, NULL, package);
4091 msiobj_release(&view->hdr);
4092 }
4093
4094 if (count)
4095 FIXME("%s -> %lu ignored %s table values\n",
4096 action, count, debugstr_w(table));
4097
4098 return ERROR_SUCCESS;
4099 }
4100
4101 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4102 {
4103 TRACE("%p\n", package);
4104 return ERROR_SUCCESS;
4105 }
4106
4107 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4108 {
4109 static const WCHAR table[] =
4110 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4111 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4112 }
4113
4114 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4115 {
4116 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4117 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4118 }
4119
4120 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4121 {
4122 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4123 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4124 }
4125
4126 static UINT ACTION_BindImage( MSIPACKAGE *package )
4127 {
4128 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4129 return msi_unimplemented_action_stub( package, "BindImage", table );
4130 }
4131
4132 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4133 {
4134 static const WCHAR table[] = {
4135 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4136 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4137 }
4138
4139 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4140 {
4141 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4142 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4143 }
4144
4145 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4146 {
4147 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4148 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4149 }
4150
4151 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4152 {
4153 static const WCHAR table[] = {
4154 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4155 return msi_unimplemented_action_stub( package, "InstallServices", table );
4156 }
4157
4158 static UINT ACTION_StartServices( MSIPACKAGE *package )
4159 {
4160 static const WCHAR table[] = {
4161 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4162 return msi_unimplemented_action_stub( package, "StartServices", table );
4163 }
4164
4165 static UINT ACTION_StopServices( MSIPACKAGE *package )
4166 {
4167 static const WCHAR table[] = {
4168 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4169 return msi_unimplemented_action_stub( package, "StopServices", table );
4170 }
4171
4172 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4173 {
4174 static const WCHAR table[] = {
4175 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4176 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4177 }
4178
4179 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4180 {
4181 static const WCHAR table[] = {
4182 'E','n','v','i','r','o','n','m','e','n','t',0 };
4183 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4184 }
4185
4186 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4187 {
4188 static const WCHAR table[] = {
4189 'E','n','v','i','r','o','n','m','e','n','t',0 };
4190 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4191 }
4192
4193 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4194 {
4195 static const WCHAR table[] = {
4196 'M','s','i','A','s','s','e','m','b','l','y',0 };
4197 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4198 }
4199
4200 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4201 {
4202 static const WCHAR table[] = {
4203 'M','s','i','A','s','s','e','m','b','l','y',0 };
4204 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4205 }
4206
4207 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4208 {
4209 static const WCHAR table[] = { 'F','o','n','t',0 };
4210 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4211 }
4212
4213 static struct _actions StandardActions[] = {
4214 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4215 { szAppSearch, ACTION_AppSearch },
4216 { szBindImage, ACTION_BindImage },
4217 { szCCPSearch, NULL},
4218 { szCostFinalize, ACTION_CostFinalize },
4219 { szCostInitialize, ACTION_CostInitialize },
4220 { szCreateFolders, ACTION_CreateFolders },
4221 { szCreateShortcuts, ACTION_CreateShortcuts },
4222 { szDeleteServices, ACTION_DeleteServices },
4223 { szDisableRollback, NULL},
4224 { szDuplicateFiles, ACTION_DuplicateFiles },
4225 { szExecuteAction, ACTION_ExecuteAction },
4226 { szFileCost, ACTION_FileCost },
4227 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4228 { szForceReboot, ACTION_ForceReboot },
4229 { szInstallAdminPackage, NULL},
4230 { szInstallExecute, ACTION_InstallExecute },
4231 { szInstallExecuteAgain, ACTION_InstallExecute },
4232 { szInstallFiles, ACTION_InstallFiles},
4233 { szInstallFinalize, ACTION_InstallFinalize },
4234 { szInstallInitialize, ACTION_InstallInitialize },
4235 { szInstallSFPCatalogFile, NULL},
4236 { szInstallValidate, ACTION_InstallValidate },
4237 { szIsolateComponents, ACTION_IsolateComponents },
4238 { szLaunchConditions, ACTION_LaunchConditions },
4239 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4240 { szMoveFiles, ACTION_MoveFiles },
4241 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4242 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4243 { szInstallODBC, NULL},
4244 { szInstallServices, ACTION_InstallServices },
4245 { szPatchFiles, ACTION_PatchFiles },
4246 { szProcessComponents, ACTION_ProcessComponents },
4247 { szPublishComponents, ACTION_PublishComponents },
4248 { szPublishFeatures, ACTION_PublishFeatures },
4249 { szPublishProduct, ACTION_PublishProduct },
4250 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4251 { szRegisterComPlus, NULL},
4252 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4253 { szRegisterFonts, ACTION_RegisterFonts },
4254 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4255 { szRegisterProduct, ACTION_RegisterProduct },
4256 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4257 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4258 { szRegisterUser, ACTION_RegisterUser},
4259 { szRemoveDuplicateFiles, NULL},
4260 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4261 { szRemoveExistingProducts, NULL},
4262 { szRemoveFiles, ACTION_RemoveFiles},
4263 { szRemoveFolders, NULL},
4264 { szRemoveIniValues, ACTION_RemoveIniValues },
4265 { szRemoveODBC, NULL},
4266 { szRemoveRegistryValues, NULL},
4267 { szRemoveShortcuts, NULL},
4268 { szResolveSource, ACTION_ResolveSource},
4269 { szRMCCPSearch, NULL},
4270 { szScheduleReboot, NULL},
4271 { szSelfRegModules, ACTION_SelfRegModules },
4272 { szSelfUnregModules, ACTION_SelfUnregModules },
4273 { szSetODBCFolders, NULL},
4274 { szStartServices, ACTION_StartServices },
4275 { szStopServices, ACTION_StopServices },
4276 { szUnpublishComponents, NULL},
4277 { szUnpublishFeatures, NULL},
4278 { szUnregisterClassInfo, NULL},
4279 { szUnregisterComPlus, NULL},
4280 { szUnregisterExtensionInfo, NULL},
4281 { szUnregisterFonts, ACTION_UnregisterFonts },
4282 { szUnregisterMIMEInfo, NULL},
4283 { szUnregisterProgIdInfo, NULL},
4284 { szUnregisterTypeLibraries, NULL},
4285 { szValidateProductID, NULL},
4286 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4287 { szWriteIniValues, ACTION_WriteIniValues },
4288 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4289 { NULL, NULL},
4290 };