Remove the unused 1st parameter of ACTION_VerifyComponentForAction.
[wine/multimedia.git] / dlls / msi / action.c
blob71df02722a06c26e2d3702beddcea68e4beb3d43
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Pages I need
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
29 #include <stdarg.h>
31 #define COBJMACROS
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"
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
49 #define LPCTSTR LPCWSTR
51 WINE_DEFAULT_DEBUG_CHANNEL(msi);
54 * Prototypes
56 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
57 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
58 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
61 * consts and values used
63 static const WCHAR c_colon[] = {'C',':','\\',0};
65 const static WCHAR szCreateFolders[] =
66 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
67 const static WCHAR szCostFinalize[] =
68 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
69 const WCHAR szInstallFiles[] =
70 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
71 const WCHAR szDuplicateFiles[] =
72 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
73 const static WCHAR szWriteRegistryValues[] =
74 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
75 'V','a','l','u','e','s',0};
76 const static WCHAR szCostInitialize[] =
77 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
78 const static WCHAR szFileCost[] =
79 {'F','i','l','e','C','o','s','t',0};
80 const static WCHAR szInstallInitialize[] =
81 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
82 const static WCHAR szInstallValidate[] =
83 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
84 const static WCHAR szLaunchConditions[] =
85 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
86 const static WCHAR szProcessComponents[] =
87 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
88 const static WCHAR szRegisterTypeLibraries[] =
89 {'R','e','g','i','s','t','e','r','T','y','p','e',
90 'L','i','b','r','a','r','i','e','s',0};
91 const WCHAR szRegisterClassInfo[] =
92 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
93 const WCHAR szRegisterProgIdInfo[] =
94 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
95 const static WCHAR szCreateShortcuts[] =
96 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
97 const static WCHAR szPublishProduct[] =
98 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
99 const static WCHAR szWriteIniValues[] =
100 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
101 const static WCHAR szSelfRegModules[] =
102 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
103 const static WCHAR szPublishFeatures[] =
104 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
105 const static WCHAR szRegisterProduct[] =
106 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
107 const static WCHAR szInstallExecute[] =
108 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
109 const static WCHAR szInstallExecuteAgain[] =
110 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
111 'A','g','a','i','n',0};
112 const static WCHAR szInstallFinalize[] =
113 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
114 const static WCHAR szForceReboot[] =
115 {'F','o','r','c','e','R','e','b','o','o','t',0};
116 const static WCHAR szResolveSource[] =
117 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
118 const WCHAR szAppSearch[] =
119 {'A','p','p','S','e','a','r','c','h',0};
120 const static WCHAR szAllocateRegistrySpace[] =
121 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
122 'S','p','a','c','e',0};
123 const static WCHAR szBindImage[] =
124 {'B','i','n','d','I','m','a','g','e',0};
125 const static WCHAR szCCPSearch[] =
126 {'C','C','P','S','e','a','r','c','h',0};
127 const static WCHAR szDeleteServices[] =
128 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
129 const static WCHAR szDisableRollback[] =
130 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
131 const static WCHAR szExecuteAction[] =
132 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
133 const WCHAR szFindRelatedProducts[] =
134 {'F','i','n','d','R','e','l','a','t','e','d',
135 'P','r','o','d','u','c','t','s',0};
136 const static WCHAR szInstallAdminPackage[] =
137 {'I','n','s','t','a','l','l','A','d','m','i','n',
138 'P','a','c','k','a','g','e',0};
139 const static WCHAR szInstallSFPCatalogFile[] =
140 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
141 'F','i','l','e',0};
142 const static WCHAR szIsolateComponents[] =
143 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
144 const WCHAR szMigrateFeatureStates[] =
145 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
146 'S','t','a','t','e','s',0};
147 const WCHAR szMoveFiles[] =
148 {'M','o','v','e','F','i','l','e','s',0};
149 const static WCHAR szMsiPublishAssemblies[] =
150 {'M','s','i','P','u','b','l','i','s','h',
151 'A','s','s','e','m','b','l','i','e','s',0};
152 const static WCHAR szMsiUnpublishAssemblies[] =
153 {'M','s','i','U','n','p','u','b','l','i','s','h',
154 'A','s','s','e','m','b','l','i','e','s',0};
155 const static WCHAR szInstallODBC[] =
156 {'I','n','s','t','a','l','l','O','D','B','C',0};
157 const static WCHAR szInstallServices[] =
158 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
159 const WCHAR szPatchFiles[] =
160 {'P','a','t','c','h','F','i','l','e','s',0};
161 const static WCHAR szPublishComponents[] =
162 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
163 const static WCHAR szRegisterComPlus[] =
164 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
165 const WCHAR szRegisterExtensionInfo[] =
166 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
167 'I','n','f','o',0};
168 const static WCHAR szRegisterFonts[] =
169 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
170 const WCHAR szRegisterMIMEInfo[] =
171 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
172 const static WCHAR szRegisterUser[] =
173 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
174 const WCHAR szRemoveDuplicateFiles[] =
175 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
176 'F','i','l','e','s',0};
177 const static WCHAR szRemoveEnvironmentStrings[] =
178 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
179 'S','t','r','i','n','g','s',0};
180 const WCHAR szRemoveExistingProducts[] =
181 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
182 'P','r','o','d','u','c','t','s',0};
183 const WCHAR szRemoveFiles[] =
184 {'R','e','m','o','v','e','F','i','l','e','s',0};
185 const static WCHAR szRemoveFolders[] =
186 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
187 const static WCHAR szRemoveIniValues[] =
188 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
189 const static WCHAR szRemoveODBC[] =
190 {'R','e','m','o','v','e','O','D','B','C',0};
191 const static WCHAR szRemoveRegistryValues[] =
192 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
193 'V','a','l','u','e','s',0};
194 const static WCHAR szRemoveShortcuts[] =
195 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
196 const static WCHAR szRMCCPSearch[] =
197 {'R','M','C','C','P','S','e','a','r','c','h',0};
198 const static WCHAR szScheduleReboot[] =
199 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
200 const static WCHAR szSelfUnregModules[] =
201 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
202 const static WCHAR szSetODBCFolders[] =
203 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
204 const static WCHAR szStartServices[] =
205 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
206 const static WCHAR szStopServices[] =
207 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
208 const static WCHAR szUnpublishComponents[] =
209 {'U','n','p','u','b','l','i','s','h',
210 'C','o','m','p','o','n','e','n','t','s',0};
211 const static WCHAR szUnpublishFeatures[] =
212 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
213 const WCHAR szUnregisterClassInfo[] =
214 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
215 'I','n','f','o',0};
216 const static WCHAR szUnregisterComPlus[] =
217 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
218 const WCHAR szUnregisterExtensionInfo[] =
219 {'U','n','r','e','g','i','s','t','e','r',
220 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
221 const static WCHAR szUnregisterFonts[] =
222 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
223 const WCHAR szUnregisterMIMEInfo[] =
224 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
225 const WCHAR szUnregisterProgIdInfo[] =
226 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
227 'I','n','f','o',0};
228 const static WCHAR szUnregisterTypeLibraries[] =
229 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
230 'L','i','b','r','a','r','i','e','s',0};
231 const static WCHAR szValidateProductID[] =
232 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
233 const static WCHAR szWriteEnvironmentStrings[] =
234 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
235 'S','t','r','i','n','g','s',0};
237 /* action handlers */
238 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
240 struct _actions {
241 LPCWSTR action;
242 STANDARDACTIONHANDLER handler;
245 static struct _actions StandardActions[];
248 /********************************************************
249 * helper functions
250 ********************************************************/
252 static void ce_actiontext(MSIPACKAGE* package, LPCWSTR action)
254 static const WCHAR szActionText[] =
255 {'A','c','t','i','o','n','T','e','x','t',0};
256 MSIRECORD *row;
258 row = MSI_CreateRecord(1);
259 MSI_RecordSetStringW(row,1,action);
260 ControlEvent_FireSubscribedEvent(package,szActionText, row);
261 msiobj_release(&row->hdr);
264 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
266 static const WCHAR template_s[]=
267 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
268 '.',0};
269 static const WCHAR format[] =
270 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
271 static const WCHAR Query_t[] =
272 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
273 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
274 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
275 ' ','\'','%','s','\'',0};
276 WCHAR message[1024];
277 WCHAR timet[0x100];
278 MSIRECORD * row = 0;
279 LPCWSTR ActionText;
280 LPWSTR deformated;
282 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
284 row = MSI_QueryGetRecord( package->db, Query_t, action );
285 if (!row)
286 return;
288 ActionText = MSI_RecordGetString(row,2);
289 deformat_string(package, ActionText, &deformated);
291 sprintfW(message,template_s,timet,action,deformated);
292 ce_actiontext(package, deformated);
293 msiobj_release(&row->hdr);
295 row = MSI_CreateRecord(1);
296 MSI_RecordSetStringW(row,1,message);
298 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
299 msiobj_release(&row->hdr);
300 msi_free(deformated);
303 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
304 UINT rc)
306 MSIRECORD * row;
307 static const WCHAR template_s[]=
308 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
309 '%','s', '.',0};
310 static const WCHAR template_e[]=
311 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
312 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
313 '%','i','.',0};
314 static const WCHAR format[] =
315 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
316 WCHAR message[1024];
317 WCHAR timet[0x100];
319 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
320 if (start)
321 sprintfW(message,template_s,timet,action);
322 else
323 sprintfW(message,template_e,timet,action,rc);
325 row = MSI_CreateRecord(1);
326 MSI_RecordSetStringW(row,1,message);
328 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
329 msiobj_release(&row->hdr);
332 static int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def )
334 LPWSTR str = msi_dup_property( package, prop );
335 int val = str ? atoiW( str ) : def;
336 msi_free( str );
337 return val;
340 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
342 LPCWSTR ptr,ptr2;
343 BOOL quote;
344 DWORD len;
345 LPWSTR prop = NULL, val = NULL;
347 if (!szCommandLine)
348 return ERROR_SUCCESS;
350 ptr = szCommandLine;
352 while (*ptr)
354 if (*ptr==' ')
356 ptr++;
357 continue;
360 TRACE("Looking at %s\n",debugstr_w(ptr));
362 ptr2 = strchrW(ptr,'=');
363 if (!ptr2)
365 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
366 break;
369 quote = FALSE;
371 len = ptr2-ptr;
372 prop = msi_alloc((len+1)*sizeof(WCHAR));
373 memcpy(prop,ptr,len*sizeof(WCHAR));
374 prop[len]=0;
375 ptr2++;
377 len = 0;
378 ptr = ptr2;
379 while (*ptr && (quote || (!quote && *ptr!=' ')))
381 if (*ptr == '"')
382 quote = !quote;
383 ptr++;
384 len++;
387 if (*ptr2=='"')
389 ptr2++;
390 len -= 2;
392 val = msi_alloc((len+1)*sizeof(WCHAR));
393 memcpy(val,ptr2,len*sizeof(WCHAR));
394 val[len] = 0;
396 if (lstrlenW(prop) > 0)
398 TRACE("Found commandline property (%s) = (%s)\n",
399 debugstr_w(prop), debugstr_w(val));
400 MSI_SetPropertyW(package,prop,val);
402 msi_free(val);
403 msi_free(prop);
406 return ERROR_SUCCESS;
410 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
412 LPWSTR p, *ret = NULL;
413 UINT count = 0;
415 if (!str)
416 return ret;
418 /* count the number of substrings */
419 for ( p = (LPWSTR)str, count = 0; p; count++ )
421 p = strchrW( p, sep );
422 if (p)
423 p++;
426 /* allocate space for an array of substring pointers and the substrings */
427 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
428 (lstrlenW(str)+1) * sizeof(WCHAR) );
429 if (!ret)
430 return ret;
432 /* copy the string and set the pointers */
433 p = (LPWSTR) &ret[count+1];
434 lstrcpyW( p, str );
435 for( count = 0; (ret[count] = p); count++ )
437 p = strchrW( p, sep );
438 if (p)
439 *p++ = 0;
442 return ret;
445 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
446 MSIDATABASE *patch_db, LPCWSTR name )
448 UINT ret = ERROR_FUNCTION_FAILED;
449 IStorage *stg = NULL;
450 HRESULT r;
452 TRACE("%p %s\n", package, debugstr_w(name) );
454 if (*name++ != ':')
456 ERR("expected a colon in %s\n", debugstr_w(name));
457 return ERROR_FUNCTION_FAILED;
460 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
461 if (SUCCEEDED(r))
463 ret = msi_table_apply_transform( package->db, stg );
464 IStorage_Release( stg );
465 ret = ERROR_SUCCESS;
467 else
468 ERR("failed to open substorage %s\n", debugstr_w(name));
470 return ret;
473 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
475 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
476 LPWSTR guid_list, *guids, product_id;
477 UINT i, ret = ERROR_FUNCTION_FAILED;
479 product_id = msi_dup_property( package, szProdID );
480 if (!product_id)
482 /* FIXME: the property ProductID should be written into the DB somewhere */
483 ERR("no product ID to check\n");
484 return ERROR_SUCCESS;
487 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
488 guids = msi_split_string( guid_list, ';' );
489 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
491 if (!lstrcmpW( guids[i], product_id ))
492 ret = ERROR_SUCCESS;
494 msi_free( guids );
495 msi_free( guid_list );
496 msi_free( product_id );
498 return ret;
501 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
503 MSISUMMARYINFO *si;
504 LPWSTR str, *substorage;
505 UINT i, r = ERROR_SUCCESS;
507 si = MSI_GetSummaryInformationW( patch_db, 0 );
508 if (!si)
509 return ERROR_FUNCTION_FAILED;
511 msi_check_patch_applicable( package, si );
513 /* enumerate the substorage */
514 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
515 substorage = msi_split_string( str, ';' );
516 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
517 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
518 msi_free( substorage );
519 msi_free( str );
521 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
523 msiobj_release( &si->hdr );
525 return r;
528 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
530 MSIDATABASE *patch_db = NULL;
531 UINT r;
533 TRACE("%p %s\n", package, debugstr_w( file ) );
535 /* FIXME:
536 * We probably want to make sure we only open a patch collection here.
537 * Patch collections (.msp) and databases (.msi) have different GUIDs
538 * but currently MSI_OpenDatabaseW will accept both.
540 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
541 if ( r != ERROR_SUCCESS )
543 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
544 return r;
547 msi_parse_patch_summary( package, patch_db );
548 msiobj_release( &patch_db->hdr );
550 return ERROR_SUCCESS;
553 /* get the PATCH property, and apply all the patches it specifies */
554 static UINT msi_apply_patches( MSIPACKAGE *package )
556 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
557 LPWSTR patch_list, *patches;
558 UINT i, r = ERROR_SUCCESS;
560 patch_list = msi_dup_property( package, szPatch );
562 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
564 patches = msi_split_string( patch_list, ';' );
565 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
566 r = msi_apply_patch_package( package, patches[i] );
568 msi_free( patches );
569 msi_free( patch_list );
571 return r;
574 /****************************************************
575 * TOP level entry points
576 *****************************************************/
578 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
579 LPCWSTR szCommandLine )
581 UINT rc;
582 BOOL ui = FALSE;
583 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
584 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
585 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
587 MSI_SetPropertyW(package, szAction, szInstall);
589 package->script = msi_alloc(sizeof(MSISCRIPT));
590 memset(package->script,0,sizeof(MSISCRIPT));
592 package->script->InWhatSequence = SEQUENCE_INSTALL;
594 if (szPackagePath)
596 LPWSTR p, check, path;
598 package->PackagePath = strdupW(szPackagePath);
599 path = strdupW(szPackagePath);
600 p = strrchrW(path,'\\');
601 if (p)
603 p++;
604 *p=0;
606 else
608 msi_free(path);
609 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
610 GetCurrentDirectoryW(MAX_PATH,path);
611 strcatW(path,cszbs);
614 check = msi_dup_property( package, cszSourceDir );
615 if (!check)
616 MSI_SetPropertyW(package, cszSourceDir, path);
617 msi_free(check);
618 msi_free(path);
621 msi_parse_command_line( package, szCommandLine );
623 msi_apply_patches( package );
625 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
627 package->script->InWhatSequence |= SEQUENCE_UI;
628 rc = ACTION_ProcessUISequence(package);
629 ui = TRUE;
630 if (rc == ERROR_SUCCESS)
632 package->script->InWhatSequence |= SEQUENCE_EXEC;
633 rc = ACTION_ProcessExecSequence(package,TRUE);
636 else
637 rc = ACTION_ProcessExecSequence(package,FALSE);
639 if (rc == -1)
641 /* install was halted but should be considered a success */
642 rc = ERROR_SUCCESS;
645 package->script->CurrentlyScripting= FALSE;
647 /* process the ending type action */
648 if (rc == ERROR_SUCCESS)
649 ACTION_PerformActionSequence(package,-1,ui);
650 else if (rc == ERROR_INSTALL_USEREXIT)
651 ACTION_PerformActionSequence(package,-2,ui);
652 else if (rc == ERROR_INSTALL_SUSPEND)
653 ACTION_PerformActionSequence(package,-4,ui);
654 else /* failed */
655 ACTION_PerformActionSequence(package,-3,ui);
657 /* finish up running custom actions */
658 ACTION_FinishCustomActions(package);
660 return rc;
663 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
665 UINT rc = ERROR_SUCCESS;
666 MSIRECORD * row = 0;
667 static const WCHAR ExecSeqQuery[] =
668 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
669 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
670 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
671 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
673 static const WCHAR UISeqQuery[] =
674 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
675 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
676 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
677 ' ', '=',' ','%','i',0};
679 if (UI)
680 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
681 else
682 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
684 if (row)
686 LPCWSTR action, cond;
688 TRACE("Running the actions\n");
690 /* check conditions */
691 cond = MSI_RecordGetString(row,2);
692 if (cond)
694 /* this is a hack to skip errors in the condition code */
695 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
696 goto end;
699 action = MSI_RecordGetString(row,1);
700 if (!action)
702 ERR("failed to fetch action\n");
703 rc = ERROR_FUNCTION_FAILED;
704 goto end;
707 if (UI)
708 rc = ACTION_PerformUIAction(package,action);
709 else
710 rc = ACTION_PerformAction(package,action,FALSE);
711 end:
712 msiobj_release(&row->hdr);
714 else
715 rc = ERROR_SUCCESS;
717 return rc;
720 typedef struct {
721 MSIPACKAGE* package;
722 BOOL UI;
723 } iterate_action_param;
725 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
727 iterate_action_param *iap= (iterate_action_param*)param;
728 UINT rc;
729 LPCWSTR cond, action;
731 action = MSI_RecordGetString(row,1);
732 if (!action)
734 ERR("Error is retrieving action name\n");
735 return ERROR_FUNCTION_FAILED;
738 /* check conditions */
739 cond = MSI_RecordGetString(row,2);
740 if (cond)
742 /* this is a hack to skip errors in the condition code */
743 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
745 TRACE("Skipping action: %s (condition is false)\n",
746 debugstr_w(action));
747 return ERROR_SUCCESS;
751 if (iap->UI)
752 rc = ACTION_PerformUIAction(iap->package,action);
753 else
754 rc = ACTION_PerformAction(iap->package,action,FALSE);
756 msi_dialog_check_messages( NULL );
758 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
759 rc = iap->package->CurrentInstallState;
761 if (rc == ERROR_FUNCTION_NOT_CALLED)
762 rc = ERROR_SUCCESS;
764 if (rc != ERROR_SUCCESS)
765 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
767 return rc;
770 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
772 MSIQUERY * view;
773 UINT r;
774 static const WCHAR query[] =
775 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
776 '`','%','s','`',
777 ' ','W','H','E','R','E',' ',
778 '`','S','e','q','u','e','n','c','e','`',' ',
779 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
780 '`','S','e','q','u','e','n','c','e','`',0};
781 iterate_action_param iap;
784 * FIXME: probably should be checking UILevel in the
785 * ACTION_PerformUIAction/ACTION_PerformAction
786 * rather than saving the UI level here. Those
787 * two functions can be merged too.
789 iap.package = package;
790 iap.UI = TRUE;
792 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
794 r = MSI_OpenQuery( package->db, &view, query, szTable );
795 if (r == ERROR_SUCCESS)
797 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
798 msiobj_release(&view->hdr);
801 return r;
804 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
806 MSIQUERY * view;
807 UINT rc;
808 static const WCHAR ExecSeqQuery[] =
809 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
810 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
811 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
812 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
813 'O','R','D','E','R',' ', 'B','Y',' ',
814 '`','S','e','q','u','e','n','c','e','`',0 };
815 MSIRECORD * row = 0;
816 static const WCHAR IVQuery[] =
817 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
818 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
819 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
820 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
821 ' ','\'', 'I','n','s','t','a','l','l',
822 'V','a','l','i','d','a','t','e','\'', 0};
823 INT seq = 0;
824 iterate_action_param iap;
826 iap.package = package;
827 iap.UI = FALSE;
829 if (package->script->ExecuteSequenceRun)
831 TRACE("Execute Sequence already Run\n");
832 return ERROR_SUCCESS;
835 package->script->ExecuteSequenceRun = TRUE;
837 /* get the sequence number */
838 if (UIran)
840 row = MSI_QueryGetRecord(package->db, IVQuery);
841 if( !row )
842 return ERROR_FUNCTION_FAILED;
843 seq = MSI_RecordGetInteger(row,1);
844 msiobj_release(&row->hdr);
847 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
848 if (rc == ERROR_SUCCESS)
850 TRACE("Running the actions\n");
852 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
853 msiobj_release(&view->hdr);
856 return rc;
859 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
861 MSIQUERY * view;
862 UINT rc;
863 static const WCHAR ExecSeqQuery [] =
864 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
865 '`','I','n','s','t','a','l','l',
866 'U','I','S','e','q','u','e','n','c','e','`',
867 ' ','W','H','E','R','E',' ',
868 '`','S','e','q','u','e','n','c','e','`',' ',
869 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
870 '`','S','e','q','u','e','n','c','e','`',0};
871 iterate_action_param iap;
873 iap.package = package;
874 iap.UI = TRUE;
876 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
878 if (rc == ERROR_SUCCESS)
880 TRACE("Running the actions \n");
882 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
883 msiobj_release(&view->hdr);
886 return rc;
889 /********************************************************
890 * ACTION helper functions and functions that perform the actions
891 *******************************************************/
892 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
893 UINT* rc, BOOL force )
895 BOOL ret = FALSE;
896 BOOL run = force;
897 int i;
899 if (!run && !package->script->CurrentlyScripting)
900 run = TRUE;
902 if (!run)
904 if (strcmpW(action,szInstallFinalize) == 0 ||
905 strcmpW(action,szInstallExecute) == 0 ||
906 strcmpW(action,szInstallExecuteAgain) == 0)
907 run = TRUE;
910 i = 0;
911 while (StandardActions[i].action != NULL)
913 if (strcmpW(StandardActions[i].action, action)==0)
915 if (!run)
917 ui_actioninfo(package, action, TRUE, 0);
918 *rc = schedule_action(package,INSTALL_SCRIPT,action);
919 ui_actioninfo(package, action, FALSE, *rc);
921 else
923 ui_actionstart(package, action);
924 if (StandardActions[i].handler)
926 *rc = StandardActions[i].handler(package);
928 else
930 FIXME("unhandled standard action %s\n",debugstr_w(action));
931 *rc = ERROR_SUCCESS;
934 ret = TRUE;
935 break;
937 i++;
939 return ret;
942 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
943 UINT* rc, BOOL force )
945 BOOL ret=FALSE;
946 UINT arc;
948 arc = ACTION_CustomAction(package,action, force);
950 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
952 *rc = arc;
953 ret = TRUE;
955 return ret;
959 * A lot of actions are really important even if they don't do anything
960 * explicit... Lots of properties are set at the beginning of the installation
961 * CostFinalize does a bunch of work to translate the directories and such
963 * But until I get write access to the database that is hard, so I am going to
964 * hack it to see if I can get something to run.
966 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
968 UINT rc = ERROR_SUCCESS;
969 BOOL handled;
971 TRACE("Performing action (%s)\n",debugstr_w(action));
973 handled = ACTION_HandleStandardAction(package, action, &rc, force);
975 if (!handled)
976 handled = ACTION_HandleCustomAction(package, action, &rc, force);
978 if (!handled)
980 FIXME("unhandled msi action %s\n",debugstr_w(action));
981 rc = ERROR_FUNCTION_NOT_CALLED;
984 return rc;
987 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
989 UINT rc = ERROR_SUCCESS;
990 BOOL handled = FALSE;
992 TRACE("Performing action (%s)\n",debugstr_w(action));
994 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
996 if (!handled)
997 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
999 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1000 handled = TRUE;
1002 if (!handled)
1004 FIXME("unhandled msi action %s\n",debugstr_w(action));
1005 rc = ERROR_FUNCTION_NOT_CALLED;
1008 return rc;
1013 * Actual Action Handlers
1016 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1018 MSIPACKAGE *package = (MSIPACKAGE*)param;
1019 LPCWSTR dir;
1020 LPWSTR full_path;
1021 MSIRECORD *uirow;
1022 MSIFOLDER *folder;
1024 dir = MSI_RecordGetString(row,1);
1025 if (!dir)
1027 ERR("Unable to get folder id \n");
1028 return ERROR_SUCCESS;
1031 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1032 if (!full_path)
1034 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1035 return ERROR_SUCCESS;
1038 TRACE("Folder is %s\n",debugstr_w(full_path));
1040 /* UI stuff */
1041 uirow = MSI_CreateRecord(1);
1042 MSI_RecordSetStringW(uirow,1,full_path);
1043 ui_actiondata(package,szCreateFolders,uirow);
1044 msiobj_release( &uirow->hdr );
1046 if (folder->State == 0)
1047 create_full_pathW(full_path);
1049 folder->State = 3;
1051 msi_free(full_path);
1052 return ERROR_SUCCESS;
1055 /* FIXME: probably should merge this with the above function */
1056 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1058 UINT rc = ERROR_SUCCESS;
1059 MSIFOLDER *folder;
1060 LPWSTR install_path;
1062 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1063 if (!install_path)
1064 return ERROR_FUNCTION_FAILED;
1066 /* create the path */
1067 if (folder->State == 0)
1069 create_full_pathW(install_path);
1070 folder->State = 2;
1072 msi_free(install_path);
1074 return rc;
1077 UINT msi_create_component_directories( MSIPACKAGE *package )
1079 MSICOMPONENT *comp;
1081 /* create all the folders required by the components are going to install */
1082 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1084 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1085 continue;
1086 msi_create_directory( package, comp->Directory );
1089 return ERROR_SUCCESS;
1093 * Also we cannot enable/disable components either, so for now I am just going
1094 * to do all the directories for all the components.
1096 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1098 static const WCHAR ExecSeqQuery[] =
1099 {'S','E','L','E','C','T',' ',
1100 '`','D','i','r','e','c','t','o','r','y','_','`',
1101 ' ','F','R','O','M',' ',
1102 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1103 UINT rc;
1104 MSIQUERY *view;
1106 /* create all the empty folders specified in the CreateFolder table */
1107 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1108 if (rc != ERROR_SUCCESS)
1109 return ERROR_SUCCESS;
1111 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1112 msiobj_release(&view->hdr);
1114 msi_create_component_directories( package );
1116 return rc;
1119 static MSICOMPONENT* load_component( MSIRECORD * row )
1121 MSICOMPONENT *comp;
1123 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1124 if (!comp)
1125 return comp;
1127 /* fill in the data */
1128 comp->Component = msi_dup_record_field( row, 1 );
1130 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1132 comp->ComponentId = msi_dup_record_field( row, 2 );
1133 comp->Directory = msi_dup_record_field( row, 3 );
1134 comp->Attributes = MSI_RecordGetInteger(row,4);
1135 comp->Condition = msi_dup_record_field( row, 5 );
1136 comp->KeyPath = msi_dup_record_field( row, 6 );
1138 comp->Installed = INSTALLSTATE_ABSENT;
1139 comp->Action = INSTALLSTATE_UNKNOWN;
1140 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1142 comp->Enabled = TRUE;
1144 return comp;
1147 typedef struct {
1148 MSIPACKAGE *package;
1149 MSIFEATURE *feature;
1150 } _ilfs;
1152 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1154 ComponentList *cl;
1156 cl = msi_alloc( sizeof (*cl) );
1157 if ( !cl )
1158 return ERROR_NOT_ENOUGH_MEMORY;
1159 cl->component = comp;
1160 list_add_tail( &feature->Components, &cl->entry );
1162 return ERROR_SUCCESS;
1165 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1167 _ilfs* ilfs= (_ilfs*)param;
1168 MSIPACKAGE *package = ilfs->package;
1169 MSIFEATURE *feature = ilfs->feature;
1170 MSICOMPONENT *comp;
1172 comp = load_component( row );
1173 if (!comp)
1174 return ERROR_FUNCTION_FAILED;
1176 list_add_tail( &package->components, &comp->entry );
1177 add_feature_component( feature, comp );
1179 TRACE("Loaded new component %p\n", comp);
1181 return ERROR_SUCCESS;
1184 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1186 _ilfs* ilfs= (_ilfs*)param;
1187 LPCWSTR component;
1188 DWORD rc;
1189 MSICOMPONENT *comp;
1190 MSIQUERY * view;
1191 static const WCHAR Query[] =
1192 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1193 '`','C','o','m','p','o','n','e','n','t','`',' ',
1194 'W','H','E','R','E',' ',
1195 '`','C','o','m','p','o','n','e','n','t','`',' ',
1196 '=','\'','%','s','\'',0};
1198 component = MSI_RecordGetString(row,1);
1200 /* check to see if the component is already loaded */
1201 comp = get_loaded_component( ilfs->package, component );
1202 if (comp)
1204 TRACE("Component %s already loaded\n", debugstr_w(component) );
1205 add_feature_component( ilfs->feature, comp );
1206 return ERROR_SUCCESS;
1209 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1210 if (rc != ERROR_SUCCESS)
1211 return ERROR_SUCCESS;
1213 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1214 msiobj_release( &view->hdr );
1216 return ERROR_SUCCESS;
1219 static UINT load_feature(MSIRECORD * row, LPVOID param)
1221 MSIPACKAGE* package = (MSIPACKAGE*)param;
1222 MSIFEATURE* feature;
1223 static const WCHAR Query1[] =
1224 {'S','E','L','E','C','T',' ',
1225 '`','C','o','m','p','o','n','e','n','t','_','`',
1226 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1227 'C','o','m','p','o','n','e','n','t','s','`',' ',
1228 'W','H','E','R','E',' ',
1229 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1230 MSIQUERY * view;
1231 UINT rc;
1232 _ilfs ilfs;
1234 /* fill in the data */
1236 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1237 if (!feature)
1238 return ERROR_NOT_ENOUGH_MEMORY;
1240 list_init( &feature->Components );
1242 feature->Feature = msi_dup_record_field( row, 1 );
1244 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1246 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1247 feature->Title = msi_dup_record_field( row, 3 );
1248 feature->Description = msi_dup_record_field( row, 4 );
1250 if (!MSI_RecordIsNull(row,5))
1251 feature->Display = MSI_RecordGetInteger(row,5);
1253 feature->Level= MSI_RecordGetInteger(row,6);
1254 feature->Directory = msi_dup_record_field( row, 7 );
1255 feature->Attributes = MSI_RecordGetInteger(row,8);
1257 feature->Installed = INSTALLSTATE_ABSENT;
1258 feature->Action = INSTALLSTATE_UNKNOWN;
1259 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1261 list_add_tail( &package->features, &feature->entry );
1263 /* load feature components */
1265 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1266 if (rc != ERROR_SUCCESS)
1267 return ERROR_SUCCESS;
1269 ilfs.package = package;
1270 ilfs.feature = feature;
1272 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1273 msiobj_release(&view->hdr);
1275 return ERROR_SUCCESS;
1278 static UINT load_file(MSIRECORD *row, LPVOID param)
1280 MSIPACKAGE* package = (MSIPACKAGE*)param;
1281 LPCWSTR component;
1282 MSIFILE *file;
1284 /* fill in the data */
1286 file = msi_alloc_zero( sizeof (MSIFILE) );
1287 if (!file)
1288 return ERROR_NOT_ENOUGH_MEMORY;
1290 file->File = msi_dup_record_field( row, 1 );
1292 component = MSI_RecordGetString( row, 2 );
1293 file->Component = get_loaded_component( package, component );
1295 if (!file->Component)
1296 ERR("Unfound Component %s\n",debugstr_w(component));
1298 file->FileName = msi_dup_record_field( row, 3 );
1299 reduce_to_longfilename( file->FileName );
1301 file->ShortName = msi_dup_record_field( row, 3 );
1302 reduce_to_shortfilename( file->ShortName );
1304 file->FileSize = MSI_RecordGetInteger( row, 4 );
1305 file->Version = msi_dup_record_field( row, 5 );
1306 file->Language = msi_dup_record_field( row, 6 );
1307 file->Attributes = MSI_RecordGetInteger( row, 7 );
1308 file->Sequence = MSI_RecordGetInteger( row, 8 );
1310 file->State = 0;
1312 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1314 list_add_tail( &package->files, &file->entry );
1316 return ERROR_SUCCESS;
1319 static UINT load_all_files(MSIPACKAGE *package)
1321 MSIQUERY * view;
1322 UINT rc;
1323 static const WCHAR Query[] =
1324 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1325 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1326 '`','S','e','q','u','e','n','c','e','`', 0};
1328 if (!package)
1329 return ERROR_INVALID_HANDLE;
1331 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1332 if (rc != ERROR_SUCCESS)
1333 return ERROR_SUCCESS;
1335 rc = MSI_IterateRecords(view, NULL, load_file, package);
1336 msiobj_release(&view->hdr);
1338 return ERROR_SUCCESS;
1343 * I am not doing any of the costing functionality yet.
1344 * Mostly looking at doing the Component and Feature loading
1346 * The native MSI does A LOT of modification to tables here. Mostly adding
1347 * a lot of temporary columns to the Feature and Component tables.
1349 * note: Native msi also tracks the short filename. But I am only going to
1350 * track the long ones. Also looking at this directory table
1351 * it appears that the directory table does not get the parents
1352 * resolved base on property only based on their entries in the
1353 * directory table.
1355 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1357 MSIQUERY * view;
1358 UINT rc;
1359 static const WCHAR Query_all[] =
1360 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1361 '`','F','e','a','t','u','r','e','`',0};
1362 static const WCHAR szCosting[] =
1363 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1364 static const WCHAR szZero[] = { '0', 0 };
1365 WCHAR buffer[3];
1366 DWORD sz = 3;
1368 MSI_GetPropertyW(package, szCosting, buffer, &sz);
1369 if (buffer[0]=='1')
1370 return ERROR_SUCCESS;
1372 MSI_SetPropertyW(package, szCosting, szZero);
1373 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1375 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1376 if (rc != ERROR_SUCCESS)
1377 return rc;
1379 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1380 msiobj_release(&view->hdr);
1382 load_all_files(package);
1384 return ERROR_SUCCESS;
1387 static UINT execute_script(MSIPACKAGE *package, UINT script )
1389 int i;
1390 UINT rc = ERROR_SUCCESS;
1392 TRACE("Executing Script %i\n",script);
1394 for (i = 0; i < package->script->ActionCount[script]; i++)
1396 LPWSTR action;
1397 action = package->script->Actions[script][i];
1398 ui_actionstart(package, action);
1399 TRACE("Executing Action (%s)\n",debugstr_w(action));
1400 rc = ACTION_PerformAction(package, action, TRUE);
1401 msi_free(package->script->Actions[script][i]);
1402 if (rc != ERROR_SUCCESS)
1403 break;
1405 msi_free(package->script->Actions[script]);
1407 package->script->ActionCount[script] = 0;
1408 package->script->Actions[script] = NULL;
1409 return rc;
1412 static UINT ACTION_FileCost(MSIPACKAGE *package)
1414 return ERROR_SUCCESS;
1418 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1420 static const WCHAR Query[] =
1421 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1422 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1423 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1424 ' ','=',' ','\'','%','s','\'',
1426 LPWSTR ptargetdir, targetdir, srcdir;
1427 LPCWSTR parent;
1428 LPWSTR shortname = NULL;
1429 MSIRECORD * row = 0;
1430 MSIFOLDER *folder;
1432 TRACE("Looking for dir %s\n",debugstr_w(dir));
1434 folder = get_loaded_folder( package, dir );
1435 if (folder)
1436 return folder;
1438 TRACE("Working to load %s\n",debugstr_w(dir));
1440 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1441 if (!folder)
1442 return NULL;
1444 folder->Directory = strdupW(dir);
1446 row = MSI_QueryGetRecord(package->db, Query, dir);
1447 if (!row)
1448 return NULL;
1450 ptargetdir = targetdir = msi_dup_record_field(row,3);
1452 /* split src and target dir */
1453 if (strchrW(targetdir,':'))
1455 srcdir=strchrW(targetdir,':');
1456 *srcdir=0;
1457 srcdir ++;
1459 else
1460 srcdir=NULL;
1462 /* for now only pick long filename versions */
1463 if (strchrW(targetdir,'|'))
1465 shortname = targetdir;
1466 targetdir = strchrW(targetdir,'|');
1467 *targetdir = 0;
1468 targetdir ++;
1470 /* for the sourcedir pick the short filename */
1471 if (srcdir && strchrW(srcdir,'|'))
1473 LPWSTR p = strchrW(srcdir,'|');
1474 *p = 0;
1477 /* now check for root dirs */
1478 if (targetdir[0] == '.' && targetdir[1] == 0)
1479 targetdir = NULL;
1481 if (targetdir)
1483 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
1484 msi_free( folder->TargetDefault);
1485 folder->TargetDefault = strdupW(targetdir);
1488 if (srcdir)
1489 folder->SourceDefault = strdupW(srcdir);
1490 else if (shortname)
1491 folder->SourceDefault = strdupW(shortname);
1492 else if (targetdir)
1493 folder->SourceDefault = strdupW(targetdir);
1494 msi_free(ptargetdir);
1495 TRACE(" SourceDefault = %s\n", debugstr_w( folder->SourceDefault ));
1497 parent = MSI_RecordGetString(row,2);
1498 if (parent)
1500 folder->Parent = load_folder( package, parent );
1501 if ( folder->Parent )
1502 TRACE("loaded parent %p %s\n", folder->Parent,
1503 debugstr_w(folder->Parent->Directory));
1504 else
1505 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1508 folder->Property = msi_dup_property( package, dir );
1510 msiobj_release(&row->hdr);
1512 list_add_tail( &package->folders, &folder->entry );
1514 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1516 return folder;
1519 /* scan for and update current install states */
1520 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1522 MSICOMPONENT *comp;
1523 MSIFEATURE *feature;
1525 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1527 INSTALLSTATE res;
1528 res = MsiGetComponentPathW( package->ProductCode,
1529 comp->ComponentId, NULL, NULL);
1530 if (res < 0)
1531 res = INSTALLSTATE_ABSENT;
1532 comp->Installed = res;
1535 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1537 ComponentList *cl;
1538 INSTALLSTATE res = -10;
1540 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1542 comp= cl->component;
1544 if (res == -10)
1545 res = comp->Installed;
1546 else
1548 if (res == comp->Installed)
1549 continue;
1551 if (res != comp->Installed)
1552 res = INSTALLSTATE_INCOMPLETE;
1555 feature->Installed = res;
1559 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1560 INSTALLSTATE state)
1562 static const WCHAR all[]={'A','L','L',0};
1563 LPWSTR override;
1564 MSIFEATURE *feature;
1566 override = msi_dup_property( package, property );
1567 if (!override)
1568 return FALSE;
1570 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1572 if (strcmpiW(override,all)==0)
1574 feature->ActionRequest= state;
1575 feature->Action = state;
1577 else
1579 LPWSTR ptr = override;
1580 LPWSTR ptr2 = strchrW(override,',');
1582 while (ptr)
1584 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1585 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1587 feature->ActionRequest= state;
1588 feature->Action = state;
1589 break;
1591 if (ptr2)
1593 ptr=ptr2+1;
1594 ptr2 = strchrW(ptr,',');
1596 else
1597 break;
1601 msi_free(override);
1603 return TRUE;
1606 static UINT SetFeatureStates(MSIPACKAGE *package)
1608 int install_level;
1609 static const WCHAR szlevel[] =
1610 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1611 static const WCHAR szAddLocal[] =
1612 {'A','D','D','L','O','C','A','L',0};
1613 static const WCHAR szRemove[] =
1614 {'R','E','M','O','V','E',0};
1615 BOOL override = FALSE;
1616 MSICOMPONENT* component;
1617 MSIFEATURE *feature;
1620 /* I do not know if this is where it should happen.. but */
1622 TRACE("Checking Install Level\n");
1624 install_level = msi_get_property_int( package, szlevel, 1 );
1626 /* ok hereis the _real_ rub
1627 * all these activation/deactivation things happen in order and things
1628 * later on the list override things earlier on the list.
1629 * 1) INSTALLLEVEL processing
1630 * 2) ADDLOCAL
1631 * 3) REMOVE
1632 * 4) ADDSOURCE
1633 * 5) ADDDEFAULT
1634 * 6) REINSTALL
1635 * 7) COMPADDLOCAL
1636 * 8) COMPADDSOURCE
1637 * 9) FILEADDLOCAL
1638 * 10) FILEADDSOURCE
1639 * 11) FILEADDDEFAULT
1640 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1641 * ignored for all the features. seems strange, especially since it is not
1642 * documented anywhere, but it is how it works.
1644 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1645 * REMOVE are the big ones, since we don't handle administrative installs
1646 * yet anyway.
1648 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1649 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1651 if (!override)
1653 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1655 BOOL feature_state = ((feature->Level > 0) &&
1656 (feature->Level <= install_level));
1658 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1660 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1662 feature->ActionRequest = INSTALLSTATE_SOURCE;
1663 feature->Action = INSTALLSTATE_SOURCE;
1665 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1667 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1668 feature->Action = INSTALLSTATE_ADVERTISED;
1670 else
1672 feature->ActionRequest = INSTALLSTATE_LOCAL;
1673 feature->Action = INSTALLSTATE_LOCAL;
1678 else
1680 /* set the Preselected Property */
1681 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1682 static const WCHAR szOne[] = { '1', 0 };
1684 MSI_SetPropertyW(package,szPreselected,szOne);
1688 * now we want to enable or disable components base on feature
1691 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1693 ComponentList *cl;
1695 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1696 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1697 feature->ActionRequest);
1699 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1701 component = cl->component;
1703 if (!component->Enabled)
1705 component->Action = INSTALLSTATE_UNKNOWN;
1706 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1708 else
1710 if (feature->Action == INSTALLSTATE_LOCAL)
1712 component->Action = INSTALLSTATE_LOCAL;
1713 component->ActionRequest = INSTALLSTATE_LOCAL;
1715 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1717 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1718 (component->Action == INSTALLSTATE_ABSENT) ||
1719 (component->Action == INSTALLSTATE_ADVERTISED))
1722 component->Action = INSTALLSTATE_SOURCE;
1723 component->ActionRequest = INSTALLSTATE_SOURCE;
1726 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1728 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1729 (component->Action == INSTALLSTATE_ABSENT))
1732 component->Action = INSTALLSTATE_ADVERTISED;
1733 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1736 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1738 if (component->Action == INSTALLSTATE_UNKNOWN)
1740 component->Action = INSTALLSTATE_ABSENT;
1741 component->ActionRequest = INSTALLSTATE_ABSENT;
1748 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1750 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1751 debugstr_w(component->Component), component->Installed,
1752 component->Action, component->ActionRequest);
1756 return ERROR_SUCCESS;
1759 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1761 MSIPACKAGE *package = (MSIPACKAGE*)param;
1762 LPCWSTR name;
1763 LPWSTR path;
1765 name = MSI_RecordGetString(row,1);
1767 /* This helper function now does ALL the work */
1768 TRACE("Dir %s ...\n",debugstr_w(name));
1769 load_folder(package,name);
1770 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1771 TRACE("resolves to %s\n",debugstr_w(path));
1772 msi_free(path);
1774 return ERROR_SUCCESS;
1777 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1779 MSIPACKAGE *package = (MSIPACKAGE*)param;
1780 LPCWSTR name;
1781 MSIFEATURE *feature;
1783 name = MSI_RecordGetString( row, 1 );
1785 feature = get_loaded_feature( package, name );
1786 if (!feature)
1787 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1788 else
1790 LPCWSTR Condition;
1791 Condition = MSI_RecordGetString(row,3);
1793 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1795 int level = MSI_RecordGetInteger(row,2);
1796 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1797 feature->Level = level;
1800 return ERROR_SUCCESS;
1805 * A lot is done in this function aside from just the costing.
1806 * The costing needs to be implemented at some point but for now I am going
1807 * to focus on the directory building
1810 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1812 static const WCHAR ExecSeqQuery[] =
1813 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1814 '`','D','i','r','e','c','t','o','r','y','`',0};
1815 static const WCHAR ConditionQuery[] =
1816 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1817 '`','C','o','n','d','i','t','i','o','n','`',0};
1818 static const WCHAR szCosting[] =
1819 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1820 static const WCHAR szlevel[] =
1821 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1822 static const WCHAR szOne[] = { '1', 0 };
1823 MSICOMPONENT *comp;
1824 MSIFILE *file;
1825 UINT rc;
1826 MSIQUERY * view;
1827 LPWSTR level;
1828 DWORD sz = 3;
1829 WCHAR buffer[3];
1831 MSI_GetPropertyW(package, szCosting, buffer, &sz);
1832 if (buffer[0]=='1')
1833 return ERROR_SUCCESS;
1835 TRACE("Building Directory properties\n");
1837 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1838 if (rc == ERROR_SUCCESS)
1840 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1841 package);
1842 msiobj_release(&view->hdr);
1845 TRACE("File calculations\n");
1847 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1849 MSICOMPONENT* comp = file->Component;
1850 LPWSTR p;
1852 if (!comp)
1853 continue;
1855 /* calculate target */
1856 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1858 msi_free(file->TargetPath);
1860 TRACE("file %s is named %s\n",
1861 debugstr_w(file->File),debugstr_w(file->FileName));
1863 file->TargetPath = build_directory_name(2, p, file->FileName);
1865 msi_free(p);
1867 TRACE("file %s resolves to %s\n",
1868 debugstr_w(file->File),debugstr_w(file->TargetPath));
1870 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1872 file->State = 1;
1873 comp->Cost += file->FileSize;
1874 continue;
1877 if (file->Version)
1879 DWORD handle;
1880 DWORD versize;
1881 UINT sz;
1882 LPVOID version;
1883 static const WCHAR name[] =
1884 {'\\',0};
1885 static const WCHAR name_fmt[] =
1886 {'%','u','.','%','u','.','%','u','.','%','u',0};
1887 WCHAR filever[0x100];
1888 VS_FIXEDFILEINFO *lpVer;
1890 TRACE("Version comparison.. \n");
1891 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1892 version = msi_alloc(versize);
1893 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1895 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1897 sprintfW(filever,name_fmt,
1898 HIWORD(lpVer->dwFileVersionMS),
1899 LOWORD(lpVer->dwFileVersionMS),
1900 HIWORD(lpVer->dwFileVersionLS),
1901 LOWORD(lpVer->dwFileVersionLS));
1903 TRACE("new %s old %s\n", debugstr_w(file->Version),
1904 debugstr_w(filever));
1905 if (strcmpiW(filever,file->Version)<0)
1907 file->State = 2;
1908 FIXME("cost should be diff in size\n");
1909 comp->Cost += file->FileSize;
1911 else
1912 file->State = 3;
1913 msi_free(version);
1915 else
1916 file->State = 3;
1919 TRACE("Evaluating Condition Table\n");
1921 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1922 if (rc == ERROR_SUCCESS)
1924 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1925 package);
1926 msiobj_release(&view->hdr);
1929 TRACE("Enabling or Disabling Components\n");
1930 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1932 if (comp->Condition)
1934 if (MSI_EvaluateConditionW(package,
1935 comp->Condition) == MSICONDITION_FALSE)
1937 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1938 comp->Enabled = FALSE;
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);
1950 ACTION_UpdateInstallStates(package);
1952 return SetFeatureStates(package);
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)
1960 LPSTR data = NULL;
1961 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1963 if (value[1]=='x')
1965 LPWSTR ptr;
1966 CHAR byte[5];
1967 LPWSTR deformated = NULL;
1968 int count;
1970 deformat_string(package, &value[2], &deformated);
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;
1980 data = msi_alloc(*size);
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)
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");
1996 while (*ptr)
1998 byte[2]= *ptr;
1999 ptr++;
2000 byte[3]= *ptr;
2001 ptr++;
2002 data[count] = (BYTE)strtol(byte,NULL,0);
2003 count ++;
2005 msi_free(deformated);
2007 TRACE("Data %li bytes(%i)\n",*size,count);
2009 else
2011 LPWSTR deformated;
2012 LPWSTR p;
2013 DWORD d = 0;
2014 deformat_string(package, &value[1], &deformated);
2016 *type=REG_DWORD;
2017 *size = sizeof(DWORD);
2018 data = msi_alloc(*size);
2019 p = deformated;
2020 if (*p == '-')
2021 p++;
2022 while (*p)
2024 if ( (*p < '0') || (*p > '9') )
2025 break;
2026 d *= 10;
2027 d += (*p - '0');
2028 p++;
2030 if (deformated[0] == '-')
2031 d = -d;
2032 *(LPDWORD)data = d;
2033 TRACE("DWORD %li\n",*(LPDWORD)data);
2035 msi_free(deformated);
2038 else
2040 static const WCHAR szMulti[] = {'[','~',']',0};
2041 LPCWSTR ptr;
2042 *type=REG_SZ;
2044 if (value[0]=='#')
2046 if (value[1]=='%')
2048 ptr = &value[2];
2049 *type=REG_EXPAND_SZ;
2051 else
2052 ptr = &value[1];
2054 else
2055 ptr=value;
2057 if (strstrW(value,szMulti))
2058 *type = REG_MULTI_SZ;
2060 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2062 return data;
2065 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
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};
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;
2092 ui_progress(package,2,0,0,0);
2094 value = NULL;
2095 key = NULL;
2096 uikey = NULL;
2097 name = NULL;
2099 component = MSI_RecordGetString(row, 6);
2100 comp = get_loaded_component(package,component);
2101 if (!comp)
2102 return ERROR_SUCCESS;
2104 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2106 TRACE("Skipping write due to disabled component %s\n",
2107 debugstr_w(component));
2109 comp->Action = comp->Installed;
2111 return ERROR_SUCCESS;
2114 comp->Action = INSTALLSTATE_LOCAL;
2116 name = MSI_RecordGetString(row, 4);
2117 if( MSI_RecordIsNull(row,5) && name )
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;
2128 root = MSI_RecordGetInteger(row,2);
2129 key = MSI_RecordGetString(row, 3);
2131 /* get the root key */
2132 switch (root)
2134 case -1:
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')
2140 root_key = HKEY_LOCAL_MACHINE;
2141 szRoot = szHLM;
2143 else
2145 root_key = HKEY_CURRENT_USER;
2146 szRoot = szHCU;
2148 msi_free(all_users);
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;
2169 if (!root_key)
2170 return ERROR_SUCCESS;
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);
2178 if (RegCreateKeyW( root_key, deformated, &hkey))
2180 ERR("Could not create key %s\n",debugstr_w(deformated));
2181 msi_free(deformated);
2182 msi_free(uikey);
2183 return ERROR_SUCCESS;
2185 msi_free(deformated);
2187 value = MSI_RecordGetString(row,5);
2188 if (value)
2189 value_data = parse_value(package, value, &type, &size);
2190 else
2192 static const WCHAR szEmpty[] = {0};
2193 value_data = (LPSTR)strdupW(szEmpty);
2194 size = 0;
2195 type = REG_SZ;
2198 deformat_string(package, name, &deformated);
2200 /* get the double nulls to terminate SZ_MULTI */
2201 if (type == REG_MULTI_SZ)
2202 size +=sizeof(WCHAR);
2204 if (!check_first)
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);
2210 else
2212 DWORD sz = 0;
2213 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2214 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2216 TRACE("value %s of %s checked already exists\n",
2217 debugstr_w(deformated), debugstr_w(uikey));
2219 else
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);
2227 RegCloseKey(hkey);
2229 uirow = MSI_CreateRecord(3);
2230 MSI_RecordSetStringW(uirow,2,deformated);
2231 MSI_RecordSetStringW(uirow,1,uikey);
2233 if (type == REG_SZ)
2234 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2235 else
2236 MSI_RecordSetStringW(uirow,3,value);
2238 ui_actiondata(package,szWriteRegistryValues,uirow);
2239 msiobj_release( &uirow->hdr );
2241 msi_free(value_data);
2242 msi_free(deformated);
2243 msi_free(uikey);
2245 return ERROR_SUCCESS;
2248 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
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 };
2256 if (!package)
2257 return ERROR_INVALID_HANDLE;
2259 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2260 if (rc != ERROR_SUCCESS)
2261 return ERROR_SUCCESS;
2263 /* increment progress bar each time action data is sent */
2264 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2266 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2268 msiobj_release(&view->hdr);
2269 return rc;
2272 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2274 package->script->CurrentlyScripting = TRUE;
2276 return ERROR_SUCCESS;
2280 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
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;
2293 TRACE("InstallValidate\n");
2295 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2296 if (rc == ERROR_SUCCESS)
2298 MSI_IterateRecords( view, &progress, NULL, package );
2299 msiobj_release( &view->hdr );
2300 total += progress * REG_PROGRESS_VALUE;
2303 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2304 total += COMPONENT_PROGRESS_VALUE;
2306 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2307 total += file->FileSize;
2309 ui_progress(package,0,total,0,0);
2311 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2313 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2314 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2315 feature->ActionRequest);
2318 return ERROR_SUCCESS;
2321 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
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};
2329 cond = MSI_RecordGetString(row,1);
2331 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
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;
2341 return ERROR_SUCCESS;
2344 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
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};
2352 TRACE("Checking launch conditions\n");
2354 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2355 if (rc != ERROR_SUCCESS)
2356 return ERROR_SUCCESS;
2358 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2359 msiobj_release(&view->hdr);
2361 return rc;
2364 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2367 if (!cmp->KeyPath)
2368 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2370 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
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};
2385 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2386 if (!row)
2387 return NULL;
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);
2395 len = strlenW(deformated) + 6;
2396 if (deformated_name)
2397 len+=strlenW(deformated_name);
2399 buffer = msi_alloc( len *sizeof(WCHAR));
2401 if (deformated_name)
2402 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2403 else
2404 sprintfW(buffer,fmt,root,deformated);
2406 msi_free(deformated);
2407 msi_free(deformated_name);
2408 msiobj_release(&row->hdr);
2410 return buffer;
2412 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2414 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2415 return NULL;
2417 else
2419 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2421 if (file)
2422 return strdupW( file->TargetPath );
2424 return NULL;
2427 static HKEY openSharedDLLsKey(void)
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};
2437 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2438 return hkey;
2441 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2443 HKEY hkey;
2444 DWORD count=0;
2445 DWORD type;
2446 DWORD sz = sizeof(count);
2447 DWORD rc;
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;
2457 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2459 HKEY hkey;
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;
2471 * Return TRUE if the count should be written out and FALSE if not
2473 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2475 MSIFEATURE *feature;
2476 INT count = 0;
2477 BOOL write = FALSE;
2479 /* only refcount DLLs */
2480 if (comp->KeyPath == NULL ||
2481 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2482 comp->Attributes & msidbComponentAttributesODBCDataSource)
2483 write = FALSE;
2484 else
2486 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2487 write = (count > 0);
2489 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2490 write = TRUE;
2493 /* increment counts */
2494 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2496 ComponentList *cl;
2498 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2499 continue;
2501 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2503 if ( cl->component == comp )
2504 count++;
2508 /* decrement counts */
2509 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2511 ComponentList *cl;
2513 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2514 continue;
2516 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2518 if ( cl->component == comp )
2519 count--;
2523 /* ref count all the files in the component */
2524 if (write)
2526 MSIFILE *file;
2528 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2530 if (file->Component == comp)
2531 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2535 /* add a count for permenent */
2536 if (comp->Attributes & msidbComponentAttributesPermanent)
2537 count ++;
2539 comp->RefCount = count;
2541 if (write)
2542 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
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
2552 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2554 WCHAR squished_pc[GUID_SIZE];
2555 WCHAR squished_cc[GUID_SIZE];
2556 UINT rc;
2557 MSICOMPONENT *comp;
2558 HKEY hkey=0,hkey2=0;
2560 if (!package)
2561 return ERROR_INVALID_HANDLE;
2563 /* writes the Component and Features values to the registry */
2565 rc = MSIREG_OpenComponents(&hkey);
2566 if (rc != ERROR_SUCCESS)
2567 goto end;
2569 squash_guid(package->ProductCode,squished_pc);
2570 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2572 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2574 ui_progress(package,2,0,0,0);
2575 if (comp->ComponentId)
2577 MSIRECORD * uirow;
2579 squash_guid(comp->ComponentId,squished_cc);
2581 msi_free(comp->FullKeypath);
2582 comp->FullKeypath = resolve_keypath( package, comp );
2584 /* do the refcounting */
2585 ACTION_RefCountComponent( package, comp );
2587 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2588 debugstr_w(comp->Component),
2589 debugstr_w(squished_cc),
2590 debugstr_w(comp->FullKeypath),
2591 comp->RefCount);
2593 * Write the keypath out if the component is to be registered
2594 * and delete the key if the component is to be deregistered
2596 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2598 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2599 if (rc != ERROR_SUCCESS)
2600 continue;
2602 if (comp->FullKeypath)
2604 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2606 if (comp->Attributes & msidbComponentAttributesPermanent)
2608 static const WCHAR szPermKey[] =
2609 { '0','0','0','0','0','0','0','0','0','0','0','0',
2610 '0','0','0','0','0','0','0','0','0','0','0','0',
2611 '0','0','0','0','0','0','0','0',0};
2613 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2616 RegCloseKey(hkey2);
2618 /* UI stuff */
2619 uirow = MSI_CreateRecord(3);
2620 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2621 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2622 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2623 ui_actiondata(package,szProcessComponents,uirow);
2624 msiobj_release( &uirow->hdr );
2627 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2629 DWORD res;
2631 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2632 if (rc != ERROR_SUCCESS)
2633 continue;
2635 RegDeleteValueW(hkey2,squished_pc);
2637 /* if the key is empty delete it */
2638 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2639 RegCloseKey(hkey2);
2640 if (res == ERROR_NO_MORE_ITEMS)
2641 RegDeleteKeyW(hkey,squished_cc);
2643 /* UI stuff */
2644 uirow = MSI_CreateRecord(2);
2645 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2646 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2647 ui_actiondata(package,szProcessComponents,uirow);
2648 msiobj_release( &uirow->hdr );
2652 end:
2653 RegCloseKey(hkey);
2654 return rc;
2657 typedef struct {
2658 CLSID clsid;
2659 LPWSTR source;
2661 LPWSTR path;
2662 ITypeLib *ptLib;
2663 } typelib_struct;
2665 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2666 LPWSTR lpszName, LONG_PTR lParam)
2668 TLIBATTR *attr;
2669 typelib_struct *tl_struct = (typelib_struct*) lParam;
2670 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2671 int sz;
2672 HRESULT res;
2674 if (!IS_INTRESOURCE(lpszName))
2676 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2677 return TRUE;
2680 sz = strlenW(tl_struct->source)+4;
2681 sz *= sizeof(WCHAR);
2683 if ((INT)lpszName == 1)
2684 tl_struct->path = strdupW(tl_struct->source);
2685 else
2687 tl_struct->path = msi_alloc(sz);
2688 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2691 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2692 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2693 if (!SUCCEEDED(res))
2695 msi_free(tl_struct->path);
2696 tl_struct->path = NULL;
2698 return TRUE;
2701 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2702 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2704 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2705 return FALSE;
2708 msi_free(tl_struct->path);
2709 tl_struct->path = NULL;
2711 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2712 ITypeLib_Release(tl_struct->ptLib);
2714 return TRUE;
2717 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2719 MSIPACKAGE* package = (MSIPACKAGE*)param;
2720 LPCWSTR component;
2721 MSICOMPONENT *comp;
2722 MSIFILE *file;
2723 typelib_struct tl_struct;
2724 HMODULE module;
2725 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2727 component = MSI_RecordGetString(row,3);
2728 comp = get_loaded_component(package,component);
2729 if (!comp)
2730 return ERROR_SUCCESS;
2732 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2734 TRACE("Skipping typelib reg due to disabled component\n");
2736 comp->Action = comp->Installed;
2738 return ERROR_SUCCESS;
2741 comp->Action = INSTALLSTATE_LOCAL;
2743 file = get_loaded_file( package, comp->KeyPath );
2744 if (!file)
2745 return ERROR_SUCCESS;
2747 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2748 if (module)
2750 LPCWSTR guid;
2751 guid = MSI_RecordGetString(row,1);
2752 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2753 tl_struct.source = strdupW( file->TargetPath );
2754 tl_struct.path = NULL;
2756 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2757 (LONG_PTR)&tl_struct);
2759 if (tl_struct.path)
2761 LPWSTR help = NULL;
2762 LPCWSTR helpid;
2763 HRESULT res;
2765 helpid = MSI_RecordGetString(row,6);
2767 if (helpid)
2768 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2769 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2770 msi_free(help);
2772 if (!SUCCEEDED(res))
2773 ERR("Failed to register type library %s\n",
2774 debugstr_w(tl_struct.path));
2775 else
2777 ui_actiondata(package,szRegisterTypeLibraries,row);
2779 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2782 ITypeLib_Release(tl_struct.ptLib);
2783 msi_free(tl_struct.path);
2785 else
2786 ERR("Failed to load type library %s\n",
2787 debugstr_w(tl_struct.source));
2789 FreeLibrary(module);
2790 msi_free(tl_struct.source);
2792 else
2793 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2795 return ERROR_SUCCESS;
2798 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2801 * OK this is a bit confusing.. I am given a _Component key and I believe
2802 * that the file that is being registered as a type library is the "key file
2803 * of that component" which I interpret to mean "The file in the KeyPath of
2804 * that component".
2806 UINT rc;
2807 MSIQUERY * view;
2808 static const WCHAR Query[] =
2809 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2810 '`','T','y','p','e','L','i','b','`',0};
2812 if (!package)
2813 return ERROR_INVALID_HANDLE;
2815 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2816 if (rc != ERROR_SUCCESS)
2817 return ERROR_SUCCESS;
2819 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2820 msiobj_release(&view->hdr);
2821 return rc;
2824 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2826 MSIPACKAGE *package = (MSIPACKAGE*)param;
2827 LPWSTR target_file, target_folder;
2828 LPCWSTR buffer;
2829 WCHAR filename[0x100];
2830 DWORD sz;
2831 MSICOMPONENT *comp;
2832 static const WCHAR szlnk[]={'.','l','n','k',0};
2833 IShellLinkW *sl;
2834 IPersistFile *pf;
2835 HRESULT res;
2837 buffer = MSI_RecordGetString(row,4);
2838 comp = get_loaded_component(package,buffer);
2839 if (!comp)
2840 return ERROR_SUCCESS;
2842 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2844 TRACE("Skipping shortcut creation due to disabled component\n");
2846 comp->Action = comp->Installed;
2848 return ERROR_SUCCESS;
2851 comp->Action = INSTALLSTATE_LOCAL;
2853 ui_actiondata(package,szCreateShortcuts,row);
2855 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2856 &IID_IShellLinkW, (LPVOID *) &sl );
2858 if (FAILED(res))
2860 ERR("Is IID_IShellLink\n");
2861 return ERROR_SUCCESS;
2864 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2865 if( FAILED( res ) )
2867 ERR("Is IID_IPersistFile\n");
2868 return ERROR_SUCCESS;
2871 buffer = MSI_RecordGetString(row,2);
2872 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2874 /* may be needed because of a bug somehwere else */
2875 create_full_pathW(target_folder);
2877 sz = 0x100;
2878 MSI_RecordGetStringW(row,3,filename,&sz);
2879 reduce_to_longfilename(filename);
2880 if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk))
2881 strcatW(filename,szlnk);
2882 target_file = build_directory_name(2, target_folder, filename);
2883 msi_free(target_folder);
2885 buffer = MSI_RecordGetString(row,5);
2886 if (strchrW(buffer,'['))
2888 LPWSTR deformated;
2889 deformat_string(package,buffer,&deformated);
2890 IShellLinkW_SetPath(sl,deformated);
2891 msi_free(deformated);
2893 else
2895 FIXME("poorly handled shortcut format, advertised shortcut\n");
2896 IShellLinkW_SetPath(sl,comp->FullKeypath);
2899 if (!MSI_RecordIsNull(row,6))
2901 LPWSTR deformated;
2902 buffer = MSI_RecordGetString(row,6);
2903 deformat_string(package,buffer,&deformated);
2904 IShellLinkW_SetArguments(sl,deformated);
2905 msi_free(deformated);
2908 if (!MSI_RecordIsNull(row,7))
2910 buffer = MSI_RecordGetString(row,7);
2911 IShellLinkW_SetDescription(sl,buffer);
2914 if (!MSI_RecordIsNull(row,8))
2915 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2917 if (!MSI_RecordIsNull(row,9))
2919 LPWSTR Path;
2920 INT index;
2922 buffer = MSI_RecordGetString(row,9);
2924 Path = build_icon_path(package,buffer);
2925 index = MSI_RecordGetInteger(row,10);
2927 IShellLinkW_SetIconLocation(sl,Path,index);
2928 msi_free(Path);
2931 if (!MSI_RecordIsNull(row,11))
2932 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2934 if (!MSI_RecordIsNull(row,12))
2936 LPWSTR Path;
2937 buffer = MSI_RecordGetString(row,12);
2938 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2939 IShellLinkW_SetWorkingDirectory(sl,Path);
2940 msi_free(Path);
2943 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2944 IPersistFile_Save(pf,target_file,FALSE);
2946 msi_free(target_file);
2948 IPersistFile_Release( pf );
2949 IShellLinkW_Release( sl );
2951 return ERROR_SUCCESS;
2954 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2956 UINT rc;
2957 HRESULT res;
2958 MSIQUERY * view;
2959 static const WCHAR Query[] =
2960 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2961 '`','S','h','o','r','t','c','u','t','`',0};
2963 if (!package)
2964 return ERROR_INVALID_HANDLE;
2966 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2967 if (rc != ERROR_SUCCESS)
2968 return ERROR_SUCCESS;
2970 res = CoInitialize( NULL );
2971 if (FAILED (res))
2973 ERR("CoInitialize failed\n");
2974 return ERROR_FUNCTION_FAILED;
2977 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2978 msiobj_release(&view->hdr);
2980 CoUninitialize();
2982 return rc;
2985 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2987 MSIPACKAGE* package = (MSIPACKAGE*)param;
2988 HANDLE the_file;
2989 LPWSTR FilePath;
2990 LPCWSTR FileName;
2991 CHAR buffer[1024];
2992 DWORD sz;
2993 UINT rc;
2995 FileName = MSI_RecordGetString(row,1);
2996 if (!FileName)
2998 ERR("Unable to get FileName\n");
2999 return ERROR_SUCCESS;
3002 FilePath = build_icon_path(package,FileName);
3004 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3006 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3007 FILE_ATTRIBUTE_NORMAL, NULL);
3009 if (the_file == INVALID_HANDLE_VALUE)
3011 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3012 msi_free(FilePath);
3013 return ERROR_SUCCESS;
3018 DWORD write;
3019 sz = 1024;
3020 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3021 if (rc != ERROR_SUCCESS)
3023 ERR("Failed to get stream\n");
3024 CloseHandle(the_file);
3025 DeleteFileW(FilePath);
3026 break;
3028 WriteFile(the_file,buffer,sz,&write,NULL);
3029 } while (sz == 1024);
3031 msi_free(FilePath);
3033 CloseHandle(the_file);
3034 return ERROR_SUCCESS;
3038 * 99% of the work done here is only done for
3039 * advertised installs. However this is where the
3040 * Icon table is processed and written out
3041 * so that is what I am going to do here.
3043 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3045 UINT rc;
3046 MSIQUERY * view;
3047 static const WCHAR Query[]=
3048 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3049 '`','I','c','o','n','`',0};
3050 /* for registry stuff */
3051 HKEY hkey=0;
3052 HKEY hukey=0;
3053 static const WCHAR szProductLanguage[] =
3054 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3055 static const WCHAR szARPProductIcon[] =
3056 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3057 static const WCHAR szProductVersion[] =
3058 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3059 DWORD langid;
3060 LPWSTR buffer;
3061 DWORD size;
3062 MSIHANDLE hDb, hSumInfo;
3064 if (!package)
3065 return ERROR_INVALID_HANDLE;
3067 /* write out icon files */
3069 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3070 if (rc == ERROR_SUCCESS)
3072 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3073 msiobj_release(&view->hdr);
3076 /* ok there is a lot more done here but i need to figure out what */
3078 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3079 if (rc != ERROR_SUCCESS)
3080 goto end;
3082 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3083 if (rc != ERROR_SUCCESS)
3084 goto end;
3087 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3088 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3089 msi_free(buffer);
3091 langid = msi_get_property_int( package, szProductLanguage, 0 );
3092 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3094 buffer = msi_dup_property( package, szARPProductIcon );
3095 if (buffer)
3097 LPWSTR path = build_icon_path(package,buffer);
3098 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3099 msi_free( path );
3101 msi_free(buffer);
3103 buffer = msi_dup_property( package, szProductVersion );
3104 if (buffer)
3106 DWORD verdword = build_version_dword(buffer);
3107 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3109 msi_free(buffer);
3111 FIXME("Need to write more keys to the user registry\n");
3113 hDb= alloc_msihandle( &package->db->hdr );
3114 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3115 MsiCloseHandle(hDb);
3116 if (rc == ERROR_SUCCESS)
3118 WCHAR guidbuffer[0x200];
3119 size = 0x200;
3120 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3121 guidbuffer, &size);
3122 if (rc == ERROR_SUCCESS)
3124 WCHAR squashed[GUID_SIZE];
3125 /* for now we only care about the first guid */
3126 LPWSTR ptr = strchrW(guidbuffer,';');
3127 if (ptr) *ptr = 0;
3128 squash_guid(guidbuffer,squashed);
3129 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3131 else
3133 ERR("Unable to query Revision_Number... \n");
3134 rc = ERROR_SUCCESS;
3136 MsiCloseHandle(hSumInfo);
3138 else
3140 ERR("Unable to open Summary Information\n");
3141 rc = ERROR_SUCCESS;
3144 end:
3146 RegCloseKey(hkey);
3147 RegCloseKey(hukey);
3149 return rc;
3152 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3154 MSIPACKAGE *package = (MSIPACKAGE*)param;
3155 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3156 LPWSTR deformated_section, deformated_key, deformated_value;
3157 LPWSTR folder, fullname = NULL;
3158 MSIRECORD * uirow;
3159 INT action;
3160 MSICOMPONENT *comp;
3161 static const WCHAR szWindowsFolder[] =
3162 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3164 component = MSI_RecordGetString(row, 8);
3165 comp = get_loaded_component(package,component);
3167 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3169 TRACE("Skipping ini file due to disabled component %s\n",
3170 debugstr_w(component));
3172 comp->Action = comp->Installed;
3174 return ERROR_SUCCESS;
3177 comp->Action = INSTALLSTATE_LOCAL;
3179 identifier = MSI_RecordGetString(row,1);
3180 filename = MSI_RecordGetString(row,2);
3181 dirproperty = MSI_RecordGetString(row,3);
3182 section = MSI_RecordGetString(row,4);
3183 key = MSI_RecordGetString(row,5);
3184 value = MSI_RecordGetString(row,6);
3185 action = MSI_RecordGetInteger(row,7);
3187 deformat_string(package,section,&deformated_section);
3188 deformat_string(package,key,&deformated_key);
3189 deformat_string(package,value,&deformated_value);
3191 if (dirproperty)
3193 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3194 if (!folder)
3195 folder = msi_dup_property( package, dirproperty );
3197 else
3198 folder = msi_dup_property( package, szWindowsFolder );
3200 if (!folder)
3202 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3203 goto cleanup;
3206 fullname = build_directory_name(2, folder, filename);
3208 if (action == 0)
3210 TRACE("Adding value %s to section %s in %s\n",
3211 debugstr_w(deformated_key), debugstr_w(deformated_section),
3212 debugstr_w(fullname));
3213 WritePrivateProfileStringW(deformated_section, deformated_key,
3214 deformated_value, fullname);
3216 else if (action == 1)
3218 WCHAR returned[10];
3219 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3220 returned, 10, fullname);
3221 if (returned[0] == 0)
3223 TRACE("Adding value %s to section %s in %s\n",
3224 debugstr_w(deformated_key), debugstr_w(deformated_section),
3225 debugstr_w(fullname));
3227 WritePrivateProfileStringW(deformated_section, deformated_key,
3228 deformated_value, fullname);
3231 else if (action == 3)
3232 FIXME("Append to existing section not yet implemented\n");
3234 uirow = MSI_CreateRecord(4);
3235 MSI_RecordSetStringW(uirow,1,identifier);
3236 MSI_RecordSetStringW(uirow,2,deformated_section);
3237 MSI_RecordSetStringW(uirow,3,deformated_key);
3238 MSI_RecordSetStringW(uirow,4,deformated_value);
3239 ui_actiondata(package,szWriteIniValues,uirow);
3240 msiobj_release( &uirow->hdr );
3241 cleanup:
3242 msi_free(fullname);
3243 msi_free(folder);
3244 msi_free(deformated_key);
3245 msi_free(deformated_value);
3246 msi_free(deformated_section);
3247 return ERROR_SUCCESS;
3250 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3252 UINT rc;
3253 MSIQUERY * view;
3254 static const WCHAR ExecSeqQuery[] =
3255 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3256 '`','I','n','i','F','i','l','e','`',0};
3258 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3259 if (rc != ERROR_SUCCESS)
3261 TRACE("no IniFile table\n");
3262 return ERROR_SUCCESS;
3265 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3266 msiobj_release(&view->hdr);
3267 return rc;
3270 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3272 MSIPACKAGE *package = (MSIPACKAGE*)param;
3273 LPCWSTR filename;
3274 LPWSTR FullName;
3275 MSIFILE *file;
3276 DWORD len;
3277 static const WCHAR ExeStr[] =
3278 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3279 static const WCHAR close[] = {'\"',0};
3280 STARTUPINFOW si;
3281 PROCESS_INFORMATION info;
3282 BOOL brc;
3284 memset(&si,0,sizeof(STARTUPINFOW));
3286 filename = MSI_RecordGetString(row,1);
3287 file = get_loaded_file( package, filename );
3289 if (!file)
3291 ERR("Unable to find file id %s\n",debugstr_w(filename));
3292 return ERROR_SUCCESS;
3295 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3297 FullName = msi_alloc(len*sizeof(WCHAR));
3298 strcpyW(FullName,ExeStr);
3299 strcatW( FullName, file->TargetPath );
3300 strcatW(FullName,close);
3302 TRACE("Registering %s\n",debugstr_w(FullName));
3303 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3304 &si, &info);
3306 if (brc)
3307 msi_dialog_check_messages(info.hProcess);
3309 msi_free(FullName);
3310 return ERROR_SUCCESS;
3313 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3315 UINT rc;
3316 MSIQUERY * view;
3317 static const WCHAR ExecSeqQuery[] =
3318 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3319 '`','S','e','l','f','R','e','g','`',0};
3321 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3322 if (rc != ERROR_SUCCESS)
3324 TRACE("no SelfReg table\n");
3325 return ERROR_SUCCESS;
3328 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3329 msiobj_release(&view->hdr);
3331 return ERROR_SUCCESS;
3334 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3336 MSIFEATURE *feature;
3337 UINT rc;
3338 HKEY hkey=0;
3339 HKEY hukey=0;
3341 if (!package)
3342 return ERROR_INVALID_HANDLE;
3344 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3345 if (rc != ERROR_SUCCESS)
3346 goto end;
3348 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3349 if (rc != ERROR_SUCCESS)
3350 goto end;
3352 /* here the guids are base 85 encoded */
3353 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3355 ComponentList *cl;
3356 LPWSTR data = NULL;
3357 GUID clsid;
3358 INT size;
3359 BOOL absent = FALSE;
3361 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3362 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3363 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3364 absent = TRUE;
3366 size = 1;
3367 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3369 size += 21;
3371 if (feature->Feature_Parent)
3372 size += strlenW( feature->Feature_Parent )+2;
3374 data = msi_alloc(size * sizeof(WCHAR));
3376 data[0] = 0;
3377 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3379 MSICOMPONENT* component = cl->component;
3380 WCHAR buf[21];
3382 memset(buf,0,sizeof(buf));
3383 if (component->ComponentId)
3385 TRACE("From %s\n",debugstr_w(component->ComponentId));
3386 CLSIDFromString(component->ComponentId, &clsid);
3387 encode_base85_guid(&clsid,buf);
3388 TRACE("to %s\n",debugstr_w(buf));
3389 strcatW(data,buf);
3392 if (feature->Feature_Parent)
3394 static const WCHAR sep[] = {'\2',0};
3395 strcatW(data,sep);
3396 strcatW(data,feature->Feature_Parent);
3399 msi_reg_set_val_str( hkey, feature->Feature, data );
3400 msi_free(data);
3402 size = 0;
3403 if (feature->Feature_Parent)
3404 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3405 if (!absent)
3407 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3408 (LPBYTE)feature->Feature_Parent,size);
3410 else
3412 size += 2*sizeof(WCHAR);
3413 data = msi_alloc(size);
3414 data[0] = 0x6;
3415 data[1] = 0;
3416 if (feature->Feature_Parent)
3417 strcpyW( &data[1], feature->Feature_Parent );
3418 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3419 (LPBYTE)data,size);
3420 msi_free(data);
3424 end:
3425 RegCloseKey(hkey);
3426 RegCloseKey(hukey);
3427 return rc;
3430 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3432 static const WCHAR installerPathFmt[] = {
3433 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3434 static const WCHAR fmt[] = {
3435 '%','s','\\',
3436 'I','n','s','t','a','l','l','e','r','\\',
3437 '%','x','.','m','s','i',0};
3438 static const WCHAR szOriginalDatabase[] =
3439 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3440 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3441 INT num, start;
3442 LPWSTR msiFilePath;
3443 BOOL r;
3445 /* copy the package locally */
3446 num = GetTickCount() & 0xffff;
3447 if (!num)
3448 num = 1;
3449 start = num;
3450 GetWindowsDirectoryW( windir, MAX_PATH );
3451 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3454 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3455 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3456 if (handle != INVALID_HANDLE_VALUE)
3458 CloseHandle(handle);
3459 break;
3461 if (GetLastError() != ERROR_FILE_EXISTS &&
3462 GetLastError() != ERROR_SHARING_VIOLATION)
3463 break;
3464 if (!(++num & 0xffff)) num = 1;
3465 sprintfW(packagefile,fmt,num);
3466 } while (num != start);
3468 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3469 create_full_pathW(path);
3471 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3473 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3474 r = CopyFileW( msiFilePath, packagefile, FALSE);
3475 msi_free( msiFilePath );
3477 if (!r)
3479 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3480 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3481 return ERROR_FUNCTION_FAILED;
3484 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3485 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3486 return ERROR_SUCCESS;
3489 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3491 LPWSTR prop, val, key;
3492 static const LPCSTR propval[] = {
3493 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3494 "ARPCONTACT", "Contact",
3495 "ARPCOMMENTS", "Comments",
3496 "ProductName", "DisplayName",
3497 "ProductVersion", "DisplayVersion",
3498 "ARPHELPLINK", "HelpLink",
3499 "ARPHELPTELEPHONE", "HelpTelephone",
3500 "ARPINSTALLLOCATION", "InstallLocation",
3501 "SourceDir", "InstallSource",
3502 "Manufacturer", "Publisher",
3503 "ARPREADME", "Readme",
3504 "ARPSIZE", "Size",
3505 "ARPURLINFOABOUT", "URLInfoAbout",
3506 "ARPURLUPDATEINFO", "URLUpdateInfo",
3507 NULL,
3509 const LPCSTR *p = propval;
3511 while( *p )
3513 prop = strdupAtoW( *p++ );
3514 key = strdupAtoW( *p++ );
3515 val = msi_dup_property( package, prop );
3516 msi_reg_set_val_str( hkey, key, val );
3517 msi_free(val);
3518 msi_free(key);
3519 msi_free(prop);
3521 return ERROR_SUCCESS;
3524 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3526 HKEY hkey=0;
3527 LPWSTR buffer = NULL;
3528 UINT rc;
3529 DWORD size, langid;
3530 static const WCHAR szWindowsInstaller[] =
3531 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3532 static const WCHAR szUpgradeCode[] =
3533 {'U','p','g','r','a','d','e','C','o','d','e',0};
3534 static const WCHAR modpath_fmt[] =
3535 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3536 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3537 static const WCHAR szModifyPath[] =
3538 {'M','o','d','i','f','y','P','a','t','h',0};
3539 static const WCHAR szUninstallString[] =
3540 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3541 static const WCHAR szEstimatedSize[] =
3542 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3543 static const WCHAR szProductLanguage[] =
3544 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3545 static const WCHAR szProductVersion[] =
3546 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3548 SYSTEMTIME systime;
3549 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3550 LPWSTR upgrade_code;
3551 WCHAR szDate[9];
3553 if (!package)
3554 return ERROR_INVALID_HANDLE;
3556 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3557 if (rc != ERROR_SUCCESS)
3558 return rc;
3560 /* dump all the info i can grab */
3561 FIXME("Flesh out more information \n");
3563 msi_write_uninstall_property_vals( package, hkey );
3565 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3567 msi_make_package_local( package, hkey );
3569 /* do ModifyPath and UninstallString */
3570 size = deformat_string(package,modpath_fmt,&buffer);
3571 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3572 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3573 msi_free(buffer);
3575 FIXME("Write real Estimated Size when we have it\n");
3576 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3578 GetLocalTime(&systime);
3579 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3580 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3582 langid = msi_get_property_int( package, szProductLanguage, 0 );
3583 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3585 buffer = msi_dup_property( package, szProductVersion );
3586 if (buffer)
3588 DWORD verdword = build_version_dword(buffer);
3590 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3591 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3592 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3594 msi_free(buffer);
3596 /* Handle Upgrade Codes */
3597 upgrade_code = msi_dup_property( package, szUpgradeCode );
3598 if (upgrade_code)
3600 HKEY hkey2;
3601 WCHAR squashed[33];
3602 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3603 squash_guid(package->ProductCode,squashed);
3604 msi_reg_set_val_str( hkey2, squashed, NULL );
3605 RegCloseKey(hkey2);
3606 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3607 squash_guid(package->ProductCode,squashed);
3608 msi_reg_set_val_str( hkey2, squashed, NULL );
3609 RegCloseKey(hkey2);
3611 msi_free(upgrade_code);
3614 RegCloseKey(hkey);
3616 return ERROR_SUCCESS;
3619 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3621 UINT rc;
3623 if (!package)
3624 return ERROR_INVALID_HANDLE;
3626 rc = execute_script(package,INSTALL_SCRIPT);
3628 return rc;
3631 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3633 UINT rc;
3635 if (!package)
3636 return ERROR_INVALID_HANDLE;
3638 /* turn off scheduleing */
3639 package->script->CurrentlyScripting= FALSE;
3641 /* first do the same as an InstallExecute */
3642 rc = ACTION_InstallExecute(package);
3643 if (rc != ERROR_SUCCESS)
3644 return rc;
3646 /* then handle Commit Actions */
3647 rc = execute_script(package,COMMIT_SCRIPT);
3649 return rc;
3652 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3654 static const WCHAR RunOnce[] = {
3655 'S','o','f','t','w','a','r','e','\\',
3656 'M','i','c','r','o','s','o','f','t','\\',
3657 'W','i','n','d','o','w','s','\\',
3658 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3659 'R','u','n','O','n','c','e',0};
3660 static const WCHAR InstallRunOnce[] = {
3661 'S','o','f','t','w','a','r','e','\\',
3662 'M','i','c','r','o','s','o','f','t','\\',
3663 'W','i','n','d','o','w','s','\\',
3664 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3665 'I','n','s','t','a','l','l','e','r','\\',
3666 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3668 static const WCHAR msiexec_fmt[] = {
3669 '%','s',
3670 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3671 '\"','%','s','\"',0};
3672 static const WCHAR install_fmt[] = {
3673 '/','I',' ','\"','%','s','\"',' ',
3674 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3675 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3676 WCHAR buffer[256], sysdir[MAX_PATH];
3677 HKEY hkey;
3678 WCHAR squished_pc[100];
3680 if (!package)
3681 return ERROR_INVALID_HANDLE;
3683 squash_guid(package->ProductCode,squished_pc);
3685 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3686 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3687 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3688 squished_pc);
3690 msi_reg_set_val_str( hkey, squished_pc, buffer );
3691 RegCloseKey(hkey);
3693 TRACE("Reboot command %s\n",debugstr_w(buffer));
3695 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3696 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3698 msi_reg_set_val_str( hkey, squished_pc, buffer );
3699 RegCloseKey(hkey);
3701 return ERROR_INSTALL_SUSPEND;
3704 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3706 DWORD attrib;
3707 UINT rc;
3709 * we are currently doing what should be done here in the top level Install
3710 * however for Adminastrative and uninstalls this step will be needed
3712 if (!package->PackagePath)
3713 return ERROR_SUCCESS;
3715 attrib = GetFileAttributesW(package->PackagePath);
3716 if (attrib == INVALID_FILE_ATTRIBUTES)
3718 LPWSTR prompt;
3719 LPWSTR msg;
3720 DWORD size = 0;
3722 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3723 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3724 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3725 if (rc == ERROR_MORE_DATA)
3727 prompt = msi_alloc(size * sizeof(WCHAR));
3728 MsiSourceListGetInfoW(package->ProductCode, NULL,
3729 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3730 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3732 else
3733 prompt = strdupW(package->PackagePath);
3735 msg = generate_error_string(package,1302,1,prompt);
3736 while(attrib == INVALID_FILE_ATTRIBUTES)
3738 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3739 if (rc == IDCANCEL)
3741 rc = ERROR_INSTALL_USEREXIT;
3742 break;
3744 attrib = GetFileAttributesW(package->PackagePath);
3746 msi_free(prompt);
3747 rc = ERROR_SUCCESS;
3749 else
3750 return ERROR_SUCCESS;
3752 return rc;
3755 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3757 HKEY hkey=0;
3758 LPWSTR buffer;
3759 LPWSTR productid;
3760 UINT rc,i;
3762 static const WCHAR szPropKeys[][80] =
3764 {'P','r','o','d','u','c','t','I','D',0},
3765 {'U','S','E','R','N','A','M','E',0},
3766 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3767 {0},
3770 static const WCHAR szRegKeys[][80] =
3772 {'P','r','o','d','u','c','t','I','D',0},
3773 {'R','e','g','O','w','n','e','r',0},
3774 {'R','e','g','C','o','m','p','a','n','y',0},
3775 {0},
3778 if (!package)
3779 return ERROR_INVALID_HANDLE;
3781 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3782 if (!productid)
3783 return ERROR_SUCCESS;
3785 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3786 if (rc != ERROR_SUCCESS)
3787 goto end;
3789 for( i = 0; szPropKeys[i][0]; i++ )
3791 buffer = msi_dup_property( package, szPropKeys[i] );
3792 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3793 msi_free( buffer );
3796 end:
3797 msi_free(productid);
3798 RegCloseKey(hkey);
3800 return ERROR_SUCCESS;
3804 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3806 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
3807 static const WCHAR szTwo[] = {'2',0};
3808 UINT rc;
3809 LPWSTR level;
3810 level = msi_dup_property( package, szUILevel );
3812 MSI_SetPropertyW(package,szUILevel,szTwo);
3813 package->script->InWhatSequence |= SEQUENCE_EXEC;
3814 rc = ACTION_ProcessExecSequence(package,FALSE);
3815 MSI_SetPropertyW(package,szUILevel,level);
3816 msi_free(level);
3817 return rc;
3822 * Code based off of code located here
3823 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3825 * Using string index 4 (full font name) instead of 1 (family name)
3827 static LPWSTR load_ttfname_from(LPCWSTR filename)
3829 HANDLE handle;
3830 LPWSTR ret = NULL;
3831 int i;
3833 typedef struct _tagTT_OFFSET_TABLE{
3834 USHORT uMajorVersion;
3835 USHORT uMinorVersion;
3836 USHORT uNumOfTables;
3837 USHORT uSearchRange;
3838 USHORT uEntrySelector;
3839 USHORT uRangeShift;
3840 }TT_OFFSET_TABLE;
3842 typedef struct _tagTT_TABLE_DIRECTORY{
3843 char szTag[4]; /* table name */
3844 ULONG uCheckSum; /* Check sum */
3845 ULONG uOffset; /* Offset from beginning of file */
3846 ULONG uLength; /* length of the table in bytes */
3847 }TT_TABLE_DIRECTORY;
3849 typedef struct _tagTT_NAME_TABLE_HEADER{
3850 USHORT uFSelector; /* format selector. Always 0 */
3851 USHORT uNRCount; /* Name Records count */
3852 USHORT uStorageOffset; /* Offset for strings storage,
3853 * from start of the table */
3854 }TT_NAME_TABLE_HEADER;
3856 typedef struct _tagTT_NAME_RECORD{
3857 USHORT uPlatformID;
3858 USHORT uEncodingID;
3859 USHORT uLanguageID;
3860 USHORT uNameID;
3861 USHORT uStringLength;
3862 USHORT uStringOffset; /* from start of storage area */
3863 }TT_NAME_RECORD;
3865 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3866 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3868 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3869 FILE_ATTRIBUTE_NORMAL, 0 );
3870 if (handle != INVALID_HANDLE_VALUE)
3872 TT_TABLE_DIRECTORY tblDir;
3873 BOOL bFound = FALSE;
3874 TT_OFFSET_TABLE ttOffsetTable;
3875 DWORD dwRead;
3877 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3878 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3879 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3880 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3882 if (ttOffsetTable.uMajorVersion != 1 ||
3883 ttOffsetTable.uMinorVersion != 0)
3884 return NULL;
3886 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3888 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3889 if (strncmp(tblDir.szTag,"name",4)==0)
3891 bFound = TRUE;
3892 tblDir.uLength = SWAPLONG(tblDir.uLength);
3893 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3894 break;
3898 if (bFound)
3900 TT_NAME_TABLE_HEADER ttNTHeader;
3901 TT_NAME_RECORD ttRecord;
3903 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3904 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3905 &dwRead,NULL);
3907 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3908 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3909 bFound = FALSE;
3910 for(i=0; i<ttNTHeader.uNRCount; i++)
3912 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3913 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3914 /* 4 is the Full Font Name */
3915 if(ttRecord.uNameID == 4)
3917 int nPos;
3918 LPSTR buf;
3919 static LPCSTR tt = " (TrueType)";
3921 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3922 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3923 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3924 SetFilePointer(handle, tblDir.uOffset +
3925 ttRecord.uStringOffset +
3926 ttNTHeader.uStorageOffset,
3927 NULL, FILE_BEGIN);
3928 buf = msi_alloc( ttRecord.uStringLength + 1 + strlen(tt) );
3929 memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
3930 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3931 if (strlen(buf) > 0)
3933 strcat(buf,tt);
3934 ret = strdupAtoW(buf);
3935 msi_free(buf);
3936 break;
3939 msi_free(buf);
3940 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3944 CloseHandle(handle);
3946 else
3947 ERR("Unable to open font file %s\n", debugstr_w(filename));
3949 TRACE("Returning fontname %s\n",debugstr_w(ret));
3950 return ret;
3953 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3955 MSIPACKAGE *package = (MSIPACKAGE*)param;
3956 LPWSTR name;
3957 LPCWSTR filename;
3958 MSIFILE *file;
3959 static const WCHAR regfont1[] =
3960 {'S','o','f','t','w','a','r','e','\\',
3961 'M','i','c','r','o','s','o','f','t','\\',
3962 'W','i','n','d','o','w','s',' ','N','T','\\',
3963 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3964 'F','o','n','t','s',0};
3965 static const WCHAR regfont2[] =
3966 {'S','o','f','t','w','a','r','e','\\',
3967 'M','i','c','r','o','s','o','f','t','\\',
3968 'W','i','n','d','o','w','s','\\',
3969 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3970 'F','o','n','t','s',0};
3971 HKEY hkey1;
3972 HKEY hkey2;
3974 filename = MSI_RecordGetString( row, 1 );
3975 file = get_loaded_file( package, filename );
3976 if (!file)
3978 ERR("Unable to load file\n");
3979 return ERROR_SUCCESS;
3982 /* check to make sure that component is installed */
3983 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3985 TRACE("Skipping: Component not scheduled for install\n");
3986 return ERROR_SUCCESS;
3989 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3990 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3992 if (MSI_RecordIsNull(row,2))
3993 name = load_ttfname_from( file->TargetPath );
3994 else
3995 name = msi_dup_record_field(row,2);
3997 if (name)
3999 msi_reg_set_val_str( hkey1, name, file->FileName );
4000 msi_reg_set_val_str( hkey2, name, file->FileName );
4003 msi_free(name);
4004 RegCloseKey(hkey1);
4005 RegCloseKey(hkey2);
4006 return ERROR_SUCCESS;
4009 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
4011 UINT rc;
4012 MSIQUERY * view;
4013 static const WCHAR ExecSeqQuery[] =
4014 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4015 '`','F','o','n','t','`',0};
4017 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4018 if (rc != ERROR_SUCCESS)
4020 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4021 return ERROR_SUCCESS;
4024 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4025 msiobj_release(&view->hdr);
4027 return ERROR_SUCCESS;
4030 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4032 MSIPACKAGE *package = (MSIPACKAGE*)param;
4033 LPCWSTR compgroupid=NULL;
4034 LPCWSTR feature=NULL;
4035 LPCWSTR text = NULL;
4036 LPCWSTR qualifier = NULL;
4037 LPCWSTR component = NULL;
4038 LPWSTR advertise = NULL;
4039 LPWSTR output = NULL;
4040 HKEY hkey;
4041 UINT rc = ERROR_SUCCESS;
4042 MSICOMPONENT *comp;
4043 DWORD sz = 0;
4045 component = MSI_RecordGetString(rec,3);
4046 comp = get_loaded_component(package,component);
4048 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4049 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4050 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4052 TRACE("Skipping: Component %s not scheduled for install\n",
4053 debugstr_w(component));
4055 return ERROR_SUCCESS;
4058 compgroupid = MSI_RecordGetString(rec,1);
4060 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4061 if (rc != ERROR_SUCCESS)
4062 goto end;
4064 text = MSI_RecordGetString(rec,4);
4065 qualifier = MSI_RecordGetString(rec,2);
4066 feature = MSI_RecordGetString(rec,5);
4068 advertise = create_component_advertise_string(package, comp, feature);
4070 sz = strlenW(advertise);
4072 if (text)
4073 sz += lstrlenW(text);
4075 sz+=3;
4076 sz *= sizeof(WCHAR);
4078 output = msi_alloc(sz);
4079 memset(output,0,sz);
4080 strcpyW(output,advertise);
4081 msi_free(advertise);
4083 if (text)
4084 strcatW(output,text);
4086 msi_reg_set_val_multi_str( hkey, qualifier, output );
4088 end:
4089 RegCloseKey(hkey);
4090 msi_free(output);
4092 return rc;
4096 * At present I am ignorning the advertised components part of this and only
4097 * focusing on the qualified component sets
4099 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4101 UINT rc;
4102 MSIQUERY * view;
4103 static const WCHAR ExecSeqQuery[] =
4104 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4105 '`','P','u','b','l','i','s','h',
4106 'C','o','m','p','o','n','e','n','t','`',0};
4108 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4109 if (rc != ERROR_SUCCESS)
4110 return ERROR_SUCCESS;
4112 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4113 msiobj_release(&view->hdr);
4115 return rc;
4118 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4119 LPCSTR action, LPCWSTR table )
4121 static const WCHAR query[] = {
4122 'S','E','L','E','C','T',' ','*',' ',
4123 'F','R','O','M',' ','`','%','s','`',0 };
4124 MSIQUERY *view = NULL;
4125 DWORD count = 0;
4126 UINT r;
4128 r = MSI_OpenQuery( package->db, &view, query, table );
4129 if (r == ERROR_SUCCESS)
4131 r = MSI_IterateRecords(view, &count, NULL, package);
4132 msiobj_release(&view->hdr);
4135 if (count)
4136 FIXME("%s -> %lu ignored %s table values\n",
4137 action, count, debugstr_w(table));
4139 return ERROR_SUCCESS;
4142 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4144 static const WCHAR table[] =
4145 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4146 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4149 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4151 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4152 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4155 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4157 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4158 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4161 static UINT ACTION_BindImage( MSIPACKAGE *package )
4163 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4164 return msi_unimplemented_action_stub( package, "BindImage", table );
4167 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4169 static const WCHAR table[] = {
4170 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4171 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4174 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4176 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4177 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4180 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4182 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4183 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4186 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4188 static const WCHAR table[] = {
4189 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4190 return msi_unimplemented_action_stub( package, "InstallServices", table );
4193 static UINT ACTION_StartServices( MSIPACKAGE *package )
4195 static const WCHAR table[] = {
4196 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4197 return msi_unimplemented_action_stub( package, "StartServices", table );
4200 static UINT ACTION_StopServices( MSIPACKAGE *package )
4202 static const WCHAR table[] = {
4203 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4204 return msi_unimplemented_action_stub( package, "StopServices", table );
4207 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4209 static const WCHAR table[] = {
4210 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4211 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4214 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4216 static const WCHAR table[] = {
4217 'E','n','v','i','r','o','n','m','e','n','t',0 };
4218 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4221 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4223 static const WCHAR table[] = {
4224 'E','n','v','i','r','o','n','m','e','n','t',0 };
4225 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4228 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4230 static const WCHAR table[] = {
4231 'M','s','i','A','s','s','e','m','b','l','y',0 };
4232 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4235 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4237 static const WCHAR table[] = {
4238 'M','s','i','A','s','s','e','m','b','l','y',0 };
4239 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4242 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4244 static const WCHAR table[] = { 'F','o','n','t',0 };
4245 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4248 static struct _actions StandardActions[] = {
4249 { szAllocateRegistrySpace, NULL},
4250 { szAppSearch, ACTION_AppSearch },
4251 { szBindImage, ACTION_BindImage },
4252 { szCCPSearch, NULL},
4253 { szCostFinalize, ACTION_CostFinalize },
4254 { szCostInitialize, ACTION_CostInitialize },
4255 { szCreateFolders, ACTION_CreateFolders },
4256 { szCreateShortcuts, ACTION_CreateShortcuts },
4257 { szDeleteServices, ACTION_DeleteServices },
4258 { szDisableRollback, NULL},
4259 { szDuplicateFiles, ACTION_DuplicateFiles },
4260 { szExecuteAction, ACTION_ExecuteAction },
4261 { szFileCost, ACTION_FileCost },
4262 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4263 { szForceReboot, ACTION_ForceReboot },
4264 { szInstallAdminPackage, NULL},
4265 { szInstallExecute, ACTION_InstallExecute },
4266 { szInstallExecuteAgain, ACTION_InstallExecute },
4267 { szInstallFiles, ACTION_InstallFiles},
4268 { szInstallFinalize, ACTION_InstallFinalize },
4269 { szInstallInitialize, ACTION_InstallInitialize },
4270 { szInstallSFPCatalogFile, NULL},
4271 { szInstallValidate, ACTION_InstallValidate },
4272 { szIsolateComponents, ACTION_IsolateComponents },
4273 { szLaunchConditions, ACTION_LaunchConditions },
4274 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4275 { szMoveFiles, ACTION_MoveFiles },
4276 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4277 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4278 { szInstallODBC, NULL},
4279 { szInstallServices, ACTION_InstallServices },
4280 { szPatchFiles, ACTION_PatchFiles },
4281 { szProcessComponents, ACTION_ProcessComponents },
4282 { szPublishComponents, ACTION_PublishComponents },
4283 { szPublishFeatures, ACTION_PublishFeatures },
4284 { szPublishProduct, ACTION_PublishProduct },
4285 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4286 { szRegisterComPlus, NULL},
4287 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4288 { szRegisterFonts, ACTION_RegisterFonts },
4289 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4290 { szRegisterProduct, ACTION_RegisterProduct },
4291 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4292 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4293 { szRegisterUser, ACTION_RegisterUser},
4294 { szRemoveDuplicateFiles, NULL},
4295 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4296 { szRemoveExistingProducts, NULL},
4297 { szRemoveFiles, NULL},
4298 { szRemoveFolders, NULL},
4299 { szRemoveIniValues, ACTION_RemoveIniValues },
4300 { szRemoveODBC, NULL},
4301 { szRemoveRegistryValues, NULL},
4302 { szRemoveShortcuts, NULL},
4303 { szResolveSource, ACTION_ResolveSource},
4304 { szRMCCPSearch, NULL},
4305 { szScheduleReboot, NULL},
4306 { szSelfRegModules, ACTION_SelfRegModules },
4307 { szSelfUnregModules, ACTION_SelfUnregModules },
4308 { szSetODBCFolders, NULL},
4309 { szStartServices, ACTION_StartServices },
4310 { szStopServices, ACTION_StopServices },
4311 { szUnpublishComponents, NULL},
4312 { szUnpublishFeatures, NULL},
4313 { szUnregisterClassInfo, NULL},
4314 { szUnregisterComPlus, NULL},
4315 { szUnregisterExtensionInfo, NULL},
4316 { szUnregisterFonts, ACTION_UnregisterFonts },
4317 { szUnregisterMIMEInfo, NULL},
4318 { szUnregisterProgIdInfo, NULL},
4319 { szUnregisterTypeLibraries, NULL},
4320 { szValidateProductID, NULL},
4321 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4322 { szWriteIniValues, ACTION_WriteIniValues },
4323 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4324 { NULL, NULL},