msi: Rename SetFeatureStates to match the naming scheme of internal msi functions.
[wine/testsucceed.git] / dlls / msi / action.c
blobd6ca5d7f7e9b326d8723a53908c2e6c98321cb69
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 WINE_DEFAULT_DEBUG_CHANNEL(msi);
52 * Prototypes
54 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
55 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
56 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
59 * consts and values used
61 static const WCHAR c_colon[] = {'C',':','\\',0};
63 static const WCHAR szCreateFolders[] =
64 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 static const WCHAR szCostFinalize[] =
66 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
67 const WCHAR szInstallFiles[] =
68 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
69 const WCHAR szDuplicateFiles[] =
70 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
71 static const WCHAR szWriteRegistryValues[] =
72 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
73 'V','a','l','u','e','s',0};
74 static const WCHAR szCostInitialize[] =
75 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 static const WCHAR szFileCost[] =
77 {'F','i','l','e','C','o','s','t',0};
78 static const WCHAR szInstallInitialize[] =
79 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 static const WCHAR szInstallValidate[] =
81 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 static const WCHAR szLaunchConditions[] =
83 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 static const WCHAR szProcessComponents[] =
85 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 static const WCHAR szRegisterTypeLibraries[] =
87 {'R','e','g','i','s','t','e','r','T','y','p','e',
88 'L','i','b','r','a','r','i','e','s',0};
89 const WCHAR szRegisterClassInfo[] =
90 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
91 const WCHAR szRegisterProgIdInfo[] =
92 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
93 static const WCHAR szCreateShortcuts[] =
94 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 static const WCHAR szPublishProduct[] =
96 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 static const WCHAR szWriteIniValues[] =
98 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 static const WCHAR szSelfRegModules[] =
100 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 static const WCHAR szPublishFeatures[] =
102 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 static const WCHAR szRegisterProduct[] =
104 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 static const WCHAR szInstallExecute[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 static const WCHAR szInstallExecuteAgain[] =
108 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
109 'A','g','a','i','n',0};
110 static const WCHAR szInstallFinalize[] =
111 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 static const WCHAR szForceReboot[] =
113 {'F','o','r','c','e','R','e','b','o','o','t',0};
114 static const WCHAR szResolveSource[] =
115 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
116 static const WCHAR szAppSearch[] =
117 {'A','p','p','S','e','a','r','c','h',0};
118 static const WCHAR szAllocateRegistrySpace[] =
119 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
120 'S','p','a','c','e',0};
121 static const WCHAR szBindImage[] =
122 {'B','i','n','d','I','m','a','g','e',0};
123 static const WCHAR szCCPSearch[] =
124 {'C','C','P','S','e','a','r','c','h',0};
125 static const WCHAR szDeleteServices[] =
126 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szDisableRollback[] =
128 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 static const WCHAR szExecuteAction[] =
130 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
131 const WCHAR szFindRelatedProducts[] =
132 {'F','i','n','d','R','e','l','a','t','e','d',
133 'P','r','o','d','u','c','t','s',0};
134 static const WCHAR szInstallAdminPackage[] =
135 {'I','n','s','t','a','l','l','A','d','m','i','n',
136 'P','a','c','k','a','g','e',0};
137 static const WCHAR szInstallSFPCatalogFile[] =
138 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
139 'F','i','l','e',0};
140 static const WCHAR szIsolateComponents[] =
141 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
142 const WCHAR szMigrateFeatureStates[] =
143 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
144 'S','t','a','t','e','s',0};
145 const WCHAR szMoveFiles[] =
146 {'M','o','v','e','F','i','l','e','s',0};
147 static const WCHAR szMsiPublishAssemblies[] =
148 {'M','s','i','P','u','b','l','i','s','h',
149 'A','s','s','e','m','b','l','i','e','s',0};
150 static const WCHAR szMsiUnpublishAssemblies[] =
151 {'M','s','i','U','n','p','u','b','l','i','s','h',
152 'A','s','s','e','m','b','l','i','e','s',0};
153 static const WCHAR szInstallODBC[] =
154 {'I','n','s','t','a','l','l','O','D','B','C',0};
155 static const WCHAR szInstallServices[] =
156 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
157 const WCHAR szPatchFiles[] =
158 {'P','a','t','c','h','F','i','l','e','s',0};
159 static const WCHAR szPublishComponents[] =
160 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szRegisterComPlus[] =
162 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 const WCHAR szRegisterExtensionInfo[] =
164 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
165 'I','n','f','o',0};
166 static const WCHAR szRegisterFonts[] =
167 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
168 const WCHAR szRegisterMIMEInfo[] =
169 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
170 static const WCHAR szRegisterUser[] =
171 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
172 const WCHAR szRemoveDuplicateFiles[] =
173 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
174 'F','i','l','e','s',0};
175 static const WCHAR szRemoveEnvironmentStrings[] =
176 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
177 'S','t','r','i','n','g','s',0};
178 const WCHAR szRemoveExistingProducts[] =
179 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
180 'P','r','o','d','u','c','t','s',0};
181 const WCHAR szRemoveFiles[] =
182 {'R','e','m','o','v','e','F','i','l','e','s',0};
183 static const WCHAR szRemoveFolders[] =
184 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 static const WCHAR szRemoveIniValues[] =
186 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 static const WCHAR szRemoveODBC[] =
188 {'R','e','m','o','v','e','O','D','B','C',0};
189 static const WCHAR szRemoveRegistryValues[] =
190 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
191 'V','a','l','u','e','s',0};
192 static const WCHAR szRemoveShortcuts[] =
193 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 static const WCHAR szRMCCPSearch[] =
195 {'R','M','C','C','P','S','e','a','r','c','h',0};
196 static const WCHAR szScheduleReboot[] =
197 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 static const WCHAR szSelfUnregModules[] =
199 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 static const WCHAR szSetODBCFolders[] =
201 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 static const WCHAR szStartServices[] =
203 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szStopServices[] =
205 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 static const WCHAR szUnpublishComponents[] =
207 {'U','n','p','u','b','l','i','s','h',
208 'C','o','m','p','o','n','e','n','t','s',0};
209 static const WCHAR szUnpublishFeatures[] =
210 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
211 const WCHAR szUnregisterClassInfo[] =
212 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
213 'I','n','f','o',0};
214 static const WCHAR szUnregisterComPlus[] =
215 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
216 const WCHAR szUnregisterExtensionInfo[] =
217 {'U','n','r','e','g','i','s','t','e','r',
218 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
219 static const WCHAR szUnregisterFonts[] =
220 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
221 const WCHAR szUnregisterMIMEInfo[] =
222 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
223 const WCHAR szUnregisterProgIdInfo[] =
224 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
225 'I','n','f','o',0};
226 static const WCHAR szUnregisterTypeLibraries[] =
227 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
228 'L','i','b','r','a','r','i','e','s',0};
229 static const WCHAR szValidateProductID[] =
230 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 static const WCHAR szWriteEnvironmentStrings[] =
232 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
233 'S','t','r','i','n','g','s',0};
235 /* action handlers */
236 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
238 struct _actions {
239 LPCWSTR action;
240 STANDARDACTIONHANDLER handler;
243 static struct _actions StandardActions[];
246 /********************************************************
247 * helper functions
248 ********************************************************/
250 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
252 static const WCHAR Query_t[] =
253 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
254 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
255 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
256 ' ','\'','%','s','\'',0};
257 MSIRECORD * row;
259 row = MSI_QueryGetRecord( package->db, Query_t, action );
260 if (!row)
261 return;
262 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
263 msiobj_release(&row->hdr);
266 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
267 UINT rc)
269 MSIRECORD * row;
270 static const WCHAR template_s[]=
271 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
272 '%','s', '.',0};
273 static const WCHAR template_e[]=
274 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
275 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
276 '%','i','.',0};
277 static const WCHAR format[] =
278 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
279 WCHAR message[1024];
280 WCHAR timet[0x100];
282 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
283 if (start)
284 sprintfW(message,template_s,timet,action);
285 else
286 sprintfW(message,template_e,timet,action,rc);
288 row = MSI_CreateRecord(1);
289 MSI_RecordSetStringW(row,1,message);
291 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
292 msiobj_release(&row->hdr);
295 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
297 LPCWSTR ptr,ptr2;
298 BOOL quote;
299 DWORD len;
300 LPWSTR prop = NULL, val = NULL;
302 if (!szCommandLine)
303 return ERROR_SUCCESS;
305 ptr = szCommandLine;
307 while (*ptr)
309 if (*ptr==' ')
311 ptr++;
312 continue;
315 TRACE("Looking at %s\n",debugstr_w(ptr));
317 ptr2 = strchrW(ptr,'=');
318 if (!ptr2)
320 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
321 break;
324 quote = FALSE;
326 len = ptr2-ptr;
327 prop = msi_alloc((len+1)*sizeof(WCHAR));
328 memcpy(prop,ptr,len*sizeof(WCHAR));
329 prop[len]=0;
330 ptr2++;
332 len = 0;
333 ptr = ptr2;
334 while (*ptr && (quote || (!quote && *ptr!=' ')))
336 if (*ptr == '"')
337 quote = !quote;
338 ptr++;
339 len++;
342 if (*ptr2=='"')
344 ptr2++;
345 len -= 2;
347 val = msi_alloc((len+1)*sizeof(WCHAR));
348 memcpy(val,ptr2,len*sizeof(WCHAR));
349 val[len] = 0;
351 if (lstrlenW(prop) > 0)
353 TRACE("Found commandline property (%s) = (%s)\n",
354 debugstr_w(prop), debugstr_w(val));
355 MSI_SetPropertyW(package,prop,val);
357 msi_free(val);
358 msi_free(prop);
361 return ERROR_SUCCESS;
365 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
367 LPWSTR p, *ret = NULL;
368 UINT count = 0;
370 if (!str)
371 return ret;
373 /* count the number of substrings */
374 for ( p = (LPWSTR)str, count = 0; p; count++ )
376 p = strchrW( p, sep );
377 if (p)
378 p++;
381 /* allocate space for an array of substring pointers and the substrings */
382 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
383 (lstrlenW(str)+1) * sizeof(WCHAR) );
384 if (!ret)
385 return ret;
387 /* copy the string and set the pointers */
388 p = (LPWSTR) &ret[count+1];
389 lstrcpyW( p, str );
390 for( count = 0; (ret[count] = p); count++ )
392 p = strchrW( p, sep );
393 if (p)
394 *p++ = 0;
397 return ret;
400 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
401 MSIDATABASE *patch_db, LPCWSTR name )
403 UINT ret = ERROR_FUNCTION_FAILED;
404 IStorage *stg = NULL;
405 HRESULT r;
407 TRACE("%p %s\n", package, debugstr_w(name) );
409 if (*name++ != ':')
411 ERR("expected a colon in %s\n", debugstr_w(name));
412 return ERROR_FUNCTION_FAILED;
415 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
416 if (SUCCEEDED(r))
418 ret = msi_table_apply_transform( package->db, stg );
419 IStorage_Release( stg );
420 ret = ERROR_SUCCESS;
422 else
423 ERR("failed to open substorage %s\n", debugstr_w(name));
425 return ret;
428 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
430 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
431 LPWSTR guid_list, *guids, product_id;
432 UINT i, ret = ERROR_FUNCTION_FAILED;
434 product_id = msi_dup_property( package, szProdID );
435 if (!product_id)
437 /* FIXME: the property ProductID should be written into the DB somewhere */
438 ERR("no product ID to check\n");
439 return ERROR_SUCCESS;
442 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
443 guids = msi_split_string( guid_list, ';' );
444 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
446 if (!lstrcmpW( guids[i], product_id ))
447 ret = ERROR_SUCCESS;
449 msi_free( guids );
450 msi_free( guid_list );
451 msi_free( product_id );
453 return ret;
456 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
458 MSISUMMARYINFO *si;
459 LPWSTR str, *substorage;
460 UINT i, r = ERROR_SUCCESS;
462 si = MSI_GetSummaryInformationW( patch_db, 0 );
463 if (!si)
464 return ERROR_FUNCTION_FAILED;
466 msi_check_patch_applicable( package, si );
468 /* enumerate the substorage */
469 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
470 substorage = msi_split_string( str, ';' );
471 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
472 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
473 msi_free( substorage );
474 msi_free( str );
476 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
478 msiobj_release( &si->hdr );
480 return r;
483 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
485 MSIDATABASE *patch_db = NULL;
486 UINT r;
488 TRACE("%p %s\n", package, debugstr_w( file ) );
490 /* FIXME:
491 * We probably want to make sure we only open a patch collection here.
492 * Patch collections (.msp) and databases (.msi) have different GUIDs
493 * but currently MSI_OpenDatabaseW will accept both.
495 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
496 if ( r != ERROR_SUCCESS )
498 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
499 return r;
502 msi_parse_patch_summary( package, patch_db );
503 msiobj_release( &patch_db->hdr );
505 return ERROR_SUCCESS;
508 /* get the PATCH property, and apply all the patches it specifies */
509 static UINT msi_apply_patches( MSIPACKAGE *package )
511 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
512 LPWSTR patch_list, *patches;
513 UINT i, r = ERROR_SUCCESS;
515 patch_list = msi_dup_property( package, szPatch );
517 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
519 patches = msi_split_string( patch_list, ';' );
520 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
521 r = msi_apply_patch_package( package, patches[i] );
523 msi_free( patches );
524 msi_free( patch_list );
526 return r;
529 static UINT msi_apply_transforms( MSIPACKAGE *package )
531 static const WCHAR szTransforms[] = {
532 'T','R','A','N','S','F','O','R','M','S',0 };
533 LPWSTR xform_list, *xforms;
534 UINT i, r = ERROR_SUCCESS;
536 xform_list = msi_dup_property( package, szTransforms );
537 xforms = msi_split_string( xform_list, ';' );
539 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
541 if (xforms[i][0] == ':')
542 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
543 else
544 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
547 msi_free( xforms );
548 msi_free( xform_list );
550 return r;
553 /****************************************************
554 * TOP level entry points
555 *****************************************************/
557 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
558 LPCWSTR szCommandLine )
560 UINT rc;
561 BOOL ui = FALSE;
562 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
563 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
564 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
566 MSI_SetPropertyW(package, szAction, szInstall);
568 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
570 package->script->InWhatSequence = SEQUENCE_INSTALL;
572 if (szPackagePath)
574 LPWSTR p, check, path;
576 package->PackagePath = strdupW(szPackagePath);
577 path = strdupW(szPackagePath);
578 p = strrchrW(path,'\\');
579 if (p)
581 p++;
582 *p=0;
584 else
586 msi_free(path);
587 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
588 GetCurrentDirectoryW(MAX_PATH,path);
589 strcatW(path,cszbs);
592 check = msi_dup_property( package, cszSourceDir );
593 if (!check)
594 MSI_SetPropertyW(package, cszSourceDir, path);
595 msi_free(check);
596 msi_free(path);
599 msi_parse_command_line( package, szCommandLine );
601 msi_apply_transforms( package );
602 msi_apply_patches( package );
604 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
606 package->script->InWhatSequence |= SEQUENCE_UI;
607 rc = ACTION_ProcessUISequence(package);
608 ui = TRUE;
609 if (rc == ERROR_SUCCESS)
611 package->script->InWhatSequence |= SEQUENCE_EXEC;
612 rc = ACTION_ProcessExecSequence(package,TRUE);
615 else
616 rc = ACTION_ProcessExecSequence(package,FALSE);
618 if (rc == -1)
620 /* install was halted but should be considered a success */
621 rc = ERROR_SUCCESS;
624 package->script->CurrentlyScripting= FALSE;
626 /* process the ending type action */
627 if (rc == ERROR_SUCCESS)
628 ACTION_PerformActionSequence(package,-1,ui);
629 else if (rc == ERROR_INSTALL_USEREXIT)
630 ACTION_PerformActionSequence(package,-2,ui);
631 else if (rc == ERROR_INSTALL_SUSPEND)
632 ACTION_PerformActionSequence(package,-4,ui);
633 else /* failed */
634 ACTION_PerformActionSequence(package,-3,ui);
636 /* finish up running custom actions */
637 ACTION_FinishCustomActions(package);
639 return rc;
642 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
644 UINT rc = ERROR_SUCCESS;
645 MSIRECORD * row = 0;
646 static const WCHAR ExecSeqQuery[] =
647 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
648 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
649 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
650 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
652 static const WCHAR UISeqQuery[] =
653 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
654 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
655 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
656 ' ', '=',' ','%','i',0};
658 if (UI)
659 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
660 else
661 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
663 if (row)
665 LPCWSTR action, cond;
667 TRACE("Running the actions\n");
669 /* check conditions */
670 cond = MSI_RecordGetString(row,2);
671 if (cond)
673 /* this is a hack to skip errors in the condition code */
674 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
675 goto end;
678 action = MSI_RecordGetString(row,1);
679 if (!action)
681 ERR("failed to fetch action\n");
682 rc = ERROR_FUNCTION_FAILED;
683 goto end;
686 if (UI)
687 rc = ACTION_PerformUIAction(package,action);
688 else
689 rc = ACTION_PerformAction(package,action,FALSE);
690 end:
691 msiobj_release(&row->hdr);
693 else
694 rc = ERROR_SUCCESS;
696 return rc;
699 typedef struct {
700 MSIPACKAGE* package;
701 BOOL UI;
702 } iterate_action_param;
704 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
706 iterate_action_param *iap= (iterate_action_param*)param;
707 UINT rc;
708 LPCWSTR cond, action;
710 action = MSI_RecordGetString(row,1);
711 if (!action)
713 ERR("Error is retrieving action name\n");
714 return ERROR_FUNCTION_FAILED;
717 /* check conditions */
718 cond = MSI_RecordGetString(row,2);
719 if (cond)
721 /* this is a hack to skip errors in the condition code */
722 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
724 TRACE("Skipping action: %s (condition is false)\n",
725 debugstr_w(action));
726 return ERROR_SUCCESS;
730 if (iap->UI)
731 rc = ACTION_PerformUIAction(iap->package,action);
732 else
733 rc = ACTION_PerformAction(iap->package,action,FALSE);
735 msi_dialog_check_messages( NULL );
737 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
738 rc = iap->package->CurrentInstallState;
740 if (rc == ERROR_FUNCTION_NOT_CALLED)
741 rc = ERROR_SUCCESS;
743 if (rc != ERROR_SUCCESS)
744 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
746 return rc;
749 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
751 MSIQUERY * view;
752 UINT r;
753 static const WCHAR query[] =
754 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
755 '`','%','s','`',
756 ' ','W','H','E','R','E',' ',
757 '`','S','e','q','u','e','n','c','e','`',' ',
758 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
759 '`','S','e','q','u','e','n','c','e','`',0};
760 iterate_action_param iap;
763 * FIXME: probably should be checking UILevel in the
764 * ACTION_PerformUIAction/ACTION_PerformAction
765 * rather than saving the UI level here. Those
766 * two functions can be merged too.
768 iap.package = package;
769 iap.UI = TRUE;
771 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
773 r = MSI_OpenQuery( package->db, &view, query, szTable );
774 if (r == ERROR_SUCCESS)
776 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
777 msiobj_release(&view->hdr);
780 return r;
783 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
785 MSIQUERY * view;
786 UINT rc;
787 static const WCHAR ExecSeqQuery[] =
788 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
789 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
790 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
791 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
792 'O','R','D','E','R',' ', 'B','Y',' ',
793 '`','S','e','q','u','e','n','c','e','`',0 };
794 MSIRECORD * row = 0;
795 static const WCHAR IVQuery[] =
796 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
797 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
798 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
799 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
800 ' ','\'', 'I','n','s','t','a','l','l',
801 'V','a','l','i','d','a','t','e','\'', 0};
802 INT seq = 0;
803 iterate_action_param iap;
805 iap.package = package;
806 iap.UI = FALSE;
808 if (package->script->ExecuteSequenceRun)
810 TRACE("Execute Sequence already Run\n");
811 return ERROR_SUCCESS;
814 package->script->ExecuteSequenceRun = TRUE;
816 /* get the sequence number */
817 if (UIran)
819 row = MSI_QueryGetRecord(package->db, IVQuery);
820 if( !row )
821 return ERROR_FUNCTION_FAILED;
822 seq = MSI_RecordGetInteger(row,1);
823 msiobj_release(&row->hdr);
826 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
827 if (rc == ERROR_SUCCESS)
829 TRACE("Running the actions\n");
831 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
832 msiobj_release(&view->hdr);
835 return rc;
838 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
840 MSIQUERY * view;
841 UINT rc;
842 static const WCHAR ExecSeqQuery [] =
843 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
844 '`','I','n','s','t','a','l','l',
845 'U','I','S','e','q','u','e','n','c','e','`',
846 ' ','W','H','E','R','E',' ',
847 '`','S','e','q','u','e','n','c','e','`',' ',
848 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
849 '`','S','e','q','u','e','n','c','e','`',0};
850 iterate_action_param iap;
852 iap.package = package;
853 iap.UI = TRUE;
855 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
857 if (rc == ERROR_SUCCESS)
859 TRACE("Running the actions\n");
861 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
862 msiobj_release(&view->hdr);
865 return rc;
868 /********************************************************
869 * ACTION helper functions and functions that perform the actions
870 *******************************************************/
871 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
872 UINT* rc, BOOL force )
874 BOOL ret = FALSE;
875 BOOL run = force;
876 int i;
878 if (!run && !package->script->CurrentlyScripting)
879 run = TRUE;
881 if (!run)
883 if (strcmpW(action,szInstallFinalize) == 0 ||
884 strcmpW(action,szInstallExecute) == 0 ||
885 strcmpW(action,szInstallExecuteAgain) == 0)
886 run = TRUE;
889 i = 0;
890 while (StandardActions[i].action != NULL)
892 if (strcmpW(StandardActions[i].action, action)==0)
894 if (!run)
896 ui_actioninfo(package, action, TRUE, 0);
897 *rc = schedule_action(package,INSTALL_SCRIPT,action);
898 ui_actioninfo(package, action, FALSE, *rc);
900 else
902 ui_actionstart(package, action);
903 if (StandardActions[i].handler)
905 *rc = StandardActions[i].handler(package);
907 else
909 FIXME("unhandled standard action %s\n",debugstr_w(action));
910 *rc = ERROR_SUCCESS;
913 ret = TRUE;
914 break;
916 i++;
918 return ret;
921 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
922 UINT* rc, BOOL force )
924 BOOL ret=FALSE;
925 UINT arc;
927 arc = ACTION_CustomAction(package,action, force);
929 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
931 *rc = arc;
932 ret = TRUE;
934 return ret;
938 * A lot of actions are really important even if they don't do anything
939 * explicit... Lots of properties are set at the beginning of the installation
940 * CostFinalize does a bunch of work to translate the directories and such
942 * But until I get write access to the database that is hard, so I am going to
943 * hack it to see if I can get something to run.
945 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
947 UINT rc = ERROR_SUCCESS;
948 BOOL handled;
950 TRACE("Performing action (%s)\n",debugstr_w(action));
952 handled = ACTION_HandleStandardAction(package, action, &rc, force);
954 if (!handled)
955 handled = ACTION_HandleCustomAction(package, action, &rc, force);
957 if (!handled)
959 FIXME("unhandled msi action %s\n",debugstr_w(action));
960 rc = ERROR_FUNCTION_NOT_CALLED;
963 return rc;
966 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
968 UINT rc = ERROR_SUCCESS;
969 BOOL handled = FALSE;
971 TRACE("Performing action (%s)\n",debugstr_w(action));
973 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
975 if (!handled)
976 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
978 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
979 handled = TRUE;
981 if (!handled)
983 FIXME("unhandled msi action %s\n",debugstr_w(action));
984 rc = ERROR_FUNCTION_NOT_CALLED;
987 return rc;
992 * Actual Action Handlers
995 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
997 MSIPACKAGE *package = (MSIPACKAGE*)param;
998 LPCWSTR dir;
999 LPWSTR full_path;
1000 MSIRECORD *uirow;
1001 MSIFOLDER *folder;
1003 dir = MSI_RecordGetString(row,1);
1004 if (!dir)
1006 ERR("Unable to get folder id\n");
1007 return ERROR_SUCCESS;
1010 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1011 if (!full_path)
1013 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1014 return ERROR_SUCCESS;
1017 TRACE("Folder is %s\n",debugstr_w(full_path));
1019 /* UI stuff */
1020 uirow = MSI_CreateRecord(1);
1021 MSI_RecordSetStringW(uirow,1,full_path);
1022 ui_actiondata(package,szCreateFolders,uirow);
1023 msiobj_release( &uirow->hdr );
1025 if (folder->State == 0)
1026 create_full_pathW(full_path);
1028 folder->State = 3;
1030 msi_free(full_path);
1031 return ERROR_SUCCESS;
1034 /* FIXME: probably should merge this with the above function */
1035 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1037 UINT rc = ERROR_SUCCESS;
1038 MSIFOLDER *folder;
1039 LPWSTR install_path;
1041 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1042 if (!install_path)
1043 return ERROR_FUNCTION_FAILED;
1045 /* create the path */
1046 if (folder->State == 0)
1048 create_full_pathW(install_path);
1049 folder->State = 2;
1051 msi_free(install_path);
1053 return rc;
1056 UINT msi_create_component_directories( MSIPACKAGE *package )
1058 MSICOMPONENT *comp;
1060 /* create all the folders required by the components are going to install */
1061 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1063 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1064 continue;
1065 msi_create_directory( package, comp->Directory );
1068 return ERROR_SUCCESS;
1072 * Also we cannot enable/disable components either, so for now I am just going
1073 * to do all the directories for all the components.
1075 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1077 static const WCHAR ExecSeqQuery[] =
1078 {'S','E','L','E','C','T',' ',
1079 '`','D','i','r','e','c','t','o','r','y','_','`',
1080 ' ','F','R','O','M',' ',
1081 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1082 UINT rc;
1083 MSIQUERY *view;
1085 /* create all the empty folders specified in the CreateFolder table */
1086 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1087 if (rc != ERROR_SUCCESS)
1088 return ERROR_SUCCESS;
1090 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1091 msiobj_release(&view->hdr);
1093 msi_create_component_directories( package );
1095 return rc;
1098 static MSICOMPONENT* load_component( MSIRECORD * row )
1100 MSICOMPONENT *comp;
1102 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1103 if (!comp)
1104 return comp;
1106 /* fill in the data */
1107 comp->Component = msi_dup_record_field( row, 1 );
1109 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1111 comp->ComponentId = msi_dup_record_field( row, 2 );
1112 comp->Directory = msi_dup_record_field( row, 3 );
1113 comp->Attributes = MSI_RecordGetInteger(row,4);
1114 comp->Condition = msi_dup_record_field( row, 5 );
1115 comp->KeyPath = msi_dup_record_field( row, 6 );
1117 comp->Installed = INSTALLSTATE_ABSENT;
1118 comp->Action = INSTALLSTATE_UNKNOWN;
1119 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1121 comp->Enabled = TRUE;
1123 return comp;
1126 typedef struct {
1127 MSIPACKAGE *package;
1128 MSIFEATURE *feature;
1129 } _ilfs;
1131 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1133 ComponentList *cl;
1135 cl = msi_alloc( sizeof (*cl) );
1136 if ( !cl )
1137 return ERROR_NOT_ENOUGH_MEMORY;
1138 cl->component = comp;
1139 list_add_tail( &feature->Components, &cl->entry );
1141 return ERROR_SUCCESS;
1144 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1146 _ilfs* ilfs= (_ilfs*)param;
1147 MSIPACKAGE *package = ilfs->package;
1148 MSIFEATURE *feature = ilfs->feature;
1149 MSICOMPONENT *comp;
1151 comp = load_component( row );
1152 if (!comp)
1153 return ERROR_FUNCTION_FAILED;
1155 list_add_tail( &package->components, &comp->entry );
1156 add_feature_component( feature, comp );
1158 TRACE("Loaded new component %p\n", comp);
1160 return ERROR_SUCCESS;
1163 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1165 _ilfs* ilfs= (_ilfs*)param;
1166 LPCWSTR component;
1167 DWORD rc;
1168 MSICOMPONENT *comp;
1169 MSIQUERY * view;
1170 static const WCHAR Query[] =
1171 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1172 '`','C','o','m','p','o','n','e','n','t','`',' ',
1173 'W','H','E','R','E',' ',
1174 '`','C','o','m','p','o','n','e','n','t','`',' ',
1175 '=','\'','%','s','\'',0};
1177 component = MSI_RecordGetString(row,1);
1179 /* check to see if the component is already loaded */
1180 comp = get_loaded_component( ilfs->package, component );
1181 if (comp)
1183 TRACE("Component %s already loaded\n", debugstr_w(component) );
1184 add_feature_component( ilfs->feature, comp );
1185 return ERROR_SUCCESS;
1188 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1189 if (rc != ERROR_SUCCESS)
1190 return ERROR_SUCCESS;
1192 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1193 msiobj_release( &view->hdr );
1195 return ERROR_SUCCESS;
1198 static UINT load_feature(MSIRECORD * row, LPVOID param)
1200 MSIPACKAGE* package = (MSIPACKAGE*)param;
1201 MSIFEATURE* feature;
1202 static const WCHAR Query1[] =
1203 {'S','E','L','E','C','T',' ',
1204 '`','C','o','m','p','o','n','e','n','t','_','`',
1205 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1206 'C','o','m','p','o','n','e','n','t','s','`',' ',
1207 'W','H','E','R','E',' ',
1208 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1209 MSIQUERY * view;
1210 UINT rc;
1211 _ilfs ilfs;
1213 /* fill in the data */
1215 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1216 if (!feature)
1217 return ERROR_NOT_ENOUGH_MEMORY;
1219 list_init( &feature->Components );
1221 feature->Feature = msi_dup_record_field( row, 1 );
1223 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1225 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1226 feature->Title = msi_dup_record_field( row, 3 );
1227 feature->Description = msi_dup_record_field( row, 4 );
1229 if (!MSI_RecordIsNull(row,5))
1230 feature->Display = MSI_RecordGetInteger(row,5);
1232 feature->Level= MSI_RecordGetInteger(row,6);
1233 feature->Directory = msi_dup_record_field( row, 7 );
1234 feature->Attributes = MSI_RecordGetInteger(row,8);
1236 feature->Installed = INSTALLSTATE_ABSENT;
1237 feature->Action = INSTALLSTATE_UNKNOWN;
1238 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1240 list_add_tail( &package->features, &feature->entry );
1242 /* load feature components */
1244 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1245 if (rc != ERROR_SUCCESS)
1246 return ERROR_SUCCESS;
1248 ilfs.package = package;
1249 ilfs.feature = feature;
1251 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1252 msiobj_release(&view->hdr);
1254 return ERROR_SUCCESS;
1257 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1259 if (!p)
1260 return p;
1261 p = strchrW(p, ch);
1262 if (!p)
1263 return p;
1264 *p = 0;
1265 return p+1;
1268 static UINT load_file(MSIRECORD *row, LPVOID param)
1270 MSIPACKAGE* package = (MSIPACKAGE*)param;
1271 LPCWSTR component;
1272 MSIFILE *file;
1274 /* fill in the data */
1276 file = msi_alloc_zero( sizeof (MSIFILE) );
1277 if (!file)
1278 return ERROR_NOT_ENOUGH_MEMORY;
1280 file->File = msi_dup_record_field( row, 1 );
1282 component = MSI_RecordGetString( row, 2 );
1283 file->Component = get_loaded_component( package, component );
1285 if (!file->Component)
1286 ERR("Unfound Component %s\n",debugstr_w(component));
1288 file->FileName = msi_dup_record_field( row, 3 );
1289 reduce_to_longfilename( file->FileName );
1291 file->ShortName = msi_dup_record_field( row, 3 );
1292 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1294 file->FileSize = MSI_RecordGetInteger( row, 4 );
1295 file->Version = msi_dup_record_field( row, 5 );
1296 file->Language = msi_dup_record_field( row, 6 );
1297 file->Attributes = MSI_RecordGetInteger( row, 7 );
1298 file->Sequence = MSI_RecordGetInteger( row, 8 );
1300 file->state = msifs_invalid;
1302 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1304 list_add_tail( &package->files, &file->entry );
1306 return ERROR_SUCCESS;
1309 static UINT load_all_files(MSIPACKAGE *package)
1311 MSIQUERY * view;
1312 UINT rc;
1313 static const WCHAR Query[] =
1314 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1315 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1316 '`','S','e','q','u','e','n','c','e','`', 0};
1318 if (!list_empty(&package->files))
1319 return ERROR_SUCCESS;
1321 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1322 if (rc != ERROR_SUCCESS)
1323 return ERROR_SUCCESS;
1325 rc = MSI_IterateRecords(view, NULL, load_file, package);
1326 msiobj_release(&view->hdr);
1328 return ERROR_SUCCESS;
1333 * I am not doing any of the costing functionality yet.
1334 * Mostly looking at doing the Component and Feature loading
1336 * The native MSI does A LOT of modification to tables here. Mostly adding
1337 * a lot of temporary columns to the Feature and Component tables.
1339 * note: Native msi also tracks the short filename. But I am only going to
1340 * track the long ones. Also looking at this directory table
1341 * it appears that the directory table does not get the parents
1342 * resolved base on property only based on their entries in the
1343 * directory table.
1345 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1347 MSIQUERY * view;
1348 UINT rc;
1349 static const WCHAR Query_all[] =
1350 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1351 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1352 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1353 static const WCHAR szCosting[] =
1354 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1355 static const WCHAR szZero[] = { '0', 0 };
1357 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1358 return ERROR_SUCCESS;
1360 MSI_SetPropertyW(package, szCosting, szZero);
1361 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1363 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1364 if (rc != ERROR_SUCCESS)
1365 return rc;
1367 if (list_empty(&package->features))
1369 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1370 msiobj_release(&view->hdr);
1373 load_all_files(package);
1375 return ERROR_SUCCESS;
1378 static UINT execute_script(MSIPACKAGE *package, UINT script )
1380 int i;
1381 UINT rc = ERROR_SUCCESS;
1383 TRACE("Executing Script %i\n",script);
1385 if (!package->script)
1387 ERR("no script!\n");
1388 return ERROR_FUNCTION_FAILED;
1391 for (i = 0; i < package->script->ActionCount[script]; i++)
1393 LPWSTR action;
1394 action = package->script->Actions[script][i];
1395 ui_actionstart(package, action);
1396 TRACE("Executing Action (%s)\n",debugstr_w(action));
1397 rc = ACTION_PerformAction(package, action, TRUE);
1398 msi_free(package->script->Actions[script][i]);
1399 if (rc != ERROR_SUCCESS)
1400 break;
1402 msi_free(package->script->Actions[script]);
1404 package->script->ActionCount[script] = 0;
1405 package->script->Actions[script] = NULL;
1406 return rc;
1409 static UINT ACTION_FileCost(MSIPACKAGE *package)
1411 return ERROR_SUCCESS;
1414 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1416 static const WCHAR Query[] =
1417 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1418 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1419 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1420 ' ','=',' ','\'','%','s','\'',
1422 static const WCHAR szDot[] = { '.',0 };
1423 static WCHAR szEmpty[] = { 0 };
1424 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1425 LPCWSTR parent;
1426 MSIRECORD *row;
1427 MSIFOLDER *folder;
1429 TRACE("Looking for dir %s\n",debugstr_w(dir));
1431 folder = get_loaded_folder( package, dir );
1432 if (folder)
1433 return folder;
1435 TRACE("Working to load %s\n",debugstr_w(dir));
1437 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1438 if (!folder)
1439 return NULL;
1441 folder->Directory = strdupW(dir);
1443 row = MSI_QueryGetRecord(package->db, Query, dir);
1444 if (!row)
1445 return NULL;
1447 p = msi_dup_record_field(row, 3);
1449 /* split src and target dir */
1450 tgt_short = p;
1451 src_short = folder_split_path( p, ':' );
1453 /* split the long and short paths */
1454 tgt_long = folder_split_path( tgt_short, '|' );
1455 src_long = folder_split_path( src_short, '|' );
1457 /* check for no-op dirs */
1458 if (!lstrcmpW(szDot, tgt_short))
1459 tgt_short = szEmpty;
1460 if (!lstrcmpW(szDot, src_short))
1461 src_short = szEmpty;
1463 if (!tgt_long)
1464 tgt_long = tgt_short;
1466 if (!src_short) {
1467 src_short = tgt_short;
1468 src_long = tgt_long;
1471 if (!src_long)
1472 src_long = src_short;
1474 /* FIXME: use the target short path too */
1475 folder->TargetDefault = strdupW(tgt_long);
1476 folder->SourceShortPath = strdupW(src_short);
1477 folder->SourceLongPath = strdupW(src_long);
1478 msi_free(p);
1480 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1481 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1482 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1484 parent = MSI_RecordGetString(row, 2);
1485 if (parent)
1487 folder->Parent = load_folder( package, parent );
1488 if ( folder->Parent )
1489 TRACE("loaded parent %p %s\n", folder->Parent,
1490 debugstr_w(folder->Parent->Directory));
1491 else
1492 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1495 folder->Property = msi_dup_property( package, dir );
1497 msiobj_release(&row->hdr);
1499 list_add_tail( &package->folders, &folder->entry );
1501 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1503 return folder;
1506 /* scan for and update current install states */
1507 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1509 MSICOMPONENT *comp;
1510 MSIFEATURE *feature;
1512 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1514 INSTALLSTATE res;
1515 res = MsiGetComponentPathW( package->ProductCode,
1516 comp->ComponentId, NULL, NULL);
1517 if (res < 0)
1518 res = INSTALLSTATE_ABSENT;
1519 comp->Installed = res;
1522 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1524 ComponentList *cl;
1525 INSTALLSTATE res = -10;
1527 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1529 comp= cl->component;
1531 if (res == -10)
1532 res = comp->Installed;
1533 else
1535 if (res == comp->Installed)
1536 continue;
1538 if (res != comp->Installed)
1539 res = INSTALLSTATE_INCOMPLETE;
1542 feature->Installed = res;
1546 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1547 INSTALLSTATE state)
1549 static const WCHAR all[]={'A','L','L',0};
1550 LPWSTR override;
1551 MSIFEATURE *feature;
1553 override = msi_dup_property( package, property );
1554 if (!override)
1555 return FALSE;
1557 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1559 if (strcmpiW(override,all)==0)
1561 feature->ActionRequest= state;
1562 feature->Action = state;
1564 else
1566 LPWSTR ptr = override;
1567 LPWSTR ptr2 = strchrW(override,',');
1569 while (ptr)
1571 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1572 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1574 feature->ActionRequest= state;
1575 feature->Action = state;
1576 break;
1578 if (ptr2)
1580 ptr=ptr2+1;
1581 ptr2 = strchrW(ptr,',');
1583 else
1584 break;
1588 msi_free(override);
1590 return TRUE;
1593 static UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1595 int install_level;
1596 static const WCHAR szlevel[] =
1597 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1598 static const WCHAR szAddLocal[] =
1599 {'A','D','D','L','O','C','A','L',0};
1600 static const WCHAR szRemove[] =
1601 {'R','E','M','O','V','E',0};
1602 static const WCHAR szReinstall[] =
1603 {'R','E','I','N','S','T','A','L','L',0};
1604 BOOL override = FALSE;
1605 MSICOMPONENT* component;
1606 MSIFEATURE *feature;
1609 /* I do not know if this is where it should happen.. but */
1611 TRACE("Checking Install Level\n");
1613 install_level = msi_get_property_int( package, szlevel, 1 );
1615 /* ok hereis the _real_ rub
1616 * all these activation/deactivation things happen in order and things
1617 * later on the list override things earlier on the list.
1618 * 1) INSTALLLEVEL processing
1619 * 2) ADDLOCAL
1620 * 3) REMOVE
1621 * 4) ADDSOURCE
1622 * 5) ADDDEFAULT
1623 * 6) REINSTALL
1624 * 7) COMPADDLOCAL
1625 * 8) COMPADDSOURCE
1626 * 9) FILEADDLOCAL
1627 * 10) FILEADDSOURCE
1628 * 11) FILEADDDEFAULT
1629 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1630 * ignored for all the features. seems strange, especially since it is not
1631 * documented anywhere, but it is how it works.
1633 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1634 * REMOVE are the big ones, since we don't handle administrative installs
1635 * yet anyway.
1637 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1638 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1639 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1641 if (!override)
1643 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1645 BOOL feature_state = ((feature->Level > 0) &&
1646 (feature->Level <= install_level));
1648 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1650 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1652 feature->ActionRequest = INSTALLSTATE_SOURCE;
1653 feature->Action = INSTALLSTATE_SOURCE;
1655 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1657 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1658 feature->Action = INSTALLSTATE_ADVERTISED;
1660 else
1662 feature->ActionRequest = INSTALLSTATE_LOCAL;
1663 feature->Action = INSTALLSTATE_LOCAL;
1668 else
1670 /* set the Preselected Property */
1671 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1672 static const WCHAR szOne[] = { '1', 0 };
1674 MSI_SetPropertyW(package,szPreselected,szOne);
1678 * now we want to enable or disable components base on feature
1681 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1683 ComponentList *cl;
1685 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1686 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1687 feature->ActionRequest);
1689 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1691 component = cl->component;
1693 if (!component->Enabled)
1695 component->Action = INSTALLSTATE_UNKNOWN;
1696 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1698 else
1700 if (feature->Action == INSTALLSTATE_LOCAL)
1702 component->Action = INSTALLSTATE_LOCAL;
1703 component->ActionRequest = INSTALLSTATE_LOCAL;
1705 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1707 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1708 (component->Action == INSTALLSTATE_ABSENT) ||
1709 (component->Action == INSTALLSTATE_ADVERTISED))
1712 component->Action = INSTALLSTATE_SOURCE;
1713 component->ActionRequest = INSTALLSTATE_SOURCE;
1716 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1718 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1719 (component->Action == INSTALLSTATE_ABSENT))
1722 component->Action = INSTALLSTATE_ADVERTISED;
1723 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1726 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1728 if (component->Action == INSTALLSTATE_UNKNOWN)
1730 component->Action = INSTALLSTATE_ABSENT;
1731 component->ActionRequest = INSTALLSTATE_ABSENT;
1738 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1740 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1741 debugstr_w(component->Component), component->Installed,
1742 component->Action, component->ActionRequest);
1746 return ERROR_SUCCESS;
1749 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1751 MSIPACKAGE *package = (MSIPACKAGE*)param;
1752 LPCWSTR name;
1753 LPWSTR path;
1755 name = MSI_RecordGetString(row,1);
1757 /* This helper function now does ALL the work */
1758 TRACE("Dir %s ...\n",debugstr_w(name));
1759 load_folder(package,name);
1760 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1761 TRACE("resolves to %s\n",debugstr_w(path));
1762 msi_free(path);
1764 return ERROR_SUCCESS;
1767 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1769 MSIPACKAGE *package = (MSIPACKAGE*)param;
1770 LPCWSTR name;
1771 MSIFEATURE *feature;
1773 name = MSI_RecordGetString( row, 1 );
1775 feature = get_loaded_feature( package, name );
1776 if (!feature)
1777 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1778 else
1780 LPCWSTR Condition;
1781 Condition = MSI_RecordGetString(row,3);
1783 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1785 int level = MSI_RecordGetInteger(row,2);
1786 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1787 feature->Level = level;
1790 return ERROR_SUCCESS;
1795 * A lot is done in this function aside from just the costing.
1796 * The costing needs to be implemented at some point but for now I am going
1797 * to focus on the directory building
1800 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1802 static const WCHAR ExecSeqQuery[] =
1803 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1804 '`','D','i','r','e','c','t','o','r','y','`',0};
1805 static const WCHAR ConditionQuery[] =
1806 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1807 '`','C','o','n','d','i','t','i','o','n','`',0};
1808 static const WCHAR szCosting[] =
1809 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1810 static const WCHAR szlevel[] =
1811 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1812 static const WCHAR szOne[] = { '1', 0 };
1813 MSICOMPONENT *comp;
1814 MSIFILE *file;
1815 UINT rc;
1816 MSIQUERY * view;
1817 LPWSTR level;
1819 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1820 return ERROR_SUCCESS;
1822 TRACE("Building Directory properties\n");
1824 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1825 if (rc == ERROR_SUCCESS)
1827 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1828 package);
1829 msiobj_release(&view->hdr);
1832 TRACE("File calculations\n");
1834 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1836 MSICOMPONENT* comp = file->Component;
1837 LPWSTR p;
1839 if (!comp)
1840 continue;
1842 /* calculate target */
1843 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1845 msi_free(file->TargetPath);
1847 TRACE("file %s is named %s\n",
1848 debugstr_w(file->File),debugstr_w(file->FileName));
1850 file->TargetPath = build_directory_name(2, p, file->FileName);
1852 msi_free(p);
1854 TRACE("file %s resolves to %s\n",
1855 debugstr_w(file->File),debugstr_w(file->TargetPath));
1857 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1859 file->state = msifs_missing;
1860 comp->Cost += file->FileSize;
1861 continue;
1864 if (file->Version)
1866 DWORD handle;
1867 DWORD versize;
1868 UINT sz;
1869 LPVOID version;
1870 static WCHAR name[] = {'\\',0};
1871 static const WCHAR name_fmt[] =
1872 {'%','u','.','%','u','.','%','u','.','%','u',0};
1873 WCHAR filever[0x100];
1874 VS_FIXEDFILEINFO *lpVer;
1876 TRACE("Version comparison..\n");
1877 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1878 version = msi_alloc(versize);
1879 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1881 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1883 sprintfW(filever,name_fmt,
1884 HIWORD(lpVer->dwFileVersionMS),
1885 LOWORD(lpVer->dwFileVersionMS),
1886 HIWORD(lpVer->dwFileVersionLS),
1887 LOWORD(lpVer->dwFileVersionLS));
1889 TRACE("new %s old %s\n", debugstr_w(file->Version),
1890 debugstr_w(filever));
1891 if (strcmpiW(filever,file->Version)<0)
1893 file->state = msifs_overwrite;
1894 /* FIXME: cost should be diff in size */
1895 comp->Cost += file->FileSize;
1897 else
1898 file->state = msifs_present;
1899 msi_free(version);
1901 else
1902 file->state = msifs_present;
1905 TRACE("Evaluating Condition Table\n");
1907 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1908 if (rc == ERROR_SUCCESS)
1910 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1911 package);
1912 msiobj_release(&view->hdr);
1915 TRACE("Enabling or Disabling Components\n");
1916 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1918 if (comp->Condition)
1920 if (MSI_EvaluateConditionW(package,
1921 comp->Condition) == MSICONDITION_FALSE)
1923 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1924 comp->Enabled = FALSE;
1929 MSI_SetPropertyW(package,szCosting,szOne);
1930 /* set default run level if not set */
1931 level = msi_dup_property( package, szlevel );
1932 if (!level)
1933 MSI_SetPropertyW(package,szlevel, szOne);
1934 msi_free(level);
1936 ACTION_UpdateInstallStates(package);
1938 return MSI_SetFeatureStates(package);
1941 /* OK this value is "interpreted" and then formatted based on the
1942 first few characters */
1943 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1944 DWORD *size)
1946 LPSTR data = NULL;
1947 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1949 if (value[1]=='x')
1951 LPWSTR ptr;
1952 CHAR byte[5];
1953 LPWSTR deformated = NULL;
1954 int count;
1956 deformat_string(package, &value[2], &deformated);
1958 /* binary value type */
1959 ptr = deformated;
1960 *type = REG_BINARY;
1961 if (strlenW(ptr)%2)
1962 *size = (strlenW(ptr)/2)+1;
1963 else
1964 *size = strlenW(ptr)/2;
1966 data = msi_alloc(*size);
1968 byte[0] = '0';
1969 byte[1] = 'x';
1970 byte[4] = 0;
1971 count = 0;
1972 /* if uneven pad with a zero in front */
1973 if (strlenW(ptr)%2)
1975 byte[2]= '0';
1976 byte[3]= *ptr;
1977 ptr++;
1978 data[count] = (BYTE)strtol(byte,NULL,0);
1979 count ++;
1980 TRACE("Uneven byte count\n");
1982 while (*ptr)
1984 byte[2]= *ptr;
1985 ptr++;
1986 byte[3]= *ptr;
1987 ptr++;
1988 data[count] = (BYTE)strtol(byte,NULL,0);
1989 count ++;
1991 msi_free(deformated);
1993 TRACE("Data %li bytes(%i)\n",*size,count);
1995 else
1997 LPWSTR deformated;
1998 LPWSTR p;
1999 DWORD d = 0;
2000 deformat_string(package, &value[1], &deformated);
2002 *type=REG_DWORD;
2003 *size = sizeof(DWORD);
2004 data = msi_alloc(*size);
2005 p = deformated;
2006 if (*p == '-')
2007 p++;
2008 while (*p)
2010 if ( (*p < '0') || (*p > '9') )
2011 break;
2012 d *= 10;
2013 d += (*p - '0');
2014 p++;
2016 if (deformated[0] == '-')
2017 d = -d;
2018 *(LPDWORD)data = d;
2019 TRACE("DWORD %li\n",*(LPDWORD)data);
2021 msi_free(deformated);
2024 else
2026 static const WCHAR szMulti[] = {'[','~',']',0};
2027 LPCWSTR ptr;
2028 *type=REG_SZ;
2030 if (value[0]=='#')
2032 if (value[1]=='%')
2034 ptr = &value[2];
2035 *type=REG_EXPAND_SZ;
2037 else
2038 ptr = &value[1];
2040 else
2041 ptr=value;
2043 if (strstrW(value,szMulti))
2044 *type = REG_MULTI_SZ;
2046 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2048 return data;
2051 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2053 MSIPACKAGE *package = (MSIPACKAGE*)param;
2054 static const WCHAR szHCR[] =
2055 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2056 'R','O','O','T','\\',0};
2057 static const WCHAR szHCU[] =
2058 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2059 'U','S','E','R','\\',0};
2060 static const WCHAR szHLM[] =
2061 {'H','K','E','Y','_','L','O','C','A','L','_',
2062 'M','A','C','H','I','N','E','\\',0};
2063 static const WCHAR szHU[] =
2064 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2066 LPSTR value_data = NULL;
2067 HKEY root_key, hkey;
2068 DWORD type,size;
2069 LPWSTR deformated;
2070 LPCWSTR szRoot, component, name, key, value;
2071 MSICOMPONENT *comp;
2072 MSIRECORD * uirow;
2073 LPWSTR uikey;
2074 INT root;
2075 BOOL check_first = FALSE;
2076 UINT rc;
2078 ui_progress(package,2,0,0,0);
2080 value = NULL;
2081 key = NULL;
2082 uikey = NULL;
2083 name = NULL;
2085 component = MSI_RecordGetString(row, 6);
2086 comp = get_loaded_component(package,component);
2087 if (!comp)
2088 return ERROR_SUCCESS;
2090 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2092 TRACE("Skipping write due to disabled component %s\n",
2093 debugstr_w(component));
2095 comp->Action = comp->Installed;
2097 return ERROR_SUCCESS;
2100 comp->Action = INSTALLSTATE_LOCAL;
2102 name = MSI_RecordGetString(row, 4);
2103 if( MSI_RecordIsNull(row,5) && name )
2105 /* null values can have special meanings */
2106 if (name[0]=='-' && name[1] == 0)
2107 return ERROR_SUCCESS;
2108 else if ((name[0]=='+' && name[1] == 0) ||
2109 (name[0] == '*' && name[1] == 0))
2110 name = NULL;
2111 check_first = TRUE;
2114 root = MSI_RecordGetInteger(row,2);
2115 key = MSI_RecordGetString(row, 3);
2117 /* get the root key */
2118 switch (root)
2120 case -1:
2122 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2123 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2124 if (all_users && all_users[0] == '1')
2126 root_key = HKEY_LOCAL_MACHINE;
2127 szRoot = szHLM;
2129 else
2131 root_key = HKEY_CURRENT_USER;
2132 szRoot = szHCU;
2134 msi_free(all_users);
2136 break;
2137 case 0: root_key = HKEY_CLASSES_ROOT;
2138 szRoot = szHCR;
2139 break;
2140 case 1: root_key = HKEY_CURRENT_USER;
2141 szRoot = szHCU;
2142 break;
2143 case 2: root_key = HKEY_LOCAL_MACHINE;
2144 szRoot = szHLM;
2145 break;
2146 case 3: root_key = HKEY_USERS;
2147 szRoot = szHU;
2148 break;
2149 default:
2150 ERR("Unknown root %i\n",root);
2151 root_key=NULL;
2152 szRoot = NULL;
2153 break;
2155 if (!root_key)
2156 return ERROR_SUCCESS;
2158 deformat_string(package, key , &deformated);
2159 size = strlenW(deformated) + strlenW(szRoot) + 1;
2160 uikey = msi_alloc(size*sizeof(WCHAR));
2161 strcpyW(uikey,szRoot);
2162 strcatW(uikey,deformated);
2164 if (RegCreateKeyW( root_key, deformated, &hkey))
2166 ERR("Could not create key %s\n",debugstr_w(deformated));
2167 msi_free(deformated);
2168 msi_free(uikey);
2169 return ERROR_SUCCESS;
2171 msi_free(deformated);
2173 value = MSI_RecordGetString(row,5);
2174 if (value)
2175 value_data = parse_value(package, value, &type, &size);
2176 else
2178 static const WCHAR szEmpty[] = {0};
2179 value_data = (LPSTR)strdupW(szEmpty);
2180 size = 0;
2181 type = REG_SZ;
2184 deformat_string(package, name, &deformated);
2186 /* get the double nulls to terminate SZ_MULTI */
2187 if (type == REG_MULTI_SZ)
2188 size +=sizeof(WCHAR);
2190 if (!check_first)
2192 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2193 debugstr_w(uikey));
2194 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2196 else
2198 DWORD sz = 0;
2199 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2200 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2202 TRACE("value %s of %s checked already exists\n",
2203 debugstr_w(deformated), debugstr_w(uikey));
2205 else
2207 TRACE("Checked and setting value %s of %s\n",
2208 debugstr_w(deformated), debugstr_w(uikey));
2209 if (deformated || size)
2210 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2213 RegCloseKey(hkey);
2215 uirow = MSI_CreateRecord(3);
2216 MSI_RecordSetStringW(uirow,2,deformated);
2217 MSI_RecordSetStringW(uirow,1,uikey);
2219 if (type == REG_SZ)
2220 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2221 else
2222 MSI_RecordSetStringW(uirow,3,value);
2224 ui_actiondata(package,szWriteRegistryValues,uirow);
2225 msiobj_release( &uirow->hdr );
2227 msi_free(value_data);
2228 msi_free(deformated);
2229 msi_free(uikey);
2231 return ERROR_SUCCESS;
2234 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2236 UINT rc;
2237 MSIQUERY * view;
2238 static const WCHAR ExecSeqQuery[] =
2239 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2240 '`','R','e','g','i','s','t','r','y','`',0 };
2242 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2243 if (rc != ERROR_SUCCESS)
2244 return ERROR_SUCCESS;
2246 /* increment progress bar each time action data is sent */
2247 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2249 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2251 msiobj_release(&view->hdr);
2252 return rc;
2255 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2257 package->script->CurrentlyScripting = TRUE;
2259 return ERROR_SUCCESS;
2263 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2265 MSICOMPONENT *comp;
2266 DWORD progress = 0;
2267 DWORD total = 0;
2268 static const WCHAR q1[]=
2269 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2270 '`','R','e','g','i','s','t','r','y','`',0};
2271 UINT rc;
2272 MSIQUERY * view;
2273 MSIFEATURE *feature;
2274 MSIFILE *file;
2276 TRACE("InstallValidate\n");
2278 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2279 if (rc == ERROR_SUCCESS)
2281 MSI_IterateRecords( view, &progress, NULL, package );
2282 msiobj_release( &view->hdr );
2283 total += progress * REG_PROGRESS_VALUE;
2286 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2287 total += COMPONENT_PROGRESS_VALUE;
2289 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2290 total += file->FileSize;
2292 ui_progress(package,0,total,0,0);
2294 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2296 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2297 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2298 feature->ActionRequest);
2301 return ERROR_SUCCESS;
2304 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2306 MSIPACKAGE* package = (MSIPACKAGE*)param;
2307 LPCWSTR cond = NULL;
2308 LPCWSTR message = NULL;
2309 static const WCHAR title[]=
2310 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2312 cond = MSI_RecordGetString(row,1);
2314 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2316 LPWSTR deformated;
2317 message = MSI_RecordGetString(row,2);
2318 deformat_string(package,message,&deformated);
2319 MessageBoxW(NULL,deformated,title,MB_OK);
2320 msi_free(deformated);
2321 return ERROR_FUNCTION_FAILED;
2324 return ERROR_SUCCESS;
2327 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2329 UINT rc;
2330 MSIQUERY * view = NULL;
2331 static const WCHAR ExecSeqQuery[] =
2332 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2333 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2335 TRACE("Checking launch conditions\n");
2337 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2338 if (rc != ERROR_SUCCESS)
2339 return ERROR_SUCCESS;
2341 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2342 msiobj_release(&view->hdr);
2344 return rc;
2347 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2350 if (!cmp->KeyPath)
2351 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2353 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2355 MSIRECORD * row = 0;
2356 UINT root,len;
2357 LPWSTR deformated,buffer,deformated_name;
2358 LPCWSTR key,name;
2359 static const WCHAR ExecSeqQuery[] =
2360 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2361 '`','R','e','g','i','s','t','r','y','`',' ',
2362 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2363 ' ','=',' ' ,'\'','%','s','\'',0 };
2364 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2365 static const WCHAR fmt2[]=
2366 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2368 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2369 if (!row)
2370 return NULL;
2372 root = MSI_RecordGetInteger(row,2);
2373 key = MSI_RecordGetString(row, 3);
2374 name = MSI_RecordGetString(row, 4);
2375 deformat_string(package, key , &deformated);
2376 deformat_string(package, name, &deformated_name);
2378 len = strlenW(deformated) + 6;
2379 if (deformated_name)
2380 len+=strlenW(deformated_name);
2382 buffer = msi_alloc( len *sizeof(WCHAR));
2384 if (deformated_name)
2385 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2386 else
2387 sprintfW(buffer,fmt,root,deformated);
2389 msi_free(deformated);
2390 msi_free(deformated_name);
2391 msiobj_release(&row->hdr);
2393 return buffer;
2395 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2397 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2398 return NULL;
2400 else
2402 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2404 if (file)
2405 return strdupW( file->TargetPath );
2407 return NULL;
2410 static HKEY openSharedDLLsKey(void)
2412 HKEY hkey=0;
2413 static const WCHAR path[] =
2414 {'S','o','f','t','w','a','r','e','\\',
2415 'M','i','c','r','o','s','o','f','t','\\',
2416 'W','i','n','d','o','w','s','\\',
2417 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2418 'S','h','a','r','e','d','D','L','L','s',0};
2420 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2421 return hkey;
2424 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2426 HKEY hkey;
2427 DWORD count=0;
2428 DWORD type;
2429 DWORD sz = sizeof(count);
2430 DWORD rc;
2432 hkey = openSharedDLLsKey();
2433 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2434 if (rc != ERROR_SUCCESS)
2435 count = 0;
2436 RegCloseKey(hkey);
2437 return count;
2440 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2442 HKEY hkey;
2444 hkey = openSharedDLLsKey();
2445 if (count > 0)
2446 msi_reg_set_val_dword( hkey, path, count );
2447 else
2448 RegDeleteValueW(hkey,path);
2449 RegCloseKey(hkey);
2450 return count;
2454 * Return TRUE if the count should be written out and FALSE if not
2456 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2458 MSIFEATURE *feature;
2459 INT count = 0;
2460 BOOL write = FALSE;
2462 /* only refcount DLLs */
2463 if (comp->KeyPath == NULL ||
2464 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2465 comp->Attributes & msidbComponentAttributesODBCDataSource)
2466 write = FALSE;
2467 else
2469 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2470 write = (count > 0);
2472 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2473 write = TRUE;
2476 /* increment counts */
2477 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2479 ComponentList *cl;
2481 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2482 continue;
2484 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2486 if ( cl->component == comp )
2487 count++;
2491 /* decrement counts */
2492 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2494 ComponentList *cl;
2496 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2497 continue;
2499 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2501 if ( cl->component == comp )
2502 count--;
2506 /* ref count all the files in the component */
2507 if (write)
2509 MSIFILE *file;
2511 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2513 if (file->Component == comp)
2514 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2518 /* add a count for permenent */
2519 if (comp->Attributes & msidbComponentAttributesPermanent)
2520 count ++;
2522 comp->RefCount = count;
2524 if (write)
2525 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2529 * Ok further analysis makes me think that this work is
2530 * actually done in the PublishComponents and PublishFeatures
2531 * step, and not here. It appears like the keypath and all that is
2532 * resolved in this step, however actually written in the Publish steps.
2533 * But we will leave it here for now because it is unclear
2535 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2537 WCHAR squished_pc[GUID_SIZE];
2538 WCHAR squished_cc[GUID_SIZE];
2539 UINT rc;
2540 MSICOMPONENT *comp;
2541 HKEY hkey=0,hkey2=0;
2543 /* writes the Component and Features values to the registry */
2545 rc = MSIREG_OpenComponents(&hkey);
2546 if (rc != ERROR_SUCCESS)
2547 return rc;
2549 squash_guid(package->ProductCode,squished_pc);
2550 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2552 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2554 MSIRECORD * uirow;
2556 ui_progress(package,2,0,0,0);
2557 if (!comp->ComponentId)
2558 continue;
2560 squash_guid(comp->ComponentId,squished_cc);
2562 msi_free(comp->FullKeypath);
2563 comp->FullKeypath = resolve_keypath( package, comp );
2565 /* do the refcounting */
2566 ACTION_RefCountComponent( package, comp );
2568 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2569 debugstr_w(comp->Component),
2570 debugstr_w(squished_cc),
2571 debugstr_w(comp->FullKeypath),
2572 comp->RefCount);
2574 * Write the keypath out if the component is to be registered
2575 * and delete the key if the component is to be deregistered
2577 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2579 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2580 if (rc != ERROR_SUCCESS)
2581 continue;
2583 if (!comp->FullKeypath)
2584 continue;
2586 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2588 if (comp->Attributes & msidbComponentAttributesPermanent)
2590 static const WCHAR szPermKey[] =
2591 { '0','0','0','0','0','0','0','0','0','0','0','0',
2592 '0','0','0','0','0','0','0','0','0','0','0','0',
2593 '0','0','0','0','0','0','0','0',0 };
2595 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2598 RegCloseKey(hkey2);
2600 /* UI stuff */
2601 uirow = MSI_CreateRecord(3);
2602 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2603 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2604 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2605 ui_actiondata(package,szProcessComponents,uirow);
2606 msiobj_release( &uirow->hdr );
2608 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2610 DWORD res;
2612 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2613 if (rc != ERROR_SUCCESS)
2614 continue;
2616 RegDeleteValueW(hkey2,squished_pc);
2618 /* if the key is empty delete it */
2619 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2620 RegCloseKey(hkey2);
2621 if (res == ERROR_NO_MORE_ITEMS)
2622 RegDeleteKeyW(hkey,squished_cc);
2624 /* UI stuff */
2625 uirow = MSI_CreateRecord(2);
2626 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2627 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2628 ui_actiondata(package,szProcessComponents,uirow);
2629 msiobj_release( &uirow->hdr );
2632 RegCloseKey(hkey);
2633 return rc;
2636 typedef struct {
2637 CLSID clsid;
2638 LPWSTR source;
2640 LPWSTR path;
2641 ITypeLib *ptLib;
2642 } typelib_struct;
2644 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2645 LPWSTR lpszName, LONG_PTR lParam)
2647 TLIBATTR *attr;
2648 typelib_struct *tl_struct = (typelib_struct*) lParam;
2649 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2650 int sz;
2651 HRESULT res;
2653 if (!IS_INTRESOURCE(lpszName))
2655 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2656 return TRUE;
2659 sz = strlenW(tl_struct->source)+4;
2660 sz *= sizeof(WCHAR);
2662 if ((INT_PTR)lpszName == 1)
2663 tl_struct->path = strdupW(tl_struct->source);
2664 else
2666 tl_struct->path = msi_alloc(sz);
2667 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2670 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2671 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2672 if (!SUCCEEDED(res))
2674 msi_free(tl_struct->path);
2675 tl_struct->path = NULL;
2677 return TRUE;
2680 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2681 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2683 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2684 return FALSE;
2687 msi_free(tl_struct->path);
2688 tl_struct->path = NULL;
2690 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2691 ITypeLib_Release(tl_struct->ptLib);
2693 return TRUE;
2696 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2698 MSIPACKAGE* package = (MSIPACKAGE*)param;
2699 LPCWSTR component;
2700 MSICOMPONENT *comp;
2701 MSIFILE *file;
2702 typelib_struct tl_struct;
2703 HMODULE module;
2704 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2706 component = MSI_RecordGetString(row,3);
2707 comp = get_loaded_component(package,component);
2708 if (!comp)
2709 return ERROR_SUCCESS;
2711 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2713 TRACE("Skipping typelib reg due to disabled component\n");
2715 comp->Action = comp->Installed;
2717 return ERROR_SUCCESS;
2720 comp->Action = INSTALLSTATE_LOCAL;
2722 file = get_loaded_file( package, comp->KeyPath );
2723 if (!file)
2724 return ERROR_SUCCESS;
2726 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2727 if (module)
2729 LPCWSTR guid;
2730 guid = MSI_RecordGetString(row,1);
2731 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2732 tl_struct.source = strdupW( file->TargetPath );
2733 tl_struct.path = NULL;
2735 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2736 (LONG_PTR)&tl_struct);
2738 if (tl_struct.path)
2740 LPWSTR help = NULL;
2741 LPCWSTR helpid;
2742 HRESULT res;
2744 helpid = MSI_RecordGetString(row,6);
2746 if (helpid)
2747 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2748 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2749 msi_free(help);
2751 if (!SUCCEEDED(res))
2752 ERR("Failed to register type library %s\n",
2753 debugstr_w(tl_struct.path));
2754 else
2756 ui_actiondata(package,szRegisterTypeLibraries,row);
2758 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2761 ITypeLib_Release(tl_struct.ptLib);
2762 msi_free(tl_struct.path);
2764 else
2765 ERR("Failed to load type library %s\n",
2766 debugstr_w(tl_struct.source));
2768 FreeLibrary(module);
2769 msi_free(tl_struct.source);
2771 else
2772 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2774 return ERROR_SUCCESS;
2777 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2780 * OK this is a bit confusing.. I am given a _Component key and I believe
2781 * that the file that is being registered as a type library is the "key file
2782 * of that component" which I interpret to mean "The file in the KeyPath of
2783 * that component".
2785 UINT rc;
2786 MSIQUERY * view;
2787 static const WCHAR Query[] =
2788 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2789 '`','T','y','p','e','L','i','b','`',0};
2791 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2792 if (rc != ERROR_SUCCESS)
2793 return ERROR_SUCCESS;
2795 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2796 msiobj_release(&view->hdr);
2797 return rc;
2800 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2802 MSIPACKAGE *package = (MSIPACKAGE*)param;
2803 LPWSTR target_file, target_folder, filename;
2804 LPCWSTR buffer, extension;
2805 MSICOMPONENT *comp;
2806 static const WCHAR szlnk[]={'.','l','n','k',0};
2807 IShellLinkW *sl = NULL;
2808 IPersistFile *pf = NULL;
2809 HRESULT res;
2811 buffer = MSI_RecordGetString(row,4);
2812 comp = get_loaded_component(package,buffer);
2813 if (!comp)
2814 return ERROR_SUCCESS;
2816 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2818 TRACE("Skipping shortcut creation due to disabled component\n");
2820 comp->Action = comp->Installed;
2822 return ERROR_SUCCESS;
2825 comp->Action = INSTALLSTATE_LOCAL;
2827 ui_actiondata(package,szCreateShortcuts,row);
2829 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2830 &IID_IShellLinkW, (LPVOID *) &sl );
2832 if (FAILED( res ))
2834 ERR("CLSID_ShellLink not available\n");
2835 goto err;
2838 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2839 if (FAILED( res ))
2841 ERR("QueryInterface(IID_IPersistFile) failed\n");
2842 goto err;
2845 buffer = MSI_RecordGetString(row,2);
2846 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2848 /* may be needed because of a bug somehwere else */
2849 create_full_pathW(target_folder);
2851 filename = msi_dup_record_field( row, 3 );
2852 reduce_to_longfilename(filename);
2854 extension = strchrW(filename,'.');
2855 if (!extension || strcmpiW(extension,szlnk))
2857 int len = strlenW(filename);
2858 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2859 memcpy(filename + len, szlnk, sizeof(szlnk));
2861 target_file = build_directory_name(2, target_folder, filename);
2862 msi_free(target_folder);
2863 msi_free(filename);
2865 buffer = MSI_RecordGetString(row,5);
2866 if (strchrW(buffer,'['))
2868 LPWSTR deformated;
2869 deformat_string(package,buffer,&deformated);
2870 IShellLinkW_SetPath(sl,deformated);
2871 msi_free(deformated);
2873 else
2875 FIXME("poorly handled shortcut format, advertised shortcut\n");
2876 IShellLinkW_SetPath(sl,comp->FullKeypath);
2879 if (!MSI_RecordIsNull(row,6))
2881 LPWSTR deformated;
2882 buffer = MSI_RecordGetString(row,6);
2883 deformat_string(package,buffer,&deformated);
2884 IShellLinkW_SetArguments(sl,deformated);
2885 msi_free(deformated);
2888 if (!MSI_RecordIsNull(row,7))
2890 buffer = MSI_RecordGetString(row,7);
2891 IShellLinkW_SetDescription(sl,buffer);
2894 if (!MSI_RecordIsNull(row,8))
2895 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2897 if (!MSI_RecordIsNull(row,9))
2899 LPWSTR Path;
2900 INT index;
2902 buffer = MSI_RecordGetString(row,9);
2904 Path = build_icon_path(package,buffer);
2905 index = MSI_RecordGetInteger(row,10);
2907 IShellLinkW_SetIconLocation(sl,Path,index);
2908 msi_free(Path);
2911 if (!MSI_RecordIsNull(row,11))
2912 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2914 if (!MSI_RecordIsNull(row,12))
2916 LPWSTR Path;
2917 buffer = MSI_RecordGetString(row,12);
2918 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2919 IShellLinkW_SetWorkingDirectory(sl,Path);
2920 msi_free(Path);
2923 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2924 IPersistFile_Save(pf,target_file,FALSE);
2926 msi_free(target_file);
2928 err:
2929 if (pf)
2930 IPersistFile_Release( pf );
2931 if (sl)
2932 IShellLinkW_Release( sl );
2934 return ERROR_SUCCESS;
2937 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2939 UINT rc;
2940 HRESULT res;
2941 MSIQUERY * view;
2942 static const WCHAR Query[] =
2943 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2944 '`','S','h','o','r','t','c','u','t','`',0};
2946 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2947 if (rc != ERROR_SUCCESS)
2948 return ERROR_SUCCESS;
2950 res = CoInitialize( NULL );
2951 if (FAILED (res))
2953 ERR("CoInitialize failed\n");
2954 return ERROR_FUNCTION_FAILED;
2957 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2958 msiobj_release(&view->hdr);
2960 CoUninitialize();
2962 return rc;
2965 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2967 MSIPACKAGE* package = (MSIPACKAGE*)param;
2968 HANDLE the_file;
2969 LPWSTR FilePath;
2970 LPCWSTR FileName;
2971 CHAR buffer[1024];
2972 DWORD sz;
2973 UINT rc;
2974 MSIRECORD *uirow;
2976 FileName = MSI_RecordGetString(row,1);
2977 if (!FileName)
2979 ERR("Unable to get FileName\n");
2980 return ERROR_SUCCESS;
2983 FilePath = build_icon_path(package,FileName);
2985 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
2987 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2988 FILE_ATTRIBUTE_NORMAL, NULL);
2990 if (the_file == INVALID_HANDLE_VALUE)
2992 ERR("Unable to create file %s\n",debugstr_w(FilePath));
2993 msi_free(FilePath);
2994 return ERROR_SUCCESS;
2999 DWORD write;
3000 sz = 1024;
3001 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3002 if (rc != ERROR_SUCCESS)
3004 ERR("Failed to get stream\n");
3005 CloseHandle(the_file);
3006 DeleteFileW(FilePath);
3007 break;
3009 WriteFile(the_file,buffer,sz,&write,NULL);
3010 } while (sz == 1024);
3012 msi_free(FilePath);
3014 CloseHandle(the_file);
3016 uirow = MSI_CreateRecord(1);
3017 MSI_RecordSetStringW(uirow,1,FileName);
3018 ui_actiondata(package,szPublishProduct,uirow);
3019 msiobj_release( &uirow->hdr );
3021 return ERROR_SUCCESS;
3025 * 99% of the work done here is only done for
3026 * advertised installs. However this is where the
3027 * Icon table is processed and written out
3028 * so that is what I am going to do here.
3030 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3032 UINT rc;
3033 MSIQUERY * view;
3034 static const WCHAR Query[]=
3035 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3036 '`','I','c','o','n','`',0};
3037 /* for registry stuff */
3038 HKEY hkey=0;
3039 HKEY hukey=0;
3040 static const WCHAR szProductLanguage[] =
3041 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3042 static const WCHAR szARPProductIcon[] =
3043 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3044 static const WCHAR szProductVersion[] =
3045 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3046 DWORD langid;
3047 LPWSTR buffer;
3048 DWORD size;
3049 MSIHANDLE hDb, hSumInfo;
3051 /* write out icon files */
3053 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3054 if (rc == ERROR_SUCCESS)
3056 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3057 msiobj_release(&view->hdr);
3060 /* ok there is a lot more done here but i need to figure out what */
3062 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3063 if (rc != ERROR_SUCCESS)
3064 goto end;
3066 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3067 if (rc != ERROR_SUCCESS)
3068 goto end;
3071 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3072 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3073 msi_free(buffer);
3075 langid = msi_get_property_int( package, szProductLanguage, 0 );
3076 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3078 buffer = msi_dup_property( package, szARPProductIcon );
3079 if (buffer)
3081 LPWSTR path = build_icon_path(package,buffer);
3082 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3083 msi_free( path );
3085 msi_free(buffer);
3087 buffer = msi_dup_property( package, szProductVersion );
3088 if (buffer)
3090 DWORD verdword = msi_version_str_to_dword(buffer);
3091 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3093 msi_free(buffer);
3095 /* FIXME: Need to write more keys to the user registry */
3097 hDb= alloc_msihandle( &package->db->hdr );
3098 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3099 MsiCloseHandle(hDb);
3100 if (rc == ERROR_SUCCESS)
3102 WCHAR guidbuffer[0x200];
3103 size = 0x200;
3104 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3105 guidbuffer, &size);
3106 if (rc == ERROR_SUCCESS)
3108 WCHAR squashed[GUID_SIZE];
3109 /* for now we only care about the first guid */
3110 LPWSTR ptr = strchrW(guidbuffer,';');
3111 if (ptr) *ptr = 0;
3112 squash_guid(guidbuffer,squashed);
3113 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3115 else
3117 ERR("Unable to query Revision_Number...\n");
3118 rc = ERROR_SUCCESS;
3120 MsiCloseHandle(hSumInfo);
3122 else
3124 ERR("Unable to open Summary Information\n");
3125 rc = ERROR_SUCCESS;
3128 end:
3130 RegCloseKey(hkey);
3131 RegCloseKey(hukey);
3133 return rc;
3136 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3138 MSIPACKAGE *package = (MSIPACKAGE*)param;
3139 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3140 LPWSTR deformated_section, deformated_key, deformated_value;
3141 LPWSTR folder, fullname = NULL;
3142 MSIRECORD * uirow;
3143 INT action;
3144 MSICOMPONENT *comp;
3145 static const WCHAR szWindowsFolder[] =
3146 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3148 component = MSI_RecordGetString(row, 8);
3149 comp = get_loaded_component(package,component);
3151 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3153 TRACE("Skipping ini file due to disabled component %s\n",
3154 debugstr_w(component));
3156 comp->Action = comp->Installed;
3158 return ERROR_SUCCESS;
3161 comp->Action = INSTALLSTATE_LOCAL;
3163 identifier = MSI_RecordGetString(row,1);
3164 filename = MSI_RecordGetString(row,2);
3165 dirproperty = MSI_RecordGetString(row,3);
3166 section = MSI_RecordGetString(row,4);
3167 key = MSI_RecordGetString(row,5);
3168 value = MSI_RecordGetString(row,6);
3169 action = MSI_RecordGetInteger(row,7);
3171 deformat_string(package,section,&deformated_section);
3172 deformat_string(package,key,&deformated_key);
3173 deformat_string(package,value,&deformated_value);
3175 if (dirproperty)
3177 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3178 if (!folder)
3179 folder = msi_dup_property( package, dirproperty );
3181 else
3182 folder = msi_dup_property( package, szWindowsFolder );
3184 if (!folder)
3186 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3187 goto cleanup;
3190 fullname = build_directory_name(2, folder, filename);
3192 if (action == 0)
3194 TRACE("Adding value %s to section %s in %s\n",
3195 debugstr_w(deformated_key), debugstr_w(deformated_section),
3196 debugstr_w(fullname));
3197 WritePrivateProfileStringW(deformated_section, deformated_key,
3198 deformated_value, fullname);
3200 else if (action == 1)
3202 WCHAR returned[10];
3203 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3204 returned, 10, fullname);
3205 if (returned[0] == 0)
3207 TRACE("Adding value %s to section %s in %s\n",
3208 debugstr_w(deformated_key), debugstr_w(deformated_section),
3209 debugstr_w(fullname));
3211 WritePrivateProfileStringW(deformated_section, deformated_key,
3212 deformated_value, fullname);
3215 else if (action == 3)
3216 FIXME("Append to existing section not yet implemented\n");
3218 uirow = MSI_CreateRecord(4);
3219 MSI_RecordSetStringW(uirow,1,identifier);
3220 MSI_RecordSetStringW(uirow,2,deformated_section);
3221 MSI_RecordSetStringW(uirow,3,deformated_key);
3222 MSI_RecordSetStringW(uirow,4,deformated_value);
3223 ui_actiondata(package,szWriteIniValues,uirow);
3224 msiobj_release( &uirow->hdr );
3225 cleanup:
3226 msi_free(fullname);
3227 msi_free(folder);
3228 msi_free(deformated_key);
3229 msi_free(deformated_value);
3230 msi_free(deformated_section);
3231 return ERROR_SUCCESS;
3234 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3236 UINT rc;
3237 MSIQUERY * view;
3238 static const WCHAR ExecSeqQuery[] =
3239 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3240 '`','I','n','i','F','i','l','e','`',0};
3242 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3243 if (rc != ERROR_SUCCESS)
3245 TRACE("no IniFile table\n");
3246 return ERROR_SUCCESS;
3249 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3250 msiobj_release(&view->hdr);
3251 return rc;
3254 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3256 MSIPACKAGE *package = (MSIPACKAGE*)param;
3257 LPCWSTR filename;
3258 LPWSTR FullName;
3259 MSIFILE *file;
3260 DWORD len;
3261 static const WCHAR ExeStr[] =
3262 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3263 static const WCHAR close[] = {'\"',0};
3264 STARTUPINFOW si;
3265 PROCESS_INFORMATION info;
3266 BOOL brc;
3267 MSIRECORD *uirow;
3268 LPWSTR uipath, p;
3270 memset(&si,0,sizeof(STARTUPINFOW));
3272 filename = MSI_RecordGetString(row,1);
3273 file = get_loaded_file( package, filename );
3275 if (!file)
3277 ERR("Unable to find file id %s\n",debugstr_w(filename));
3278 return ERROR_SUCCESS;
3281 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3283 FullName = msi_alloc(len*sizeof(WCHAR));
3284 strcpyW(FullName,ExeStr);
3285 strcatW( FullName, file->TargetPath );
3286 strcatW(FullName,close);
3288 TRACE("Registering %s\n",debugstr_w(FullName));
3289 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3290 &si, &info);
3292 if (brc)
3293 msi_dialog_check_messages(info.hProcess);
3295 msi_free(FullName);
3297 /* the UI chunk */
3298 uirow = MSI_CreateRecord( 2 );
3299 uipath = strdupW( file->TargetPath );
3300 p = strrchrW(uipath,'\\');
3301 if (p)
3302 p[1]=0;
3303 MSI_RecordSetStringW( uirow, 1, &p[2] );
3304 MSI_RecordSetStringW( uirow, 2, uipath);
3305 ui_actiondata( package, szSelfRegModules, uirow);
3306 msiobj_release( &uirow->hdr );
3307 msi_free( uipath );
3308 /* FIXME: call ui_progress? */
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 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3342 if (rc != ERROR_SUCCESS)
3343 goto end;
3345 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3346 if (rc != ERROR_SUCCESS)
3347 goto end;
3349 /* here the guids are base 85 encoded */
3350 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3352 ComponentList *cl;
3353 LPWSTR data = NULL;
3354 GUID clsid;
3355 INT size;
3356 BOOL absent = FALSE;
3357 MSIRECORD *uirow;
3359 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3360 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3361 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3362 absent = TRUE;
3364 size = 1;
3365 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3367 size += 21;
3369 if (feature->Feature_Parent)
3370 size += strlenW( feature->Feature_Parent )+2;
3372 data = msi_alloc(size * sizeof(WCHAR));
3374 data[0] = 0;
3375 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3377 MSICOMPONENT* component = cl->component;
3378 WCHAR buf[21];
3380 buf[0] = 0;
3381 if (component->ComponentId)
3383 TRACE("From %s\n",debugstr_w(component->ComponentId));
3384 CLSIDFromString(component->ComponentId, &clsid);
3385 encode_base85_guid(&clsid,buf);
3386 TRACE("to %s\n",debugstr_w(buf));
3387 strcatW(data,buf);
3390 if (feature->Feature_Parent)
3392 static const WCHAR sep[] = {'\2',0};
3393 strcatW(data,sep);
3394 strcatW(data,feature->Feature_Parent);
3397 msi_reg_set_val_str( hkey, feature->Feature, data );
3398 msi_free(data);
3400 size = 0;
3401 if (feature->Feature_Parent)
3402 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3403 if (!absent)
3405 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3406 (LPBYTE)feature->Feature_Parent,size);
3408 else
3410 size += 2*sizeof(WCHAR);
3411 data = msi_alloc(size);
3412 data[0] = 0x6;
3413 data[1] = 0;
3414 if (feature->Feature_Parent)
3415 strcpyW( &data[1], feature->Feature_Parent );
3416 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3417 (LPBYTE)data,size);
3418 msi_free(data);
3421 /* the UI chunk */
3422 uirow = MSI_CreateRecord( 1 );
3423 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3424 ui_actiondata( package, szPublishFeatures, uirow);
3425 msiobj_release( &uirow->hdr );
3426 /* FIXME: call ui_progress? */
3429 end:
3430 RegCloseKey(hkey);
3431 RegCloseKey(hukey);
3432 return rc;
3435 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3437 static const WCHAR installerPathFmt[] = {
3438 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3439 static const WCHAR fmt[] = {
3440 '%','s','\\',
3441 'I','n','s','t','a','l','l','e','r','\\',
3442 '%','x','.','m','s','i',0};
3443 static const WCHAR szOriginalDatabase[] =
3444 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3445 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3446 INT num, start;
3447 LPWSTR msiFilePath;
3448 BOOL r;
3450 /* copy the package locally */
3451 num = GetTickCount() & 0xffff;
3452 if (!num)
3453 num = 1;
3454 start = num;
3455 GetWindowsDirectoryW( windir, MAX_PATH );
3456 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3459 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3460 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3461 if (handle != INVALID_HANDLE_VALUE)
3463 CloseHandle(handle);
3464 break;
3466 if (GetLastError() != ERROR_FILE_EXISTS &&
3467 GetLastError() != ERROR_SHARING_VIOLATION)
3468 break;
3469 if (!(++num & 0xffff)) num = 1;
3470 sprintfW(packagefile,fmt,num);
3471 } while (num != start);
3473 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3474 create_full_pathW(path);
3476 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3478 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3479 r = CopyFileW( msiFilePath, packagefile, FALSE);
3480 msi_free( msiFilePath );
3482 if (!r)
3484 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3485 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3486 return ERROR_FUNCTION_FAILED;
3489 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3490 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3491 return ERROR_SUCCESS;
3494 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3496 LPWSTR prop, val, key;
3497 static const LPCSTR propval[] = {
3498 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3499 "ARPCONTACT", "Contact",
3500 "ARPCOMMENTS", "Comments",
3501 "ProductName", "DisplayName",
3502 "ProductVersion", "DisplayVersion",
3503 "ARPHELPLINK", "HelpLink",
3504 "ARPHELPTELEPHONE", "HelpTelephone",
3505 "ARPINSTALLLOCATION", "InstallLocation",
3506 "SourceDir", "InstallSource",
3507 "Manufacturer", "Publisher",
3508 "ARPREADME", "Readme",
3509 "ARPSIZE", "Size",
3510 "ARPURLINFOABOUT", "URLInfoAbout",
3511 "ARPURLUPDATEINFO", "URLUpdateInfo",
3512 NULL,
3514 const LPCSTR *p = propval;
3516 while( *p )
3518 prop = strdupAtoW( *p++ );
3519 key = strdupAtoW( *p++ );
3520 val = msi_dup_property( package, prop );
3521 msi_reg_set_val_str( hkey, key, val );
3522 msi_free(val);
3523 msi_free(key);
3524 msi_free(prop);
3526 return ERROR_SUCCESS;
3529 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3531 HKEY hkey=0;
3532 LPWSTR buffer = NULL;
3533 UINT rc;
3534 DWORD size, langid;
3535 static const WCHAR szWindowsInstaller[] =
3536 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3537 static const WCHAR szUpgradeCode[] =
3538 {'U','p','g','r','a','d','e','C','o','d','e',0};
3539 static const WCHAR modpath_fmt[] =
3540 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3541 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3542 static const WCHAR szModifyPath[] =
3543 {'M','o','d','i','f','y','P','a','t','h',0};
3544 static const WCHAR szUninstallString[] =
3545 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3546 static const WCHAR szEstimatedSize[] =
3547 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3548 static const WCHAR szProductLanguage[] =
3549 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3550 static const WCHAR szProductVersion[] =
3551 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3553 SYSTEMTIME systime;
3554 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3555 LPWSTR upgrade_code;
3556 WCHAR szDate[9];
3558 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3559 if (rc != ERROR_SUCCESS)
3560 return rc;
3562 /* dump all the info i can grab */
3563 /* FIXME: Flesh out more information */
3565 msi_write_uninstall_property_vals( package, hkey );
3567 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3569 msi_make_package_local( package, hkey );
3571 /* do ModifyPath and UninstallString */
3572 size = deformat_string(package,modpath_fmt,&buffer);
3573 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3574 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3575 msi_free(buffer);
3577 /* FIXME: Write real Estimated Size when we have it */
3578 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3580 GetLocalTime(&systime);
3581 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3582 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3584 langid = msi_get_property_int( package, szProductLanguage, 0 );
3585 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3587 buffer = msi_dup_property( package, szProductVersion );
3588 if (buffer)
3590 DWORD verdword = msi_version_str_to_dword(buffer);
3592 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3593 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3594 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3596 msi_free(buffer);
3598 /* Handle Upgrade Codes */
3599 upgrade_code = msi_dup_property( package, szUpgradeCode );
3600 if (upgrade_code)
3602 HKEY hkey2;
3603 WCHAR squashed[33];
3604 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3605 squash_guid(package->ProductCode,squashed);
3606 msi_reg_set_val_str( hkey2, squashed, NULL );
3607 RegCloseKey(hkey2);
3608 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3609 squash_guid(package->ProductCode,squashed);
3610 msi_reg_set_val_str( hkey2, squashed, NULL );
3611 RegCloseKey(hkey2);
3613 msi_free(upgrade_code);
3616 RegCloseKey(hkey);
3618 /* FIXME: call ui_actiondata */
3620 return ERROR_SUCCESS;
3623 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3625 return execute_script(package,INSTALL_SCRIPT);
3628 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3630 UINT rc;
3632 /* turn off scheduleing */
3633 package->script->CurrentlyScripting= FALSE;
3635 /* first do the same as an InstallExecute */
3636 rc = ACTION_InstallExecute(package);
3637 if (rc != ERROR_SUCCESS)
3638 return rc;
3640 /* then handle Commit Actions */
3641 rc = execute_script(package,COMMIT_SCRIPT);
3643 return rc;
3646 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3648 static const WCHAR RunOnce[] = {
3649 'S','o','f','t','w','a','r','e','\\',
3650 'M','i','c','r','o','s','o','f','t','\\',
3651 'W','i','n','d','o','w','s','\\',
3652 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3653 'R','u','n','O','n','c','e',0};
3654 static const WCHAR InstallRunOnce[] = {
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 'I','n','s','t','a','l','l','e','r','\\',
3660 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3662 static const WCHAR msiexec_fmt[] = {
3663 '%','s',
3664 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3665 '\"','%','s','\"',0};
3666 static const WCHAR install_fmt[] = {
3667 '/','I',' ','\"','%','s','\"',' ',
3668 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3669 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3670 WCHAR buffer[256], sysdir[MAX_PATH];
3671 HKEY hkey;
3672 WCHAR squished_pc[100];
3674 squash_guid(package->ProductCode,squished_pc);
3676 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3677 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3678 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3679 squished_pc);
3681 msi_reg_set_val_str( hkey, squished_pc, buffer );
3682 RegCloseKey(hkey);
3684 TRACE("Reboot command %s\n",debugstr_w(buffer));
3686 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3687 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3689 msi_reg_set_val_str( hkey, squished_pc, buffer );
3690 RegCloseKey(hkey);
3692 return ERROR_INSTALL_SUSPEND;
3695 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3697 DWORD attrib;
3698 UINT rc;
3700 * we are currently doing what should be done here in the top level Install
3701 * however for Adminastrative and uninstalls this step will be needed
3703 if (!package->PackagePath)
3704 return ERROR_SUCCESS;
3706 attrib = GetFileAttributesW(package->PackagePath);
3707 if (attrib == INVALID_FILE_ATTRIBUTES)
3709 LPWSTR prompt;
3710 LPWSTR msg;
3711 DWORD size = 0;
3713 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3714 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3715 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3716 if (rc == ERROR_MORE_DATA)
3718 prompt = msi_alloc(size * sizeof(WCHAR));
3719 MsiSourceListGetInfoW(package->ProductCode, NULL,
3720 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3721 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3723 else
3724 prompt = strdupW(package->PackagePath);
3726 msg = generate_error_string(package,1302,1,prompt);
3727 while(attrib == INVALID_FILE_ATTRIBUTES)
3729 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3730 if (rc == IDCANCEL)
3732 rc = ERROR_INSTALL_USEREXIT;
3733 break;
3735 attrib = GetFileAttributesW(package->PackagePath);
3737 msi_free(prompt);
3738 rc = ERROR_SUCCESS;
3740 else
3741 return ERROR_SUCCESS;
3743 return rc;
3746 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3748 HKEY hkey=0;
3749 LPWSTR buffer;
3750 LPWSTR productid;
3751 UINT rc,i;
3753 static const WCHAR szPropKeys[][80] =
3755 {'P','r','o','d','u','c','t','I','D',0},
3756 {'U','S','E','R','N','A','M','E',0},
3757 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3758 {0},
3761 static const WCHAR szRegKeys[][80] =
3763 {'P','r','o','d','u','c','t','I','D',0},
3764 {'R','e','g','O','w','n','e','r',0},
3765 {'R','e','g','C','o','m','p','a','n','y',0},
3766 {0},
3769 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3770 if (!productid)
3771 return ERROR_SUCCESS;
3773 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3774 if (rc != ERROR_SUCCESS)
3775 goto end;
3777 for( i = 0; szPropKeys[i][0]; i++ )
3779 buffer = msi_dup_property( package, szPropKeys[i] );
3780 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3781 msi_free( buffer );
3784 end:
3785 msi_free(productid);
3786 RegCloseKey(hkey);
3788 /* FIXME: call ui_actiondata */
3790 return ERROR_SUCCESS;
3794 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3796 UINT rc;
3798 package->script->InWhatSequence |= SEQUENCE_EXEC;
3799 rc = ACTION_ProcessExecSequence(package,FALSE);
3800 return rc;
3805 * Code based off of code located here
3806 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3808 * Using string index 4 (full font name) instead of 1 (family name)
3810 static LPWSTR load_ttfname_from(LPCWSTR filename)
3812 HANDLE handle;
3813 LPWSTR ret = NULL;
3814 int i;
3816 typedef struct _tagTT_OFFSET_TABLE{
3817 USHORT uMajorVersion;
3818 USHORT uMinorVersion;
3819 USHORT uNumOfTables;
3820 USHORT uSearchRange;
3821 USHORT uEntrySelector;
3822 USHORT uRangeShift;
3823 }TT_OFFSET_TABLE;
3825 typedef struct _tagTT_TABLE_DIRECTORY{
3826 char szTag[4]; /* table name */
3827 ULONG uCheckSum; /* Check sum */
3828 ULONG uOffset; /* Offset from beginning of file */
3829 ULONG uLength; /* length of the table in bytes */
3830 }TT_TABLE_DIRECTORY;
3832 typedef struct _tagTT_NAME_TABLE_HEADER{
3833 USHORT uFSelector; /* format selector. Always 0 */
3834 USHORT uNRCount; /* Name Records count */
3835 USHORT uStorageOffset; /* Offset for strings storage,
3836 * from start of the table */
3837 }TT_NAME_TABLE_HEADER;
3839 typedef struct _tagTT_NAME_RECORD{
3840 USHORT uPlatformID;
3841 USHORT uEncodingID;
3842 USHORT uLanguageID;
3843 USHORT uNameID;
3844 USHORT uStringLength;
3845 USHORT uStringOffset; /* from start of storage area */
3846 }TT_NAME_RECORD;
3848 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3849 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3851 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3852 FILE_ATTRIBUTE_NORMAL, 0 );
3853 if (handle != INVALID_HANDLE_VALUE)
3855 TT_TABLE_DIRECTORY tblDir;
3856 BOOL bFound = FALSE;
3857 TT_OFFSET_TABLE ttOffsetTable;
3858 DWORD dwRead;
3860 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3861 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3862 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3863 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3865 if (ttOffsetTable.uMajorVersion != 1 ||
3866 ttOffsetTable.uMinorVersion != 0)
3867 return NULL;
3869 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3871 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3872 if (strncmp(tblDir.szTag,"name",4)==0)
3874 bFound = TRUE;
3875 tblDir.uLength = SWAPLONG(tblDir.uLength);
3876 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3877 break;
3881 if (bFound)
3883 TT_NAME_TABLE_HEADER ttNTHeader;
3884 TT_NAME_RECORD ttRecord;
3886 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3887 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3888 &dwRead,NULL);
3890 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3891 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3892 bFound = FALSE;
3893 for(i=0; i<ttNTHeader.uNRCount; i++)
3895 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3896 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3897 /* 4 is the Full Font Name */
3898 if(ttRecord.uNameID == 4)
3900 int nPos;
3901 LPSTR buf;
3902 static LPCSTR tt = " (TrueType)";
3904 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3905 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3906 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3907 SetFilePointer(handle, tblDir.uOffset +
3908 ttRecord.uStringOffset +
3909 ttNTHeader.uStorageOffset,
3910 NULL, FILE_BEGIN);
3911 buf = msi_alloc_zero( ttRecord.uStringLength + 1 + strlen(tt) );
3912 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3913 if (strlen(buf) > 0)
3915 strcat(buf,tt);
3916 ret = strdupAtoW(buf);
3917 msi_free(buf);
3918 break;
3921 msi_free(buf);
3922 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3926 CloseHandle(handle);
3928 else
3929 ERR("Unable to open font file %s\n", debugstr_w(filename));
3931 TRACE("Returning fontname %s\n",debugstr_w(ret));
3932 return ret;
3935 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3937 MSIPACKAGE *package = (MSIPACKAGE*)param;
3938 LPWSTR name;
3939 LPCWSTR filename;
3940 MSIFILE *file;
3941 static const WCHAR regfont1[] =
3942 {'S','o','f','t','w','a','r','e','\\',
3943 'M','i','c','r','o','s','o','f','t','\\',
3944 'W','i','n','d','o','w','s',' ','N','T','\\',
3945 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3946 'F','o','n','t','s',0};
3947 static const WCHAR regfont2[] =
3948 {'S','o','f','t','w','a','r','e','\\',
3949 'M','i','c','r','o','s','o','f','t','\\',
3950 'W','i','n','d','o','w','s','\\',
3951 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3952 'F','o','n','t','s',0};
3953 HKEY hkey1;
3954 HKEY hkey2;
3955 MSIRECORD *uirow;
3956 LPWSTR uipath, p;
3958 filename = MSI_RecordGetString( row, 1 );
3959 file = get_loaded_file( package, filename );
3960 if (!file)
3962 ERR("Unable to load file\n");
3963 return ERROR_SUCCESS;
3966 /* check to make sure that component is installed */
3967 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3969 TRACE("Skipping: Component not scheduled for install\n");
3970 return ERROR_SUCCESS;
3973 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3974 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3976 if (MSI_RecordIsNull(row,2))
3977 name = load_ttfname_from( file->TargetPath );
3978 else
3979 name = msi_dup_record_field(row,2);
3981 if (name)
3983 msi_reg_set_val_str( hkey1, name, file->FileName );
3984 msi_reg_set_val_str( hkey2, name, file->FileName );
3987 msi_free(name);
3988 RegCloseKey(hkey1);
3989 RegCloseKey(hkey2);
3991 /* the UI chunk */
3992 uirow = MSI_CreateRecord( 1 );
3993 uipath = strdupW( file->TargetPath );
3994 p = strrchrW(uipath,'\\');
3995 if (p) p++;
3996 else p = uipath;
3997 MSI_RecordSetStringW( uirow, 1, p );
3998 ui_actiondata( package, szRegisterFonts, uirow);
3999 msiobj_release( &uirow->hdr );
4000 msi_free( uipath );
4001 /* FIXME: call ui_progress? */
4003 return ERROR_SUCCESS;
4006 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
4008 UINT rc;
4009 MSIQUERY * view;
4010 static const WCHAR ExecSeqQuery[] =
4011 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4012 '`','F','o','n','t','`',0};
4014 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4015 if (rc != ERROR_SUCCESS)
4017 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4018 return ERROR_SUCCESS;
4021 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4022 msiobj_release(&view->hdr);
4024 return ERROR_SUCCESS;
4027 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4029 MSIPACKAGE *package = (MSIPACKAGE*)param;
4030 LPCWSTR compgroupid=NULL;
4031 LPCWSTR feature=NULL;
4032 LPCWSTR text = NULL;
4033 LPCWSTR qualifier = NULL;
4034 LPCWSTR component = NULL;
4035 LPWSTR advertise = NULL;
4036 LPWSTR output = NULL;
4037 HKEY hkey;
4038 UINT rc = ERROR_SUCCESS;
4039 MSICOMPONENT *comp;
4040 DWORD sz = 0;
4041 MSIRECORD *uirow;
4043 component = MSI_RecordGetString(rec,3);
4044 comp = get_loaded_component(package,component);
4046 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4047 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4048 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4050 TRACE("Skipping: Component %s not scheduled for install\n",
4051 debugstr_w(component));
4053 return ERROR_SUCCESS;
4056 compgroupid = MSI_RecordGetString(rec,1);
4057 qualifier = MSI_RecordGetString(rec,2);
4059 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4060 if (rc != ERROR_SUCCESS)
4061 goto end;
4063 text = MSI_RecordGetString(rec,4);
4064 feature = MSI_RecordGetString(rec,5);
4066 advertise = create_component_advertise_string(package, comp, feature);
4068 sz = strlenW(advertise);
4070 if (text)
4071 sz += lstrlenW(text);
4073 sz+=3;
4074 sz *= sizeof(WCHAR);
4076 output = msi_alloc_zero(sz);
4077 strcpyW(output,advertise);
4078 msi_free(advertise);
4080 if (text)
4081 strcatW(output,text);
4083 msi_reg_set_val_multi_str( hkey, qualifier, output );
4085 end:
4086 RegCloseKey(hkey);
4087 msi_free(output);
4089 /* the UI chunk */
4090 uirow = MSI_CreateRecord( 2 );
4091 MSI_RecordSetStringW( uirow, 1, compgroupid );
4092 MSI_RecordSetStringW( uirow, 2, qualifier);
4093 ui_actiondata( package, szPublishComponents, uirow);
4094 msiobj_release( &uirow->hdr );
4095 /* FIXME: call ui_progress? */
4097 return rc;
4101 * At present I am ignorning the advertised components part of this and only
4102 * focusing on the qualified component sets
4104 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4106 UINT rc;
4107 MSIQUERY * view;
4108 static const WCHAR ExecSeqQuery[] =
4109 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4110 '`','P','u','b','l','i','s','h',
4111 'C','o','m','p','o','n','e','n','t','`',0};
4113 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4114 if (rc != ERROR_SUCCESS)
4115 return ERROR_SUCCESS;
4117 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4118 msiobj_release(&view->hdr);
4120 return rc;
4123 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4124 LPCSTR action, LPCWSTR table )
4126 static const WCHAR query[] = {
4127 'S','E','L','E','C','T',' ','*',' ',
4128 'F','R','O','M',' ','`','%','s','`',0 };
4129 MSIQUERY *view = NULL;
4130 DWORD count = 0;
4131 UINT r;
4133 r = MSI_OpenQuery( package->db, &view, query, table );
4134 if (r == ERROR_SUCCESS)
4136 r = MSI_IterateRecords(view, &count, NULL, package);
4137 msiobj_release(&view->hdr);
4140 if (count)
4141 FIXME("%s -> %lu ignored %s table values\n",
4142 action, count, debugstr_w(table));
4144 return ERROR_SUCCESS;
4147 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4149 TRACE("%p\n", package);
4150 return ERROR_SUCCESS;
4153 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4155 static const WCHAR table[] =
4156 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4157 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4160 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4162 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4163 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4166 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4168 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4169 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4172 static UINT ACTION_BindImage( MSIPACKAGE *package )
4174 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4175 return msi_unimplemented_action_stub( package, "BindImage", table );
4178 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4180 static const WCHAR table[] = {
4181 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4182 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4185 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4187 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4188 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4191 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4193 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4194 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4197 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4199 static const WCHAR table[] = {
4200 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4201 return msi_unimplemented_action_stub( package, "InstallServices", table );
4204 static UINT ACTION_StartServices( MSIPACKAGE *package )
4206 static const WCHAR table[] = {
4207 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4208 return msi_unimplemented_action_stub( package, "StartServices", table );
4211 static UINT ACTION_StopServices( MSIPACKAGE *package )
4213 static const WCHAR table[] = {
4214 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4215 return msi_unimplemented_action_stub( package, "StopServices", table );
4218 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4220 static const WCHAR table[] = {
4221 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4222 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4225 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4227 static const WCHAR table[] = {
4228 'E','n','v','i','r','o','n','m','e','n','t',0 };
4229 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4232 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4234 static const WCHAR table[] = {
4235 'E','n','v','i','r','o','n','m','e','n','t',0 };
4236 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4239 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4241 static const WCHAR table[] = {
4242 'M','s','i','A','s','s','e','m','b','l','y',0 };
4243 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4246 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4248 static const WCHAR table[] = {
4249 'M','s','i','A','s','s','e','m','b','l','y',0 };
4250 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4253 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4255 static const WCHAR table[] = { 'F','o','n','t',0 };
4256 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4259 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4261 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4262 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4265 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4267 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4268 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4271 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4273 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4274 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4277 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4279 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4280 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4283 static struct _actions StandardActions[] = {
4284 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4285 { szAppSearch, ACTION_AppSearch },
4286 { szBindImage, ACTION_BindImage },
4287 { szCCPSearch, ACTION_CCPSearch},
4288 { szCostFinalize, ACTION_CostFinalize },
4289 { szCostInitialize, ACTION_CostInitialize },
4290 { szCreateFolders, ACTION_CreateFolders },
4291 { szCreateShortcuts, ACTION_CreateShortcuts },
4292 { szDeleteServices, ACTION_DeleteServices },
4293 { szDisableRollback, NULL},
4294 { szDuplicateFiles, ACTION_DuplicateFiles },
4295 { szExecuteAction, ACTION_ExecuteAction },
4296 { szFileCost, ACTION_FileCost },
4297 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4298 { szForceReboot, ACTION_ForceReboot },
4299 { szInstallAdminPackage, NULL},
4300 { szInstallExecute, ACTION_InstallExecute },
4301 { szInstallExecuteAgain, ACTION_InstallExecute },
4302 { szInstallFiles, ACTION_InstallFiles},
4303 { szInstallFinalize, ACTION_InstallFinalize },
4304 { szInstallInitialize, ACTION_InstallInitialize },
4305 { szInstallSFPCatalogFile, NULL},
4306 { szInstallValidate, ACTION_InstallValidate },
4307 { szIsolateComponents, ACTION_IsolateComponents },
4308 { szLaunchConditions, ACTION_LaunchConditions },
4309 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4310 { szMoveFiles, ACTION_MoveFiles },
4311 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4312 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4313 { szInstallODBC, NULL},
4314 { szInstallServices, ACTION_InstallServices },
4315 { szPatchFiles, ACTION_PatchFiles },
4316 { szProcessComponents, ACTION_ProcessComponents },
4317 { szPublishComponents, ACTION_PublishComponents },
4318 { szPublishFeatures, ACTION_PublishFeatures },
4319 { szPublishProduct, ACTION_PublishProduct },
4320 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4321 { szRegisterComPlus, ACTION_RegisterComPlus},
4322 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4323 { szRegisterFonts, ACTION_RegisterFonts },
4324 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4325 { szRegisterProduct, ACTION_RegisterProduct },
4326 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4327 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4328 { szRegisterUser, ACTION_RegisterUser},
4329 { szRemoveDuplicateFiles, NULL},
4330 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4331 { szRemoveExistingProducts, NULL},
4332 { szRemoveFiles, ACTION_RemoveFiles},
4333 { szRemoveFolders, NULL},
4334 { szRemoveIniValues, ACTION_RemoveIniValues },
4335 { szRemoveODBC, NULL},
4336 { szRemoveRegistryValues, NULL},
4337 { szRemoveShortcuts, NULL},
4338 { szResolveSource, ACTION_ResolveSource},
4339 { szRMCCPSearch, ACTION_RMCCPSearch},
4340 { szScheduleReboot, NULL},
4341 { szSelfRegModules, ACTION_SelfRegModules },
4342 { szSelfUnregModules, ACTION_SelfUnregModules },
4343 { szSetODBCFolders, NULL},
4344 { szStartServices, ACTION_StartServices },
4345 { szStopServices, ACTION_StopServices },
4346 { szUnpublishComponents, NULL},
4347 { szUnpublishFeatures, NULL},
4348 { szUnregisterClassInfo, NULL},
4349 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4350 { szUnregisterExtensionInfo, NULL},
4351 { szUnregisterFonts, ACTION_UnregisterFonts },
4352 { szUnregisterMIMEInfo, NULL},
4353 { szUnregisterProgIdInfo, NULL},
4354 { szUnregisterTypeLibraries, NULL},
4355 { szValidateProductID, NULL},
4356 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4357 { szWriteIniValues, ACTION_WriteIniValues },
4358 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4359 { NULL, NULL},